From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-qv1-xf2a.google.com (mail-qv1-xf2a.google.com [IPv6:2607:f8b0:4864:20::f2a]) by sourceware.org (Postfix) with ESMTPS id 60CCA3858034 for ; Mon, 24 May 2021 12:45:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 60CCA3858034 Received: by mail-qv1-xf2a.google.com with SMTP id z1so14073405qvo.4 for ; Mon, 24 May 2021 05:45:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=SqntsFNhQk+V1xibTL6/GO+7h2pPLDlFU6zOKuMoT1s=; b=K7whi3NPIXKByUaKYhcdhGg+BZEp5ecZCqHOY4brOr8fQBnYdJK4xTHKiEM1fOL+uk n32camMJUkZd8VmBxAsnI1eBn8+G8GrPYP7DzX0FZzt4jA52d+SFOW8W4rIVj20HFzuV rRx2yQf9eMOMLP9oRSihvXnhVToI4HnUj0Nle0kyOCpo/z9iAVOcy0R8Uw88Tev/s/6K m391pLWe8luHUyhe2WIjyWWGyWFJ/6bzE0ufVnKmztOecrRxTGpC4CrrYgXzgoyeKEYZ TdWt+6bBoaSttXjoTThnNRJL1jwQZd8lFPrwAGlCcrjGc1C7YPFu9fiZlSAsWukyeaoD u/Qg== X-Gm-Message-State: AOAM530HA/21Oqku7+oNNZk9eh/k1JCWKfLl76ENnz4C/awgKnIcmpf3 Rfo6e5W7P343ndZIoyGd4mcveg== X-Google-Smtp-Source: ABdhPJw9e8hiIsh5H31DjqDf2SugapMn1pSt6emZR8doMZnoOcMhOs0TTB5hFw2hmT4FkB1wAxKsvQ== X-Received: by 2002:ad4:56a8:: with SMTP id bd8mr30790593qvb.9.1621860312454; Mon, 24 May 2021 05:45:12 -0700 (PDT) Received: from ?IPv6:2804:7f0:4841:5c9d:b127:8b5d:e87f:5e7d? ([2804:7f0:4841:5c9d:b127:8b5d:e87f:5e7d]) by smtp.gmail.com with ESMTPSA id z4sm9991302qtq.34.2021.05.24.05.45.09 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 24 May 2021 05:45:11 -0700 (PDT) Subject: Re: [PATCH] [AArch64] MTE corefile support To: Alan Hayward Cc: "gdb-patches\\@sourceware.org" , "jhb@freebsd.org" , "david.spickett@linaro.org" , Catalin Marinas , nd References: <20210518202047.3492211-1-luis.machado@linaro.org> <8214C923-1DC2-4996-B070-FF248FE1669C@arm.com> <5b09fe6a-3d94-c355-8c81-6d7327760cb6@linaro.org> From: Luis Machado Message-ID: Date: Mon, 24 May 2021 09:45:06 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 24 May 2021 12:45:18 -0000 On 5/24/21 5:07 AM, Alan Hayward wrote: > > >> On 21 May 2021, at 16:30, Luis Machado > > wrote: >> >> Hi Alan, >> >> On 5/21/21 12:12 PM, Alan Hayward wrote: >>>> On 18 May 2021, at 21:20, Luis Machado >>> > wrote: >>>> >>>> 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. >>>> >>> This is a wider question than this patch - but is there someplace >>> this format will >>> be documented? Ideally either Linux or GDB needs something written >>> down in >>> text format. >>> A few nits below too, but mostly looks fine. >> >> Yes. I'm still thinking whether this should go into the Linux Kernel's >> documentation or somewhere in the GDB manual. >> >> Given GDB reads core files generated by the Linux Kernel and also >> creates cores files itself, I'm thinking it may be best to put it in >> the GDB manual. >> >> I want to wait for possible feedbacks about the format before we >> document how it will look like in the manual. >> >>>> 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  >>> > >>>> >>>> * aarch64-linux-tdep.c: Include elf/common.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. >>>> * arch/aarch64-mte-linux.h (AARCH64_MTE_TAG_BIT_SIZE): New constant. >>>> (struct tag_dump_header): New struct. >>>> (struct tag_dump_mte): New struct. >>>> (MEMTAG_NOTE_HEADER_SIZE): New constant. >>>> * corelow.c (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 (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. >>>> * NEWS: Mention core file support for memory tagging. >>>> >>>> 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. >>>> --- >>>> gdb/NEWS                                     |   4 + >>>> gdb/aarch64-linux-tdep.c                     | 179 +++++++++++++++++++ >>>> gdb/arch/aarch64-mte-linux.h                 |  29 +++ >>>> gdb/corelow.c                                |  88 +++++++++ >>>> gdb/doc/gdb.texinfo                          |   4 + >>>> gdb/gdbarch.c                                |  64 +++++++ >>>> gdb/gdbarch.h                                |  16 ++ >>>> gdb/gdbarch.sh                               |   6 + >>>> gdb/linux-tdep.c                             | 141 ++++++++++++++- >>>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.c   |  93 ++++++++++ >>>> gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 115 ++++++++++++ >>>> 11 files changed, 736 insertions(+), 3 deletions(-) >>>> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.c >>>> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp >>>> >>>> diff --git a/gdb/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..663d0e1a215 100644 >>>> --- a/gdb/aarch64-linux-tdep.c >>>> +++ b/gdb/aarch64-linux-tdep.c >>>> @@ -53,6 +53,8 @@ >>>> >>>> #include "gdbsupport/selftest.h" >>>> >>>> +#include "elf/common.h" >>>> + >>>> /* Signal frame handling. >>>> >>>>       +------------+  ^ >>>> @@ -1779,6 +1781,172 @@ aarch64_linux_report_signal_info (struct >>>> gdbarch *gdbarch, >>>>     } >>>> } >>>> >>>> +/* 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.  */ >>>> +  int 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 (MEMTAG_NOTE_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 (uint16_t), byte_order, >>>> + NT_MEMTAG_TYPE_AARCH_MTE); >>>> +  buf += sizeof (uint16_t); >>>> + >>>> +  /* Start address */ >>>> +  store_unsigned_integer (buf, sizeof (uint64_t), byte_order, >>>> start_address); >>>> +  buf += sizeof (uint64_t); >>>> + >>>> +  /* End address */ >>>> +  store_unsigned_integer (buf, sizeof (uint64_t), byte_order, >>>> end_address); >>>> +  buf += sizeof (uint64_t); >>>> + >>>> +  /* MTE-specific header.  */ >>>> +  /* Granule byte size */ >>>> +  store_unsigned_integer (buf, sizeof (uint16_t), byte_order, >>>> + AARCH64_MTE_GRANULE_SIZE); >>>> +  buf += sizeof (uint16_t); >>>> + >>>> +  /* Tag bit size */ >>>> +  store_unsigned_integer (buf, sizeof (uint16_t), byte_order, >>>> + AARCH64_MTE_TAG_BIT_SIZE); >>>> +  buf += sizeof (uint16_t); >>>> + >>>> +  /* Unused value */ >>>> +  store_unsigned_integer (buf, sizeof (uint16_t), byte_order, 0); >>>> + >>>> +  /* Store the tags.  */ >>>> +  memcpy (notes[0].data () + MEMTAG_NOTE_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 request tags.  */ >>>> + >>>> +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; >>>> + >>>> +  /* Read the generic header.  */ >>>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); >>>> +  struct tag_dump_header header; >>>> +  const gdb_byte *buf = note.data (); >>>> + >>>> +  header.format >>>> +    = extract_unsigned_integer (buf, sizeof (uint16_t), byte_order); >>>> +  buf += sizeof (uint16_t); >>>> + >>>> +  header.start_vma >>>> +    = extract_unsigned_integer (buf, sizeof (uint64_t), byte_order); >>>> +  buf += sizeof (uint64_t); >>>> + >>>> +  header.end_vma >>>> +    = extract_unsigned_integer (buf, sizeof (uint64_t), byte_order); >>>> +  buf += sizeof (uint64_t); >>>> + >>>> +  /* Sanity check  */ >>>> +  if (header.format != NT_MEMTAG_TYPE_AARCH_MTE) >>>> +    { >>>> +      warning (_("Unexpected memory tag note format (%x).\n"), >>>> header.format); >>>> +      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 (header.start_vma, AARCH64_MTE_GRANULE_SIZE); >>>> +  CORE_ADDR aligned_address = align_down (address, >>>> AARCH64_MTE_GRANULE_SIZE); >>>> + >>>> +  int skipped_granules >>>> +    = aarch64_mte_get_tag_granules (aligned_start_address, >>>> +   aligned_address - aligned_start_address, >>>> +   AARCH64_MTE_GRANULE_SIZE); >>>> + >>>> +  /* The amount of memory tag granules we need to fetch.  */ >>>> +  int 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; >>>> + >>>> +  /* Point to the block of data that contains the first granule we are >>>> +     interested in.  */ >>>> +  const gdb_byte *tags_data = note.data () + sizeof (header) + >>>> skipped_granules; >>>> + >>>> +  /* Read the tag granules.  */ >>>> +  for (unsigned int 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 +2030,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..a4a26628847 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,32 @@ 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); >>>> >>>> +/* Headers for the NT_MEMTAG notes.  */ >>>> + >>>> +/* 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; >>>> +}; >>>> + >>>> +/* MTE-specific NT_MEMTAG header.  */ >>>> +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; >>>> +}; >>>> + >>>> +/* Memory tag note header size.  Includes both the generic and the >>>> +   arch-specific parts.  */ >>>> +#define MEMTAG_NOTE_HEADER_SIZE (2 + 8 + 8 + 2 + 2 + 2) >>> This should compile down to a constant value: ? >>> #define MEMTAG_NOTE_HEADER_SIZE >>> (sizeof(tag_dump_header)+sizeof(tag_dump_mte)) >> >> Right. But there may be padding between the members of the struct, and >> we don't want to rely on what the compiler is doing. We could force >> this to be "packed" maybe? > > Should the data inside the core file be packed? > Packed saves the space, but padded ensures the file is aligned and maybe > easier to copy. > Packing it makes the layout predictable. With padding, we may have differing layouts between a 32-bit target and a 64-bit target. I wanted to avoid that sort of thing. At least on the generic header that is used by GDB's core target. >> >>>> + >>>> #endif /* ARCH_AARCH64_LINUX_H */ >>>> diff --git a/gdb/corelow.c b/gdb/corelow.c >>>> index 452b4dd4f9a..33d16b7220a 100644 >>>> --- a/gdb/corelow.c >>>> +++ b/gdb/corelow.c >>>> @@ -100,6 +100,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 +1122,87 @@ 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.  */ >>>> +  if (bfd_get_section_by_name (core_bfd, ".memtag") == nullptr) >>>> +    return false; >>>> + >>>> +  return true; >>>> +} >>>> + >>>> +/* 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)) >>>> +    warning (_("gdbarch_decode_memtag_note not implemented for this " >>>> +      "architecture.")); >>>> + >>>> +  asection *section >>>> +    = bfd_get_section_by_name (core_bfd, ".memtag"); >>>> + >>>> +  /* Remove the top byte for the memory range check.  */ >>>> +  address = address_significant (gdbarch, address); >>>> + >>>> +  /* 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 < 2 * sizeof (uint64_t) + sizeof (uint16_t)) >>> I’m not sure why 64+16 ? >> >> Actually 2 * 8 + 2. Two 64-bit entries and a 16-bit entry in the >> generic header. >> >> Does that make sense? > > I completely missed the 2. > Does this need a #define TAG_NOTE_SIZE then? (And use it in the > MEMTAG_NOTE_HEADER_SIZE) > It does. I'll add it. Thanks! >> >>>> +{ >>>> + warning (_("malformed core note - too short for header")); >>>> + return false; >>>> +} >>>> + >>>> +      gdb::byte_vector note (note_size); >>>> + >>>> +      /* Fetch the contents of this particular memtag note.  */ >>>> +      if (!bfd_get_section_contents (core_bfd, section, >>>> +    note.data (), 0, note_size)) >>>> +{ >>>> + warning (_("could not get core note contents.")); >>>> + return false; >>>> +} >>>> + >>>> +      /* Read the generic header of the note.  Thos contains the >>>> format, >>>> +start address and end address.  */ >>>> +      uint64_t start_address >>>> += bfd_get_64 (core_bfd, note.data () + sizeof (uint16_t)); >>>> +      uint64_t end_address >>>> += bfd_get_64 (core_bfd, note.data () + sizeof (uint16_t) >>>> ++ sizeof (uint64_t)); >>>> + >>>> +      /* Is the address within [start_address, end_address)?  */ >>>> +      if (address >= start_address >>>> + && address < end_address) >>>> +{ >>>> + /* Decode the memory tag note and return the tags.  */ >>>> + tags = gdbarch_decode_memtag_note (gdbarch, note, address, len); >>>> + return true; >>>> +} >>>> + >>>> +      /* The requested address lies outside this particular memtag >>>> note.  Keep >>>> +looking and get the next section.  */ >>>> +      section = bfd_get_next_section_by_name (core_bfd, section); >>>> +    } >>>> + >>>> +  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 56f37eb2288..738cb3b56eb 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>>> 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..f4ff57dec87 100644 >>>> --- a/gdb/linux-tdep.c >>>> +++ b/gdb/linux-tdep.c >>>> @@ -1438,10 +1438,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 +1474,137 @@ 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; >>>> + >>>> +  asection *section >>>> +    = bfd_get_section_by_name (core_bfd, ".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 < 2 * sizeof (uint64_t) + sizeof (uint16_t)) >>>> +{ >>>> + warning (_("malformed core note - too short for header")); >>>> + return false; >>>> +} >>>> + >>>> +      gdb::byte_vector note (note_size); >>>> + >>>> +      /* Fetch the contents of this particular memtag note.  */ >>>> +      if (!bfd_get_section_contents (core_bfd, section, >>>> +    note.data (), 0, note_size)) >>>> +{ >>>> + warning (_("could not get core note contents.")); >>>> + return false; >>>> +} >>>> + >>>> +      /* Read the generic header of the note.  Those contain the >>>> format, >>>> +start address and end address.  */ >>>> +      uint64_t start_address >>>> += bfd_get_64 (core_bfd, note.data () + sizeof (uint16_t)); >>>> +      uint64_t end_address >>>> += bfd_get_64 (core_bfd, note.data () + sizeof (uint16_t) >>>> ++ sizeof (uint64_t)); >>>> + >>>> +      /* Is the address within [start_address, end_address)?  */ >>>> +      if (address >= start_address >>>> + && address < end_address) >>>> +return true; >>>> + >>>> +      /* The requested address lies outside this particular memtag >>>> note.  Keep >>>> +looking and get the next section.  */ >>>> +      section = bfd_get_next_section_by_name (core_bfd, section); >>>> +    } >>>> + >>>> +  return false; >>>> +} >>>> + >>>> +/* 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; >>>> + >>>> +  std::vector smaps; >>>> + >>>> +  /* Parse the contents of smaps into a 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; >>>> +      memory_tag_notes >>>> += gdbarch_create_memtag_notes_from_range (gdbarch, >>>> + map.start_address, >>>> + map.end_address); >>>> +      /* Write notes to the core file.  */ >>>> +      for (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 +2183,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/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_SHIFT1 >>>> +#define PR_MTE_TCF_SYNC(1UL << PR_MTE_TCF_SHIFT) >>>> +#define PR_MTE_TAG_SHIFT3 >>>> + >>>> +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..bb529a8b369 >>>> --- /dev/null >>>> +++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp >>>> @@ -0,0 +1,115 @@ >>>> +# Copyright (C) 2018-2021 Free Software Foundation, Inc. >>> 2018? >> >> I really copied the template from an existing file. The rule, AFAIR, >> is to keep the copyright years from the original file. > > Ok > >> >>>> +# >>>> +# 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 >>>> + >>>> +# Load the program file. >>>> +set program_filename [standard_output_file $testfile] >>>> +set program_loaded [gdb_file_cmd $program_filename] >>>> + >>>> +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" >>>> +} >>>> -- >>>> 2.25.1 >