From patchwork Tue Apr 11 04:26:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Machado X-Patchwork-Id: 67609 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C48A23854144 for ; Tue, 11 Apr 2023 04:29:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C48A23854144 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1681187384; bh=/bV5YknSyCpwG1qVGGm5Xe+n772XkimNn+sW8aZNYdg=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=eydY6xBghty1c+3gAoZuhh+jTZmnFLyv4f103qX8GS0TPSFhpsj6fE9irfqFRlKE4 ZYHVD8ZMsFnArkJh2f/b8U4nRYeCzYvW3PNPILPM+SGQp0j5G3l2lWo0wycQJboHHM Mx6tZdb3b0OpbaPw38Cd9WHav7+6qHdTZJQUPCrY= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from EUR02-AM0-obe.outbound.protection.outlook.com (mail-am0eur02on2075.outbound.protection.outlook.com [40.107.247.75]) by sourceware.org (Postfix) with ESMTPS id 9BF173858D28 for ; Tue, 11 Apr 2023 04:27:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9BF173858D28 Received: from AS8PR04CA0004.eurprd04.prod.outlook.com (2603:10a6:20b:310::9) by DB9PR08MB9610.eurprd08.prod.outlook.com (2603:10a6:10:454::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6277.34; Tue, 11 Apr 2023 04:27:26 +0000 Received: from AM7EUR03FT013.eop-EUR03.prod.protection.outlook.com (2603:10a6:20b:310:cafe::e9) by AS8PR04CA0004.outlook.office365.com (2603:10a6:20b:310::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6277.40 via Frontend Transport; Tue, 11 Apr 2023 04:27:26 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by AM7EUR03FT013.mail.protection.outlook.com (100.127.140.191) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6298.28 via Frontend Transport; Tue, 11 Apr 2023 04:27:26 +0000 Received: ("Tessian outbound 8b05220b4215:v136"); Tue, 11 Apr 2023 04:27:26 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: e858b75013e621ad X-CR-MTA-TID: 64aa7808 Received: from 07c47421e7c3.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id DDD650A8-36D9-4D68-AF5C-805FACA4C4DC.1; Tue, 11 Apr 2023 04:27:19 +0000 Received: from EUR05-AM6-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 07c47421e7c3.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Tue, 11 Apr 2023 04:27:19 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=k86qvUc46c7IKEHGiYWInc1t3A5tuCdev8yvJiYuE8yzNLaqaeFHB0ptpowKzRlqcMBJr6gIthisLoADXNFuIkdFEzwvR4aCPX9kotQSDbapKc6WaYTqm9xLKQz0yaujX+QI4baK4SqE1Vzk3w3Dx3kA5E+5jbObIUpLO0Sqp52zKhwiJBlSbUqZ1nW4qNg3f3CtOMz5d217FGmlvxI+12PaJAB7MkT18ySBermzJYkkgK0pLNFRxBQ9ArzrSZX9GF0bQuIXEoxhP/vGS83XnBZbvc51Lk1VkHvBlaG/5/Ynkmd1R1XEcaoLj7iDK9BGou413r2Bmiy22CrjmR7D2A== 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=/bV5YknSyCpwG1qVGGm5Xe+n772XkimNn+sW8aZNYdg=; b=QOL1M1BJZuui3VbwubUaeWHeX93MKhoJ2OtrVX1cPL2VxhN070tRPmca3GIhUwzApioFW2AkWT9LCpognGcWapnrFPBADSHTOISxzsk0kvowxLAgtmipEBZwHFeiuZLSEtmFop4zTjPb9ob6C3yDsCCuq6PK2B4devMttgA8P9pz+KtqBzQ46Yjr76iF9XiNoayS1iiiOd7+BG7h2ZgtIOPIYK8nQs8NUnnaB82/U7i67erGH+g5lFhDawqU8cQiVj6Wem9mHObongsCQgt9gKdp33P4U5D7fMaGft64J3AnDW2IZKFbJoiX0nAX2B7dweJq7oQ6UqA/JOzgef/1RQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 40.67.248.234) smtp.rcpttodomain=sourceware.org smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=none (message not signed); arc=none Received: from AS9PR06CA0427.eurprd06.prod.outlook.com (2603:10a6:20b:49e::7) by PAXPR08MB6720.eurprd08.prod.outlook.com (2603:10a6:102:130::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6277.38; Tue, 11 Apr 2023 04:27:07 +0000 Received: from AM7EUR03FT037.eop-EUR03.prod.protection.outlook.com (2603:10a6:20b:49e:cafe::65) by AS9PR06CA0427.outlook.office365.com (2603:10a6:20b:49e::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6277.39 via Frontend Transport; Tue, 11 Apr 2023 04:27:07 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 40.67.248.234) smtp.mailfrom=arm.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 40.67.248.234 as permitted sender) receiver=protection.outlook.com; client-ip=40.67.248.234; helo=nebula.arm.com; pr=C Received: from nebula.arm.com (40.67.248.234) by AM7EUR03FT037.mail.protection.outlook.com (100.127.140.225) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.6298.27 via Frontend Transport; Tue, 11 Apr 2023 04:27:07 +0000 Received: from AZ-NEU-EX02.Emea.Arm.com (10.251.26.5) by AZ-NEU-EX04.Arm.com (10.251.24.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.17; Tue, 11 Apr 2023 04:27:07 +0000 Received: from AZ-NEU-EX03.Arm.com (10.251.24.31) by AZ-NEU-EX02.Emea.Arm.com (10.251.26.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.17; Tue, 11 Apr 2023 04:27:06 +0000 Received: from e129171.arm.com (10.57.80.123) by mail.arm.com (10.251.24.31) with Microsoft SMTP Server id 15.1.2507.17 via Frontend Transport; Tue, 11 Apr 2023 04:27:06 +0000 To: Subject: [PATCH 15/17] [gdb/aarch64] sme: Core file support for Linux Date: Tue, 11 Apr 2023 05:26:56 +0100 Message-ID: <20230411042658.1852730-16-luis.machado@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230411042658.1852730-1-luis.machado@arm.com> References: <20230411042658.1852730-1-luis.machado@arm.com> MIME-Version: 1.0 X-EOPAttributedMessage: 1 X-MS-TrafficTypeDiagnostic: AM7EUR03FT037:EE_|PAXPR08MB6720:EE_|AM7EUR03FT013:EE_|DB9PR08MB9610:EE_ X-MS-Office365-Filtering-Correlation-Id: 7467910a-ce4b-4de6-6377-08db3a450dfe x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: XdHqTB6enY9IC5P0Hdr4JHtnj6o5E1Zj5e+KMUriDoTMQKu/FjGpV0CRaX8hYZXlmNOym/3pF5vlyOO46EP1Uwr78M1mMMQkiTSxYcX/M6ErKTv6fTEBk+KG5U5PwdU4iYe9V04ScRv2RUIhJTfaRT+WCsFv73dpTk7MBJlbsFygze6BVorrEmsUbqlSsgMefP7kFW4lJvdoQ0LPCYRsKpCE76J4cz484jT8ofAQ9Nxql/+uk/d8Y+GEopiFiVPCcDHDLUEDKmKwc7qAEaG8zPy1j67IGXiBcQrnvrvQMcofpybjFONOsaGvaReJ9Cakv1idRmoYk0JGssdBR6JFbe/nFmZuDkyEQc+QP1g644sTYIgrKLPuO8pVGuWagNXkG2A2UkxQu+eqPgt7hQpowFoXP55R8wX8sAxaS0CgJ8PGLXdJDcXAizXCNprXxZ0Hkle6170zI0xTHXbZHe+rngJyZS5SCO3rWCS1QEZfvm6QmYQOsZ6FtOAHhRFZsmLnVyEohdCcL+jeGvhFBruWOHAUH08160BRD4zsl/poO/U+eMh9uFYjYPoaDXU7M2/zNhIK4X1sChQUlt+PjVmR7ojWlZoLleE6GSR7zhe/XhgeTIzlcTPlPFGGvbQ8no24FmzQwzP8cp4KPGd+x3FotJH0eH/nrSrkF7YwDehIzgge/zSrwVYcvNgMKLEQlX8h X-Forefront-Antispam-Report-Untrusted: CIP:40.67.248.234; CTRY:IE; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:nebula.arm.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230028)(4636009)(346002)(396003)(376002)(39860400002)(136003)(451199021)(46966006)(36840700001)(7696005)(478600001)(1076003)(316002)(26005)(44832011)(186003)(6666004)(2906002)(30864003)(5660300002)(70206006)(70586007)(41300700001)(8676002)(6916009)(82310400005)(8936002)(81166007)(356005)(82740400003)(40480700001)(86362001)(83380400001)(36756003)(47076005)(2616005)(426003)(36860700001)(336012)(36900700001); DIR:OUT; SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR08MB6720 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AM7EUR03FT013.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: 81235ffa-e886-4ac0-edda-08db3a4502af X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: qIQ/yPBA0FNO7ezFqWVwuAPc6QFG8Q0/y22ljIPvgqDkv728Xv8Oi6EybJ0HJ5D87wTNi1p1dSLMiY3Ac71b9kpuU67b5Yck0gXAs+zHWGEAOBLyethmzaHhD1cYRuqQfNe2DOUYPsS9pPT15J9s5N0m86xxLiz3f5mUWPDrIZLwc+HvPkD3R6nvuF9BgjUO9xWMh/ZMVvXoZBX52dglw38hHwNl7byRqDZuunWk9N/YCy8r+KNKYb1Wyijyu1Ed2fUut3bJgV3bR3eA3INEt91y19kQspDKLcqLDRHKpJHGVvdX0jUonQ0U4Kic6w7H89eosZfU0MmPHgXW0G9S60TXb+npzB8H3AF5tGRSTvg6MzpoIBX526pgJZPrPSvC0pGPOXmSmaa8/dVF/Y2l8kx0ZoVgD0ewSACOwOjasCmnPrQ81yGEbFCSLjEfLfiwshMqkbFSyCzLIH0+DZlhjMNFwoTECYho2rXIMAORs78eGcsMX1ajhCRcyz3HyER3c7FDO7cHtr3WE4bT4fCi6kpdYgxlBLjjTasykyilPBkaegxL3QTbGfNRpESGPr3kDtOIxX7jS0fCZQjGPiYxb03yp1wAUhfqqK5rYxi0hkpIAXDHbHoib4lK3GbjbtFZzUYpPcPG3ZMlybyzKAHTkfCFEcZbBgX0EUjDmwGWwF1Sn2o/cQREMyExcXaFAnl5 X-Forefront-Antispam-Report: CIP:63.35.35.123; CTRY:IE; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:64aa7808-outbound-1.mta.getcheckrecipient.com; PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com; CAT:NONE; SFS:(13230028)(4636009)(346002)(136003)(396003)(376002)(39860400002)(451199021)(40470700004)(46966006)(36840700001)(8676002)(86362001)(40480700001)(336012)(83380400001)(36860700001)(2616005)(47076005)(478600001)(7696005)(6666004)(26005)(426003)(316002)(186003)(1076003)(2906002)(30864003)(5660300002)(81166007)(40460700003)(82740400003)(44832011)(6916009)(70586007)(70206006)(41300700001)(82310400005)(8936002)(36756003); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 Apr 2023 04:27:26.4362 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7467910a-ce4b-4de6-6377-08db3a450dfe X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d; Ip=[63.35.35.123]; Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: AM7EUR03FT013.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR08MB9610 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_NONE, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_NONE, TXREP, UNPARSEABLE_RELAY 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: 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-Patchwork-Original-From: Luis Machado via Gdb-patches From: Luis Machado Reply-To: Luis Machado Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This patch enables dumping SME state via gdb's gcore command and also enables gdb to read SME state from a core file generated by the Linux Kernel. Regression-tested on aarch64-linux Ubuntu 22.04/20.04. --- gdb/aarch64-linux-tdep.c | 532 ++++++++++++++++++++++++++++-- gdb/arch/aarch64-scalable-linux.c | 34 ++ gdb/arch/aarch64-scalable-linux.h | 15 + 3 files changed, 548 insertions(+), 33 deletions(-) diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 7ce34ee6846..0bd75daa994 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -57,6 +57,10 @@ #include "elf/common.h" #include "elf/aarch64.h" +#include "arch/aarch64-insn.h" + +/* For std::sqrt */ +#include /* Signal frame handling. @@ -743,50 +747,55 @@ const struct regset aarch64_linux_fpregset = #define SVE_HEADER_FLAG_SVE 1 -/* Get VQ value from SVE section in the core dump. */ +/* Get the vector quotient (VQ) or streaming vector quotient (SVQ) value + from the section named SECTION_NAME. + + Return non-zero if successful and 0 otherwise. */ static uint64_t -aarch64_linux_core_read_vq (struct gdbarch *gdbarch, bfd *abfd) +aarch64_linux_core_read_vq (struct gdbarch *gdbarch, bfd *abfd, + const char *section_name) { - gdb_byte header[SVE_HEADER_SIZE]; - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - asection *sve_section = bfd_get_section_by_name (abfd, ".reg-aarch-sve"); + gdb_assert (section_name != nullptr); - if (sve_section == nullptr) + asection *section = bfd_get_section_by_name (abfd, section_name); + + if (section == nullptr) { /* No SVE state. */ return 0; } - size_t size = bfd_section_size (sve_section); + size_t size = bfd_section_size (section); /* Check extended state size. */ if (size < SVE_HEADER_SIZE) { - warning (_("'.reg-aarch-sve' section in core file too small.")); + warning (_("'%s' core file section is too small. " + "Expected %s bytes, got %s bytes"), section_name, + pulongest (SVE_HEADER_SIZE), pulongest (size)); return 0; } - if (!bfd_get_section_contents (abfd, sve_section, header, 0, SVE_HEADER_SIZE)) + gdb_byte header[SVE_HEADER_SIZE]; + + if (!bfd_get_section_contents (abfd, section, header, 0, SVE_HEADER_SIZE)) { warning (_("Couldn't read sve header from " - "'.reg-aarch-sve' section in core file.")); + "'%s' core file section."), section_name); return 0; } - uint64_t vl = extract_unsigned_integer (header + SVE_HEADER_VL_OFFSET, - SVE_HEADER_VL_LENGTH, byte_order); - uint64_t vq = sve_vq_from_vl (vl); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + uint64_t vq + = sve_vq_from_vl (extract_unsigned_integer (header + SVE_HEADER_VL_OFFSET, + SVE_HEADER_VL_LENGTH, + byte_order)); - if (vq > AARCH64_MAX_SVE_VQ) - { - warning (_("SVE Vector length in core file not supported by this version" - " of GDB. (VQ=%s)"), pulongest (vq)); - return 0; - } - else if (vq == 0) + if (vq > AARCH64_MAX_SVE_VQ || vq == 0) { - warning (_("SVE Vector length in core file is invalid. (VQ=%s"), + warning (_("SVE/SSVE vector length in core file is invalid." + " (max vq=%d) (detected vq=%s)"), AARCH64_MAX_SVE_VQ, pulongest (vq)); return 0; } @@ -794,14 +803,53 @@ aarch64_linux_core_read_vq (struct gdbarch *gdbarch, bfd *abfd) return vq; } +/* Get the vector quotient (VQ) value from CORE_BFD's sections. + + Return non-zero if successful and 0 otherwise. */ + +static uint64_t +aarch64_linux_core_read_vq_from_sections (struct gdbarch *gdbarch, + bfd *core_bfd) +{ + /* First check if we have a SSVE section. If so, check if it is active. */ + asection *section = bfd_get_section_by_name (core_bfd, ".reg-aarch-ssve"); + + if (section != nullptr) + { + /* We've found a SSVE section, so now fetch its data. */ + gdb_byte header[SVE_HEADER_SIZE]; + + if (bfd_get_section_contents (core_bfd, section, header, 0, + SVE_HEADER_SIZE)) + { + /* Check if the SSVE section has SVE contents. */ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + uint16_t flags + = extract_unsigned_integer (header + SVE_HEADER_FLAGS_OFFSET, + SVE_HEADER_FLAGS_LENGTH, byte_order); + + if (flags & SVE_HEADER_FLAG_SVE) + { + /* The SSVE state is active, so return the vector length from the + the SSVE section. */ + return aarch64_linux_core_read_vq (gdbarch, core_bfd, + ".reg-aarch-ssve"); + } + } + } + + /* No valid SSVE section. Return the vq from the SVE section (if any). */ + return aarch64_linux_core_read_vq (gdbarch, core_bfd, ".reg-aarch-sve"); +} + /* Supply register REGNUM from BUF to REGCACHE, using the register map in REGSET. If REGNUM is -1, do this for all registers in REGSET. - If BUF is NULL, set the registers to "unavailable" status. */ + If BUF is nullptr, set the registers to "unavailable" status. */ static void -aarch64_linux_supply_sve_regset (const struct regset *regset, - struct regcache *regcache, - int regnum, const void *buf, size_t size) +supply_sve_regset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *buf, size_t size) { gdb_byte *header = (gdb_byte *) buf; struct gdbarch *gdbarch = regcache->arch (); @@ -853,14 +901,89 @@ aarch64_linux_supply_sve_regset (const struct regset *regset, } } +/* Collect an inactive SVE register set state. This is equivalent to a + fpsimd layout. + + Collect the data from REGCACHE to BUF, using the register + map in REGSET. */ + +static void +collect_inactive_sve_regset (const struct regcache *regcache, + void *buf, size_t size, int vg_regnum) +{ + gdb_byte *header = (gdb_byte *) buf; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + gdb_assert (buf != nullptr); + gdb_assert (size > SVE_HEADER_SIZE); + + /* Zero out everything first. */ + memset ((gdb_byte *) buf, 0, SVE_CORE_DUMMY_SIZE); + + /* BUF starts with a SVE header prior to the register dump. */ + + /* Dump the default size of an empty SVE payload. */ + uint32_t real_size = SVE_CORE_DUMMY_SIZE; + store_unsigned_integer (header + SVE_HEADER_SIZE_OFFSET, + SVE_HEADER_SIZE_LENGTH, byte_order, real_size); + + /* Dump a dummy max size. */ + uint32_t max_size = SVE_CORE_DUMMY_MAX_SIZE; + store_unsigned_integer (header + SVE_HEADER_MAX_SIZE_OFFSET, + SVE_HEADER_MAX_SIZE_LENGTH, byte_order, max_size); + + /* Dump the vector length. */ + ULONGEST vg = 0; + regcache->raw_collect (vg_regnum, &vg); + uint16_t vl = sve_vl_from_vg (vg); + store_unsigned_integer (header + SVE_HEADER_VL_OFFSET, SVE_HEADER_VL_LENGTH, + byte_order, vl); + + /* Dump the standard maximum vector length. */ + uint16_t max_vl = SVE_CORE_DUMMY_MAX_VL; + store_unsigned_integer (header + SVE_HEADER_MAX_VL_OFFSET, + SVE_HEADER_MAX_VL_LENGTH, byte_order, + max_vl); + + /* The rest of the fields is zero. */ + uint16_t flags = SVE_CORE_DUMMY_FLAGS; + store_unsigned_integer (header + SVE_HEADER_FLAGS_OFFSET, + SVE_HEADER_FLAGS_LENGTH, byte_order, + flags); + uint16_t reserved = SVE_CORE_DUMMY_RESERVED; + store_unsigned_integer (header + SVE_HEADER_RESERVED_OFFSET, + SVE_HEADER_RESERVED_LENGTH, byte_order, reserved); + + /* We are done with the header part of it. Now dump the register state + in the FPSIMD format. */ + + /* Dump the first 128 bits of each of the Z registers. */ + header += AARCH64_SVE_CONTEXT_REGS_OFFSET; + for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + regcache->raw_collect_part (AARCH64_SVE_Z0_REGNUM + i, 0, V_REGISTER_SIZE, + header + V_REGISTER_SIZE * i); + + /* Dump FPSR and FPCR. */ + header += 32 * V_REGISTER_SIZE; + regcache->raw_collect (AARCH64_FPSR_REGNUM, header); + regcache->raw_collect (AARCH64_FPCR_REGNUM, header); + + /* Dump two reserved empty fields of 4 bytes. */ + header += 8; + memset (header, 0, 8); + + /* We should have a FPSIMD-formatted register dump now. */ +} + /* Collect register REGNUM from REGCACHE to BUF, using the register map in REGSET. If REGNUM is -1, do this for all registers in REGSET. */ static void -aarch64_linux_collect_sve_regset (const struct regset *regset, - const struct regcache *regcache, - int regnum, void *buf, size_t size) +collect_sve_regset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *buf, size_t size) { gdb_byte *header = (gdb_byte *) buf; struct gdbarch *gdbarch = regcache->arch (); @@ -875,24 +998,308 @@ aarch64_linux_collect_sve_regset (const struct regset *regset, store_unsigned_integer (header + SVE_HEADER_SIZE_OFFSET, SVE_HEADER_SIZE_LENGTH, byte_order, size); + uint32_t max_size = SVE_CORE_DUMMY_MAX_SIZE; store_unsigned_integer (header + SVE_HEADER_MAX_SIZE_OFFSET, - SVE_HEADER_MAX_SIZE_LENGTH, byte_order, size); + SVE_HEADER_MAX_SIZE_LENGTH, byte_order, max_size); store_unsigned_integer (header + SVE_HEADER_VL_OFFSET, SVE_HEADER_VL_LENGTH, byte_order, sve_vl_from_vq (vq)); + uint16_t max_vl = SVE_CORE_DUMMY_MAX_VL; store_unsigned_integer (header + SVE_HEADER_MAX_VL_OFFSET, SVE_HEADER_MAX_VL_LENGTH, byte_order, - sve_vl_from_vq (vq)); + max_vl); + uint16_t flags = SVE_HEADER_FLAG_SVE; store_unsigned_integer (header + SVE_HEADER_FLAGS_OFFSET, SVE_HEADER_FLAGS_LENGTH, byte_order, - SVE_HEADER_FLAG_SVE); + flags); + uint16_t reserved = SVE_CORE_DUMMY_RESERVED; store_unsigned_integer (header + SVE_HEADER_RESERVED_OFFSET, - SVE_HEADER_RESERVED_LENGTH, byte_order, 0); + SVE_HEADER_RESERVED_LENGTH, byte_order, reserved); /* The SVE register dump follows. */ regcache->collect_regset (regset, regnum, (gdb_byte *) buf + SVE_HEADER_SIZE, size - SVE_HEADER_SIZE); } +/* Supply register REGNUM from BUF to REGCACHE, using the register map + in REGSET. If REGNUM is -1, do this for all registers in REGSET. + If BUF is NULL, set the registers to "unavailable" status. */ + +static void +aarch64_linux_supply_sve_regset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *buf, size_t size) +{ + struct gdbarch *gdbarch = regcache->arch (); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->has_sme ()) + { + ULONGEST svcr = 0; + regcache->raw_collect (tdep->sme_svcr_regnum, &svcr); + + /* Is streaming mode enabled? */ + if (svcr & SVCR_SM_BIT) + /* If so, don't load SVE data from the SVE section. The data to be + used is in the SSVE section. */ + return; + } + /* If streaming mode is not enabled, load the SVE regcache data from the SVE + section. */ + supply_sve_regset (regset, regcache, regnum, buf, size); +} + +/* Collect register REGNUM from REGCACHE to BUF, using the register + map in REGSET. If REGNUM is -1, do this for all registers in + REGSET. */ + +static void +aarch64_linux_collect_sve_regset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *buf, size_t size) +{ + struct gdbarch *gdbarch = regcache->arch (); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + bool streaming_mode = false; + + if (tdep->has_sme ()) + { + ULONGEST svcr = 0; + regcache->raw_collect (tdep->sme_svcr_regnum, &svcr); + + /* Is streaming mode enabled? */ + if (svcr & SVCR_SM_BIT) + { + /* If so, don't dump SVE regcache data to the SVE section. The SVE + data should be dumped to the SSVE section. Dump an empty SVE + block instead. */ + streaming_mode = true; + } + } + + /* If streaming mode is not enabled or there is no SME support, dump the + SVE regcache data to the SVE section. */ + + /* Check if we have an active SVE state (non-zero Z/P/FFR registers). + If so, then we need to dump registers in the SVE format. + + Otherwise we should dump the registers in the FPSIMD format. */ + if (sve_state_is_empty (regcache) || streaming_mode) + collect_inactive_sve_regset (regcache, buf, size, AARCH64_SVE_VG_REGNUM); + else + collect_sve_regset (regset, regcache, regnum, buf, size); +} + +/* Supply register REGNUM from BUF to REGCACHE, using the register map + in REGSET. If REGNUM is -1, do this for all registers in REGSET. + If BUF is NULL, set the registers to "unavailable" status. */ + +static void +aarch64_linux_supply_ssve_regset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *buf, size_t size) +{ + gdb_byte *header = (gdb_byte *) buf; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + uint16_t flags = extract_unsigned_integer (header + SVE_HEADER_FLAGS_OFFSET, + SVE_HEADER_FLAGS_LENGTH, + byte_order); + + /* Since SVCR's bits are inferred from the data we have in the header of the + SSVE section, we need to initialize it to zero first, so that it doesn't + carry garbage data. */ + ULONGEST svcr = 0; + regcache->raw_supply (tdep->sme_svcr_regnum, &svcr); + + /* Is streaming mode enabled? */ + if (flags & SVE_HEADER_FLAG_SVE) + { + /* Streaming mode is active, so flip the SM bit. */ + svcr = SVCR_SM_BIT; + regcache->raw_supply (tdep->sme_svcr_regnum, &svcr); + + /* Fetch the SVE data from the SSVE section. */ + supply_sve_regset (regset, regcache, regnum, buf, size); + } +} + +/* Collect register REGNUM from REGCACHE to BUF, using the register + map in REGSET. If REGNUM is -1, do this for all registers in + REGSET. */ + +static void +aarch64_linux_collect_ssve_regset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *buf, size_t size) +{ + struct gdbarch *gdbarch = regcache->arch (); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + ULONGEST svcr = 0; + regcache->raw_collect (tdep->sme_svcr_regnum, &svcr); + + /* Is streaming mode enabled? */ + if (svcr & SVCR_SM_BIT) + { + /* If so, dump SVE regcache data to the SSVE section. */ + collect_sve_regset (regset, regcache, regnum, buf, size); + } + else + { + /* Otherwise dump an empty SVE block to the SSVE section with the + streaming vector length. */ + collect_inactive_sve_regset (regcache, buf, size, tdep->sme_svg_regnum); + } +} + +/* Supply register REGNUM from BUF to REGCACHE, using the register map + in REGSET. If REGNUM is -1, do this for all registers in REGSET. + If BUF is NULL, set the registers to "unavailable" status. */ + +static void +aarch64_linux_supply_za_regset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *buf, size_t size) +{ + gdb_byte *header = (gdb_byte *) buf; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + /* Handle an empty buffer. */ + if (buf == nullptr) + return regcache->supply_regset (regset, regnum, nullptr, size); + + if (size < SVE_HEADER_SIZE) + warning (_("ZA state header size (%s) invalid. Should be at least %s."), + pulongest (size), pulongest (SVE_HEADER_SIZE)); + + /* The ZA register note in a core file can have a couple of states: + + 1 - Just the header without the payload. This means that there is no + ZA data, and we should populate only SVCR and SVG registers on GDB's + side. The ZA data should be marked as unavailable. + + 2 - The header with an additional data payload. This means there is + actual ZA data, and we should populate ZA, SVCR and SVG. */ + + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* Populate SVG. */ + ULONGEST svg + = sve_vg_from_vl (extract_unsigned_integer (header + SVE_HEADER_VL_OFFSET, + SVE_HEADER_VL_LENGTH, + byte_order)); + regcache->raw_supply (tdep->sme_svg_regnum, &svg); + + size_t data_size + = extract_unsigned_integer (header + SVE_HEADER_SIZE_OFFSET, + SVE_HEADER_SIZE_LENGTH, byte_order) + - SVE_HEADER_SIZE; + + /* Populate SVCR. */ + bool has_za_payload = (data_size > 0); + ULONGEST svcr; + regcache->raw_collect (tdep->sme_svcr_regnum, &svcr); + + /* If we have a ZA payload, enable bit 2 of SVCR, otherwise clear it. This + register gets updated by the SVE/SSVE-handling functions as well, as they + report the SM bit 1. */ + if (has_za_payload) + svcr |= SVCR_ZA_BIT; + else + svcr &= ~SVCR_ZA_BIT; + + /* Update SVCR in the register buffer. */ + regcache->raw_supply (tdep->sme_svcr_regnum, &svcr); + + /* Populate the register cache with ZA register contents, if we have any. */ + buf = has_za_payload ? (gdb_byte *) buf + SVE_HEADER_SIZE : nullptr; + + /* Update ZA in the register buffer. */ + if (has_za_payload) + regcache->raw_supply (tdep->sme_za_regnum, buf); + else + { + size_t za_bytes = std::pow (sve_vl_from_vg (svg), 2); + gdb_byte za_zeroed[za_bytes]; + memset (za_zeroed, 0, za_bytes); + regcache->raw_supply (tdep->sme_za_regnum, za_zeroed); + } +} + +/* Collect register REGNUM from REGCACHE to BUF, using the register + map in REGSET. If REGNUM is -1, do this for all registers in + REGSET. */ + +static void +aarch64_linux_collect_za_regset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *buf, size_t size) +{ + gdb_assert (buf != nullptr); + + if (size < SVE_HEADER_SIZE) + warning (_("ZA state header size (%s) invalid. Should be at least %s."), + pulongest (size), pulongest (SVE_HEADER_SIZE)); + + /* The ZA register note in a core file can have a couple of states: + + 1 - Just the header without the payload. This means that there is no + ZA data, and we should dump just the header. + + 2 - The header with an additional data payload. This means there is + actual ZA data, and we should dump both the header and the ZA data + payload. */ + + aarch64_gdbarch_tdep *tdep + = gdbarch_tdep (regcache->arch ()); + + /* Determine if we have ZA state from the SVCR register ZA bit. */ + ULONGEST svcr; + regcache->raw_collect (tdep->sme_svcr_regnum, &svcr); + + /* Check the ZA payload. */ + bool has_za_payload = (svcr & SVCR_ZA_BIT) != 0; + size = has_za_payload ? size : SVE_HEADER_SIZE; + + /* Write the size and max_size fields. */ + gdb_byte *header = (gdb_byte *) buf; + enum bfd_endian byte_order = gdbarch_byte_order (regcache->arch ()); + store_unsigned_integer (header + SVE_HEADER_SIZE_OFFSET, + SVE_HEADER_SIZE_LENGTH, byte_order, size); + + uint32_t max_size + = SVE_HEADER_SIZE + std::pow (sve_vl_from_vq (tdep->sme_svq), 2); + store_unsigned_integer (header + SVE_HEADER_MAX_SIZE_OFFSET, + SVE_HEADER_MAX_SIZE_LENGTH, byte_order, max_size); + + /* Output the other fields of the ZA header (vl, max_vl, flags and + reserved). */ + uint64_t svq = tdep->sme_svq; + store_unsigned_integer (header + SVE_HEADER_VL_OFFSET, SVE_HEADER_VL_LENGTH, + byte_order, sve_vl_from_vq (svq)); + + uint16_t max_vl = SVE_CORE_DUMMY_MAX_VL; + store_unsigned_integer (header + SVE_HEADER_MAX_VL_OFFSET, + SVE_HEADER_MAX_VL_LENGTH, byte_order, + max_vl); + + uint16_t flags = SVE_CORE_DUMMY_FLAGS; + store_unsigned_integer (header + SVE_HEADER_FLAGS_OFFSET, + SVE_HEADER_FLAGS_LENGTH, byte_order, flags); + + uint16_t reserved = SVE_CORE_DUMMY_RESERVED; + store_unsigned_integer (header + SVE_HEADER_RESERVED_OFFSET, + SVE_HEADER_RESERVED_LENGTH, byte_order, reserved); + + buf = has_za_payload ? (gdb_byte *) buf + SVE_HEADER_SIZE : nullptr; + + /* Dump the register cache contents for the ZA register to the buffer. */ + regcache->collect_regset (regset, regnum, (gdb_byte *) buf, + size - SVE_HEADER_SIZE); +} + /* Implement the "iterate_over_regset_sections" gdbarch method. */ static void @@ -919,6 +1326,30 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, { 0 } }; + const struct regset aarch64_linux_ssve_regset = + { + sve_regmap, + aarch64_linux_supply_ssve_regset, aarch64_linux_collect_ssve_regset, + REGSET_VARIABLE_SIZE + }; + + /* If SME is supported in the core file, process the SSVE section first, + and the SVE section last. This is because we need information from + the SSVE set to determine if streaming mode is active. If streaming + mode is active, we need to extract the data from the SSVE section. + + Otherwise, if streaming mode is not active, we fetch the data from the + SVE section. */ + if (tdep->has_sme ()) + { + cb (".reg-aarch-ssve", + SVE_HEADER_SIZE + + regcache_map_entry_size (aarch64_linux_fpregmap), + SVE_HEADER_SIZE + regcache_map_entry_size (sve_regmap), + &aarch64_linux_ssve_regset, "SSVE registers", cb_data); + } + + /* Handle the SVE register set. */ const struct regset aarch64_linux_sve_regset = { sve_regmap, @@ -935,6 +1366,29 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, cb (".reg2", AARCH64_LINUX_SIZEOF_FPREGSET, AARCH64_LINUX_SIZEOF_FPREGSET, &aarch64_linux_fpregset, NULL, cb_data); + if (tdep->has_sme ()) + { + /* Setup the register set information for a ZA register set core + dump. */ + + /* Create this on the fly in order to handle the ZA register size. */ + const struct regcache_map_entry za_regmap[] = + { + { 1, tdep->sme_za_regnum, (int) std::pow (sve_vl_from_vq (tdep->sme_svq), 2) } + }; + + const struct regset aarch64_linux_za_regset = + { + za_regmap, + aarch64_linux_supply_za_regset, aarch64_linux_collect_za_regset, + REGSET_VARIABLE_SIZE + }; + + cb (".reg-aarch-za", + SVE_HEADER_SIZE, + SVE_HEADER_SIZE + std::pow (sve_vl_from_vq (tdep->sme_svq), 2), + &aarch64_linux_za_regset, "ZA register", cb_data); + } if (tdep->has_pauth ()) { @@ -1013,7 +1467,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, CORE_ADDR hwcap2 = linux_get_hwcap2 (auxv, target, gdbarch); aarch64_features features; - features.vq = aarch64_linux_core_read_vq (gdbarch, abfd); + + /* We need to extract the SVE data from the .reg-aarch-sve section or the + .reg-aarch-ssve section depending on which one was active when the core + file was generated. + + If the SSVE section contains SVE data, then it is considered active. + Otherwise the SVE section is considered active. This guarantees we will + have the correct target description with the correct SVE vector + length. */ + features.vq = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd); features.pauth = hwcap & AARCH64_HWCAP_PACA; features.mte = hwcap2 & HWCAP2_MTE; @@ -1027,6 +1490,9 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, features.tls = size / AARCH64_TLS_REGISTER_SIZE; } + features.svq + = aarch64_linux_core_read_vq (gdbarch, abfd, ".reg-aarch-za"); + return aarch64_read_description (features); } diff --git a/gdb/arch/aarch64-scalable-linux.c b/gdb/arch/aarch64-scalable-linux.c index 3803acfd9a8..2e4aa92e36f 100644 --- a/gdb/arch/aarch64-scalable-linux.c +++ b/gdb/arch/aarch64-scalable-linux.c @@ -19,3 +19,37 @@ along with this program. If not, see . */ #include "arch/aarch64-scalable-linux.h" +#include "arch/aarch64.h" +#include "gdbsupport/byte-vector.h" +#include "gdbsupport/common-regcache.h" + +/* See arch/aarch64-scalable-linux.h */ + +bool +sve_state_is_empty (const struct reg_buffer_common *reg_buf) +{ + /* Instead of allocating a buffer with the size of the current vector + length, just use a buffer that is big enough for all cases. */ + gdb_byte zero_buffer[256]; + + /* Zero it out. */ + memset (zero_buffer, 0, 256); + + /* Are any of the Z registers set (non-zero) after the first 128 bits? */ + for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++) + { + if (!reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i, zero_buffer, + V_REGISTER_SIZE)) + return false; + } + + /* Are any of the P registers set (non-zero)? */ + for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++) + { + if (!reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i, zero_buffer, 0)) + return false; + } + + /* Is the FFR register set (non-zero)? */ + return reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM, zero_buffer, 0); +} diff --git a/gdb/arch/aarch64-scalable-linux.h b/gdb/arch/aarch64-scalable-linux.h index df1741004ed..cb9d85a9d5d 100644 --- a/gdb/arch/aarch64-scalable-linux.h +++ b/gdb/arch/aarch64-scalable-linux.h @@ -22,6 +22,7 @@ #define ARCH_AARCH64_SCALABLE_LINUX_H #include "gdbsupport/common-defs.h" +#include "gdbsupport/common-regcache.h" /* Feature check for Scalable Matrix Extension. */ #ifndef HWCAP2_SME @@ -35,4 +36,18 @@ /* Mask including all valid SVCR bits. */ #define SVCR_BIT_MASK (SVCR_SM_BIT | SVCR_ZA_BIT) +/* SVE/SSVE-related constants used for an empty SVE/SSVE register set + dumped to a core file. When SME is supported, either the SVE state or + the SSVE state will be empty when it is dumped to a core file. */ +#define SVE_CORE_DUMMY_SIZE 0x220 +#define SVE_CORE_DUMMY_MAX_SIZE 0x2240 +#define SVE_CORE_DUMMY_VL 0x10 +#define SVE_CORE_DUMMY_MAX_VL 0x100 +#define SVE_CORE_DUMMY_FLAGS 0x0 +#define SVE_CORE_DUMMY_RESERVED 0x0 + +/* Return TRUE if the SVE state in the register cache REGCACHE + is empty (zero). Return FALSE otherwise. */ +extern bool sve_state_is_empty (const struct reg_buffer_common *reg_buf); + #endif /* ARCH_AARCH64_SCALABLE_LINUX_H */