From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM10-DM6-obe.outbound.protection.outlook.com (mail-dm6nam10on2054.outbound.protection.outlook.com [40.107.93.54]) by sourceware.org (Postfix) with ESMTPS id D42BB382C401 for ; Fri, 28 Jan 2022 14:32:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D42BB382C401 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Xo20LpP5j/VWnAt46ihWBNrt9a6QOmw/OFukVZGbG2EnO4eee6x8MGZzarc0yOhbBGBLTpOXrzvXVS79nuGm/WPxKPJ7T1gRGNZiQq34PCXrvOXYJfG2TLdikRvsB/qFktGebKB61Hl7/8SUWSfyChOuNEDawQw0IjmEF/KBeaWcfpO87JOq5xsnplqZxvYvN9kFOjwVi2DrkXCrW3E+hDb/h9RQ1T0Ls6Bd+wkSx+6dYyeOylmApFogN0Akbxa1SZX1zQzKhHBBfBbl15w/JB2OhHXUAZTjggq281fllaTSYQFGvk2Duc64JQS+H9uvyRbTq48DIVaaEDcDeAx0eA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=YUsi8Cs3l2VLJa6Nb8XVIxq7AxiUhxxxTpj9JeAf92I=; b=ExDBbJ2ttCV6h1532yPb+RfOLwDdcc1ZmptNKasFSVKdBhNkWMSjUll0281hHCyzw7m+lgH6xmGGM/kMraPt1XUrczddyAHEKAH6kONLllANit51+a+LIrUa2Zh015E8AXtUPCmHzwb/qh0rXLJ/x1mpzNLJZvE1rRboXn5cmWeUPAL++W8vgzfo7kl4Q+tcTb3iDe9KAvxePod9zD7sh+FyR6flMQigASQ+NTgWEr3R6GhVTpvQXie+e+JDXh+jIlle5DmRkZlGc8JJkR4S/iObxF6BZDVcZ5Ni8yiWv0Sd2WVImGlcM2eDB3/911ZdKRQMJ8q3Kr5+ij7U6f1/sg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=sourceware.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none Received: from DM6PR01CA0001.prod.exchangelabs.com (2603:10b6:5:296::6) by DM6PR12MB2793.namprd12.prod.outlook.com (2603:10b6:5:4f::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4930.17; Fri, 28 Jan 2022 14:32:27 +0000 Received: from DM6NAM11FT065.eop-nam11.prod.protection.outlook.com (2603:10b6:5:296:cafe::2c) by DM6PR01CA0001.outlook.office365.com (2603:10b6:5:296::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4930.17 via Frontend Transport; Fri, 28 Jan 2022 14:32:27 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; Received: from SATLEXMB04.amd.com (165.204.84.17) by DM6NAM11FT065.mail.protection.outlook.com (10.13.172.109) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4930.15 via Frontend Transport; Fri, 28 Jan 2022 14:32:27 +0000 Received: from node-bp126-r03c.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.18; Fri, 28 Jan 2022 08:32:17 -0600 From: Lancelot SIX To: CC: , Lancelot SIX Subject: [PATCH v2 2/2] gdb: Respect the DW_CC_nocall attribute Date: Fri, 28 Jan 2022 08:29:31 -0600 Message-ID: <20220128142931.39750-3-lancelot.six@amd.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220128142931.39750-1-lancelot.six@amd.com> References: <20220128142931.39750-1-lancelot.six@amd.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: SATLEXMB03.amd.com (10.181.40.144) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 5f50235c-71c1-4bc6-80bf-08d9e26b024b X-MS-TrafficTypeDiagnostic: DM6PR12MB2793:EE_ X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:4941; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: SDhrqsKtsMsPEHBPo1d10xRqK+8af2ZN8We1tvwMN1cN0gpLcM4C/X0hgo55MI6LulBLgnWdNdXpuA1vJYnO7GxykS/aFoF2i/7EEnBui1tYGNq8gpdN8bgKiz8ORbrlG/DZGDsG0yDk8BEMGAIRLkactg3VOxBPbMixPmeci73G6oB98j6nfkhV6diNLipiTgCeP9ZpMxyyb7nfeNGOhpsjYWOGV87WsGe+6ZZ8BlvOu2+3L1u02/0dKuN5972Uihu7/e+6DH+ZPIUeUIX7/ciU6WjkGDjJVhboIapnavxxJYqM5YmC99vm3++UosDG2BxYZC6NkOUBUbwah7JTQ94vCMdsCdOXR+qoJtLjJHiEO0GPrB5igxpjSJp9j46ZdN+LQYnCGXblHDDpJzwdXzzLwCPUCfBrSbDKmCLHRiBqt8OYl8Kq3wWijPVtrwOmQVVq3y+lgI4+nIcz1kgUbPuAzEQt3IOrWYnHI9AQZcEqKtwKUVGqlnLPzhTyGFkIf0X9n4WOSEiQXe63r4UOd3cR57XWmdxVGrHnTBnGSKNRnkt5Z9d8yZ4UABxL6yGslzWadhKflzNX5nZl4QPBR44PLvz2GnkEL0GdSmtWIdam1gEX4VUL8nuWGJAW0DNkh+Hzp8VfYf4f+Edhkf+ijd/ZoFgmxEYDU1YRx+885plmfEabyDCmY+JnMenK9cQ3f522gpIIsdAfzPiiYID3GQunhOxCNYykRsLn07dSjGfWvAiGPBMXUUDXqVAw9tmgnV+2QLTcvO99056dxBfdk9XDmIlWYK61Nc85JsH1JxBmHW4Lk4jOeNHCXe1yS2ap X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230001)(4636009)(46966006)(40470700004)(36840700001)(70586007)(70206006)(26005)(186003)(1076003)(16526019)(6916009)(54906003)(5660300002)(426003)(4326008)(8676002)(316002)(356005)(82310400004)(8936002)(81166007)(336012)(6666004)(83380400001)(2616005)(86362001)(30864003)(47076005)(40460700003)(36860700001)(7696005)(36756003)(2906002)(508600001)(2004002)(36900700001)(20210929001); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jan 2022 14:32:27.6422 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 5f50235c-71c1-4bc6-80bf-08d9e26b024b X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT065.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR12MB2793 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Jan 2022 14:32:32 -0000 It is possible for a compiler to optimize a function in a such ways that the function does not follow the calling convention of the target. In such situation, the compiler can use the DW_AT_calling_convention attribute with the value DW_CC_nocall to tell the debugger that it is unsafe to call the function. The DWARF5 standard states, in 3.3.1.1: > If the value of the calling convention attribute is the constant > DW_CC_nocall, the subroutine does not obey standard calling > conventions, and it may not be safe for the debugger to call this > subroutine. Non standard calling convention can affect GDB's assumptions in multiple ways, including how arguments are passed to the function, how values are returned, and so on. For this reason, it is unsafe for GDB to try to do the following operations on a function with marked with DW_CC_nocall: - call / print an expression requiring the function to be evaluated, - inspect the value a function returns using the 'finish' command, - force the value returned by a function using the 'return' command. This patch ensures that if a command which relies on GDB's knowledge of the target's calling convention is used on a function marked nocall, GDB prints an appropriate message to the user and does not proceed with the operation which is unreliable. Note that it is still possible for someone to use a vendor specific value for the DW_AT_calling_convention attribute for example to indicate the use of an alternative calling convention. This commit does not prevent this, and target dependent code can be adjusted if one wanted to support multiple calling conventions. Tested on x86_64-Linux, with no regression observed. Change-Id: I72970dae68234cb83edbc0cf71aa3d6002a4a540 --- gdb/gdbtypes.c | 11 +++ gdb/gdbtypes.h | 9 ++ gdb/infcall.c | 5 + gdb/infcmd.c | 19 ++++ gdb/stack.c | 16 ++- gdb/testsuite/gdb.dwarf2/calling-convention.c | 36 +++++++ .../gdb.dwarf2/calling-convention.exp | 97 +++++++++++++++++++ 7 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/calling-convention.c create mode 100644 gdb/testsuite/gdb.dwarf2/calling-convention.exp diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 8af96c79e6c..0c2586e28f2 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -3903,6 +3903,17 @@ type_byte_order (const struct type *type) return byteorder; } +/* See gdbtypes.h. */ + +bool +is_nocall_function (const struct type *type) +{ + gdb_assert (type->code () == TYPE_CODE_FUNC + || type->code () == TYPE_CODE_METHOD); + + return TYPE_CALLING_CONVENTION (type) == DW_CC_nocall; +} + /* Overload resolution. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 7238873e4db..c8c45fa2817 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -2852,4 +2852,13 @@ extern enum bfd_endian type_byte_order (const struct type *type); extern unsigned int overload_debug; +/* The function is marked as unsafe to call by the debugger. + + This usually indicates that the function does not follow the target's + standard calling convention. + + The TYPE argument must be of code TYPE_CODE_FUNC or TYPE_CODE_METHOD. */ + +extern bool is_nocall_function (const struct type *type); + #endif /* GDBTYPES_H */ diff --git a/gdb/infcall.c b/gdb/infcall.c index 571e790fbee..f2afe0d35e0 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -775,6 +775,11 @@ call_function_by_hand_dummy (struct value *function, type *values_type; CORE_ADDR funaddr = find_function_addr (function, &values_type, &ftype); + if (is_nocall_function (ftype)) + error (_("Cannot call the function '%s' which does not follow the " + "target calling convention."), + get_function_name (funaddr, name_buf, sizeof (name_buf))); + if (values_type == NULL) values_type = default_return_type; if (values_type == NULL) diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 994dd5b32a3..186b1a2024a 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1419,6 +1419,25 @@ get_return_value (struct value *function, struct type *value_type) value_type = check_typedef (value_type); gdb_assert (value_type->code () != TYPE_CODE_VOID); + if (is_nocall_function (check_typedef (::value_type (function)))) + { + CORE_ADDR funaddr = value_address (function); + const char *fname = nullptr; + char buf[RAW_FUNCTION_ADDRESS_SIZE]; + if (funaddr != 0) + fname = get_function_name (funaddr, buf, sizeof (buf)); + + if (fname != nullptr) + warning (_("The function '%s' does not follow the target calling " + "convention, cannot determine its returned value."), + fname); + else + warning (_("Cannot determine the return value of a function which " + "does not follow the target's calling convention.")); + + return nullptr; + } + /* FIXME: 2003-09-27: When returning from a nested inferior function call, it's possible (with no help from the architecture vector) to locate and return/print a "struct return" value. This is just diff --git a/gdb/stack.c b/gdb/stack.c index c7269e2ac32..e95459d7767 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -2737,7 +2737,7 @@ return_command (const char *retval_exp, int from_tty) struct symbol *thisfun; struct value *return_value = NULL; struct value *function = NULL; - const char *query_prefix = ""; + std::string query_prefix; thisframe = get_selected_frame ("No selected frame."); thisfun = get_frame_function (thisframe); @@ -2793,6 +2793,15 @@ return_command (const char *retval_exp, int from_tty) return_value = NULL; else if (thisfun != NULL) { + if (is_nocall_function (check_typedef (value_type (function)))) + query_prefix + = string_printf ("The function ’%s’ does not follow the target " + "calling convention.\n" + "If you continue, setting the return value " + "will probably lead to unpredictable " + "behaviors.\n", + thisfun->print_name ()); + rv_conv = struct_return_convention (gdbarch, function, return_type); if (rv_conv == RETURN_VALUE_STRUCT_CONVENTION || rv_conv == RETURN_VALUE_ABI_RETURNS_ADDRESS) @@ -2815,12 +2824,13 @@ return_command (const char *retval_exp, int from_tty) if (thisfun == NULL) confirmed = query (_("%sMake selected stack frame return now? "), - query_prefix); + query_prefix.c_str ()); else { if (TYPE_NO_RETURN (thisfun->type)) warning (_("Function does not return normally to caller.")); - confirmed = query (_("%sMake %s return now? "), query_prefix, + confirmed = query (_("%sMake %s return now? "), + query_prefix.c_str (), thisfun->print_name ()); } if (!confirmed) diff --git a/gdb/testsuite/gdb.dwarf2/calling-convention.c b/gdb/testsuite/gdb.dwarf2/calling-convention.c new file mode 100644 index 00000000000..48c71185a1f --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/calling-convention.c @@ -0,0 +1,36 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Dummy foo function. */ + +int +foo () +{ + asm ("foo_label: .globl foo_label"); + return 42; +} + +/* Dummy main function. */ + +int +main() +{ + asm ("main_label: .globl main_label"); + foo (); + return 0; +} + diff --git a/gdb/testsuite/gdb.dwarf2/calling-convention.exp b/gdb/testsuite/gdb.dwarf2/calling-convention.exp new file mode 100644 index 00000000000..0e77396d553 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/calling-convention.exp @@ -0,0 +1,97 @@ +# Copyright 2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This testcase checks that if a function has the DW_AT_calling_convention +# attribute with the value DW_CC_nocall, then will not: +# - call the function, +# - try to access the value returned by the function when using the finish +# command, +# - force a user-provided return value when using the return command. +# +# In every case, GDB prints a message to the user indicating the issue. For +# the return command, GDB asks the user to confirm if the specified value +# should be forced. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile .c .S + +# First compile the .c file so we can ask GDB what is sizeof(int). +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { + untested "failed to compile" + return -1 +} + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + compile_unit { + {language @DW_LANG_C} + {name "calling-convention"} + } { + declare_labels int_label + + int_label: base_type { + {byte_size [get_sizeof "int" 4] sdata} + {encoding @DW_ATE_signed} + {name "int"} + } + + subprogram { + {MACRO_AT_func { foo }} + {type :$int_label} + {calling_convention @DW_CC_nocall} + } + + subprogram { + {MACRO_AT_func { main }} + {type :$int_label} + } + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "call foo ()" \ + "Cannot call the function 'foo' which does not follow the target calling convention." +gdb_breakpoint "foo" +gdb_continue_to_breakpoint "foo" + +gdb_test_multiple "return 35" "" { + -re ".*The function ’foo’ does not follow the target calling convention.\r\nIf you continue, setting the return value will probably lead to unpredictable behaviors.\r\nMake foo return now?.*\\(y or n\\) $" { + send_gdb "n\n" + pass $gdb_test_name + } +} + +gdb_test "finish" [multi_line \ + "Run till exit from #0 $hex in foo \\(\\)" \ + "warning: The function 'foo' does not follow the target calling convention, cannot determine its returned value\." \ + "$hex in main \\(\\)" \ + "Value returned has type: int. Cannot determine contents"] -- 2.25.1