]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Core file support (C registers + capability tags)
authorLuis Machado <luis.machado@linaro.org>
Fri, 16 Apr 2021 13:43:59 +0000 (10:43 -0300)
committerLuis Machado <luis.machado@linaro.org>
Tue, 25 May 2021 01:19:33 +0000 (22:19 -0300)
Enable core file dumping through the gcore command and enable reading of
kernel-generated core files for Morello.

This patch enables writing and reading Morello core file containing dumps
of the C register set and dumps of the capability tags from memory.

The C register dumps are stored in a NT_ARM_MORELLO note, while the capability
tag dumps are stored into multiple NT_MEMTAG notes.

The NT_MEMTAG notes have the following format:

NT_MEMTAG:
<header>
<tag data>

The header has the following format:

/* Header for NT_MEMTAG notes.  */
struct __attribute__ ((packed)) tag_dump_header
{
  uint16_t format;
  uint64_t start_vma;
  uint64_t end_vma;

  union
  {
    struct tag_dump_fmt
    {
      uint16_t granule_byte_size;
      uint16_t tag_bit_size;
      uint16_t __unused;
    } cheri;
  } u;

  // Other formats may be added here later.
};

There is a speed limitation while saving capability tags.  That's because GDB
only has access to one capability per-ptrace call. In the future there may be
a ptrace request to read capability tags in bulk, which will make things much
faster.

Tested by writing a gcore-based core file and reading it back, and also
exercised by reading a kernel-generated core file.

bfd/ChangeLog:

2021-05-24  Luis Machado  <luis.machado@arm.com>

* elf-bfd.h (elfcore_write_aarch_morello): New prototype.
* elf.c (elfcore_grok_aarch_morello): New function.
(elfcore_grok_note): Handle NT_ARM_MORELLO.
(elfcore_write_aarch_morello): New function.
(elfcore_write_register_note): Handle reg-aarch-morello.
(elfcore_make_memtag_note_section): New function.
(elfcore_grok_note): Handle NT_MEMTAG note types.

binutils/ChangeLog:

2021-05-24  Luis Machado  <luis.machado@linaro.org>

* readelf.c (get_note_type): Handle NT_MEMTAG note types.

include/ChangeLog:

2021-05-24  Luis Machado  <luis.machado@linaro.org>

* elf/common.h (NT_MEMTAG): New constant.
(ELF_CORE_TAG_CHERI): New constant.

gdb/ChangeLog:

2021-05-24  Luis Machado  <luis.machado@arm.com>

