public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Joel Brobecker <brobecker@adacore.com>
To: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
Cc: simon.marchi@polymtl.ca, david.spickett@linaro.org,
	catalin.marinas@arm.com, Joel Brobecker <brobecker@adacore.com>
Subject: Re: [PING][PATCH,v5][AArch64] MTE corefile support
Date: Sun, 11 Jul 2021 07:22:00 -0700	[thread overview]
Message-ID: <20210711142200.GA637634@adacore.com> (raw)
In-Reply-To: <defd68d8-ddd6-5d6b-9df6-8f69712a34bd@linaro.org>

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/<pid>/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/<pid>/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/<pid>/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  <luis.machado@linaro.org>
> > 
> > 	* 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) <supports_memory_tagging, fetch_memtags>: 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  <luis.machado@linaro.org>
> > 
> > 	* gdb.texinfo (AArch64 Memory Tagging Extension): Mention support
> > 	for memory tagging in core files.
> > 
> > gdb/testsuite/ChangeLog:
> > 
> > YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> > 
> > 	* gdb.arch/aarch64-mte-gcore.c: New file.
> > 	* gdb.arch/aarch64-mte-gcore.exp: New file.
> > 
> > gdbsupport/ChangeLog:
> > 
> > YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> > 
> > 	* 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<gdb::byte_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<gdb::byte_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<int> (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 <const gdb_byte> 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<const gdb_byte> 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<gdb::byte_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<const gdb_byte> 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<gdb::byte_vector> (gdbarch_create_memtag_notes_from_range_ftype) (struct gdbarch *gdbarch, CORE_ADDR start_address, CORE_ADDR end_address);
> > +extern std::vector<gdb::byte_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<const gdb_byte> note, CORE_ADDR address, size_t length);
> > +extern gdb::byte_vector gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdb::array_view<const gdb_byte> 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<char>;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<gdb::byte_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<const gdb_byte> 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 <ctype.h>
> > @@ -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<char> &note_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<char> data
> > +    = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
> > +
> > +  if (data == nullptr)
> > +    return;
> > +
> > +  /* Parse the contents of smaps into a vector.  */
> > +  std::vector<struct smaps_data> 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<gdb::byte_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 &note : 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 <http://www.gnu.org/licenses/>.  */
> > +
> > +#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 <http://www.gnu.org/licenses/>.  */
> > +
> > +#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 <http://www.gnu.org/licenses/>.  */
> > +
> > +/* 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 <errno.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <sys/auxv.h>
> > +#include <sys/mman.h>
> > +#include <sys/prctl.h>
> > +
> > +/* 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 <http://www.gnu.org/licenses/>.
> > +
> > +# 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 <http://www.gnu.org/licenses/>.  */
> > +
> > +#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

  reply	other threads:[~2021-07-11 14:22 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-18 20:20 [PATCH] [AArch64] " Luis Machado
2021-05-19 10:01 ` David Spickett
2021-05-19 11:11   ` Luis Machado
2021-05-19 12:13 ` Eli Zaretskii
2021-05-21 15:12 ` Alan Hayward
2021-05-21 15:30   ` Luis Machado
2021-05-21 17:20     ` John Baldwin
2021-05-24 13:41       ` Luis Machado
2021-05-24  8:07     ` Alan Hayward
2021-05-24 12:45       ` Luis Machado
2021-05-26 14:08 ` [PATCH,v2] " Luis Machado
2021-05-29  3:14   ` Simon Marchi
2021-05-31 14:12     ` Luis Machado
2021-05-31 14:49       ` Simon Marchi
2021-05-31 14:56         ` Luis Machado
2021-05-31 14:15   ` [PATCH,v3][AArch64] " Luis Machado
2021-05-31 16:44 ` [PATCH,v4][AArch64] " Luis Machado
2021-06-01 17:45 ` [PATCH,v5][AArch64] " Luis Machado
2021-06-15 14:10   ` [Ping][PATCH,v5][AArch64] " Luis Machado
2021-06-24 14:00   ` [PATCH,v5][AArch64] " Alan Hayward
2021-06-24 14:37     ` Luis Machado
2021-06-24 15:18       ` Alan Hayward
2021-07-01 13:50   ` [PING][PATCH,v5][AArch64] " Luis Machado
2021-07-11 14:22     ` Joel Brobecker [this message]
2021-07-14 13:07       ` Catalin Marinas
2021-07-29  2:26         ` Simon Marchi
2021-07-29 16:03           ` John Baldwin
2021-07-29 18:10           ` Catalin Marinas
2021-07-29 18:20             ` Simon Marchi
2021-08-01 15:44               ` Joel Brobecker
2021-08-02 12:06                 ` Luis Machado
2021-07-19 19:05   ` Luis Machado
2021-07-27 16:10   ` Luis Machado

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210711142200.GA637634@adacore.com \
    --to=brobecker@adacore.com \
    --cc=catalin.marinas@arm.com \
    --cc=david.spickett@linaro.org \
    --cc=gdb-patches@sourceware.org \
    --cc=simon.marchi@polymtl.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).