summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@linaro.org>2021-04-16 10:43:59 -0300
committerLuis Machado <luis.machado@linaro.org>2021-05-24 22:19:33 -0300
commitffbda24e0309c1e53a7c30e77d2bfd7ad4a84fc5 (patch)
tree6b61c7a9959d1db031373e60524037762fa0ea57
parentcc7925bc9a89be00938ac7a00cee4e42789eb145 (diff)
downloadbinutils-gdb-ffbda24e0309c1e53a7c30e77d2bfd7ad4a84fc5.tar.gz
Core file support (C registers + capability tags)
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.
-rw-r--r--bfd/ChangeLog10
-rw-r--r--bfd/elf-bfd.h2
-rw-r--r--bfd/elf.c46
-rw-r--r--binutils/ChangeLog4
-rw-r--r--binutils/readelf.c2
-rw-r--r--gdb/ChangeLog25
-rw-r--r--gdb/aarch64-linux-tdep.c186
-rw-r--r--gdb/arch/aarch64-cap-linux.h24
-rw-r--r--gdb/corelow.c71
-rw-r--r--gdb/gdbarch.c64
-rw-r--r--gdb/gdbarch.h16
-rwxr-xr-xgdb/gdbarch.sh6
-rw-r--r--gdb/linux-tdep.c59
-rw-r--r--include/ChangeLog5
-rw-r--r--include/elf/common.h5
15 files changed, 494 insertions, 31 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index db416fb90cc..d4586cbd1ed 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index f383cd8bf6e..ef9a722bac8 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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
diff --git a/bfd/elf.c b/bfd/elf.c
index 9d7cbd52e02..9a5b472cda2 100644
--- 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
@@ -9886,6 +9903,12 @@ elfcore_grok_aarch_pauth (bfd *abfd, Elf_Internal_Note *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)
{
return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", 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);
}
}
@@ -11918,6 +11950,18 @@ elfcore_write_aarch_pauth (bfd *abfd,
}
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,
int *bufsiz,
@@ -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;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 4fee9910311..c87b7934646 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 03cfc97464b..b6c632b2c99 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -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;
}
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index cde1f20b1db..0ad646af651 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 0b2c02d3cb8..11564009023 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -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
{
diff --git a/gdb/arch/aarch64-cap-linux.h b/gdb/arch/aarch64-cap-linux.h
index 7a9df0bffba..0c8fe2d9d55 100644
--- a/gdb/arch/aarch64-cap-linux.h
+++ b/gdb/arch/aarch64-cap-linux.h
@@ -37,4 +37,28 @@
#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 */
diff --git a/gdb/corelow.c b/gdb/corelow.c
index d557475e06f..3b2d96681f1 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 51db02361f6..a79d9bdfcf3 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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. */
@@ -919,6 +923,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -3801,6 +3817,54 @@ set_gdbarch_find_memory_regions (struct gdbarch *gdbarch,
}
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)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index ec32bf50f01..49c7f1c7a8d 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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).
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 09881fb5aad..01d1a6972b2 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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).
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index d46cc96ca61..209cea11065 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -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);
diff --git a/include/ChangeLog b/include/ChangeLog
index 47bc2399587..e94dfdfc6ac 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -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.
diff --git a/include/elf/common.h b/include/elf/common.h
index 3980a0749ff..c6a31cc1f5e 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -581,6 +581,7 @@
#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 */
@@ -668,6 +669,10 @@
#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 */