From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by sourceware.org (Postfix) with ESMTPS id 1BF6038485AF for ; Mon, 6 Jun 2022 09:54:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1BF6038485AF X-UUID: ff7fa8f75a5d471282b044fefba3faa9-20220606 X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.5, REQID:51f24031-5ef1-4cdb-8c74-59deb235cbd1, OB:0, LO B:0,IP:0,URL:5,TC:0,Content:0,EDM:0,RT:0,SF:26,FILE:0,RULE:Release_Ham,ACT ION:release,TS:31 X-CID-INFO: VERSION:1.1.5, REQID:51f24031-5ef1-4cdb-8c74-59deb235cbd1, OB:0, LOB: 0,IP:0,URL:5,TC:0,Content:0,EDM:0,RT:0,SF:26,FILE:0,RULE:Release_Ham,ACTIO N:release,TS:31 X-CID-META: VersionHash:2a19b09, CLOUDID:7194c0ad-3171-4dd4-a2d9-73b846daf167, C OID:f04af5edd5f5,Recheck:0,SF:28|100|17|19|48|101,TC:nil,Content:0,EDM:-3, IP:nil,URL:1,File:nil,QS:0,BEC:nil X-UUID: ff7fa8f75a5d471282b044fefba3faa9-20220606 Received: from mtkcas10.mediatek.inc [(172.21.101.39)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1302101600; Mon, 06 Jun 2022 17:54:33 +0800 Received: from mtkmbs11n2.mediatek.inc (172.21.101.187) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.792.15; Mon, 6 Jun 2022 17:54:31 +0800 Received: from mtksdccf07 (172.21.84.99) by mtkmbs11n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.792.3 via Frontend Transport; Mon, 6 Jun 2022 17:54:31 +0800 Message-ID: <54830e42a402b2f3c694be25c51670c12a4bd181.camel@mediatek.com> Subject: Re: [PATCH, v4] [AArch64] MTE corefile support From: Kuan-Ying Lee To: Luis Machado , "gdb-patches@sourceware.org" Date: Mon, 6 Jun 2022 17:54:31 +0800 In-Reply-To: References: <20220331140343.9047-1-luis.machado@arm.com> <20220503215632.914608-1-luis.machado@arm.com> <1dd14ec1-b0e3-8c4b-678c-1c67341ef978@arm.com> <04febcab961d9ae834ffdea960a7469a3a309b13.camel@mediatek.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.28.5-0ubuntu0.18.04.2 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-MTK: N X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, 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, 06 Jun 2022 09:54:45 -0000 On Mon, 2022-06-06 at 17:47 +0800, Luis Machado wrote: > On 6/6/22 10:42, Kuan-Ying Lee wrote: > > On Mon, 2022-06-06 at 17:28 +0800, Luis Machado via Gdb-patches > > wrote: > > > Ping? > > > > > > > Hi Luis, > > > > I don't see PT_AARCH64_MEMTAG_MTE in include/elf/common.h. > > > > I think we need to add below in include/elf/common.h. > > Based on binutils@ feedback, this constant was moved to > include/elf/aarch64.h, and is > part of the binutils patch. Got it. Thanks. :) > > > > > #define PT_AARCH64_MEMTAG_MTE (PT_LOPROC + 0x2) > > > > Or do I miss something? > > > > Best regards, > > Kuan-Ying Lee > > > > > 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_G > > > > RANULE_S > > > > IZE); > > > > + > > > > + /* 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_G > > > > RANULE_S > > > > IZE); > > > > + /* 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_sign > > > > al_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_m > > > > emtag_se > > > > ction); > > > > } > > > > > > > > /* 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_secti > > > > on_callb > > > > ack, > > > > + 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_secti > > > > on_f > > > > type 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_f > > > > type > > > > 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_secti > > > > on_f > > > > type 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 < > > > > https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$ > > > > >. */ > > > > + > > > > +#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 < > > > > https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$ > > > > >. */ > > > > + > > > > +#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 < > > > > https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$ > > > > >. */ > > > > + > > > > +/* 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 < > > > > https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!CTRNKA9wMg0ARbw!0jBVgsoE-RaTGT098YRLfC3gcQJlvfuMujbUqmtqoh3JjeD2BI4JNxmWCGaefncNfKBbmw$ > > > > >. > > > > + > > > > +# 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" > > > > +}