* aarch64-linux-tdep.c (aarch64_linux_cregmap): Update to match
Morello's register layout in the core file.
(aarch64_linux_iterate_over_regset_sections): Update to handle
Morello's register set.
(aarch64_linux_init_abi): Likewise.
Register core file hooks.
(aarch64_linux_decode_memtag_note)
(aarch64_linux_create_memtag_notes_from_range)
(morello_get_tag_granules): New functions.
(MAX_TAGS_TO_TRANSFER): New constant.
* arch/aarch64-cap-linux.h (MORELLO_TAG_GRANULE_SIZE)
(MORELLO_TAG_BIT_SIZE): New constants.
(tag_dump_header): New struct.
* corelow.c (core_target <read_capability>: New method overrides.
(core_target::read_capability): New methods.
* gdbarch.sh (create_memtag_notes_from_range)
(decode_memtag_note): New hooks.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* linux-tdep.c (linux_make_memtag_corefile_notes): New function.
(linux_make_corefile_notes): Call linux_make_memtag_corefile_notes.
(linux_address_in_memtag_page): Removed.

15 files changed:
bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf.c
binutils/ChangeLog
binutils/readelf.c
gdb/ChangeLog
gdb/aarch64-linux-tdep.c
gdb/arch/aarch64-cap-linux.h
gdb/corelow.c
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/linux-tdep.c
include/ChangeLog
include/elf/common.h

index db416fb90cc22aae000336ab4b556dc70144b608..d4586cbd1ed91a8917930dba84e640a19aeae534 100644 (file)
@@ -1,3 +1,13 @@
+2021-05-25  Luis Machado  <luis.machado@arm.com>
+
+       * elf-bfd.h (elfcore_write_aarch_morello): New prototype.
+       * elf.c (elfcore_grok_aarch_morello): New function.
+       (elfcore_grok_note): Handle NT_ARM_MORELLO.
+       (elfcore_write_aarch_morello): New function.
+       (elfcore_write_register_note): Handle reg-aarch-morello.
+       (elfcore_make_memtag_note_section): New function.
+       (elfcore_grok_note): Handle NT_MEMTAG note types.
+
 2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * elfnn-aarch64.c (IS_AARCH64_TLSDESC_RELOC): Add Morello
index f383cd8bf6eeae1e0a83b176cf067f02430aec09..ef9a722bac843d61e92c898d071cbefd49af28de 100644 (file)
@@ -2804,6 +2804,8 @@ extern char *elfcore_write_aarch_sve
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_aarch_pauth
   (bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_aarch_morello
+  (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_arc_v2
   (bfd *, char *, int *, const void *, int);
 extern char *elfcore_write_lwpstatus
index 9d7cbd52e024e312bdc10c700c47d05da85d4267..9a5b472cda2c953cae40d2dfcbce493048ed8168 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9557,6 +9557,23 @@ elfcore_make_auxv_note_section (bfd *abfd, Elf_Internal_Note *note,
   return TRUE;
 }
 
+static bfd_boolean
+elfcore_make_memtag_note_section (bfd *abfd, Elf_Internal_Note *note,
+                                 size_t offs)
+{
+  asection *sect = bfd_make_section_anyway_with_flags (abfd, ".memtag",
+                                                      SEC_HAS_CONTENTS);
+
+  if (sect == NULL)
+    return FALSE;
+
+  sect->size = note->descsz - offs;
+  sect->filepos = note->descpos + offs;
+  sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+  return TRUE;
+}
+
 /* prstatus_t exists on:
      solaris 2.5+
      linux 2.[01] + glibc
@@ -9885,6 +9902,12 @@ elfcore_grok_aarch_pauth (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-aarch-pauth", note);
 }
 
+static bfd_boolean
+elfcore_grok_aarch_morello (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-morello", note);
+}
+
 static bfd_boolean
 elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -10548,6 +10571,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
        return TRUE;
 
+    case NT_ARM_MORELLO:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_morello (abfd, note);
+      else
+       return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -10570,6 +10600,8 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
                                              note);
 
+    case NT_MEMTAG:
+      return elfcore_make_memtag_note_section (abfd, note, 0);
     }
 }
 
@@ -11917,6 +11949,18 @@ elfcore_write_aarch_pauth (bfd *abfd,
                             note_name, NT_ARM_PAC_MASK, aarch_pauth, size);
 }
 
+char *
+elfcore_write_aarch_morello (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const void *aarch_morello,
+                            int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_MORELLO, aarch_morello, size);
+}
+
 char *
 elfcore_write_arc_v2 (bfd *abfd,
                      char *buf,
@@ -12011,6 +12055,8 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_aarch_sve (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-aarch-pauth") == 0)
     return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-morello") == 0)
+    return elfcore_write_aarch_morello (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arc-v2") == 0)
     return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
   return NULL;
index 4fee9910311b005b3923692b551156392ca13a2d..c87b7934646ed2be0a3417570074935bc5a46ab3 100644 (file)
@@ -1,3 +1,7 @@
+2021-05-24  Luis Machado  <luis.machado@linaro.org>
+
+       * readelf.c (get_note_type): Handle NT_MEMTAG note types.
+
 2020-10-20  Luis Machado  <luis.machado@arm.com>
 
        * dwarf.c (get_type_signedness): Handles capabilities.
index 03cfc97464b1d68d9f58787781afa6c94b9a5404..b6c632b2c991f94ed4b598e4ebad19c4ff9809c9 100644 (file)
@@ -18290,6 +18290,8 @@ get_note_type (Filedata * filedata, unsigned e_type)
        return _("NT_SIGINFO (siginfo_t data)");
       case NT_FILE:
        return _("NT_FILE (mapped files)");
+      case NT_MEMTAG:
+       return _("NT_MEMTAG (memory tags)");
       default:
        break;
       }
index cde1f20b1dbaef3ce84eb10f07ddaf22b00e76e6..0ad646af6510e961b5796073833b6fa85fee4cc9 100644 (file)
@@ -1,3 +1,28 @@
+2021-05-24  Luis Machado  <luis.machado@arm.com>
+
+       * aarch64-linux-tdep.c (aarch64_linux_cregmap): Update to match
+       Morello's register layout in the core file.
+       (aarch64_linux_iterate_over_regset_sections): Update to handle
+       Morello's register set.
+       (aarch64_linux_init_abi): Likewise.
+       Register core file hooks.
+       (aarch64_linux_decode_memtag_note)
+       (aarch64_linux_create_memtag_notes_from_range)
+       (morello_get_tag_granules): New functions.
+       (MAX_TAGS_TO_TRANSFER): New constant.
+       * arch/aarch64-cap-linux.h (MORELLO_TAG_GRANULE_SIZE)
+       (MORELLO_TAG_BIT_SIZE): New constants.
+       (tag_dump_header): New struct.
+       * corelow.c (core_target <read_capability>: New method overrides.
+       (core_target::read_capability): New methods.
+       * gdbarch.sh (create_memtag_notes_from_range)
+       (decode_memtag_note): New hooks.
+       * gdbarch.c: Regenerate.
+       * gdbarch.h: Regenerate.
+       * linux-tdep.c (linux_make_memtag_corefile_notes): New function.
+       (linux_make_corefile_notes): Call linux_make_memtag_corefile_notes.
+       (linux_address_in_memtag_page): Removed.
+
 2021-05-04  Luis Machado  <luis.machado@arm.com>
 
        Adapted from upstream GDB master commit
index 0b2c02d3cb85753ebf6662c0968842244516dd8b..115640090236a3f31e26f4b7f897f90d862a835f 100644 (file)
@@ -51,6 +51,8 @@
 /* For aarch64_debug.  */
 #include "arch/aarch64-insn.h"
 
+#include "elf/common.h"
+
 /* Signal frame handling.
 
       +------------+  ^
@@ -475,13 +477,17 @@ static const struct regcache_map_entry aarch64_linux_fpregmap[] =
    placeholders so we can update the numbers later.  */
 static struct regcache_map_entry aarch64_linux_cregmap[] =
   {
-    /* FIXME-Morello: Need to decide if we are reading the whole 16 bytes or
-       just the upper 8 bytes of the capability registers.  */
-    { 31, -1, 8 }, /* c0 ... c30 */
-    { 1, -1, 8 }, /* Stack Pointer Capability */
-    { 1, -1, 8 }, /* Program Counter Capability */
-    { 1, -1, 16 }, /* Default Data Capability */
-    { 1, -1, 8 },
+    { 31, -1, 16 }, /* c0 ... c30 */
+    { 1, -1, 16 }, /* pcc */
+    { 1, -1, 16 }, /* csp */
+    { 1, -1, 16 }, /* ddc */
+    { 1, -1, 16 }, /* ctpidr */
+    { 1, -1, 16 }, /* rcsp */
+    { 1, -1, 16 }, /* rddc */
+    { 1, -1, 16 }, /* rctpidr */
+    { 1, -1, 16 }, /* cid */
+    { 1, -1, 8 },  /* tag_map */
+    { 1, -1, 8 },  /* cctlr */
     { 0 }
   };
 
@@ -742,11 +748,10 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
          "pauth registers", cb_data);
     }
 
-  /* FIXME-Morello: We still need to provide a valid check for the presence of
-     capability registers.  */
+  /* Morello capability registers.  */
   if (tdep->has_capability ())
     {
-      cb (".reg-cap", AARCH64_LINUX_CREGS_SIZE,
+      cb (".reg-aarch-morello", AARCH64_LINUX_CREGS_SIZE,
          AARCH64_LINUX_CREGS_SIZE, &aarch64_linux_cregset,
          NULL, cb_data);
     }
@@ -1629,6 +1634,137 @@ aarch64_linux_get_cap_tag_from_address (struct gdbarch *gdbarch, CORE_ADDR addr)
   return cap[0] != 0;
 }
 
+/* Return the number of Morello memory tag granules contained in the memory
+   range [addr, addr + len).  */
+
+static size_t
+morello_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
+{
+  /* An empty range has 0 tag granules.  */
+  if (len == 0)
+    return 0;
+
+  /* Start address */
+  CORE_ADDR s_addr = align_down (addr, granule_size);
+  /* End address */
+  CORE_ADDR e_addr = align_down (addr + len - 1, granule_size);
+
+  /* We always have at least 1 granule because len is non-zero at this
+     point.  */
+  return 1 + (e_addr - s_addr) / granule_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 CHERI capability tags for now.  */
+
+  /* Figure out how many tags we need to store in this memory range.  */
+  int granules = morello_get_tag_granules (start_address,
+                                          end_address - start_address,
+                                          MORELLO_TAG_GRANULE_SIZE);
+
+  /* A vector to store multiple notes.  */
+  std::vector<gdb::byte_vector> notes;
+
+  /* Add the CHERI note.  */
+  notes.resize (1);
+  /* Resize to the number of bytes the tag granules will take.  */
+  notes[0].resize (sizeof (struct tag_dump_header) + granules);
+
+  /* Retrieve the tags and store them in the vector.  */
+  gdb::byte_vector tags;
+  CORE_ADDR address = start_address;
+  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 : granules;
+
+      /* First clear the vector of tags.  */
+      tags_read.resize (0);
+
+      /* Copy tags in chunks.  */
+      while (tags_read.size () < xfer_len)
+       {
+         CORE_ADDR addr
+           = address + tags_read.size () * MORELLO_TAG_GRANULE_SIZE;
+
+         /* Always align the address to 16 bytes so we can read the
+            capability properly.  When we have a request to read only the
+            capability tags, then we won't need to do this.  */
+         CORE_ADDR aligned_addr = align_down (addr, MORELLO_TAG_GRANULE_SIZE);
+         bool tag
+           = aarch64_linux_get_cap_tag_from_address (gdbarch, aligned_addr);
+         gdb_byte tag_byte = (tag == false)? 0 : 1;
+         tags_read.push_back (tag_byte);
+       }
+
+      /* This process may take a while.  Make sure it is interruptible.  */
+      QUIT;
+
+      /* 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 () * MORELLO_TAG_GRANULE_SIZE;
+    }
+
+  /* Create the header.  Please note we don't yet compress the tag data.
+     We may do so in the future to save space, since a capability tag is only
+     1 bit in size.  */
+  struct tag_dump_header header;
+  header.format = ELF_CORE_TAG_CHERI;
+  header.start_vma = start_address;
+  header.end_vma = end_address;
+  header.u.cheri.granule_byte_size = MORELLO_TAG_GRANULE_SIZE;
+  header.u.cheri.tag_bit_size = MORELLO_TAG_BIT_SIZE;
+  header.u.cheri.__unused = 0;
+
+  /* Copy the tags to the note.  */
+  memcpy (notes[0].data (), &header, sizeof (header));
+  memcpy (notes[0].data () + sizeof (header), tags.data (), tags.size ());
+
+  return notes;
+}
+
+/* AArch64 Linux implementation of the aarch64_decode_memtag_note gdbarch
+   hook.  Decode a memory tag note and return the tag that it contains for
+   a particular address.  */
+
+static gdb_byte
+aarch64_linux_decode_memtag_note (struct gdbarch *gdbarch,
+                                 gdb::array_view <const gdb_byte> note,
+                                 CORE_ADDR address)
+{
+  /* Read the header.  */
+  struct tag_dump_header header;
+  memcpy (&header, note.data (), sizeof (header));
+
+  /* Align the address to 16 bytes.  We assume the start_vma is already
+     aligned to the proper boundary, otherwise we would have tags dumped
+     into two different memory mappings.  */
+  address = align_down (address, MORELLO_TAG_GRANULE_SIZE);
+  CORE_ADDR offset = address - header.start_vma;
+  gdb_byte tag;
+
+  /* Read the tag.  */
+  memcpy (&tag, note.data () + sizeof (header)
+         + (offset / header.u.cheri.granule_byte_size), 1);
+
+  return tag;
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1857,17 +1993,37 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   if (tdep->has_capability ())
     {
-      /* Initialize the register numbers for the core file register set.  */
-      /* FIXME-Morello: This needs to be updated.  */
+      /* Initialize the register numbers for the core file register set.
+        Please note the PCC/CSP position in GDB's target description is
+        the inverse of the position in the Linux Kernel's user_morello_state
+        data structure.  This can cause some confusion.  */
       aarch64_linux_cregmap[0].regno = tdep->cap_reg_base;
-      aarch64_linux_cregmap[1].regno = tdep->cap_reg_base + 32;
-      aarch64_linux_cregmap[2].regno = tdep->cap_reg_base + 31;
-      aarch64_linux_cregmap[3].regno = tdep->cap_reg_base + 33;
+      aarch64_linux_cregmap[1].regno = tdep->cap_reg_pcc;
+      aarch64_linux_cregmap[2].regno = tdep->cap_reg_csp;
+
+      /* Set the rest of the registers.  */
+      int next_regnum = tdep->cap_reg_base + 33;
+      for (int i = 3; i <= 10; i++)
+       {
+         aarch64_linux_cregmap[i].regno = next_regnum;
+         next_regnum++;
+       }
 
       set_gdbarch_report_signal_info (gdbarch,
                                      aarch64_linux_report_signal_info);
       set_gdbarch_get_cap_tag_from_address (gdbarch,
                                            aarch64_linux_get_cap_tag_from_address);
+
+      /* 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);
     }
   else
     {
index 7a9df0bffbafcb081d45eb1bc7fcf03f04c2bae4..0c8fe2d9d552c4c0f76bc2f43abbbbdf8f46cbb1 100644 (file)
 #define SEGV_CAPPERMERR              13  /* Capability permission fault */
 #define SEGV_CAPSTORETAGERR   14  /* Capability tag store fault */
 
+#define MORELLO_TAG_GRANULE_SIZE 16
+#define MORELLO_TAG_BIT_SIZE 1
+
+/* Header for NT_MEMTAG notes.  */
+struct __attribute__ ((packed)) tag_dump_header
+{
+  uint16_t format;
+
+  uint64_t start_vma;
+  uint64_t end_vma;
+
+  union
+  {
+    struct tag_dump_fmt
+    {
+      uint16_t granule_byte_size;
+      uint16_t tag_bit_size;
+      uint16_t __unused;
+    } cheri;
+  } u;
+
+  // Other formats may be added here later.
+};
+
 #endif /* ARCH_AARCH64_CAP_LINUX_H */
index d557475e06f0fe9a77a9f46028045cfa8e493eb0..3b2d96681f1db7d07a6fd4e8a2a326cbdab57281 100644 (file)
@@ -117,6 +117,8 @@ public:
   /* See definition.  */
   void info_proc_mappings (struct gdbarch *gdbarch);
 
+  gdb::byte_vector read_capability (CORE_ADDR addr) override;
+
 private: /* per-core data */
 
   /* The core's section table.  Note that these target sections are
@@ -1141,6 +1143,75 @@ core_target::info_proc_mappings (struct gdbarch *gdbarch)
     }
 }
 
+/* Implement the read_capability target method.  */
+
+gdb::byte_vector
+core_target::read_capability (CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = target_gdbarch ();
+
+  gdb::byte_vector cap(0);
+
+  /* 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");
+
+  /* Go through all the memtag sections and figure out if ADDR
+     falls within one of the memory ranges that contain tags.  */
+  while (section != nullptr)
+    {
+      size_t note_size = bfd_section_size (section);
+
+      if (note_size < 2 * sizeof (uint64_t) + sizeof (uint16_t))
+       {
+         warning (_("malformed core note - too short for header"));
+         return cap;
+       }
+
+      gdb::byte_vector note (note_size);
+
+      if (!bfd_get_section_contents (core_bfd, section,
+                                    note.data (), 0, note_size))
+       {
+         warning (_("could not get core note contents."));
+         return cap;
+       }
+
+      uint64_t start_address;
+      memcpy (&start_address, note.data () + sizeof (uint16_t),
+             sizeof (uint64_t));
+      uint64_t end_address;
+      memcpy (&end_address,
+             note.data () + sizeof (uint16_t) + sizeof (uint64_t),
+             sizeof (uint64_t));
+
+      /* Is the address within [start_address, end_address)?  */
+      if (addr >= start_address
+         && addr < end_address)
+       {
+         /* Hardcoded to hold Morello capabilities for now.  */
+         cap.resize (17);
+         /* Decode the memory tag note and return the tags.  */
+         cap[0] = gdbarch_decode_memtag_note (gdbarch, note, addr);
+
+         /* Read the capability.  */
+         if (target_read_memory (addr, cap.data () + 1, 16) == 0)
+           return cap;
+         else
+           error (_("Could not read capability from core file.\n"));
+       }
+
+      /* Keep looking.  Get the next session.  */
+      section = bfd_get_next_section_by_name (core_bfd, section);
+    }
+
+  return cap;
+}
+
 /* Implement "maintenance print core-file-backed-mappings" command.  
 
    If mappings are loaded, the results should be similar to the
index 51db02361f6fe1f874d9dc7510eeda00cdd0d10d..a79d9bdfcf32b8046c113015f4bacf0f4a681f83 100644 (file)
@@ -279,6 +279,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;
@@ -657,6 +659,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.  */
@@ -918,6 +922,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));
@@ -3800,6 +3816,54 @@ set_gdbarch_find_memory_regions (struct gdbarch *gdbarch,
   gdbarch->find_memory_regions = find_memory_regions;
 }
 
+int
+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;
+}
+
+int
+gdbarch_decode_memtag_note_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->decode_memtag_note != NULL;
+}
+
+gdb_byte
+gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdb::array_view<const gdb_byte> note, CORE_ADDR address)
+{
+  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);
+}
+
+void
+set_gdbarch_decode_memtag_note (struct gdbarch *gdbarch,
+                                gdbarch_decode_memtag_note_ftype decode_memtag_note)
+{
+  gdbarch->decode_memtag_note = decode_memtag_note;
+}
+
 int
 gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch)
 {
index ec32bf50f01a1ef78f37bdf5b176a2b336ec75fa..49c7f1c7a8d82f70e02c2b46e6b1f0ef9c9f0845 100644 (file)
@@ -938,6 +938,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 int 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 tag that it contains at ADDRESS */
+
+extern int gdbarch_decode_memtag_note_p (struct gdbarch *gdbarch);
+
+typedef gdb_byte (gdbarch_decode_memtag_note_ftype) (struct gdbarch *gdbarch, gdb::array_view<const gdb_byte> note, CORE_ADDR address);
+extern gdb_byte gdbarch_decode_memtag_note (struct gdbarch *gdbarch, gdb::array_view<const gdb_byte> note, CORE_ADDR address);
+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).
index 09881fb5aad7f321abcf7e5410df2fa4f0cafa34..01d1a6972b2556241da422b931bdf59b48ba7463 100755 (executable)
@@ -729,6 +729,12 @@ M;char *;make_corefile_notes;bfd *obfd, int *note_size;obfd, note_size
 # 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 tag that it contains at ADDRESS
