From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR02-HE1-obe.outbound.protection.outlook.com (mail-eopbgr10073.outbound.protection.outlook.com [40.107.1.73]) by sourceware.org (Postfix) with ESMTPS id 927823834F01 for ; Wed, 22 Jun 2022 09:04:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 927823834F01 ARC-Seal: i=2; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=pass; b=LP48GA4iWU6Zdh1qTIiDdB33IMkbPPGxSmMmSEyXczWI4kLSKrAI2DrVpMXtA03xVyF21GJKyU3I8PvAbXjq0xyWxhTeznWtQPNzU1bz10yW9/+twh6LwUpU04ZVVN+lr9ZYWEM93faJ5sSFy6DVKhc/0kT7MCxFV3kitah8udT6aN39v3Okv6DMY8FvZNxg8DdN4tffQaTiG1knym4+BFpfByhQtTi2zb7UYKvMGIw3N7A9WVR3s/+i8Sw9E7bf2xT4EVGibwoLTTNNtKs1VwdIAQPuWPEna6+OIaVrWHfmAz3FtUo/L6lqGkqlBIHtNodP/+7VH2OrjhvJbvrO8w== ARC-Message-Signature: i=2; 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=4/PAz7BLwFRgQndQAvqYVrcub6d9T0aRiSsD5TjLHQE=; b=fdBPaa19HjYuDnv/a1x3m8VEYhpZejhv3Y1vbbnPmFpsGEB+4BhNzKsxXbfoxgmwH8+Y/uz65+zNFMHstRGNnAV0wOAXV7NUqyE+y0weywSiw+KqUitphT+eSBu0lzqLDdOsGkTuaa0kYH7mlzrJ1nV1o0LUehwCIaci/YgO+U4wKvFBWfWTnn+wL3Ucu1/wLNNXEgU1p/01/GIZYU/1CGrUaTNglWewnuRE4jeNNX4UsLyykRrvjVf38GJ6jZ+OVs6phCgV28Ygu8Oe7S5x38NU8JNHN7FGSK8Ugem0Lmpzv7bCOGZmVFkpiGWNv/Q0//ilvgKBGYSn76TDL92YBg== ARC-Authentication-Results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 63.35.35.123) smtp.rcpttodomain=sourceware.org smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com]) Received: from AS9PR06CA0332.eurprd06.prod.outlook.com (2603:10a6:20b:466::11) by AM0PR08MB5122.eurprd08.prod.outlook.com (2603:10a6:208:160::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5353.14; Wed, 22 Jun 2022 09:04:41 +0000 Received: from AM5EUR03FT023.eop-EUR03.prod.protection.outlook.com (2603:10a6:20b:466:cafe::d6) by AS9PR06CA0332.outlook.office365.com (2603:10a6:20b:466::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5353.15 via Frontend Transport; Wed, 22 Jun 2022 09:04:41 +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 AM5EUR03FT023.mail.protection.outlook.com (10.152.16.169) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5353.14 via Frontend Transport; Wed, 22 Jun 2022 09:04:41 +0000 Received: ("Tessian outbound 1766a3bff204:v120"); Wed, 22 Jun 2022 09:04:41 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 13c1b50d71a090b5 X-CR-MTA-TID: 64aa7808 Received: from 8363e76a3b3c.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 424003BB-F650-4D98-9596-8160ACE4207F.1; Wed, 22 Jun 2022 09:04:33 +0000 Received: from EUR05-AM6-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 8363e76a3b3c.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Wed, 22 Jun 2022 09:04:33 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=mH3AXKSBxi/gfCSFoXGIF4IGzYcN9RlW/K4Vu/qIfWhq1BK0zxBbvT4jIXOE1jIvDEADT6FgDje+62t+uE2iHPcH6ceIaPyBYhYx1g5GJ1AGvczKkE6nVlKb/xVpQTKLngKRQ8/trmxHUQ3Ssr+6TPVxOYrtZU1OBpJhxKXeShAriVAz0JJWB+9VP4A0Ul2a9FfwvvvHHVYXhV2krmWvjItHJNREGWHTYcmpS6Tvd+pYCemaBNLbNPfh2+gExfJn45FaBPw7ul22F1hFrhN9iUCncPp9uMOQWenUbjDw9DmWvStImaC8XZQW3nXjvyx1aZYIyBFUMG22/t9vxwBPQw== 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=4/PAz7BLwFRgQndQAvqYVrcub6d9T0aRiSsD5TjLHQE=; b=ZbnxCKha1S4K2WX49BmS0RHJlouEhNpYN7zJJ1+c6hEaiqaV2v5izO6v6lk5kdQqJp18v2EN2DbTxEMeuqQFXd/SbIEQqq96WWCdR9OTgXY3Rhs01q+rvdRxg69+QpKrT7K3KnE2D7QI8EVXR1AnTs6SidwmoIWemWspo7LfSxzil81FBYHIwF9L/RgWXlgKCAW6cu8vWBOdDX7KB4JC5f64rzOZcJDPfq9lrSeGCzb3O/217hhIEdEPJBcYa78bNy63lu0U9UNHpDXzk1iMPsYSjaz8BeZfQhFXyDwAOvXEUIHCkgAmrQgAMN9895lbyieUEx/mkJW8IDCtQmsUVg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) by AM9PR08MB6275.eurprd08.prod.outlook.com (2603:10a6:20b:286::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5373.15; Wed, 22 Jun 2022 09:04:30 +0000 Received: from VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::1cda:8ca1:6353:572c]) by VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::1cda:8ca1:6353:572c%4]) with mapi id 15.20.5353.022; Wed, 22 Jun 2022 09:04:30 +0000 Message-ID: <99a048a4-e763-3d44-7765-f0f9ebfd61c4@arm.com> Date: Wed, 22 Jun 2022 10:04:28 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.9.1 Subject: Re: [PATCH, v4] [AArch64] MTE corefile support Content-Language: en-US To: gdb-patches@sourceware.org References: <20220331140343.9047-1-luis.machado@arm.com> <20220503215632.914608-1-luis.machado@arm.com> From: Luis Machado In-Reply-To: <20220503215632.914608-1-luis.machado@arm.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-ClientProxiedBy: LO4P123CA0448.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:1a9::21) To VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 53a18b8f-0bf6-4355-b9d5-08da542e3e52 X-MS-TrafficTypeDiagnostic: AM9PR08MB6275:EE_|AM5EUR03FT023:EE_|AM0PR08MB5122:EE_ X-Microsoft-Antispam-PRVS: 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: +ERKyTFJIMayvXiXE3D21vG3+tpDqypfcmMoGyDyIh2/5tLSha4yuEslGSgaznVrS7uxFcN4vRXTaRYclSMlWQELPMRUJgKKx+OKAHr3M9THZY2lqbqaEx6TNR6fgJbDE0Ij9SqFgmA+fe6yin3S+UAWAqiRoQE3f8WRjoB4FjR+S4Y2MEUmLwpvoVuKoAVpOWogwn9UrolgGegEo5FShNozH+CSAgmW/r1w3o19weKJ2Z27EyPw5kfGeFsbjhsT6RQH0cI9zvtlwa/W+UsgyWydthJ8/B1riyd8CKiYMtWVuoGZcqlTtQFcCVorakZGF4+iEvkzVpQLDmPqOsr5Pv/lEyJdzajEU5vWJxeLTflevLygERtCuOOUuEZjpgKStGfuw5zetIe9t+DAnLEUeVao8EKlPOrK2B4SiiK/WmHIdo9P+2kNlkyfPs2WsAmB9DqDt5E+lqa1pTfudQO6FpFA92KkXUwVnqCIY0CLO/wSnwrwS3oeWuS006naYn3PqE0yzC9y81+f/xDvvh6xBIi7qd720J1LsGDkmggj1+YYBXo9B83wmPjrh+pfRwFzS4T2Q3804VLnMLWNBGrt14q7DpFmDqLW3YyRWg7rnHUV/XvaUsvhTRI56L/NQfzB6kuvvnsePJnpMppLpGyjtepA2XWnII4V3aF2VcyNYLjqmvSkNkojg5Ymkehd2/P4XvNUUwVPvQni8e5EbaKCjX8NaU6iFrhFfggv3PJgfwsh0AxgxhbbI98rSu4GJo5xNu2sI7gJV2f5ko6VqHB//Vkw1SOFP0+HvZmVVbpf9dua1fbrmwHDWEW/kZnyY9J113sk9XKA2zSeznxaRFyduA== X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI1PR08MB3919.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230016)(4636009)(376002)(346002)(39860400002)(396003)(136003)(366004)(31696002)(86362001)(8936002)(30864003)(2906002)(6512007)(44832011)(26005)(5660300002)(478600001)(6506007)(316002)(6486002)(38100700002)(53546011)(6916009)(66556008)(66946007)(66476007)(8676002)(2616005)(83380400001)(36756003)(41300700001)(186003)(31686004)(2004002)(43740500002)(45980500001)(579004); DIR:OUT; SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM9PR08MB6275 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AM5EUR03FT023.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: 275fe0c7-e05f-494c-e7e5-08da542e3736 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: gjatZgKmJnWUb9lZH4/bATG8I3Shplz2MK6Z+dmNNFCwdE5NcLuy/1TLweH//BNJ1HAREMI7up4Qhpf1xZpOi2xJnkcRvZFmtScMYzIBMHNriSvmniagfxs7HXAJ/frKB6VZhV20cu2TGizJLfhgleAucxzgePdawTpC/DXmvrAARQYnSyofzZirUr4uuVsXtv4Ofq2S8xCRQ0R04JlsOGbthjalXroBgHRg64Ou9eFxQD9O9nBhMXmA8QQ7AR/lt0hhwYN8qfoDsxPueQnc+y5YXAParP07tC/Wa4HY20yDpfpeKja9wMBabQVS8vh7tnngfpzF8xO0E2AXPdcc90wW4SFe8xzMCx5C8gqqxrH6zW8unokrZ/WtVmm5ytGV7SQM25JX43xUBkRK3+rx+9C+jrRImzIX4unA35ZqFNgWRlwRQK5HK2Ztp8SLWwpIrSgXvQP7ex9jFlh4Gw5u82rWdML0FJnB+COIOZfpBEHpxkUwxho7oQyCF8a8KL8BPTDVkFQgbhWPN9AorPiPS7ASLv7K8msrvFOPgwis7jA7rMeUHo7v7+53/7aTapKmLVxJ1Dp4zQZImfeWc79ge8Z8D9B3RmZLJT6uew4VL5pdV9uiwNjsRrU2gIF8eWwHfEEai0kIEgatEZxFRojd4KfEQvYvvjApITHwOBOFMWTUTn1wwFIilY5dzcQlbqv8fY5j0HJOw0G4uwYqU2lNnbS4+vymh69wnJ8vH4DQVIZOc5ze77fz0aW1l326TM6DjFZF6Wd9B7dVvNcDKCbNPgAA+NwI4/jQdgDD4WhY1RJO5IYrZtM60/LvlT76PtELh3BlkEeYMGpgU6yrokAgvw== 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:(13230016)(4636009)(136003)(39860400002)(396003)(376002)(346002)(46966006)(40470700004)(36840700001)(6506007)(26005)(356005)(83380400001)(6916009)(316002)(81166007)(86362001)(6512007)(31696002)(186003)(47076005)(53546011)(2616005)(40460700003)(82740400003)(41300700001)(36860700001)(336012)(31686004)(70206006)(36756003)(8676002)(44832011)(40480700001)(5660300002)(2906002)(82310400005)(8936002)(30864003)(70586007)(6486002)(478600001)(2004002)(43740500002)(579004); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Jun 2022 09:04:41.6415 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 53a18b8f-0bf6-4355-b9d5-08da542e3e52 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: AM5EUR03FT023.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR08MB5122 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, FORGED_SPF_HELO, GIT_PATCH_0, KAM_DMARC_NONE, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE, 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-List-Received-Date: Wed, 22 Jun 2022 09:04:56 -0000 Ping? Could I please get a code review on the following? Eli has approved the documentation changes. On 5/3/22 22:56, Luis Machado via Gdb-patches wrote: > v4: > > - Updated documentation (added cross-references). > - Updated the segment name from PT_ARM_MEMTAG_MTE to > PT_AARCH64_MEMTAG_MTE. > > v3: > > - Updated NEWS and documentation to be more thorough. > > v2: > > - Rework memory tag section handling to use generic section fields. > > -- > > Teach GDB how to dump memory tags for AArch64 when using the gcore command > and how to read memory tag data back from a core file generated by GDB > (via gcore) or by the Linux kernel. > > The format is documented in the Linux Kernel documentation [1]. > > Each tagged memory range (listed in /proc//smaps) gets dumped to its > own PT_AARCH64_MEMTAG_MTE segment. A section named ".memtag" is created for each > of those segments when reading the core file back. > > To save a little bit of space, given MTE tags only take 4 bits, the memory tags > are stored packed as 2 tags per byte. > > When reading the data back, the tags are unpacked. > > I've added a new testcase to exercise the feature. > > Build-tested with --enable-targets=all and regression tested on aarch64-linux > Ubuntu 20.04. > > [1] Documentation/arm64/memory-tagging-extension.rst (Core Dump Support) > --- > gdb/Makefile.in | 1 + > gdb/NEWS | 10 ++ > gdb/aarch64-linux-tdep.c | 167 +++++++++++++++++++ > gdb/arch/aarch64-mte-linux.c | 56 +++++++ > gdb/arch/aarch64-mte-linux.h | 10 ++ > gdb/corelow.c | 62 +++++++ > gdb/defs.h | 3 +- > gdb/doc/gdb.texinfo | 19 +++ > gdb/gcore.c | 83 ++++++++- > gdb/gdbarch-components.py | 35 ++++ > gdb/gdbarch-gen.h | 26 +++ > gdb/gdbarch.c | 96 +++++++++++ > gdb/linux-tdep.c | 39 ++++- > gdb/memtag.c | 61 +++++++ > gdb/memtag.h | 50 ++++++ > gdb/testsuite/gdb.arch/aarch64-mte-gcore.c | 93 +++++++++++ > gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 107 ++++++++++++ > 17 files changed, 910 insertions(+), 8 deletions(-) > create mode 100644 gdb/memtag.c > create mode 100644 gdb/memtag.h > create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.c > create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in > index 418094775a5..fac9364bea4 100644 > --- a/gdb/Makefile.in > +++ b/gdb/Makefile.in > @@ -1120,6 +1120,7 @@ COMMON_SFILES = \ > memattr.c \ > memory-map.c \ > memrange.c \ > + memtag.c \ > minidebug.c \ > minsyms.c \ > mipsread.c \ > diff --git a/gdb/NEWS b/gdb/NEWS > index 982f4a1a18c..3d925dc3663 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -3,6 +3,16 @@ > > *** Changes since GDB 12 > > +* GDB now supports dumping memory tag data for AArch64 MTE. It also supports > + reading memory tag data for AArch64 MTE from core files generated by > + the gcore command or the Linux kernel. > + > + When a process uses memory-mapped pages protected by memory tags (for > + example, AArch64 MTE), this additional information will be recorded in > + the core file in the event of a crash or if GDB generates a core file > + from the current process state. GDB will show this additional information > + automatically, or through one of the memory-tag subcommands. > + > * GDB now supports hardware watchpoints on FreeBSD/Aarch64. > > * Remove support for building against Python 2, it is now only possible to > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c > index 55094b3d88b..12d98e71796 100644 > --- a/gdb/aarch64-linux-tdep.c > +++ b/gdb/aarch64-linux-tdep.c > @@ -53,6 +53,9 @@ > > #include "gdbsupport/selftest.h" > > +#include "elf/common.h" > +#include "elf/aarch64.h" > + > /* Signal frame handling. > > +------------+ ^ > @@ -1781,6 +1784,155 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, > } > } > > +/* AArch64 Linux implementation of the gdbarch_create_memtag_section hook. */ > + > +static asection * > +aarch64_linux_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd, > + CORE_ADDR address, size_t size) > +{ > + gdb_assert (obfd != nullptr); > + gdb_assert (size > 0); > + > + /* Create the section and associated program header. */ > + asection *mte_section = bfd_make_section_anyway (obfd, "memtag"); > + > + if (mte_section == nullptr) > + return nullptr; > + > + bfd_set_section_vma (mte_section, address); > + /* The size of the memory range covered by the memory tags. We reuse the > + section's rawsize field for this purpose. */ > + mte_section->rawsize = size; > + /* Tags are stored packed as 2 tags per byte. */ > + bfd_set_section_size (mte_section, (size / AARCH64_MTE_GRANULE_SIZE) / 2); > + /* Make sure the section's flags has SEC_HAS_CONTENTS, otherwise BFD will > + refuse to write data to this section. */ > + bfd_set_section_flags (mte_section, SEC_HAS_CONTENTS); > + > + /* Store program header information. */ > + bfd_record_phdr (obfd, PT_AARCH64_MEMTAG_MTE, 1, 0, 0, 0, 0, 0, 1, > + &mte_section); > + > + return mte_section; > +} > + > +/* Maximum number of tags to request. */ > +#define MAX_TAGS_TO_TRANSFER 1024 > + > +/* AArch64 Linux implementation of the gdbarch_fill_memtag_section hook. */ > + > +static bool > +aarch64_linux_fill_memtag_section (struct gdbarch *gdbarch, asection *osec) > +{ > + /* We only handle MTE tags for now. */ > + > + size_t segment_size = osec->rawsize; > + CORE_ADDR start_address = bfd_section_vma (osec); > + CORE_ADDR end_address = start_address + segment_size; > + > + /* Figure out how many tags we need to store in this memory range. */ > + size_t granules = aarch64_mte_get_tag_granules (start_address, segment_size, > + AARCH64_MTE_GRANULE_SIZE); > + > + /* If there are no tag granules to fetch, just return. */ > + if (granules == 0) > + return true; > + > + CORE_ADDR address = start_address; > + > + /* Vector of tags. */ > + gdb::byte_vector tags; > + > + while (granules > 0) > + { > + /* Transfer tags in chunks. */ > + gdb::byte_vector tags_read; > + size_t xfer_len > + = (granules >= MAX_TAGS_TO_TRANSFER)? > + MAX_TAGS_TO_TRANSFER * AARCH64_MTE_GRANULE_SIZE : > + granules * AARCH64_MTE_GRANULE_SIZE; > + > + if (!target_fetch_memtags (address, xfer_len, tags_read, > + static_cast (memtag_type::allocation))) > + { > + warning (_("Failed to read MTE tags from memory range [%s,%s)."), > + phex_nz (start_address, sizeof (start_address)), > + phex_nz (end_address, sizeof (end_address))); > + return false; > + } > + > + /* Transfer over the tags that have been read. */ > + tags.insert (tags.end (), tags_read.begin (), tags_read.end ()); > + > + /* Adjust the remaining granules and starting address. */ > + granules -= tags_read.size (); > + address += tags_read.size () * AARCH64_MTE_GRANULE_SIZE; > + } > + > + /* Pack the MTE tag bits. */ > + aarch64_mte_pack_tags (tags); > + > + if (!bfd_set_section_contents (osec->owner, osec, tags.data (), > + 0, tags.size ())) > + { > + warning (_("Failed to write %s bytes of corefile memory " > + "tag content (%s)."), > + pulongest (tags.size ()), > + bfd_errmsg (bfd_get_error ())); > + } > + return true; > +} > + > +/* AArch64 Linux implementation of the gdbarch_decode_memtag_section > + hook. Decode a memory tag section and return the requested tags. > + > + The section is guaranteed to cover the [ADDRESS, ADDRESS + length) > + range. */ > + > +static gdb::byte_vector > +aarch64_linux_decode_memtag_section (struct gdbarch *gdbarch, > + bfd_section *section, > + int type, > + CORE_ADDR address, size_t length) > +{ > + gdb_assert (section != nullptr); > + > + /* The requested address must not be less than section->vma. */ > + gdb_assert (section->vma <= address); > + > + /* Figure out how many tags we need to fetch in this memory range. */ > + size_t granules = aarch64_mte_get_tag_granules (address, length, > + AARCH64_MTE_GRANULE_SIZE); > + /* Sanity check. */ > + gdb_assert (granules > 0); > + > + /* Fetch the total number of tags in the range [VMA, address + length). */ > + size_t granules_from_vma > + = aarch64_mte_get_tag_granules (section->vma, > + address - section->vma + length, > + AARCH64_MTE_GRANULE_SIZE); > + > + /* Adjust the tags vector to contain the exact number of packed bytes. */ > + gdb::byte_vector tags (((granules - 1) >> 1) + 1); > + > + /* Figure out the starting offset into the packed tags data. */ > + file_ptr offset = ((granules_from_vma - granules) >> 1); > + > + if (!bfd_get_section_contents (section->owner, section, tags.data (), > + offset, tags.size ())) > + error (_("Couldn't read contents from memtag section.")); > + > + /* At this point, the tags are packed 2 per byte. Unpack them before > + returning. */ > + bool skip_first = ((granules_from_vma - granules) % 2) != 0; > + aarch64_mte_unpack_tags (tags, skip_first); > + > + /* Resize to the exact number of tags that was requested. */ > + tags.resize (granules); > + > + return tags; > +} > + > static void > aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > { > @@ -1864,6 +2016,21 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > > set_gdbarch_report_signal_info (gdbarch, > aarch64_linux_report_signal_info); > + > + /* Core file helpers. */ > + > + /* Core file helper to create a memory tag section for a particular > + PT_LOAD segment. */ > + set_gdbarch_create_memtag_section > + (gdbarch, aarch64_linux_create_memtag_section); > + > + /* Core file helper to fill a memory tag section with tag data. */ > + set_gdbarch_fill_memtag_section > + (gdbarch, aarch64_linux_fill_memtag_section); > + > + /* Core file helper to decode a memory tag section. */ > + set_gdbarch_decode_memtag_section (gdbarch, > + aarch64_linux_decode_memtag_section); > } > > /* Initialize the aarch64_linux_record_tdep. */ > diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c > index fc7a8cc00f7..3af6f364e91 100644 > --- a/gdb/arch/aarch64-mte-linux.c > +++ b/gdb/arch/aarch64-mte-linux.c > @@ -21,6 +21,62 @@ > > /* See arch/aarch64-mte-linux.h */ > > +void > +aarch64_mte_pack_tags (gdb::byte_vector &tags) > +{ > + /* Nothing to pack? */ > + if (tags.empty ()) > + return; > + > + /* If the tags vector has an odd number of elements, add another > + zeroed-out element to make it even. This facilitates packing. */ > + if ((tags.size () % 2) != 0) > + tags.emplace_back (0); > + > + for (int unpacked = 0, packed = 0; unpacked < tags.size (); > + unpacked += 2, packed++) > + tags[packed] = (tags[unpacked + 1] << 4) | tags[unpacked]; > + > + /* Now we have half the size. */ > + tags.resize (tags.size () / 2); > +} > + > +/* See arch/aarch64-mte-linux.h */ > + > +void > +aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first) > +{ > + /* Nothing to unpack? */ > + if (tags.empty ()) > + return; > + > + /* An unpacked MTE tags vector will have twice the number of elements > + compared to an unpacked one. */ > + gdb::byte_vector unpacked_tags (tags.size () * 2); > + > + int unpacked = 0, packed = 0; > + > + if (skip_first) > + { > + /* We are not interested in the first unpacked element, just discard > + it. */ > + unpacked_tags[unpacked] = (tags[packed] >> 4) & 0xf; > + unpacked++; > + packed++; > + } > + > + for (; packed < tags.size (); unpacked += 2, packed++) > + { > + unpacked_tags[unpacked] = tags[packed] & 0xf; > + unpacked_tags[unpacked + 1] = (tags[packed] >> 4) & 0xf; > + } > + > + /* Update the original tags vector. */ > + tags = std::move (unpacked_tags); > +} > + > +/* See arch/aarch64-mte-linux.h */ > + > size_t > aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size) > { > diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h > index d158926feff..8a145b447aa 100644 > --- a/gdb/arch/aarch64-mte-linux.h > +++ b/gdb/arch/aarch64-mte-linux.h > @@ -32,6 +32,7 @@ > > /* We have one tag per 16 bytes of memory. */ > #define AARCH64_MTE_GRANULE_SIZE 16 > +#define AARCH64_MTE_TAG_BIT_SIZE 4 > #define AARCH64_MTE_LOGICAL_TAG_START_BIT 56 > #define AARCH64_MTE_LOGICAL_MAX_VALUE 0xf > > @@ -71,4 +72,13 @@ extern CORE_ADDR aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag); > It is always possible to get the logical tag. */ > extern CORE_ADDR aarch64_mte_get_ltag (CORE_ADDR address); > > +/* Given a TAGS vector containing 1 MTE tag per byte, pack the data as > + 2 tags per byte and resize the vector. */ > +void aarch64_mte_pack_tags (gdb::byte_vector &tags); > + > +/* Given a TAGS vector containing 2 MTE tags per byte, unpack the data as > + 1 tag per byte and resize the vector. If SKIP_FIRST is TRUE, skip the > + first unpacked element. Otherwise leave it in the unpacked vector. */ > +void aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first); > + > #endif /* ARCH_AARCH64_LINUX_H */ > diff --git a/gdb/corelow.c b/gdb/corelow.c > index 8c33fb7ebb2..8b8994f80db 100644 > --- a/gdb/corelow.c > +++ b/gdb/corelow.c > @@ -52,6 +52,7 @@ > #include > #include "gdbcmd.h" > #include "xml-tdesc.h" > +#include "memtag.h" > > #ifndef O_LARGEFILE > #define O_LARGEFILE 0 > @@ -101,6 +102,13 @@ class core_target final : public process_stratum_target > > bool info_proc (const char *, enum info_proc_what) override; > > + bool supports_memory_tagging () override; > + > + /* Core file implementation of fetch_memtags. Fetch the memory tags from > + core file notes. */ > + bool fetch_memtags (CORE_ADDR address, size_t len, > + gdb::byte_vector &tags, int type) override; > + > /* A few helpers. */ > > /* Getter, see variable definition. */ > @@ -1162,6 +1170,60 @@ core_target::info_proc (const char *args, enum info_proc_what request) > return true; > } > > +/* Implementation of the "supports_memory_tagging" target_ops method. */ > + > +bool > +core_target::supports_memory_tagging () > +{ > + /* Look for memory tag sections. If they exist, that means this core file > + supports memory tagging. */ > + > + return (bfd_get_section_by_name (core_bfd, "memtag") != nullptr); > +} > + > +/* Implementation of the "fetch_memtags" target_ops method. */ > + > +bool > +core_target::fetch_memtags (CORE_ADDR address, size_t len, > + gdb::byte_vector &tags, int type) > +{ > + struct gdbarch *gdbarch = target_gdbarch (); > + > + /* Make sure we have a way to decode the memory tag notes. */ > + if (!gdbarch_decode_memtag_section_p (gdbarch)) > + error (_("gdbarch_decode_memtag_section not implemented for this " > + "architecture.")); > + > + memtag_section_info info; > + info.memtag_section = nullptr; > + > + while (get_next_core_memtag_section (core_bfd, info.memtag_section, > + address, info)) > + { > + size_t adjusted_length > + = (address + len < info.end_address)? len : (info.end_address - address); > + > + /* Decode the memory tag note and return the tags. */ > + gdb::byte_vector tags_read > + = gdbarch_decode_memtag_section (gdbarch, info.memtag_section, type, > + address, adjusted_length); > + > + /* Transfer over the tags that have been read. */ > + tags.insert (tags.end (), tags_read.begin (), tags_read.end ()); > + > + /* ADDRESS + LEN may cross the boundaries of a particular memory tag > + segment. Check if we need to fetch tags from a different section. */ > + if (!tags_read.empty () && (address + len) < info.end_address) > + return true; > + > + /* There are more tags to fetch. Update ADDRESS and LEN. */ > + len -= (info.end_address - address); > + address = info.end_address; > + } > + > + return false; > +} > + > /* Get a pointer to the current core target. If not connected to a > core target, return NULL. */ > > diff --git a/gdb/defs.h b/gdb/defs.h > index 99bfdd526ff..51a7576a56a 100644 > --- a/gdb/defs.h > +++ b/gdb/defs.h > @@ -344,7 +344,8 @@ extern const char *pc_prefix (CORE_ADDR); > > typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned long size, > int read, int write, int exec, > - int modified, void *data); > + int modified, bool memory_tagged, > + void *data); > > /* * Possible lvalue types. Like enum language, this should be in > value.h, but needs to be here for the same reason. */ > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 38ad2ac32b0..36f10f20cfb 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -25555,6 +25555,25 @@ options that can be controlled at runtime and emulates the @code{prctl} > option @code{PR_SET_TAGGED_ADDR_CTRL}. For further information, see the > documentation in the Linux kernel. > > +@value{GDBN} supports dumping memory tag data to core files through the > +@command{gcore} command and reading memory tag data from core files generated > +by the @command{gcore} command or the Linux kernel. > + > +When a process uses memory-mapped pages protected by memory tags (for > +example, AArch64 MTE), this additional information will be recorded in > +the core file in the event of a crash or if @value{GDBN} generates a core file > +from the current process state. > + > +The memory tag data will be used so developers can display the memory > +tags from a particular memory region (using the @samp{m} modifier to the > +@command{x} command, using the @command{print} command or using the various > +@command{memory-tag} subcommands. > + > +In the case of a crash, @value{GDBN} will attempt to retrieve the memory tag > +information automatically from the core file, and will show one of the above > +messages depending on whether the synchronous or asynchronous mode is selected. > +@xref{Memory Tagging}. @xref{Memory}. > + > @node i386 > @subsection x86 Architecture-specific Issues > > diff --git a/gdb/gcore.c b/gdb/gcore.c > index fdb22b72a07..b81ef81ab84 100644 > --- a/gdb/gcore.c > +++ b/gdb/gcore.c > @@ -349,6 +349,12 @@ make_output_phdrs (bfd *obfd, asection *osec) > int p_flags = 0; > int p_type = 0; > > + /* Memory tag segments have already been handled by the architecture, as > + those contain arch-specific information. If we have one of those, just > + return. */ > + if (startswith (bfd_section_name (osec), "memtag")) > + return; > + > /* FIXME: these constants may only be applicable for ELF. */ > if (startswith (bfd_section_name (osec), "load")) > p_type = PT_LOAD; > @@ -371,7 +377,8 @@ make_output_phdrs (bfd *obfd, asection *osec) > > static int > gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read, > - int write, int exec, int modified, void *data) > + int write, int exec, int modified, bool memory_tagged, > + void *data) > { > bfd *obfd = (bfd *) data; > asection *osec; > @@ -454,6 +461,45 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read, > return 0; > } > > +/* gdbarch_find_memory_region callback for creating a memory tag section. > + DATA is 'bfd *' for the core file GDB is creating. */ > + > +static int > +gcore_create_memtag_section_callback (CORE_ADDR vaddr, unsigned long size, > + int read, int write, int exec, > + int modified, bool memory_tagged, > + void *data) > +{ > + /* Are there memory tags in this particular memory map entry? */ > + if (!memory_tagged) > + return 0; > + > + bfd *obfd = (bfd *) data; > + > + /* Ask the architecture to create a memory tag section for this particular > + memory map entry. It will be populated with contents later, as we can't > + start writing the contents before we have all the sections sorted out. */ > + asection *memtag_section > + = gdbarch_create_memtag_section (target_gdbarch (), obfd, vaddr, size); > + > + if (memtag_section == nullptr) > + { > + warning (_("Couldn't make gcore memory tag segment: %s"), > + bfd_errmsg (bfd_get_error ())); > + return 1; > + } > + > + if (info_verbose) > + { > + gdb_printf (gdb_stdout, "Saved memory tag segment, %s bytes " > + "at %s\n", > + plongest (bfd_section_size (memtag_section)), > + paddress (target_gdbarch (), vaddr)); > + } > + > + return 0; > +} > + > int > objfile_find_memory_regions (struct target_ops *self, > find_memory_region_ftype func, void *obfd) > @@ -483,6 +529,7 @@ objfile_find_memory_regions (struct target_ops *self, > (flags & SEC_READONLY) == 0, /* Writable. */ > (flags & SEC_CODE) != 0, /* Executable. */ > 1, /* MODIFIED is unknown, pass it as true. */ > + false, /* No memory tags in the object file. */ > obfd); > if (ret != 0) > return ret; > @@ -496,6 +543,7 @@ objfile_find_memory_regions (struct target_ops *self, > 1, /* Stack section will be writable. */ > 0, /* Stack section will not be executable. */ > 1, /* Stack section will be modified. */ > + false, /* No memory tags in the object file. */ > obfd); > > /* Make a heap segment. */ > @@ -506,6 +554,7 @@ objfile_find_memory_regions (struct target_ops *self, > 1, /* Heap section will be writable. */ > 0, /* Heap section will not be executable. */ > 1, /* Heap section will be modified. */ > + false, /* No memory tags in the object file. */ > obfd); > > return 0; > @@ -555,6 +604,20 @@ gcore_copy_callback (bfd *obfd, asection *osec) > } > } > > +/* Callback to copy contents to a particular memory tag section. */ > + > +static void > +gcore_copy_memtag_section_callback (bfd *obfd, asection *osec) > +{ > + /* We are only interested in "memtag" sections. */ > + if (!startswith (bfd_section_name (osec), "memtag")) > + return; > + > + /* Fill the section with memory tag contents. */ > + if (!gdbarch_fill_memtag_section (target_gdbarch (), osec)) > + error (_("Failed to fill memory tag section for core file.")); > +} > + > static int > gcore_memory_sections (bfd *obfd) > { > @@ -567,13 +630,27 @@ gcore_memory_sections (bfd *obfd) > return 0; /* FIXME: error return/msg? */ > } > > + /* Take care of dumping memory tags, if there are any. */ > + if (!gdbarch_find_memory_regions_p (target_gdbarch ()) > + || gdbarch_find_memory_regions (target_gdbarch (), > + gcore_create_memtag_section_callback, > + obfd) != 0) > + { > + if (target_find_memory_regions (gcore_create_memtag_section_callback, > + obfd) != 0) > + return 0; > + } > + > /* Record phdrs for section-to-segment mapping. */ > for (asection *sect : gdb_bfd_sections (obfd)) > make_output_phdrs (obfd, sect); > > - /* Copy memory region contents. */ > + /* Copy memory region and memory tag contents. */ > for (asection *sect : gdb_bfd_sections (obfd)) > - gcore_copy_callback (obfd, sect); > + { > + gcore_copy_callback (obfd, sect); > + gcore_copy_memtag_section_callback (obfd, sect); > + } > > return 1; > } > diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py > index e8f20c83ff0..6fa1b7591db 100644 > --- a/gdb/gdbarch-components.py > +++ b/gdb/gdbarch-components.py > @@ -1522,6 +1522,41 @@ Find core file memory regions > invalid=True, > ) > > +Method( > + comment=""" > +Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag section to be dumped to a core file > +""", > + type="asection *", > + name="create_memtag_section", > + params=[("bfd *", "obfd"), ("CORE_ADDR", "address"), ("size_t", "size")], > + predicate=True, > + invalid=True, > +) > + > +Method( > + comment=""" > +Given a memory tag section OSEC, fill OSEC's contents with the appropriate tag data > +""", > + type="bool", > + name="fill_memtag_section", > + params=[("asection *", "osec")], > + predicate=True, > + invalid=True, > +) > + > +Method( > + comment=""" > +Decode a memory tag SECTION and return the tags of type TYPE contained in > +the memory range [ADDRESS, ADDRESS + LENGTH). > +If no tags were found, return an empty vector. > +""", > + type="gdb::byte_vector", > + name="decode_memtag_section", > + params=[("bfd_section *", "section"), ("int", "type"), ("CORE_ADDR", "address"), ("size_t", "length")], > + predicate=True, > + invalid=True, > +) > + > Method( > comment=""" > Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from > diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h > index 882b9057b1a..1d19f51f21d 100644 > --- a/gdb/gdbarch-gen.h > +++ b/gdb/gdbarch-gen.h > @@ -874,6 +874,32 @@ typedef int (gdbarch_find_memory_regions_ftype) (struct gdbarch *gdbarch, find_m > extern int gdbarch_find_memory_regions (struct gdbarch *gdbarch, find_memory_region_ftype func, void *data); > extern void set_gdbarch_find_memory_regions (struct gdbarch *gdbarch, gdbarch_find_memory_regions_ftype *find_memory_regions); > > +/* Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag section to be dumped to a core file */ > + > +extern bool gdbarch_create_memtag_section_p (struct gdbarch *gdbarch); > + > +typedef asection * (gdbarch_create_memtag_section_ftype) (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size); > +extern asection * gdbarch_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size); > +extern void set_gdbarch_create_memtag_section (struct gdbarch *gdbarch, gdbarch_create_memtag_section_ftype *create_memtag_section); > + > +/* Given a memory tag section OSEC, fill OSEC's contents with the appropriate tag data */ > + > +extern bool gdbarch_fill_memtag_section_p (struct gdbarch *gdbarch); > + > +typedef bool (gdbarch_fill_memtag_section_ftype) (struct gdbarch *gdbarch, asection *osec); > +extern bool gdbarch_fill_memtag_section (struct gdbarch *gdbarch, asection *osec); > +extern void set_gdbarch_fill_memtag_section (struct gdbarch *gdbarch, gdbarch_fill_memtag_section_ftype *fill_memtag_section); > + > +/* Decode a memory tag SECTION and return the tags of type TYPE contained in > + the memory range [ADDRESS, ADDRESS + LENGTH). > + If no tags were found, return an empty vector. */ > + > +extern bool gdbarch_decode_memtag_section_p (struct gdbarch *gdbarch); > + > +typedef gdb::byte_vector (gdbarch_decode_memtag_section_ftype) (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length); > +extern gdb::byte_vector gdbarch_decode_memtag_section (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length); > +extern void set_gdbarch_decode_memtag_section (struct gdbarch *gdbarch, gdbarch_decode_memtag_section_ftype *decode_memtag_section); > + > /* Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from > core file into buffer READBUF with length LEN. Return the number of bytes read > (zero indicates failure). > diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c > index a588bdef61a..f5dbacb14e7 100644 > --- a/gdb/gdbarch.c > +++ b/gdb/gdbarch.c > @@ -171,6 +171,9 @@ struct gdbarch > gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections; > gdbarch_make_corefile_notes_ftype *make_corefile_notes; > gdbarch_find_memory_regions_ftype *find_memory_regions; > + gdbarch_create_memtag_section_ftype *create_memtag_section; > + gdbarch_fill_memtag_section_ftype *fill_memtag_section; > + gdbarch_decode_memtag_section_ftype *decode_memtag_section; > gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries; > gdbarch_core_xfer_shared_libraries_aix_ftype *core_xfer_shared_libraries_aix; > gdbarch_core_pid_to_str_ftype *core_pid_to_str; > @@ -527,6 +530,9 @@ verify_gdbarch (struct gdbarch *gdbarch) > /* Skip verify of iterate_over_regset_sections, has predicate. */ > /* Skip verify of make_corefile_notes, has predicate. */ > /* Skip verify of find_memory_regions, has predicate. */ > + /* Skip verify of create_memtag_section, has predicate. */ > + /* Skip verify of fill_memtag_section, has predicate. */ > + /* Skip verify of decode_memtag_section, has predicate. */ > /* Skip verify of core_xfer_shared_libraries, has predicate. */ > /* Skip verify of core_xfer_shared_libraries_aix, has predicate. */ > /* Skip verify of core_pid_to_str, has predicate. */ > @@ -1096,6 +1102,24 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) > gdb_printf (file, > "gdbarch_dump: find_memory_regions = <%s>\n", > host_address_to_string (gdbarch->find_memory_regions)); > + gdb_printf (file, > + "gdbarch_dump: gdbarch_create_memtag_section_p() = %d\n", > + gdbarch_create_memtag_section_p (gdbarch)); > + gdb_printf (file, > + "gdbarch_dump: create_memtag_section = <%s>\n", > + host_address_to_string (gdbarch->create_memtag_section)); > + gdb_printf (file, > + "gdbarch_dump: gdbarch_fill_memtag_section_p() = %d\n", > + gdbarch_fill_memtag_section_p (gdbarch)); > + gdb_printf (file, > + "gdbarch_dump: fill_memtag_section = <%s>\n", > + host_address_to_string (gdbarch->fill_memtag_section)); > + gdb_printf (file, > + "gdbarch_dump: gdbarch_decode_memtag_section_p() = %d\n", > + gdbarch_decode_memtag_section_p (gdbarch)); > + gdb_printf (file, > + "gdbarch_dump: decode_memtag_section = <%s>\n", > + host_address_to_string (gdbarch->decode_memtag_section)); > gdb_printf (file, > "gdbarch_dump: gdbarch_core_xfer_shared_libraries_p() = %d\n", > gdbarch_core_xfer_shared_libraries_p (gdbarch)); > @@ -3744,6 +3768,78 @@ set_gdbarch_find_memory_regions (struct gdbarch *gdbarch, > gdbarch->find_memory_regions = find_memory_regions; > } > > +bool > +gdbarch_create_memtag_section_p (struct gdbarch *gdbarch) > +{ > + gdb_assert (gdbarch != NULL); > + return gdbarch->create_memtag_section != NULL; > +} > + > +asection * > +gdbarch_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size) > +{ > + gdb_assert (gdbarch != NULL); > + gdb_assert (gdbarch->create_memtag_section != NULL); > + if (gdbarch_debug >= 2) > + gdb_printf (gdb_stdlog, "gdbarch_create_memtag_section called\n"); > + return gdbarch->create_memtag_section (gdbarch, obfd, address, size); > +} > + > +void > +set_gdbarch_create_memtag_section (struct gdbarch *gdbarch, > + gdbarch_create_memtag_section_ftype create_memtag_section) > +{ > + gdbarch->create_memtag_section = create_memtag_section; > +} > + > +bool > +gdbarch_fill_memtag_section_p (struct gdbarch *gdbarch) > +{ > + gdb_assert (gdbarch != NULL); > + return gdbarch->fill_memtag_section != NULL; > +} > + > +bool > +gdbarch_fill_memtag_section (struct gdbarch *gdbarch, asection *osec) > +{ > + gdb_assert (gdbarch != NULL); > + gdb_assert (gdbarch->fill_memtag_section != NULL); > + if (gdbarch_debug >= 2) > + gdb_printf (gdb_stdlog, "gdbarch_fill_memtag_section called\n"); > + return gdbarch->fill_memtag_section (gdbarch, osec); > +} > + > +void > +set_gdbarch_fill_memtag_section (struct gdbarch *gdbarch, > + gdbarch_fill_memtag_section_ftype fill_memtag_section) > +{ > + gdbarch->fill_memtag_section = fill_memtag_section; > +} > + > +bool > +gdbarch_decode_memtag_section_p (struct gdbarch *gdbarch) > +{ > + gdb_assert (gdbarch != NULL); > + return gdbarch->decode_memtag_section != NULL; > +} > + > +gdb::byte_vector > +gdbarch_decode_memtag_section (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length) > +{ > + gdb_assert (gdbarch != NULL); > + gdb_assert (gdbarch->decode_memtag_section != NULL); > + if (gdbarch_debug >= 2) > + gdb_printf (gdb_stdlog, "gdbarch_decode_memtag_section called\n"); > + return gdbarch->decode_memtag_section (gdbarch, section, type, address, length); > +} > + > +void > +set_gdbarch_decode_memtag_section (struct gdbarch *gdbarch, > + gdbarch_decode_memtag_section_ftype decode_memtag_section) > +{ > + gdbarch->decode_memtag_section = decode_memtag_section; > +} > + > bool > gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch) > { > diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c > index 4e728a06e7e..8a83ed320cf 100644 > --- a/gdb/linux-tdep.c > +++ b/gdb/linux-tdep.c > @@ -42,6 +42,7 @@ > #include "gcore.h" > #include "gcore-elf.h" > #include "solib-svr4.h" > +#include "memtag.h" > > #include > #include > @@ -1320,6 +1321,7 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size, > ULONGEST offset, ULONGEST inode, > int read, int write, > int exec, int modified, > + bool memory_tagged, > const char *filename, > void *data); > > @@ -1470,10 +1472,11 @@ parse_smaps_data (const char *data, > return smaps; > } > > -/* See linux-tdep.h. */ > +/* Helper that checks if an address is in a memory tag page for a live > + process. */ > > -bool > -linux_address_in_memtag_page (CORE_ADDR address) > +static bool > +linux_process_address_in_memtag_page (CORE_ADDR address) > { > if (current_inferior ()->fake_pid_p) > return false; > @@ -1505,6 +1508,30 @@ linux_address_in_memtag_page (CORE_ADDR address) > return false; > } > > +/* Helper that checks if an address is in a memory tag page for a core file > + process. */ > + > +static bool > +linux_core_file_address_in_memtag_page (CORE_ADDR address) > +{ > + if (core_bfd == nullptr) > + return false; > + > + memtag_section_info info; > + return get_next_core_memtag_section (core_bfd, nullptr, address, info); > +} > + > +/* See linux-tdep.h. */ > + > +bool > +linux_address_in_memtag_page (CORE_ADDR address) > +{ > + if (!target_has_execution ()) > + return linux_core_file_address_in_memtag_page (address); > + > + return linux_process_address_in_memtag_page (address); > +} > + > /* List memory regions in the inferior for a corefile. */ > > static int > @@ -1593,6 +1620,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch, > map.offset, map.inode, map.read, map.write, map.exec, > 1, /* MODIFIED is true because we want to dump > the mapping. */ > + map.vmflags.memory_tagging != 0, > map.filename.c_str (), obfd); > } > } > @@ -1621,12 +1649,14 @@ static int > linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size, > ULONGEST offset, ULONGEST inode, > int read, int write, int exec, int modified, > + bool memory_tagged, > const char *filename, void *arg) > { > struct linux_find_memory_regions_data *data > = (struct linux_find_memory_regions_data *) arg; > > - return data->func (vaddr, size, read, write, exec, modified, data->obfd); > + return data->func (vaddr, size, read, write, exec, modified, memory_tagged, > + data->obfd); > } > > /* A variant of linux_find_memory_regions_full that is suitable as the > @@ -1675,6 +1705,7 @@ static int > linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size, > ULONGEST offset, ULONGEST inode, > int read, int write, int exec, int modified, > + bool memory_tagged, > const char *filename, void *data) > { > struct linux_make_mappings_data *map_data > diff --git a/gdb/memtag.c b/gdb/memtag.c > new file mode 100644 > index 00000000000..af86137c49d > --- /dev/null > +++ b/gdb/memtag.c > @@ -0,0 +1,61 @@ > +/* GDB generic memory tagging functions. > + > + Copyright (C) 2022 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + 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 . */ > + > +#include "defs.h" > +#include "memtag.h" > +#include "bfd.h" > + > +/* See memtag.h */ > + > +bool > +get_next_core_memtag_section (bfd *abfd, asection *section, > + CORE_ADDR address, memtag_section_info &info) > +{ > + /* If the caller provided no SECTION to start from, search from the > + beginning. */ > + if (section == nullptr) > + section = bfd_get_section_by_name (abfd, "memtag"); > + > + /* Go through all the memtag sections and figure out if ADDRESS > + falls within one of the memory ranges that contain tags. */ > + while (section != nullptr) > + { > + size_t memtag_range_size = section->rawsize; > + size_t tags_size = bfd_section_size (section); > + > + /* Empty memory range and empty tag dump should not happen. */ > + gdb_assert (memtag_range_size != 0); > + gdb_assert (tags_size != 0); > + > + CORE_ADDR start_address = bfd_section_vma (section); > + CORE_ADDR end_address = start_address + memtag_range_size; > + > + /* Is the address within [start_address, end_address)? */ > + if (address >= start_address > + && address < end_address) > + { > + info.start_address = start_address; > + info.end_address = end_address; > + info.memtag_section = section; > + return true; > + } > + section = bfd_get_next_section_by_name (abfd, section); > + } > + return false; > +} > diff --git a/gdb/memtag.h b/gdb/memtag.h > new file mode 100644 > index 00000000000..fe908c1e5e3 > --- /dev/null > +++ b/gdb/memtag.h > @@ -0,0 +1,50 @@ > +/* GDB generic memory tagging definitions. > + Copyright (C) 2022 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + 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 . */ > + > +#ifndef MEMTAG_H > +#define MEMTAG_H > + > +#include "bfd.h" > + > +struct memtag_section_info > +{ > + /* The start address of the tagged memory range. */ > + CORE_ADDR start_address; > + /* The final address of the tagged memory range. */ > + CORE_ADDR end_address; > + /* The section containing tags for the memory range > + [start_address, end_address). */ > + asection *memtag_section; > +}; > + > +/* Helper function to walk through memory tag sections in a core file. > + > + Return TRUE if there is a "memtag" section containing ADDRESS. Return FALSE > + otherwise. > + > + If SECTION is provided, search from that section onwards. If SECTION is > + nullptr, then start a new search. > + > + If a "memtag" section containing ADDRESS is found, fill INFO with data > + about such section. Otherwise leave it unchanged. */ > + > +bool get_next_core_memtag_section (bfd *abfd, asection *section, > + CORE_ADDR address, > + memtag_section_info &info); > + > +#endif /* MEMTAG_H */ > diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c > new file mode 100644 > index 00000000000..b20ebcff424 > --- /dev/null > +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c > @@ -0,0 +1,93 @@ > +/* This test program is part of GDB, the GNU debugger. > + > + Copyright 2021 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 . */ > + > +/* Exercise AArch64's Memory Tagging Extension with tagged pointers. */ > + > +/* This test was based on the documentation for the AArch64 Memory Tagging > + Extension from the Linux Kernel, found in the sources in > + Documentation/arm64/memory-tagging-extension.rst. */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* From arch/arm64/include/uapi/asm/hwcap.h */ > +#define HWCAP2_MTE (1 << 18) > + > +/* From arch/arm64/include/uapi/asm/mman.h */ > +#define PROT_MTE 0x20 > + > +/* From include/uapi/linux/prctl.h */ > +#define PR_SET_TAGGED_ADDR_CTRL 55 > +#define PR_GET_TAGGED_ADDR_CTRL 56 > +#define PR_TAGGED_ADDR_ENABLE (1UL << 0) > +#define PR_MTE_TCF_SHIFT 1 > +#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT) > +#define PR_MTE_TAG_SHIFT 3 > + > +void > +access_memory (unsigned char *tagged_ptr) > +{ > + tagged_ptr[0] = 'a'; > +} > + > +int > +main (int argc, char **argv) > +{ > + unsigned char *tagged_ptr; > + unsigned long page_sz = sysconf (_SC_PAGESIZE); > + unsigned long hwcap2 = getauxval(AT_HWCAP2); > + > + /* Bail out if MTE is not supported. */ > + if (!(hwcap2 & HWCAP2_MTE)) > + return 1; > + > + /* Enable the tagged address ABI, synchronous MTE tag check faults and > + allow all non-zero tags in the randomly generated set. */ > + if (prctl (PR_SET_TAGGED_ADDR_CTRL, > + PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC > + | (0xfffe << PR_MTE_TAG_SHIFT), > + 0, 0, 0)) > + { > + perror ("prctl () failed"); > + return 1; > + } > + > + /* Create a mapping that will have PROT_MTE set. */ > + tagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE, > + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); > + if (tagged_ptr == MAP_FAILED) > + { > + perror ("mmap () failed"); > + return 1; > + } > + > + /* Enable MTE on the above anonymous mmap. */ > + if (mprotect (tagged_ptr, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) > + { > + perror ("mprotect () failed"); > + return 1; > + } > + > + access_memory (tagged_ptr); > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp > new file mode 100644 > index 00000000000..8a19c4b449e > --- /dev/null > +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp > @@ -0,0 +1,107 @@ > +# Copyright (C) 2018-2021 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 file is part of the gdb testsuite. > + > +# Test generating and reading a core file with MTE memory tags. > + > +if {![is_aarch64_target]} { > + verbose "Skipping ${gdb_test_file_name}." > + return > +} > + > +standard_testfile > +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { > + return -1 > +} > + > +if ![runto_main] { > + untested "could not run to main" > + return -1 > +} > + > +# Targets that don't support memory tagging should not execute the > +# runtime memory tagging tests. > +if {![supports_memtag]} { > + unsupported "memory tagging unsupported" > + return -1 > +} > + > +gdb_breakpoint "access_memory" > + > +if [gdb_continue "access_memory"] { > + return -1 > +} > + > +# Set each tag granule to a different tag value, from 0x0 to 0xf. > +set atag_msg "Allocation tag\\(s\\) updated successfully\." > +for {set i 15} {$i >= 0} {incr i -1} { > + set index [expr [expr 15 - $i] * 16] > + set tag [format "%02x" $i] > + gdb_test "memory-tag set-allocation-tag &tagged_ptr\[$index\] 1 $tag" \ > + $atag_msg \ > + "set memory tag of &tagged_ptr\[$index\] to $tag" > +} > + > +# Run until a crash and confirm GDB displays memory tag violation > +# information. > +gdb_test "continue" \ > + [multi_line \ > + "Program received signal SIGSEGV, Segmentation fault" \ > + "Memory tag violation while accessing address $hex" \ > + "Allocation tag $hex" \ > + "Logical tag $hex\." \ > + "$hex in access_memory \\(.*\\) at .*" \ > + ".*tagged_ptr\\\[0\\\] = 'a';"] \ > + "display tag violation information for live process" > + > +# Generate the core file. > +set core_filename [standard_output_file "$testfile.core"] > +set core_generated [gdb_gcore_cmd "$core_filename" "generate core file"] > + > +if { !$core_generated } { > + return -1 > +} > + > +clean_restart $binfile > + > +# Load the core file and make sure we see the tag violation fault > +# information. > +gdb_test "core $core_filename" \ > + [multi_line \ > + "Core was generated by.*\." \ > + "Program terminated with signal SIGSEGV, Segmentation fault" \ > + "Memory tag violation while accessing address $hex" \ > + "Allocation tag 0xf" \ > + "Logical tag 0x0\." \ > + "#0.*$hex in access_memory \\(.*\\) at .*" \ > + ".*tagged_ptr\\\[0\\\] = 'a';"] \ > + "core file shows tag violation information" > + > +# Make sure we have the tag_ctl register. > +gdb_test "info register tag_ctl" \ > + "tag_ctl.*$hex.*${::decimal}" \ > + "tag_ctl is available" > + > +# Check if the tag granules have the expected values. If they do, that > +# means the core file saved the tags properly and GDB has read them > +# correctly. > +for {set i 15} {$i >= 0} {incr i -1} { > + set index [expr [expr 15 - $i] * 16] > + set tag [format "%x" $i] > + gdb_test "memory-tag print-allocation-tag &tagged_ptr\[$index\]" \ > + "= 0x$tag" \ > + "memory tag of &tagged_ptr\[$index\] is correct" > +}