From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR04-DB3-obe.outbound.protection.outlook.com (mail-eopbgr60053.outbound.protection.outlook.com [40.107.6.53]) by sourceware.org (Postfix) with ESMTPS id 77B28383E6B4 for ; Mon, 23 May 2022 09:49:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 77B28383E6B4 ARC-Seal: i=2; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=pass; b=ITTze0+46utK9wYjTqPXtDVTx1CeRpte3Koudgz8bYrH68vI3cOghxc+ro8cAFDvIlO4AQ2O4DNrNXeS+rSBOmAg1uDhc3aO0+VUn59i8SR/H5ESbbOI8/gDtsT6yfYvek6SIIgnSifAudv15L8cu036itvZbviMW5LTjDlsCpNpm4KR55gNAcL2Lt6c6fMAi+V8WV46/ERmhy0QqcRLaePCx9zpEEB8rd04RRUmr7Kg7hkbdyJSMhByuZBiDJB4KXtGlyJANo9PsW8UX72gAKG8ZKx3L6C+eVa1YSBly4bWLuMIYH7kYICa4CdhU3PqukvrEcc613cBQsBYne8MrQ== 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=kG70eD1R5+FT6iGEIGDosRrX57Kxe52EueCGlTNNoN4=; b=H1XfrRjEmbGg9mTsaiWnvv47pugrfJvQ+0fGmDcn82GM7KfhKyCk+Oy7LqZLN0644aYhd0jj2hwyJs4gSVukPvbtT0ptrPtGWaTFSTE8Y8CmFeeYDC0hFnLih1GK/m3toJZFegygWVO0Lt540DonS1hdSKxlmtlOH0d1zJAsirYlg615A/mVDFdH3hlO9mercAdwws6jJo+XLqpzhjPHAX+Knx2naRp6R2+NR0fOoGCsxtSJyJFYQHrE2i3wijQQSsklxiI7meqMImpho5g5jCFA/gs7T32/GqYoCaQCe6oQ4gKePBKRdBpa7M3x1MIyBoNpNz/LUFNp4eH3K7jJQQ== 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 DB8P191CA0006.EURP191.PROD.OUTLOOK.COM (2603:10a6:10:130::16) by DB6PR0801MB1941.eurprd08.prod.outlook.com (2603:10a6:4:76::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.14; Mon, 23 May 2022 09:49:43 +0000 Received: from DBAEUR03FT054.eop-EUR03.prod.protection.outlook.com (2603:10a6:10:130:cafe::37) by DB8P191CA0006.outlook.office365.com (2603:10a6:10:130::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5273.15 via Frontend Transport; Mon, 23 May 2022 09:49:43 +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 DBAEUR03FT054.mail.protection.outlook.com (100.127.142.218) 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:49:43 +0000 Received: ("Tessian outbound c1f35bac1852:v119"); Mon, 23 May 2022 09:49:43 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 20061d01ac8de1f2 X-CR-MTA-TID: 64aa7808 Received: from 3e5f94741bc2.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 0EBF504D-8CA6-4430-883F-005DBC6B598F.1; Mon, 23 May 2022 09:49:36 +0000 Received: from EUR04-HE1-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 3e5f94741bc2.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Mon, 23 May 2022 09:49:36 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=eshPc/A4N2N77NLp7FEkPupjtRI9gm8bdAOiPMv03kTMKesfoHX8SXpUwqeIiMMPUJ8vELolAhNr3V7UcvTDNw65l2FJRmEMD7/Fnlzk/6rC8d0rHFnV8d+onYvV8vRsByuDMWhwnOyHIohfKVwKDIYH79y7pJ1jvRuo2ubDrUshOH3P4oGdJZP+fnax0FOgaNva35zAFAOdNkJ3V6lXHJ/qXje9QLLItqAMe9pLzl30LDSKCRkr2Cai7x+PCcngAyu7sa6dx5lS8gh5ycCtVWnZOKiROdR0AdvTx5BWoVfuZ6w0qjXwexxdVqUMHReMGnfYurpLE+r3VZrN7NSD1Q== 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=kG70eD1R5+FT6iGEIGDosRrX57Kxe52EueCGlTNNoN4=; b=ha7SohG2y80IqzYNGmKj66Pdswkx6k8LzDPJMIuEy4iF2IqIvg6pv+QtFBkTxMv3Fvxp6qYTuHysNXnzwEYKv2VVz2Q3s3Zqkjd0f+rG+qqwqm9jQUfrF42BRojcntiEfq08HPNtCh+w3UuNPMxNfgUEFmiAjkH0QwQ6B+tdP7RcxXGm0/Dib9PyRPbgtrMICCWRScdVaxpXFetyCdA0UruptifPpc66FVI+hcJ6U29+tSykqSzjTkyX3MbCiDVmfzlhpijHS+BqydCGs5ysys5qDtLZIGhzTegQlhqBHmLrWssZyayCCDD4Rex7pmhfucEAvs7RUZSVO0Mxk9CRiA== 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:49:33 +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:49:33 +0000 Message-ID: <75645adc-fae3-d293-3628-e2ddfb26c9b5@arm.com> Date: Mon, 23 May 2022 10:49:31 +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: 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> From: Luis Machado In-Reply-To: <0fbdfe5d-ba10-d2ec-58d2-6fbb300f485b@arm.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-ClientProxiedBy: LO2P265CA0318.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:a4::18) To VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 4bd3e82f-7f0e-4f8f-c6f9-08da3ca19056 X-MS-TrafficTypeDiagnostic: AM6PR08MB3526:EE_|DBAEUR03FT054:EE_|DB6PR0801MB1941: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: gglvrUMPdJxLdvmDb/s61LErfO/ON+q8oTmIRfed6FxS5drEDpwBSl+iOI8uu3EwdMFuATjaJA+CT7bOca/UzbuPiJ5baJYMUQhHmSkPIYvf4VmdqWZtd8SL2riafCHWl027a/RIGT7H+2fay/q0Ui0IOIKy0sYxrGWTFUw+ka0RcjKBigNIl9M1QtjTVbxgA1kXmTMVa38QOTliU9kladi74/Is5ONvP3PH5oDhwqmxyw+0H+9QIJ5VDLA+8KziOH8GCDT+VnWgOG1CSKUIukB9vx8UgZJb5NM3hRR2CURezTfhQpnh1blzOsMXgaW+E17mP22SmB5e2anFo60jUvQ38WzvLNkY81goaaUyRdGjhXxs5JU+A55TJDsl3FhBovVON7Z7k/8lqpw9YS1ThZJ2IegM99PYSi/ej0OK60wxLczFm9KpgPItTRbxm6BRbGSdwetcON4chJ/l0KswvtCa6jXcqeZKt1HgmdGiiMTSoej/HC3v5Nddr5sOQuCCRZuzHZlZ6eOk85Rjumvk5PrL86fSFPSTTG/GsnIJoNxf6n5vZ11nZgNk1oibAtKrD2I4g8e7hXoi6WAda34UWIHzoMgxr66fyLY6Y7Fn1EvD+C1es40Kwy9rXd18HWeqCK2EpekKz0CXzVRzhK7qqdf1MSmrRhEVMoRC3CjGf57wOxnF+dg5l+xLLjoddYv/LkOWeeMNcF3/N/6DO/6bFW0JzV+PEj4/KgLKc6u5Hxb6/nIOOTrFWimE54twchnkfGtEilnDNOsY+nPC/2CQoxxs/70O8DHdIh+5YXGV2sopi8jT2gq68MKdEcg4OTQB 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)(38100700002)(8936002)(6506007)(186003)(53546011)(31696002)(86362001)(44832011)(30864003)(83380400001)(66556008)(6512007)(316002)(8676002)(66946007)(66476007)(31686004)(6916009)(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: DBAEUR03FT054.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: cd6e2ce9-76b7-4dcf-70e5-08da3ca189da X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: yZrj97Mc4YAKUsS9sQKKljG5uEYzR8CAVeIUcS5YqCqdGzhuLFK01CgKzcvQ4p4MK1aOrwBIocIrNpGUt9VnFeSTxnbuH4lEst2e9GvWk0kaPBP68Uh7ho6u2yvXEpfXigtsy1aBmSm+ouN7cR5YtxUzYu5BUZRGbHWA2lYIdX5lehCdAu3zR0QeEXwBq6fEQODs8OotPLyHo/lAVrv+kLEUOuuLtdtE3jvggASjwMdOiMlkpHC8hXsKp9oqJPxPKchiwzS4HFe81dKVrHsFf8L8msHMn9v8waUuOq7xfkI9LrFB+CgQUgw4+FO8ZdbRscJ2ePnd5Dp5IdkPrIoiAJ2ZZ8i8GgBA5+QJaHkLHBU3ZwXmAojktsRj3J5ig0CQDazddra3UMcTBa66Xk1bPcuY0XKYm+7jRx+PuREQcwalwsjUq3Fm+IIkof/n0W0nsPa2tny0KpAaiR3iKQoDlbEn5trCUnsF+qZivva1D5RtwsF9I8DldSJ5h2X+JQiU9lfInutkSLtLwVaTFZC5RpkfXYHJwRqasIWQb1UvylNryGzJ1MRTYempBtpanNN2ME9tdRjHYPsKcwG6fYC5b+1X1gLAUYG4NItoUyeOzuLfRTKlwf34+SU6p4+KNJxotdIsGWOxZrMMeOp0CKLq9gCAQSOG/mhRw/B2LNAJKyCimeWwenbD8qNUGi82+HgJCr2GnZVPEzOWBAys3QP9JIMqQsQAsGOgZ5HeJntc++QMFB3Lg1L/V/JnJndSHbRrv25zZs7hkNLksjW2EysQ/U35X4ZD3UxvNhIfbR3iYRhgwPi9mb99WDEVwYsX18fd 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)(40470700004)(46966006)(6506007)(53546011)(186003)(44832011)(81166007)(6916009)(30864003)(6512007)(26005)(356005)(2906002)(2616005)(31696002)(5660300002)(40460700003)(6486002)(36756003)(8936002)(508600001)(83380400001)(86362001)(70586007)(70206006)(47076005)(82310400005)(336012)(36860700001)(8676002)(316002)(31686004)(2004002)(43740500002)(579004)(559001); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 May 2022 09:49:43.5353 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 4bd3e82f-7f0e-4f8f-c6f9-08da3ca19056 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: DBAEUR03FT054.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0801MB1941 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:50:03 -0000 Ping? On 5/18/22 13:46, 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" >> +} >