+M;gdb_byte;decode_memtag_note;gdb::array_view<const gdb_byte> note, CORE_ADDR address;note, address
+
 # 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).
index d46cc96ca61c15b345ddfef06ca7e410aa4d87fc..209cea1106561748c4616650f5793d582185b5a8 100644 (file)
@@ -1434,13 +1434,21 @@ parse_smaps_data (const char *data,
   return smaps;
 }
 
-/* See linux-tdep.h.  */
+/* For each memory map entry, create a new core file note that contains all of
+   its memory tags.  Save the data to NOTE_DATA and update NOTE_SIZE
+   accordingly.  */
 
-bool
-linux_address_in_memtag_page (CORE_ADDR address)
+static void
+linux_make_memtag_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
+                                 char **note_data, int *note_size)
 {
   if (current_inferior ()->fake_pid_p)
-    return false;
+    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;
 
@@ -1450,23 +1458,39 @@ linux_address_in_memtag_page (CORE_ADDR address)
     = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
 
   if (data == nullptr)
-    return false;
+    return;
+
+  std::vector<struct smaps_data> smaps;
 
   /* Parse the contents of smaps into a vector.  */
-  std::vector<struct smaps_data> smaps
-    = parse_smaps_data (data.get (), smaps_file);
+  smaps = parse_smaps_data (data.get (), smaps_file);
 
-  for (const smaps_data &map : smaps)
+  if (!smaps.empty ())
     {
-      /* Is the address within [start_address, end_address) in a page
-        mapped with memory tagging?  */
-      if (address >= map.start_address
-         && address < map.end_address
-         && map.vmflags.memory_tagging)
-       return true;
+      for (struct smaps_data map : smaps)
+       {
+         /* 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;
+         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 = elfcore_write_note (obfd, *note_data, note_size,
+                                              "CORE", NT_MEMTAG,
+                                              note.data (), note.size ());
+           }
+       }
     }
-
-  return false;
 }
 
 /* List memory regions in the inferior for a corefile.  */
@@ -2158,6 +2182,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.  */
   note_data = linux_make_mappings_corefile_notes (gdbarch, obfd,
                                                  note_data, note_size);
index 47bc23995874384c5a6d3b7759d1f43a9342128d..e94dfdfc6aca2f64dd2477dfc109d9528d93671b 100644 (file)
@@ -1,3 +1,8 @@
+2021-05-24  Luis Machado  <luis.machado@linaro.org>
+
+       * elf/common.h (NT_MEMTAG): New constant.
+       (ELF_CORE_TAG_CHERI): New constant.
+
 2021-03-17  Luis Machado  <luis.machado@arm.com>
 
        * opcode/aarch64.h (enum map_type): Moved from opcodes/aarch64-dis.c.
index 3980a0749ffb025a7df81aa62028896769f3b5d7..c6a31cc1f5e638ac962515a6fb51b228b0020179 100644 (file)
 #define NT_PRPSINFO    3               /* Contains copy of prpsinfo struct */
 #define NT_TASKSTRUCT  4               /* Contains copy of task struct */
 #define NT_AUXV                6               /* Contains copy of Elfxx_auxv_t */
+#define NT_MEMTAG      7               /* Contains a copy of the memory tags */
 #define NT_PRXFPREG    0x46e62b7f      /* Contains a user_xfpregs_struct; */
                                        /*   note name must be "LINUX".  */
 #define NT_PPC_VMX     0x100           /* PowerPC Altivec/VMX registers */
 #define NT_SIGINFO     0x53494749      /* Fields of siginfo_t.  */
 #define NT_FILE                0x46494c45      /* Description of mapped files.  */
 
+/* NT_MEMTAG record types.  Reuse the same 0x4xx prefix to identify this
+   type as ARM-specific.  */
+#define ELF_CORE_TAG_CHERI     0x401   /* CHERI memory tags for AArch64.  */
+
 /* Note segments for core files on dir-style procfs systems.  */
 
 #define NT_PSTATUS     10              /* Has a struct pstatus */