diff options
author | Luis Machado <luis.machado@linaro.org> | 2021-04-16 10:43:59 -0300 |
---|---|---|
committer | Luis Machado <luis.machado@linaro.org> | 2021-05-24 22:19:33 -0300 |
commit | ffbda24e0309c1e53a7c30e77d2bfd7ad4a84fc5 (patch) | |
tree | 6b61c7a9959d1db031373e60524037762fa0ea57 | |
parent | cc7925bc9a89be00938ac7a00cee4e42789eb145 (diff) | |
download | binutils-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/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 2 | ||||
-rw-r--r-- | bfd/elf.c | 46 | ||||
-rw-r--r-- | binutils/ChangeLog | 4 | ||||
-rw-r--r-- | binutils/readelf.c | 2 | ||||
-rw-r--r-- | gdb/ChangeLog | 25 | ||||
-rw-r--r-- | gdb/aarch64-linux-tdep.c | 186 | ||||
-rw-r--r-- | gdb/arch/aarch64-cap-linux.h | 24 | ||||
-rw-r--r-- | gdb/corelow.c | 71 | ||||
-rw-r--r-- | gdb/gdbarch.c | 64 | ||||
-rw-r--r-- | gdb/gdbarch.h | 16 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 6 | ||||
-rw-r--r-- | gdb/linux-tdep.c | 59 | ||||
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/elf/common.h | 5 |
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, ¬e_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 */ |