From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by sourceware.org (Postfix) with ESMTPS id 3B0A33854833 for ; Sun, 11 Jul 2021 14:22:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3B0A33854833 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com Received: by mail-pj1-x1035.google.com with SMTP id x21-20020a17090aa395b029016e25313bfcso8913853pjp.2 for ; Sun, 11 Jul 2021 07:22:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=SKkIepI+7ZETvUdGW7sTw23wFe44PD7f0/8sgfsp16c=; b=X8nqLRpAjhtma9+nf0U1GUMSsWsaMvLdnDFY9L+bEIGFfr4TaQ0Rxv8AOn8ImGsj/D CPA0Bmi6ZqQ/l4shnAuV991XWcBIwu30sKsgAxLGkYAoLZqA1dDpId5M6slkHcbsXlMR 3K+8Q4eQKI0zB9ZJ+njr5ajMFbKBB7kTQe5+r+4AwbFmx7vzKBFEO4Sbpu4rq5Bgx/Fj GHuK1fKEP1K11Gv8bt7ckSKxE9qardWAgxEfulGJhX0JzkK5epfvM0ZtDaN8g+HqmK4T lXa/oTguQ8RBxmCBgyCQ33u9sw0upeg5/Ay5dAWYx3U4ZOLn07UfMyKwmHRJJNM4tJLL l1PA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=SKkIepI+7ZETvUdGW7sTw23wFe44PD7f0/8sgfsp16c=; b=YBK3zo/PUPhuaZlCFaBkH8GOT4keFahqVOdRvtTys3lT7aadaER2V2x6qX8nq1Oti7 1GBRj86txkdtwIgoFd14l6I+YGtxRV/y4iiJP0H9ti8pgk/n6jtCikuikQKp7YzKJiwY i8+z37IERvmbW8nte7EynbNbT/yvqVY3xMZEfYLSn0b1lzNd188vDCF9CkqBm4Kj49VU OGkSSVRRQ3BRDendkSlqAwAEo2oQQmG/FU3r9oOq7rZEZWpTBOvyHFVUtdQ87S65waC2 RrAeYOb/PtK1WAHlNo9KWPbmYXEkwLTcRyQ8VN4LJqKOXLEysoPZ1fgq86oNo3/31RnR VFjQ== X-Gm-Message-State: AOAM530l2OTSXrHfM4iuw0DaeQTaVFbBQRcE4nAzzaZQsvnJUTkNiAlS NKSfVk0oFFx/M3uJhCFsDoNA X-Google-Smtp-Source: ABdhPJxpePjmrJfwUbFJEn7yok3usFJJNL4e1zg32chLB85PdKV4NvsMzGO/9x9ssNLSk3jgiS5eTw== X-Received: by 2002:a17:90b:4c12:: with SMTP id na18mr19108101pjb.157.1626013322642; Sun, 11 Jul 2021 07:22:02 -0700 (PDT) Received: from takamaka.home ([184.69.131.86]) by smtp.gmail.com with ESMTPSA id b20sm12473946pfl.9.2021.07.11.07.22.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Jul 2021 07:22:01 -0700 (PDT) Received: by takamaka.home (Postfix, from userid 1000) id E9F0B89CFD; Sun, 11 Jul 2021 07:22:00 -0700 (PDT) Date: Sun, 11 Jul 2021 07:22:00 -0700 From: Joel Brobecker To: Luis Machado via Gdb-patches Cc: simon.marchi@polymtl.ca, david.spickett@linaro.org, catalin.marinas@arm.com, Joel Brobecker Subject: Re: [PING][PATCH,v5][AArch64] MTE corefile support Message-ID: <20210711142200.GA637634@adacore.com> References: <20210518202047.3492211-1-luis.machado@linaro.org> <20210601174519.4157316-1-luis.machado@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: Sun, 11 Jul 2021 14:22:09 -0000 Hi everyone, Luis is trying to have this new feature ready for the GDB 11.1 release. As I understand it, the AArch64-specific part has already been approved, so he's waiting for someone to review the rest of the changes. Is there a Global Maintainer who would feel comfortable doing so and who would have the time? Thank you! On Thu, Jul 01, 2021 at 10:50:44AM -0300, Luis Machado via Gdb-patches wrote: > > > On 6/1/21 2:45 PM, Luis Machado wrote: > > Updates on v5: > > > > - Fixed format warning output. > > > > Updates on v4: > > > > - Calculate sizes based on individual struct field sizes. > > > > Updates on v3: > > > > - Addressed review comments. > > - New files gdbsupport/memtag.h, gdb/memtag.h and gdb/memtag.c. > > - Updated code documentation. > > - Removed code duplication. > > > > Updates on v2: > > > > - Reworked core_target::fetch_memtags to handle cases where address + len runs > > over the NT_MEMTAG note. > > - Turned a few magic numbers into constants. There is an unfortunate duplication > > of a constant (NT_MEMTAG_HEADER_SIZE). It is a generic constant, but there is > > no file generic enough that gets included by both corelow and linux-tdep. > > - More sanity checks to make sure the note format is correct. > > - Documented aarch64_linux_decode_memtag_note a little more. > > > > --- > > > > Teach GDB how to dump memory tags when using the gcore command and how > > to read them back from a core file generated via gcore or the kernel. > > > > Each tagged memory range (listed in /proc//smaps) gets dumped to its > > own NT_MEMTAG note. A section named ".memtag" is created for each of those > > when reading the core file back. > > > > Dumping memory tags > > - > > > > When using the gcore command to dump a core file, GDB will go through the maps > > in /proc//smaps looking for tagged ranges. Each of those entries gets > > passed to an arch-specific gdbarch hook that generates a vector of blobs of > > memory tag data that are blindly put into a NT_MEMTAG note. > > > > The vector is used because we may have, in the future, multiple tag types for > > a particular memory range. > > > > Each of the NT_MEMTAG notes have a generic header and a arch-specific header, > > like so: > > > > struct tag_dump_header > > { > > uint16_t format; // Only NT_MEMTAG_TYPE_AARCH_MTE at present > > uint64_t start_vma; > > uint64_t end_vma; > > }; > > > > struct tag_dump_mte > > { > > uint16_t granule_byte_size; > > uint16_t tag_bit_size; > > uint16_t __unused; > > }; > > > > The only bits meant to be generic are the tag_dump_format, start_vma and > > end_vma fields. > > > > The format-specific data is supposed to be opaque and only useful for the > > arch-specific code. > > > > We can extend the format in the future to make room for other memory tag > > layouts. > > > > Reading memory tags > > - > > > > When reading a core file that contains NT_MEMTAG entries, GDB will use > > a different approach to check for tagged memory range. Rather than looking > > at /proc//smaps, it will now look for ".memtag" sections with the right > > memory range. > > > > When reading tags, GDB will now use the core target's implementation of > > fetch_memtags (store_memtags doesn't exist for core targets). Then the data > > is fed into an arch-specific hook that will decode the memory tag format and > > return a vector of tags. > > > > I've added a test to exercise writing and reading of memory tags in core > > files. > > > > gdb/ChangeLog: > > > > YYYY-MM-DD Luis Machado > > > > * Makefile.in (COMMON_SFILES): Add memtag.c. > > * NEWS: Mention core file support for memory tagging. > > * aarch64-linux-tdep.c: Include elf/common.h. > > Include gdbsupport/memtag.h. > > (MAX_TAGS_TO_TRANSFER): New constant. > > (aarch64_linux_create_memtag_notes_from_range): New function. > > (aarch64_linux_decode_memtag_note): Likewise. > > (aarch64_linux_init_abi): Register new core file hooks. > > (NT_MEMTAG_TOTAL_HEADER_SIZE): New constant. > > * arch/aarch64-mte-linux.h (tag_dump_mte): New struct. > > (AARCH64_MTE_TAG_BIT_SIZE): New constant. > > * corelow.c: Include gdbsupport/memtag.h and memtag.h. > > (core_target) : New > > method overrides. > > * gdbarch.c: Regenerate. > > * gdbarch.h: Likewise. > > * gdbarch.sh (create_memtag_notes_from_range): New hook. > > (decode_memtag_note): Likewise. > > * linux-tdep.c: Include gdbsupport/memtag.h and memtag.h. > > (linux_address_in_memtag_page): Renamed to... > > (linux_process_address_in_memtag_page): ... this. > > (linux_core_file_address_in_memtag_page): New function. > > (linux_address_in_memtag_page): Likewise. > > (linux_make_memtag_corefile_notes): Likewise. > > (linux_make_corefile_notes): Handle memory tag notes. > > * memtag.c: New file. > > * memtag.h: New file. > > > > gdb/doc/ChangeLog: > > > > YYYY-MM-DD Luis Machado > > > > * gdb.texinfo (AArch64 Memory Tagging Extension): Mention support > > for memory tagging in core files. > > > > gdb/testsuite/ChangeLog: > > > > YYYY-MM-DD Luis Machado > > > > * gdb.arch/aarch64-mte-gcore.c: New file. > > * gdb.arch/aarch64-mte-gcore.exp: New file. > > > > gdbsupport/ChangeLog: > > > > YYYY-MM-DD Luis Machado > > > > * memtag.h: New file. > > --- > > gdb/Makefile.in | 1 + > > gdb/NEWS | 4 + > > gdb/aarch64-linux-tdep.c | 221 +++++++++++++++++++ > > gdb/arch/aarch64-mte-linux.h | 17 ++ > > gdb/corelow.c | 63 ++++++ > > gdb/doc/gdb.texinfo | 4 + > > gdb/gdbarch.c | 64 ++++++ > > gdb/gdbarch.h | 16 ++ > > gdb/gdbarch.sh | 6 + > > gdb/linux-tdep.c | 97 +++++++- > > gdb/memtag.c | 88 ++++++++ > > gdb/memtag.h | 46 ++++ > > gdb/testsuite/gdb.arch/aarch64-mte-gcore.c | 93 ++++++++ > > gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 111 ++++++++++ > > gdbsupport/memtag.h | 39 ++++ > > 15 files changed, 867 insertions(+), 3 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 > > create mode 100644 gdbsupport/memtag.h > > > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in > > index f664d964536..12fb3b390b1 100644 > > --- a/gdb/Makefile.in > > +++ b/gdb/Makefile.in > > @@ -1100,6 +1100,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 ab678acec8b..58b9f739d4f 100644 > > --- a/gdb/NEWS > > +++ b/gdb/NEWS > > @@ -3,6 +3,10 @@ > > *** Changes since GDB 10 > > +* 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. > > + > > * GDB now supports general memory tagging functionality if the underlying > > architecture supports the proper primitives and hooks. Currently this is > > enabled only for AArch64 MTE. > > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c > > index e9761ed2189..04498f3b6c0 100644 > > --- a/gdb/aarch64-linux-tdep.c > > +++ b/gdb/aarch64-linux-tdep.c > > @@ -52,6 +52,9 @@ > > #include "value.h" > > #include "gdbsupport/selftest.h" > > +#include "gdbsupport/memtag.h" > > + > > +#include "elf/common.h" > > /* Signal frame handling. > > @@ -1779,6 +1782,213 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, > > } > > } > > +/* Memory tag note header size. Includes both the generic and the > > + arch-specific parts. */ > > +#define NT_MEMTAG_TOTAL_HEADER_SIZE (NT_MEMTAG_GENERIC_HEADER_SIZE \ > > + + NT_MEMTAG_MTE_HEADER_SIZE) > > + > > +/* Maximum number of tags to request. */ > > +#define MAX_TAGS_TO_TRANSFER 1024 > > + > > +/* AArch64 Linux implementation of the aarch64_create_memtag_notes_from_range > > + gdbarch hook. Create core file notes for memory tags. */ > > + > > +static std::vector > > +aarch64_linux_create_memtag_notes_from_range (struct gdbarch *gdbarch, > > + CORE_ADDR start_address, > > + CORE_ADDR end_address) > > +{ > > + /* We only handle MTE tags for now. */ > > + > > + /* Figure out how many tags we need to store in this memory range. */ > > + size_t granules = aarch64_mte_get_tag_granules (start_address, > > + end_address - start_address, > > + AARCH64_MTE_GRANULE_SIZE); > > + > > + /* Vector of memory tag notes. Add the MTE note (we only have MTE tags > > + at the moment). */ > > + std::vector notes (1); > > + > > + /* If there are no tag granules to fetch, just return. */ > > + if (granules == 0) > > + return notes; > > + > > + /* Adjust the MTE note size to hold the header + tags. */ > > + notes[0].resize (NT_MEMTAG_TOTAL_HEADER_SIZE + granules); > > + > > + 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))); > > + notes.resize (0); > > + return notes; > > + } > > + > > + /* 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; > > + } > > + > > + /* Create the header. */ > > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > > + gdb_byte *buf = notes[0].data (); > > + > > + /* Generic header. */ > > + /* Tag dump format */ > > + store_unsigned_integer (buf, sizeof (tag_dump_header::format), > > + byte_order, NT_MEMTAG_TYPE_AARCH_MTE); > > + buf += sizeof (tag_dump_header::format); > > + > > + /* Start address */ > > + store_unsigned_integer (buf, sizeof (tag_dump_header::start_vma), > > + byte_order, start_address); > > + buf += sizeof (tag_dump_header::start_vma); > > + > > + /* End address */ > > + store_unsigned_integer (buf, sizeof (tag_dump_header::end_vma), > > + byte_order, end_address); > > + buf += sizeof (tag_dump_header::end_vma); > > + > > + /* MTE-specific header. */ > > + /* Granule byte size */ > > + store_unsigned_integer (buf, sizeof (tag_dump_mte::granule_byte_size), > > + byte_order, AARCH64_MTE_GRANULE_SIZE); > > + buf += sizeof (tag_dump_mte::granule_byte_size); > > + > > + /* Tag bit size */ > > + store_unsigned_integer (buf, sizeof (tag_dump_mte::tag_bit_size), > > + byte_order, AARCH64_MTE_TAG_BIT_SIZE); > > + buf += sizeof (tag_dump_mte::tag_bit_size); > > + > > + /* Unused value */ > > + store_unsigned_integer (buf, sizeof (tag_dump_mte::__unused), byte_order, 0); > > + > > + /* Store the tags. */ > > + memcpy (notes[0].data () + NT_MEMTAG_TOTAL_HEADER_SIZE, tags.data (), > > + tags.size ()); > > + > > + return notes; > > +} > > + > > +/* AArch64 Linux implementation of the decode_memtag_note gdbarch > > + hook. Decode a memory tag note and return the requested tags. > > + > > + The note is guaranteed to cover the [ADDRESS, ADDRESS + length) > > + range. */ > > + > > +static gdb::byte_vector > > +aarch64_linux_decode_memtag_note (struct gdbarch *gdbarch, > > + gdb::array_view note, > > + CORE_ADDR address, size_t length) > > +{ > > + gdb::byte_vector tags; > > + > > + /* Sanity check. */ > > + if (note.size () < NT_MEMTAG_TOTAL_HEADER_SIZE) > > + { > > + warning (_("Malformed core note - too short for MTE header.\n" > > + "Expected %s bytes but got %s bytes."), > > + pulongest (NT_MEMTAG_TOTAL_HEADER_SIZE), > > + pulongest (note.size ())); > > + return tags; > > + } > > + > > + /* The amount of memory tag granules we need to fetch. */ > > + size_t granules > > + = aarch64_mte_get_tag_granules (address, length, AARCH64_MTE_GRANULE_SIZE); > > + > > + /* If there are no tag granules to decode, just return. */ > > + if (granules == 0) > > + return tags; > > + > > + /* Read the generic header. */ > > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > > + const gdb_byte *buf = note.data (); > > + > > + unsigned int format > > + = extract_unsigned_integer (buf, sizeof (tag_dump_header::format), > > + byte_order); > > + buf += sizeof (tag_dump_header::format); > > + > > + CORE_ADDR start_vma > > + = extract_unsigned_integer (buf, sizeof (tag_dump_header::start_vma), > > + byte_order); > > + buf += sizeof (tag_dump_header::start_vma); > > + > > + CORE_ADDR end_vma > > + = extract_unsigned_integer (buf, sizeof (tag_dump_header::end_vma), > > + byte_order); > > + buf += sizeof (tag_dump_header::end_vma); > > + > > + /* Validate that ADDRESS + LENGTH doesn't fall outside of this note's > > + range of addresses. */ > > + gdb_assert (address + length < end_vma); > > + > > + /* Is the tag header format correct for this note? */ > > + if (format != NT_MEMTAG_TYPE_AARCH_MTE) > > + { > > + warning (_("Unexpected memory tag note format.\n" > > + "Expected %x but got %x."), NT_MEMTAG_TYPE_AARCH_MTE, > > + format); > > + return tags; > > + } > > + > > + size_t expected_tag_bytes = (end_vma - start_vma)/AARCH64_MTE_GRANULE_SIZE; > > + > > + /* Does the number of tag bytes in this note match the expected number > > + of tag bytes the note says it has? */ > > + if (note.size () < (NT_MEMTAG_TOTAL_HEADER_SIZE + expected_tag_bytes)) > > + { > > + warning (_("Unexpected tag data size.\n" > > + "Expected %s but got %s."), pulongest (expected_tag_bytes), > > + pulongest (note.size () - NT_MEMTAG_TOTAL_HEADER_SIZE)); > > + return tags; > > + } > > + > > + /* Calculate how many granules we need to skip to get to the granule of > > + ADDRESS. Align both the start address and the requested address > > + so it is easier to get the number of granules to skip. This way we > > + don't need to consider cases where ADDRESS falls in the middle of a > > + tag granule range. */ > > + CORE_ADDR aligned_start_address > > + = align_down (start_vma, AARCH64_MTE_GRANULE_SIZE); > > + CORE_ADDR aligned_address = align_down (address, AARCH64_MTE_GRANULE_SIZE); > > + > > + size_t skipped_granules > > + = aarch64_mte_get_tag_granules (aligned_start_address, > > + aligned_address - aligned_start_address, > > + AARCH64_MTE_GRANULE_SIZE); > > + > > + /* Point to the block of data that contains the first granule we are > > + interested in. */ > > + const gdb::array_view tags_data > > + = note.slice (NT_MEMTAG_TOTAL_HEADER_SIZE + skipped_granules, granules); > > + > > + /* Read the tag granules. */ > > + for (size_t i = 0; i < granules; i++) > > + tags.push_back (tags_data[i]); > > + > > + return tags; > > +} > > + > > static void > > aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) > > { > > @@ -1862,6 +2072,17 @@ 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 memory tag notes for a particular range of > > + addresses. */ > > + set_gdbarch_create_memtag_notes_from_range > > + (gdbarch, aarch64_linux_create_memtag_notes_from_range); > > + > > + /* Core file helper to decode a memory tag note. */ > > + set_gdbarch_decode_memtag_note (gdbarch, > > + aarch64_linux_decode_memtag_note); > > } > > /* Initialize the aarch64_linux_record_tdep. */ > > diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h > > index 2aa97eb861a..7da9de4aefb 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,20 @@ 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); > > +/* NT_MEMTAG header for MTE tags. */ > > +struct tag_dump_mte > > +{ > > + /* Size of the tag granule in bytes. */ > > + uint16_t granule_byte_size; > > + /* Size of the tag in bits. */ > > + uint16_t tag_bit_size; > > + /* Reserved field for the future. */ > > + uint16_t __unused; > > +}; > > + > > +/* Size of the MTE header for a NT_MEMTAG note. */ > > +#define NT_MEMTAG_MTE_HEADER_SIZE (sizeof (tag_dump_mte::granule_byte_size) \ > > + + sizeof (tag_dump_mte::tag_bit_size) \ > > + + sizeof (tag_dump_mte::__unused)) > > + > > #endif /* ARCH_AARCH64_LINUX_H */ > > diff --git a/gdb/corelow.c b/gdb/corelow.c > > index 452b4dd4f9a..24c5bf29a11 100644 > > --- a/gdb/corelow.c > > +++ b/gdb/corelow.c > > @@ -51,6 +51,8 @@ > > #include "gdbcmd.h" > > #include "xml-tdesc.h" > > #include "observable.h" > > +#include "gdbsupport/memtag.h" > > +#include "memtag.h" > > #ifndef O_LARGEFILE > > #define O_LARGEFILE 0 > > @@ -100,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. */ > > @@ -1115,6 +1124,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 notes. 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_note_p (gdbarch)) > > + error (_("gdbarch_decode_memtag_note not implemented for this " > > + "architecture.")); > > + > > + memtag_note_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_note (gdbarch, info.note, 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 NT_MEMTAG > > + note. Check if we need to fetch tags from a different section. */ > > + if (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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > > index 90d827a50e7..1b001e6cacb 100644 > > --- a/gdb/doc/gdb.texinfo > > +++ b/gdb/doc/gdb.texinfo > > @@ -25257,6 +25257,10 @@ 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. > > + > > @node i386 > > @subsection x86 Architecture-specific Issues > > diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c > > index 208cf4b5aaa..de384da2e9a 100644 > > --- a/gdb/gdbarch.c > > +++ b/gdb/gdbarch.c > > @@ -283,6 +283,8 @@ 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_notes_from_range_ftype *create_memtag_notes_from_range; > > + gdbarch_decode_memtag_note_ftype *decode_memtag_note; > > 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; > > @@ -667,6 +669,8 @@ 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_notes_from_range, has predicate. */ > > + /* Skip verify of decode_memtag_note, 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. */ > > @@ -925,6 +929,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) > > fprintf_unfiltered (file, > > "gdbarch_dump: core_xfer_siginfo = <%s>\n", > > host_address_to_string (gdbarch->core_xfer_siginfo)); > > + fprintf_unfiltered (file, > > + "gdbarch_dump: gdbarch_create_memtag_notes_from_range_p() = %d\n", > > + gdbarch_create_memtag_notes_from_range_p (gdbarch)); > > + fprintf_unfiltered (file, > > + "gdbarch_dump: create_memtag_notes_from_range = <%s>\n", > > + host_address_to_string (gdbarch->create_memtag_notes_from_range)); > > + fprintf_unfiltered (file, > > + "gdbarch_dump: gdbarch_decode_memtag_note_p() = %d\n", > > + gdbarch_decode_memtag_note_p (gdbarch)); > > + fprintf_unfiltered (file, > > + "gdbarch_dump: decode_memtag_note = <%s>\n", > > + host_address_to_string (gdbarch->decode_memtag_note)); > > fprintf_unfiltered (file, > > "gdbarch_dump: decr_pc_after_break = %s\n", > > core_addr_to_string_nz (gdbarch->decr_pc_after_break)); > > @@ -3898,6 +3914,54 @@ set_gdbarch_find_memory_regions (struct gdbarch *gdbarch, > > gdbarch->find_memory_regions = find_memory_regions; > > } > > +bool > > +gdbarch_create_memtag_notes_from_range_p (struct gdbarch *gdbarch) > > +{ > > + gdb_assert (gdbarch != NULL); > > + return gdbarch->create_memtag_notes_from_range != NULL; > > +} > > + > > +std::vector > > +gdbarch_create_memtag_notes_from_range (struct gdbarch *gdbarch, CORE_ADDR start_address, CORE_ADDR end_address) > > +{ > > + gdb_assert (gdbarch != NULL); > > + gdb_assert (gdbarch->create_memtag_notes_from_range != NULL); > > + if (gdbarch_debug >= 2) > > + fprintf_unfiltered (gdb_stdlog, "gdbarch_create_memtag_notes_from_range called\n"); > > + return gdbarch->create_memtag_notes_from_range (gdbarch, start_address, end_address); > > +} > > + > > +void > > +set_gdbarch_create_memtag_notes_from_range (struct gdbarch *gdbarch, > > + gdbarch_create_memtag_notes_from_range_ftype create_memtag_notes_from_range) > > +{ > > + gdbarch->create_memtag_notes_from_range = create_memtag_notes_from_range; > > +} > > + > > +bool > > +gdbarch_decode_memtag_note_p (struct gdbarch *gdbarch) > > +{ > > + gdb_assert (gdbarch != NULL); > > + return gdbarch->decode_memtag_note != NULL; > > +} > > + > > +gdb::byte_vector > > +gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdb::array_view note, CORE_ADDR address, size_t length) > > +{ > > + gdb_assert (gdbarch != NULL); > > + gdb_assert (gdbarch->decode_memtag_note != NULL); > > + if (gdbarch_debug >= 2) > > + fprintf_unfiltered (gdb_stdlog, "gdbarch_decode_memtag_note called\n"); > > + return gdbarch->decode_memtag_note (gdbarch, note, address, length); > > +} > > + > > +void > > +set_gdbarch_decode_memtag_note (struct gdbarch *gdbarch, > > + gdbarch_decode_memtag_note_ftype decode_memtag_note) > > +{ > > + gdbarch->decode_memtag_note = decode_memtag_note; > > +} > > + > > bool > > gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch) > > { > > diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h > > index 7157e5596fd..80e244624de 100644 > > --- a/gdb/gdbarch.h > > +++ b/gdb/gdbarch.h > > @@ -980,6 +980,22 @@ 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); > > +/* Create memory tag core file notes given a range of addresses. */ > > + > > +extern bool gdbarch_create_memtag_notes_from_range_p (struct gdbarch *gdbarch); > > + > > +typedef std::vector (gdbarch_create_memtag_notes_from_range_ftype) (struct gdbarch *gdbarch, CORE_ADDR start_address, CORE_ADDR end_address); > > +extern std::vector gdbarch_create_memtag_notes_from_range (struct gdbarch *gdbarch, CORE_ADDR start_address, CORE_ADDR end_address); > > +extern void set_gdbarch_create_memtag_notes_from_range (struct gdbarch *gdbarch, gdbarch_create_memtag_notes_from_range_ftype *create_memtag_notes_from_range); > > + > > +/* Decode a memory tag note and return the tags that it contains. */ > > + > > +extern bool gdbarch_decode_memtag_note_p (struct gdbarch *gdbarch); > > + > > +typedef gdb::byte_vector (gdbarch_decode_memtag_note_ftype) (struct gdbarch *gdbarch, gdb::array_view note, CORE_ADDR address, size_t length); > > +extern gdb::byte_vector gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdb::array_view note, CORE_ADDR address, size_t length); > > +extern void set_gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdbarch_decode_memtag_note_ftype *decode_memtag_note); > > + > > /* 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.sh b/gdb/gdbarch.sh > > index 43e51341f97..7c5eed0780c 100755 > > --- a/gdb/gdbarch.sh > > +++ b/gdb/gdbarch.sh > > @@ -745,6 +745,12 @@ M;gdb::unique_xmalloc_ptr;make_corefile_notes;bfd *obfd, int *note_size;ob > > # Find core file memory regions > > M;int;find_memory_regions;find_memory_region_ftype func, void *data;func, data > > +# Create memory tag core file notes given a range of addresses. > > +M;std::vector;create_memtag_notes_from_range;CORE_ADDR start_address, CORE_ADDR end_address;start_address, end_address > > + > > +# Decode a memory tag note and return the tags that it contains. > > +M;gdb::byte_vector;decode_memtag_note;gdb::array_view note, CORE_ADDR address, size_t length;note, address, length > > + > > # 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/linux-tdep.c b/gdb/linux-tdep.c > > index 927e69bf1e1..6192cc4421b 100644 > > --- a/gdb/linux-tdep.c > > +++ b/gdb/linux-tdep.c > > @@ -41,6 +41,8 @@ > > #include "gdbsupport/gdb_optional.h" > > #include "gcore.h" > > #include "gcore-elf.h" > > +#include "gdbsupport/memtag.h" > > +#include "memtag.h" > > #include > > @@ -1438,10 +1440,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; > > @@ -1473,6 +1476,91 @@ 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_note_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); > > +} > > + > > +/* For each memory map entry that has memory tagging enabled, create a new > > + core file note that contains all of its memory tags. Save the data to > > + NOTE_DATA and update NOTE_SIZE accordingly. */ > > + > > +static void > > +linux_make_memtag_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, > > + gdb::unique_xmalloc_ptr ¬e_data, > > + int *note_size) > > +{ > > + if (current_inferior ()->fake_pid_p) > > + return; > > + > > + /* If the architecture doesn't have a hook to return memory tag notes, > > + there is nothing left to do. */ > > + if (!gdbarch_create_memtag_notes_from_range_p (gdbarch)) > > + return; > > + > > + pid_t pid = current_inferior ()->pid; > > + > > + std::string smaps_file = string_printf ("/proc/%d/smaps", pid); > > + > > + gdb::unique_xmalloc_ptr data > > + = target_fileio_read_stralloc (NULL, smaps_file.c_str ()); > > + > > + if (data == nullptr) > > + return; > > + > > + /* Parse the contents of smaps into a vector. */ > > + std::vector smaps > > + = parse_smaps_data (data.get (), smaps_file); > > + > > + for (const smaps_data &map : smaps) > > + { > > + /* Does this mapping have memory tagging enabled? If so, save the > > + memory tags to the core file note. */ > > + if (map.vmflags.memory_tagging == 0) > > + continue; > > + > > + /* Ask the architecture to create (one or more) NT_MEMTAG notes for > > + this particular memory range, including the header. > > + > > + If the notes are too big, we may need to break up the transfer > > + into smaller chunks. > > + > > + If the architecture returns an empty vector, that means there are > > + no memory tag notes to write. */ > > + std::vector memory_tag_notes > > + = gdbarch_create_memtag_notes_from_range (gdbarch, > > + map.start_address, > > + map.end_address); > > + /* Write notes to the core file. */ > > + for (const gdb::byte_vector ¬e : memory_tag_notes) > > + { > > + note_data.reset (elfcore_write_note (obfd, note_data.release (), > > + note_size, "CORE", > > + NT_MEMTAG, note.data (), > > + note.size ())); > > + } > > + } > > +} > > + > > /* List memory regions in the inferior for a corefile. */ > > static int > > @@ -2051,6 +2139,9 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) > > return NULL; > > } > > + /* Dump the memory tags, if any. */ > > + linux_make_memtag_corefile_notes (gdbarch, obfd, note_data, note_size); > > + > > /* File mappings. */ > > linux_make_mappings_corefile_notes (gdbarch, obfd, note_data, note_size); > > diff --git a/gdb/memtag.c b/gdb/memtag.c > > new file mode 100644 > > index 00000000000..4d92ecde84a > > --- /dev/null > > +++ b/gdb/memtag.c > > @@ -0,0 +1,88 @@ > > +/* GDB generic memory tagging functions. > > + > > + Copyright (C) 2021 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 "gdbsupport/memtag.h" > > +#include "bfd.h" > > + > > +/* Helper function to walk through NT_MEMTAG notes in a core file. > > + > > + Return a pointer to a .memtag section containing ADDRESS or nullptr > > + of none are found. > > + > > + If SECTION is provided, search from that section onwards. */ > > + > > +bool > > +get_next_core_memtag_section (bfd *abfd, asection *section, > > + CORE_ADDR address, memtag_note_info &info) > > +{ > > + /* If SECTION is nullptr, start a fresh lookup. */ > > + 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 note_size = bfd_section_size (section); > > + > > + /* If the note is smaller than the size of the header, this core note > > + is malformed. */ > > + if (note_size < NT_MEMTAG_GENERIC_HEADER_SIZE) > > + { > > + warning (_("Malformed core note - too short for NT_MEMTAG generic " > > + "header.\n" > > + "Expected %s bytes but got %s bytes."), > > + pulongest (NT_MEMTAG_GENERIC_HEADER_SIZE), > > + pulongest (note_size)); > > + return false; > > + } > > + > > + gdb::byte_vector note (note_size); > > + > > + /* Fetch the contents of this particular memtag note. */ > > + if (!bfd_get_section_contents (abfd, section, > > + note.data (), 0, note_size)) > > + { > > + warning (_("could not get core note contents.")); > > + return false; > > + } > > + > > + /* Read the generic header of the note. It contains the format, > > + start address and end address. */ > > + uint64_t start_address > > + = bfd_get_64 (abfd, note.data () + sizeof (tag_dump_header::format)); > > + uint64_t end_address > > + = bfd_get_64 (abfd, note.data () + sizeof (tag_dump_header::format) > > + + sizeof (tag_dump_header::start_vma)); > > + > > + /* 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.note = note; > > + info.memtag_section = section; > > + return true; > > + } > > + } > > + return false; > > +} > > diff --git a/gdb/memtag.h b/gdb/memtag.h > > new file mode 100644 > > index 00000000000..43c9efb39a3 > > --- /dev/null > > +++ b/gdb/memtag.h > > @@ -0,0 +1,46 @@ > > +/* GDB generic memory tagging definitions. > > + Copyright (C) 2021 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_note_info > > +{ > > + CORE_ADDR start_address; > > + CORE_ADDR end_address; > > + gdb::byte_vector note; > > + asection *memtag_section; > > +}; > > + > > +/* Helper function to walk through NT_MEMTAG notes 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_note_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..d0bcd036972 > > --- /dev/null > > +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp > > @@ -0,0 +1,111 @@ > > +# 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 > > + > > +if { $program_loaded } { > > + return -1 > > +} > > + > > +# 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" > > +} > > diff --git a/gdbsupport/memtag.h b/gdbsupport/memtag.h > > new file mode 100644 > > index 00000000000..bb47eed220b > > --- /dev/null > > +++ b/gdbsupport/memtag.h > > @@ -0,0 +1,39 @@ > > +/* Generic memory tagging definitions. > > + Copyright (C) 2021 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 GDBSUPPORT_MEMTAG_H > > +#define GDBSUPPORT_MEMTAG_H > > + > > +/* Generic NT_MEMTAG header. */ > > +struct tag_dump_header > > +{ > > + /* Tag format. */ > > + uint16_t format; > > + /* Start address of the tagged range. */ > > + uint64_t start_vma; > > + /* End address of the tagged range. */ > > + uint64_t end_vma; > > +}; > > + > > +/* Size of the generic header for the NT_MEMTAG note. This is OS-independent > > + and should be shared with OS-specific and arch-specific code. */ > > +#define NT_MEMTAG_GENERIC_HEADER_SIZE (sizeof (tag_dump_header::format) \ > > + + sizeof (tag_dump_header::start_vma) \ > > + + sizeof (tag_dump_header::end_vma)) > > + > > +#endif /* GDBSUPPORT_MEMTAG_H */ > > -- Joel