From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2088.outbound.protection.outlook.com [40.107.21.88]) by sourceware.org (Postfix) with ESMTPS id D43BE383E6B4 for ; Mon, 23 May 2022 09:51:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D43BE383E6B4 ARC-Seal: i=2; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=pass; b=ltqjVARfEcnq3QRCCzoqC1po/6mu/qHyEN4wBckroelqsAzSPhE87xKzHQWEVudVmJ6kX7UNOMNtIXQr648ii56JHNEApBHk81T/wZ40rhMphYA3Zo6uQnB2MD7tZkZWSoJzrSW/fWgYirj+C4SHPI5Pi2HkxcZjpIhDsGa9OMyJ/ojCKEmwhm4EauJHoaJa4agS6iLDC52C4sXGsBs+L3w11XG+uW3GhZtuVh5ey8tB51Fk5mgdo6CBjvty+q1oYzK0DuxWdTz8om6t08KLnrojSDq/ZPgCO4h2AbKzgYI4TeMBEUXohcX2e3CIa/3Cq0AOPBxE6L4tc3JnVFHm9w== 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=9zF12Yr0TF5Hy0Ih8V7GG+DUaa0767w2hpHQCLktPOc=; b=Ij8DreOFHH4Hm8bGduyicNUI5t3gMPqIfytfihT1BLq6Uqj6HruBNlgFuiXc/wgbIJetU4zheE0TKBacL4lF7F6j2iwgG/a8JNfnRNJ3106Tz8SyHs9eQbcr9UvUex7LOFFPZdzULN0s2/+YZf1P7+/3D6n593t5R4b+aE+hmySg3dU565QEbas1V1l+ESctLmw1nyl/1xCVYDdEwywefRAsZ9ip1zMM5VwCLFJP2H5RLx6E7up8xTqYjlAv0ewmF98nWbmB7PH0OM8x78qvhfdmvlTBqMQcIHe305fssD8+ABx+hDpbgPIxTyRG0yXUAYqPi+zAn4OH2M+DBacSdQ== 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 AM6PR04CA0011.eurprd04.prod.outlook.com (2603:10a6:20b:92::24) by AM0PR08MB5073.eurprd08.prod.outlook.com (2603:10a6:208:15c::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.15; Mon, 23 May 2022 09:51:11 +0000 Received: from VE1EUR03FT025.eop-EUR03.prod.protection.outlook.com (2603:10a6:20b:92:cafe::70) by AM6PR04CA0011.outlook.office365.com (2603:10a6:20b:92::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.22 via Frontend Transport; Mon, 23 May 2022 09:51:11 +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 VE1EUR03FT025.mail.protection.outlook.com (10.152.18.74) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.14 via Frontend Transport; Mon, 23 May 2022 09:51:10 +0000 Received: ("Tessian outbound 361d68419a2f:v119"); Mon, 23 May 2022 09:51:10 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 832b7328ae889928 X-CR-MTA-TID: 64aa7808 Received: from 5b51b7d641be.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id E7DE0947-F515-435F-827D-1387D2FB32CC.1; Mon, 23 May 2022 09:51:04 +0000 Received: from EUR04-HE1-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 5b51b7d641be.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Mon, 23 May 2022 09:51:04 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WED/QFznF8OOXyAv2FGCg56fa6Hvw+XI8M3IY8tbZ8GWbqmHeCXORGL6ogevFJEgkQgxqrEGHHfLnAEG005/i2yANLqQOFdxp+ujMFJQAaEFpHiSip6+f6H5CeNglG7C2011Il4fapHxto1ydS3P2c6yAr07nXGGGR/QbZ11Vs6Sv+EtV9TikfVy+Z8PTdi8KcT9UlsEMDeuCOLkyd7P/xMiCOHaSFN1vG1227cC1yNJ0WUC0y4skByMx7Cl5p8EW6Wt1bEF6AEhCjNOi5cKo3N88u+Xz3R0yOON3raGHuAhHOrNBaU0HOg64QwHi+VFOmQvb9v4aW9VpqIpi9kLmA== 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=9zF12Yr0TF5Hy0Ih8V7GG+DUaa0767w2hpHQCLktPOc=; b=A5uUmYWjnYSsujxpFWES5Hg3hJnq8Bzs1wGGfjjXrX/wLve0jQylGfNzbdfisXZ7fOeoRdVtj+qJ4gJl7wDQEb0Y65IwILSYAgVYf3Yf1ss6TSY+bkzJOrT28YSMw3yk4TXpr9eERuPzbl6s005X1r2SWlF0bqBzZUplMXlOYxwP0juDVPy4SrEi1DG6sp6jRMAIdZhvpX9HrLyrPqxTlZFYu3u8ngj+4EdaBskjSBsjRlROWD+TackpzOni0S0mTyGiMrr1FTr4EHpuyf0hRkZdoIxr47CCwvpYkgjHhNIjOwRm/HbvdIQrT49GPPFf8z8lN5G0ntPzdHaJkWgD1w== 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 AM6PR08MB3526.eurprd08.prod.outlook.com (2603:10a6:20b:4e::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.18; Mon, 23 May 2022 09:51:00 +0000 Received: from VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::7080:6233:cf8f:a8a6]) by VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::7080:6233:cf8f:a8a6%7]) with mapi id 15.20.5273.022; Mon, 23 May 2022 09:51:00 +0000 Message-ID: Date: Mon, 23 May 2022 10:50:56 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.1 Subject: Re: [PATCH, v4] [AArch64] MTE corefile support Content-Language: en-US To: John Baldwin , gdb-patches@sourceware.org References: <20220331140343.9047-1-luis.machado@arm.com> <20220503215632.914608-1-luis.machado@arm.com> <0fbdfe5d-ba10-d2ec-58d2-6fbb300f485b@arm.com> <10cac250-853a-c03e-9a1e-e545c98fa428@FreeBSD.org> From: Luis Machado In-Reply-To: <10cac250-853a-c03e-9a1e-e545c98fa428@FreeBSD.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-ClientProxiedBy: LO2P265CA0336.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:a4::36) To VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: f9ada1f4-2fea-4d63-552a-08da3ca1c459 X-MS-TrafficTypeDiagnostic: AM6PR08MB3526:EE_|VE1EUR03FT025:EE_|AM0PR08MB5073: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: 5Z+waJF2yyanM4Ahc7NEMSv+WD97mYYIJhH9vUf2B7Rb0kffaMOJ9Ac10SuppeRjegLMubEd02N+HRMQAMTGx0OH9l0ati1d6vXsXq8YQdcbMGlTrpLGEixLMQp2kRMhQZQIZCuhbsn5m+KibBB8KR0ARgZ7TTFgvtEzaHorLMXDRKXxlJyYkYNLJsCpVUx99P0UZsEl+wswrALDj0poqqz7KuolZk8Faf+LMGnUdy3ilWtlYKsd2ZPBemiXHgYd8NV7SNcx3qd82Are3ld42jwOpwOSnlT0hfXCNeTVcqVN83IDnKvMmaL2DZ3v856Wc2IJuDuq8t6UZVDAvIvD/5v1u1Z+6VffpEu1Dco8nW4Zrf+vGoeVBnoIQKD5cecO8ub7ASXsFL85FF8ujeFX/j88uGFJW40VfQg9yfnDJKEct2X25Pp3h6s1zhNAWTNd2aRCGT2VTLysrut0FRRaJkOfmbDUYqx80va+3kwtdlgXXmiZ1XW+p9NhQzJ3kh/xte6RbQD5j+Va8i3QfIA53c/FzRgYR4bT8VkmyPGu3CE7R4OuE14QX5XpNdnD4tmkZfsCZyr9sqkfSj34L6OS1+LLTmoApA0Y1l4qSezvx+wOxIFyZ98FiUxHIpG/vjIkqaxZBfajU33wkOmcIQZM+IDlTBfdHjYPEnr5JhtZ32wShhBc8M9zHYlmyme/e3Fbd/usG+wt0K7+IQ7o8DNMxdSdCDzqkWkOqb72kEWAdSMeLQb9Vgfl5kB4XtoctPvxNOlxVZaffK2xvbdjtvYjxpGZn/TnTC44taBWaoZkkviH1WRu15qqJiW3JLVOFaxa7ZAZsUEc11W8NVrcofC9GA== 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:(13230001)(4636009)(366004)(5660300002)(2616005)(508600001)(6486002)(26005)(6666004)(38100700002)(8936002)(6506007)(186003)(53546011)(31696002)(86362001)(44832011)(30864003)(83380400001)(66556008)(6512007)(316002)(8676002)(66946007)(66476007)(31686004)(2906002)(36756003)(2004002)(43740500002)(45980500001)(579004)(559001); DIR:OUT; SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR08MB3526 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: VE1EUR03FT025.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: b815adc5-6758-4bdb-a8cc-08da3ca1bda8 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RiyjJwer752MaZcsC9vaVev/7SJBouqdC3MRnm5vuMJuosSW788/fLKDaD88nsqx7fVHwrb+0me09DDcW0SZRu2BuISnLCfCLv16WpA0fyu1CyDJZvG85nrvvW6K8DTObPGf1hDqnw2v5aVM4DAuKmsJPTEjj/26dH5E7ByOCLdH6FIwmk+/yPa0OEs2yTyUjy4RDkLPjl4V/xAfp3HAjFswgQ575NaLHpGr8RpRrLK09qFpFCQDiQCCsDT9vC/I1LFRVrv/R7zE4cj49XKx3hDAS5PCq8fJM5n6kyECq1nR+cMRb9VSE6i69Hc96EjOVUcQRc181sKrBThTSAkQ3w5vg46hOYvvOb9lRgAoByBc3aGftBcUuFiX99Gq22jRLOiJLG2KBYgkTMiSoRrLVm5Sgz77FB8QLGIUPrzrgi2V+WZS55nYOZkcnyRwrUGO0zwo1zA66qUSPIMM0e7YbNX/Ckd3ZuI+0ouA8CBEkqoqn4+18wW3qHtwU7wHaEr7n861BBwi4hqz+EfprD/Gi8z65EizzZxPqtkcEfnSvkv/LrG9i9FVAyDK3r5Gv2uxLwtW8ih2DczXbkcb/VWPeunRmRkyl4e/z5BQThr08lul/UUTm9QSlAjFfWuHLyHep5U+RPDbTH9feJ67Yb3Zd+in+YCEOax6nblz5GQe3no5Tg91vgXU+uX3J7zmgtLf5IJdxe/MjziVtgoRyBnynlKWOZwqr8Zx/0RYoIK4DKnKgLdj9RgXIpXCrktvEfceJcazTx0GVqsw3XS2KBCqxML4DiqVIHHmZT4ZuMR22UhfT3kElkeYGAuus+BVdmp0 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:(13230001)(4636009)(36840700001)(46966006)(40470700004)(70586007)(70206006)(508600001)(83380400001)(47076005)(336012)(2906002)(2616005)(186003)(31696002)(8676002)(5660300002)(40460700003)(36756003)(6486002)(36860700001)(44832011)(53546011)(86362001)(30864003)(6506007)(8936002)(31686004)(26005)(316002)(6512007)(82310400005)(81166007)(6666004)(356005)(2004002)(43740500002)(579004)(559001); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 May 2022 09:51:10.6530 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: f9ada1f4-2fea-4d63-552a-08da3ca1c459 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: VE1EUR03FT025.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR08MB5073 X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, 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: Mon, 23 May 2022 09:51:22 -0000 Hi, On 5/18/22 14:58, John Baldwin wrote: > From my perspective this looks ok. Great. Thanks for the feedback. > > On 5/18/22 5:46 AM, Luis Machado via Gdb-patches wrote: >> Ping? The binutils patch has been approved, but I'd like to push both at the same time. >> >> 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" >>> +} >> > >