From: Luis Machado <luis.machado@arm.com>
To: <gdb-patches@sourceware.org>
Subject: [PATCH, v3] [AArch64] MTE corefile support
Date: Fri, 22 Apr 2022 14:30:14 +0100 [thread overview]
Message-ID: <20220422133014.22973-1-luis.machado@arm.com> (raw)
In-Reply-To: <20220331140343.9047-1-luis.machado@arm.com>
Apologies for double posting, but the subject line for the previous submission
was off and misleading.
v3:
- Updated NEWS and documentation to be more thorough.
v2:
- Rework memory tag section handling to use generic section fields.
--
Teach GDB how to dump memory tags for AArch64 when using the gcore command
and how to read memory tag data back from a core file generated by GDB
(via gcore) or by the Linux kernel.
The format is documented in the Linux Kernel documentation [1].
Each tagged memory range (listed in /proc/<pid>/smaps) gets dumped to its
own PT_ARM_MEMTAG_MTE segment. A section named ".memtag" is created for each
of those segments when reading the core file back.
To save a little bit of space, given MTE tags only take 4 bits, the memory tags
are stored packed as 2 tags per byte.
When reading the data back, the tags are unpacked.
I've added a new testcase to exercise the feature.
Build-tested with --enable-targets=all and regression tested on aarch64-linux
Ubuntu 20.04.
[1] Documentation/arm64/memory-tagging-extension.rst (Core Dump Support)
---
gdb/Makefile.in | 1 +
gdb/NEWS | 10 ++
gdb/aarch64-linux-tdep.c | 166 +++++++++++++++++++
gdb/arch/aarch64-mte-linux.c | 56 +++++++
gdb/arch/aarch64-mte-linux.h | 10 ++
gdb/corelow.c | 62 +++++++
gdb/defs.h | 3 +-
gdb/doc/gdb.texinfo | 18 ++
gdb/gcore.c | 83 +++++++++-
gdb/gdbarch-components.py | 35 ++++
gdb/gdbarch-gen.h | 26 +++
gdb/gdbarch.c | 96 +++++++++++
gdb/linux-tdep.c | 39 ++++-
gdb/memtag.c | 61 +++++++
gdb/memtag.h | 50 ++++++
gdb/testsuite/gdb.arch/aarch64-mte-gcore.c | 93 +++++++++++
gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp | 107 ++++++++++++
17 files changed, 908 insertions(+), 8 deletions(-)
create mode 100644 gdb/memtag.c
create mode 100644 gdb/memtag.h
create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ec0e55dd803..a11054d6a5c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1119,6 +1119,7 @@ COMMON_SFILES = \
memattr.c \
memory-map.c \
memrange.c \
+ memtag.c \
minidebug.c \
minsyms.c \
mipsread.c \
diff --git a/gdb/NEWS b/gdb/NEWS
index 760cb2b7abc..d6818d54972 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,16 @@
*** Changes since GDB 12
+* GDB now supports dumping memory tag data for AArch64 MTE. It also supports
+ reading memory tag data for AArch64 MTE from core files generated by
+ the gcore command or the Linux kernel.
+
+ When a process uses memory-mapped pages protected by memory tags (for
+ example, AArch64 MTE), this additional information will be recorded in
+ the core file in the event of a crash or if GDB generates a core file
+ from the current process state. GDB will show this additional information
+ automatically, or through one of the memory-tag subcommands.
+
* GDB now supports hardware watchpoints on FreeBSD/Aarch64.
* Remove support for building against Python 2, it is now only possible to
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 55094b3d88b..ebde9c3f167 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -53,6 +53,8 @@
#include "gdbsupport/selftest.h"
+#include "elf/common.h"
+
/* Signal frame handling.
+------------+ ^
@@ -1781,6 +1783,155 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
}
}
+/* AArch64 Linux implementation of the gdbarch_create_memtag_section hook. */
+
+static asection *
+aarch64_linux_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd,
+ CORE_ADDR address, size_t size)
+{
+ gdb_assert (obfd != nullptr);
+ gdb_assert (size > 0);
+
+ /* Create the section and associated program header. */
+ asection *mte_section = bfd_make_section_anyway (obfd, "memtag");
+
+ if (mte_section == nullptr)
+ return nullptr;
+
+ bfd_set_section_vma (mte_section, address);
+ /* The size of the memory range covered by the memory tags. We reuse the
+ section's rawsize field for this purpose. */
+ mte_section->rawsize = size;
+ /* Tags are stored packed as 2 tags per byte. */
+ bfd_set_section_size (mte_section, (size / AARCH64_MTE_GRANULE_SIZE) / 2);
+ /* Make sure the section's flags has SEC_HAS_CONTENTS, otherwise BFD will
+ refuse to write data to this section. */
+ bfd_set_section_flags (mte_section, SEC_HAS_CONTENTS);
+
+ /* Store program header information. */
+ bfd_record_phdr (obfd, PT_ARM_MEMTAG_MTE, 1, 0, 0, 0, 0, 0, 1,
+ &mte_section);
+
+ return mte_section;
+}
+
+/* Maximum number of tags to request. */
+#define MAX_TAGS_TO_TRANSFER 1024
+
+/* AArch64 Linux implementation of the gdbarch_fill_memtag_section hook. */
+
+static bool
+aarch64_linux_fill_memtag_section (struct gdbarch *gdbarch, asection *osec)
+{
+ /* We only handle MTE tags for now. */
+
+ size_t segment_size = osec->rawsize;
+ CORE_ADDR start_address = bfd_section_vma (osec);
+ CORE_ADDR end_address = start_address + segment_size;
+
+ /* Figure out how many tags we need to store in this memory range. */
+ size_t granules = aarch64_mte_get_tag_granules (start_address, segment_size,
+ AARCH64_MTE_GRANULE_SIZE);
+
+ /* If there are no tag granules to fetch, just return. */
+ if (granules == 0)
+ return true;
+
+ CORE_ADDR address = start_address;
+
+ /* Vector of tags. */
+ gdb::byte_vector tags;
+
+ while (granules > 0)
+ {
+ /* Transfer tags in chunks. */
+ gdb::byte_vector tags_read;
+ size_t xfer_len
+ = (granules >= MAX_TAGS_TO_TRANSFER)?
+ MAX_TAGS_TO_TRANSFER * AARCH64_MTE_GRANULE_SIZE :
+ granules * AARCH64_MTE_GRANULE_SIZE;
+
+ if (!target_fetch_memtags (address, xfer_len, tags_read,
+ static_cast<int> (memtag_type::allocation)))
+ {
+ warning (_("Failed to read MTE tags from memory range [%s,%s)."),
+ phex_nz (start_address, sizeof (start_address)),
+ phex_nz (end_address, sizeof (end_address)));
+ return false;
+ }
+
+ /* Transfer over the tags that have been read. */
+ tags.insert (tags.end (), tags_read.begin (), tags_read.end ());
+
+ /* Adjust the remaining granules and starting address. */
+ granules -= tags_read.size ();
+ address += tags_read.size () * AARCH64_MTE_GRANULE_SIZE;
+ }
+
+ /* Pack the MTE tag bits. */
+ aarch64_mte_pack_tags (tags);
+
+ if (!bfd_set_section_contents (osec->owner, osec, tags.data (),
+ 0, tags.size ()))
+ {
+ warning (_("Failed to write %ld bytes of corefile memory "
+ "tag content (%s)."),
+ tags.size (),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ return true;
+}
+
+/* AArch64 Linux implementation of the gdbarch_decode_memtag_section
+ hook. Decode a memory tag section and return the requested tags.
+
+ The section is guaranteed to cover the [ADDRESS, ADDRESS + length)
+ range. */
+
+static gdb::byte_vector
+aarch64_linux_decode_memtag_section (struct gdbarch *gdbarch,
+ bfd_section *section,
+ int type,
+ CORE_ADDR address, size_t length)
+{
+ gdb_assert (section != nullptr);
+
+ /* The requested address must not be less than section->vma. */
+ gdb_assert (section->vma <= address);
+
+ /* Figure out how many tags we need to fetch in this memory range. */
+ size_t granules = aarch64_mte_get_tag_granules (address, length,
+ AARCH64_MTE_GRANULE_SIZE);
+ /* Sanity check. */
+ gdb_assert (granules > 0);
+
+ /* Fetch the total number of tags in the range [VMA, address + length). */
+ size_t granules_from_vma
+ = aarch64_mte_get_tag_granules (section->vma,
+ address - section->vma + length,
+ AARCH64_MTE_GRANULE_SIZE);
+
+ /* Adjust the tags vector to contain the exact number of packed bytes. */
+ gdb::byte_vector tags (((granules - 1) >> 1) + 1);
+
+ /* Figure out the starting offset into the packed tags data. */
+ file_ptr offset = ((granules_from_vma - granules) >> 1);
+
+ if (!bfd_get_section_contents (section->owner, section, tags.data (),
+ offset, tags.size ()))
+ error (_("Couldn't read contents from memtag section."));
+
+ /* At this point, the tags are packed 2 per byte. Unpack them before
+ returning. */
+ bool skip_first = ((granules_from_vma - granules) % 2) != 0;
+ aarch64_mte_unpack_tags (tags, skip_first);
+
+ /* Resize to the exact number of tags that was requested. */
+ tags.resize (granules);
+
+ return tags;
+}
+
static void
aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -1864,6 +2015,21 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_report_signal_info (gdbarch,
aarch64_linux_report_signal_info);
+
+ /* Core file helpers. */
+
+ /* Core file helper to create a memory tag section for a particular
+ PT_LOAD segment. */
+ set_gdbarch_create_memtag_section
+ (gdbarch, aarch64_linux_create_memtag_section);
+
+ /* Core file helper to fill a memory tag section with tag data. */
+ set_gdbarch_fill_memtag_section
+ (gdbarch, aarch64_linux_fill_memtag_section);
+
+ /* Core file helper to decode a memory tag section. */
+ set_gdbarch_decode_memtag_section (gdbarch,
+ aarch64_linux_decode_memtag_section);
}
/* Initialize the aarch64_linux_record_tdep. */
diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
index fc7a8cc00f7..3af6f364e91 100644
--- a/gdb/arch/aarch64-mte-linux.c
+++ b/gdb/arch/aarch64-mte-linux.c
@@ -21,6 +21,62 @@
/* See arch/aarch64-mte-linux.h */
+void
+aarch64_mte_pack_tags (gdb::byte_vector &tags)
+{
+ /* Nothing to pack? */
+ if (tags.empty ())
+ return;
+
+ /* If the tags vector has an odd number of elements, add another
+ zeroed-out element to make it even. This facilitates packing. */
+ if ((tags.size () % 2) != 0)
+ tags.emplace_back (0);
+
+ for (int unpacked = 0, packed = 0; unpacked < tags.size ();
+ unpacked += 2, packed++)
+ tags[packed] = (tags[unpacked + 1] << 4) | tags[unpacked];
+
+ /* Now we have half the size. */
+ tags.resize (tags.size () / 2);
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+void
+aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first)
+{
+ /* Nothing to unpack? */
+ if (tags.empty ())
+ return;
+
+ /* An unpacked MTE tags vector will have twice the number of elements
+ compared to an unpacked one. */
+ gdb::byte_vector unpacked_tags (tags.size () * 2);
+
+ int unpacked = 0, packed = 0;
+
+ if (skip_first)
+ {
+ /* We are not interested in the first unpacked element, just discard
+ it. */
+ unpacked_tags[unpacked] = (tags[packed] >> 4) & 0xf;
+ unpacked++;
+ packed++;
+ }
+
+ for (; packed < tags.size (); unpacked += 2, packed++)
+ {
+ unpacked_tags[unpacked] = tags[packed] & 0xf;
+ unpacked_tags[unpacked + 1] = (tags[packed] >> 4) & 0xf;
+ }
+
+ /* Update the original tags vector. */
+ tags = std::move (unpacked_tags);
+}
+
+/* See arch/aarch64-mte-linux.h */
+
size_t
aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
{
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index d158926feff..8a145b447aa 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -32,6 +32,7 @@
/* We have one tag per 16 bytes of memory. */
#define AARCH64_MTE_GRANULE_SIZE 16
+#define AARCH64_MTE_TAG_BIT_SIZE 4
#define AARCH64_MTE_LOGICAL_TAG_START_BIT 56
#define AARCH64_MTE_LOGICAL_MAX_VALUE 0xf
@@ -71,4 +72,13 @@ extern CORE_ADDR aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag);
It is always possible to get the logical tag. */
extern CORE_ADDR aarch64_mte_get_ltag (CORE_ADDR address);
+/* Given a TAGS vector containing 1 MTE tag per byte, pack the data as
+ 2 tags per byte and resize the vector. */
+void aarch64_mte_pack_tags (gdb::byte_vector &tags);
+
+/* Given a TAGS vector containing 2 MTE tags per byte, unpack the data as
+ 1 tag per byte and resize the vector. If SKIP_FIRST is TRUE, skip the
+ first unpacked element. Otherwise leave it in the unpacked vector. */
+void aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first);
+
#endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 8c33fb7ebb2..8b8994f80db 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -52,6 +52,7 @@
#include <unordered_set>
#include "gdbcmd.h"
#include "xml-tdesc.h"
+#include "memtag.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
@@ -101,6 +102,13 @@ class core_target final : public process_stratum_target
bool info_proc (const char *, enum info_proc_what) override;
+ bool supports_memory_tagging () override;
+
+ /* Core file implementation of fetch_memtags. Fetch the memory tags from
+ core file notes. */
+ bool fetch_memtags (CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags, int type) override;
+
/* A few helpers. */
/* Getter, see variable definition. */
@@ -1162,6 +1170,60 @@ core_target::info_proc (const char *args, enum info_proc_what request)
return true;
}
+/* Implementation of the "supports_memory_tagging" target_ops method. */
+
+bool
+core_target::supports_memory_tagging ()
+{
+ /* Look for memory tag sections. If they exist, that means this core file
+ supports memory tagging. */
+
+ return (bfd_get_section_by_name (core_bfd, "memtag") != nullptr);
+}
+
+/* Implementation of the "fetch_memtags" target_ops method. */
+
+bool
+core_target::fetch_memtags (CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags, int type)
+{
+ struct gdbarch *gdbarch = target_gdbarch ();
+
+ /* Make sure we have a way to decode the memory tag notes. */
+ if (!gdbarch_decode_memtag_section_p (gdbarch))
+ error (_("gdbarch_decode_memtag_section not implemented for this "
+ "architecture."));
+
+ memtag_section_info info;
+ info.memtag_section = nullptr;
+
+ while (get_next_core_memtag_section (core_bfd, info.memtag_section,
+ address, info))
+ {
+ size_t adjusted_length
+ = (address + len < info.end_address)? len : (info.end_address - address);
+
+ /* Decode the memory tag note and return the tags. */
+ gdb::byte_vector tags_read
+ = gdbarch_decode_memtag_section (gdbarch, info.memtag_section, type,
+ address, adjusted_length);
+
+ /* Transfer over the tags that have been read. */
+ tags.insert (tags.end (), tags_read.begin (), tags_read.end ());
+
+ /* ADDRESS + LEN may cross the boundaries of a particular memory tag
+ segment. Check if we need to fetch tags from a different section. */
+ if (!tags_read.empty () && (address + len) < info.end_address)
+ return true;
+
+ /* There are more tags to fetch. Update ADDRESS and LEN. */
+ len -= (info.end_address - address);
+ address = info.end_address;
+ }
+
+ return false;
+}
+
/* Get a pointer to the current core target. If not connected to a
core target, return NULL. */
diff --git a/gdb/defs.h b/gdb/defs.h
index 99bfdd526ff..51a7576a56a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -344,7 +344,8 @@ extern const char *pc_prefix (CORE_ADDR);
typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned long size,
int read, int write, int exec,
- int modified, void *data);
+ int modified, bool memory_tagged,
+ void *data);
/* * Possible lvalue types. Like enum language, this should be in
value.h, but needs to be here for the same reason. */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c1e9b09e833..d9021f1c56d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -25545,6 +25545,24 @@ options that can be controlled at runtime and emulates the @code{prctl}
option @code{PR_SET_TAGGED_ADDR_CTRL}. For further information, see the
documentation in the Linux kernel.
+@value{GDBN} supports dumping memory tag data to core files through the
+@command{gcore} command and reading memory tag data from core files generated
+by the @command{gcore} command or the Linux kernel.
+
+When a process uses memory-mapped pages protected by memory tags (for
+example, AArch64 MTE), this additional information will be recorded in
+the core file in the event of a crash or if @value{GDB} generates a core file
+from the current process state.
+
+The memory tag data will be used so developers can display the memory
+tags from a particular memory region (using the @samp{m} modifier to the
+@command{x} command, using the @command{print} command or using the various
+@command{memory-tag} subcommands.
+
+In the case of a crash, @value{GDB} will attempt to retrieve the memory tag
+information automatically from the core file, and will show one of the above
+messages depending on whether the synchronous or asynchronous mode is selected.
+
@node i386
@subsection x86 Architecture-specific Issues
diff --git a/gdb/gcore.c b/gdb/gcore.c
index fdb22b72a07..b81ef81ab84 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -349,6 +349,12 @@ make_output_phdrs (bfd *obfd, asection *osec)
int p_flags = 0;
int p_type = 0;
+ /* Memory tag segments have already been handled by the architecture, as
+ those contain arch-specific information. If we have one of those, just
+ return. */
+ if (startswith (bfd_section_name (osec), "memtag"))
+ return;
+
/* FIXME: these constants may only be applicable for ELF. */
if (startswith (bfd_section_name (osec), "load"))
p_type = PT_LOAD;
@@ -371,7 +377,8 @@ make_output_phdrs (bfd *obfd, asection *osec)
static int
gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
- int write, int exec, int modified, void *data)
+ int write, int exec, int modified, bool memory_tagged,
+ void *data)
{
bfd *obfd = (bfd *) data;
asection *osec;
@@ -454,6 +461,45 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read,
return 0;
}
+/* gdbarch_find_memory_region callback for creating a memory tag section.
+ DATA is 'bfd *' for the core file GDB is creating. */
+
+static int
+gcore_create_memtag_section_callback (CORE_ADDR vaddr, unsigned long size,
+ int read, int write, int exec,
+ int modified, bool memory_tagged,
+ void *data)
+{
+ /* Are there memory tags in this particular memory map entry? */
+ if (!memory_tagged)
+ return 0;
+
+ bfd *obfd = (bfd *) data;
+
+ /* Ask the architecture to create a memory tag section for this particular
+ memory map entry. It will be populated with contents later, as we can't
+ start writing the contents before we have all the sections sorted out. */
+ asection *memtag_section
+ = gdbarch_create_memtag_section (target_gdbarch (), obfd, vaddr, size);
+
+ if (memtag_section == nullptr)
+ {
+ warning (_("Couldn't make gcore memory tag segment: %s"),
+ bfd_errmsg (bfd_get_error ()));
+ return 1;
+ }
+
+ if (info_verbose)
+ {
+ gdb_printf (gdb_stdout, "Saved memory tag segment, %s bytes "
+ "at %s\n",
+ plongest (bfd_section_size (memtag_section)),
+ paddress (target_gdbarch (), vaddr));
+ }
+
+ return 0;
+}
+
int
objfile_find_memory_regions (struct target_ops *self,
find_memory_region_ftype func, void *obfd)
@@ -483,6 +529,7 @@ objfile_find_memory_regions (struct target_ops *self,
(flags & SEC_READONLY) == 0, /* Writable. */
(flags & SEC_CODE) != 0, /* Executable. */
1, /* MODIFIED is unknown, pass it as true. */
+ false, /* No memory tags in the object file. */
obfd);
if (ret != 0)
return ret;
@@ -496,6 +543,7 @@ objfile_find_memory_regions (struct target_ops *self,
1, /* Stack section will be writable. */
0, /* Stack section will not be executable. */
1, /* Stack section will be modified. */
+ false, /* No memory tags in the object file. */
obfd);
/* Make a heap segment. */
@@ -506,6 +554,7 @@ objfile_find_memory_regions (struct target_ops *self,
1, /* Heap section will be writable. */
0, /* Heap section will not be executable. */
1, /* Heap section will be modified. */
+ false, /* No memory tags in the object file. */
obfd);
return 0;
@@ -555,6 +604,20 @@ gcore_copy_callback (bfd *obfd, asection *osec)
}
}
+/* Callback to copy contents to a particular memory tag section. */
+
+static void
+gcore_copy_memtag_section_callback (bfd *obfd, asection *osec)
+{
+ /* We are only interested in "memtag" sections. */
+ if (!startswith (bfd_section_name (osec), "memtag"))
+ return;
+
+ /* Fill the section with memory tag contents. */
+ if (!gdbarch_fill_memtag_section (target_gdbarch (), osec))
+ error (_("Failed to fill memory tag section for core file."));
+}
+
static int
gcore_memory_sections (bfd *obfd)
{
@@ -567,13 +630,27 @@ gcore_memory_sections (bfd *obfd)
return 0; /* FIXME: error return/msg? */
}
+ /* Take care of dumping memory tags, if there are any. */
+ if (!gdbarch_find_memory_regions_p (target_gdbarch ())
+ || gdbarch_find_memory_regions (target_gdbarch (),
+ gcore_create_memtag_section_callback,
+ obfd) != 0)
+ {
+ if (target_find_memory_regions (gcore_create_memtag_section_callback,
+ obfd) != 0)
+ return 0;
+ }
+
/* Record phdrs for section-to-segment mapping. */
for (asection *sect : gdb_bfd_sections (obfd))
make_output_phdrs (obfd, sect);
- /* Copy memory region contents. */
+ /* Copy memory region and memory tag contents. */
for (asection *sect : gdb_bfd_sections (obfd))
- gcore_copy_callback (obfd, sect);
+ {
+ gcore_copy_callback (obfd, sect);
+ gcore_copy_memtag_section_callback (obfd, sect);
+ }
return 1;
}
diff --git a/gdb/gdbarch-components.py b/gdb/gdbarch-components.py
index e8f20c83ff0..6fa1b7591db 100644
--- a/gdb/gdbarch-components.py
+++ b/gdb/gdbarch-components.py
@@ -1522,6 +1522,41 @@ Find core file memory regions
invalid=True,
)
+Method(
+ comment="""
+Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag section to be dumped to a core file
+""",
+ type="asection *",
+ name="create_memtag_section",
+ params=[("bfd *", "obfd"), ("CORE_ADDR", "address"), ("size_t", "size")],
+ predicate=True,
+ invalid=True,
+)
+
+Method(
+ comment="""
+Given a memory tag section OSEC, fill OSEC's contents with the appropriate tag data
+""",
+ type="bool",
+ name="fill_memtag_section",
+ params=[("asection *", "osec")],
+ predicate=True,
+ invalid=True,
+)
+
+Method(
+ comment="""
+Decode a memory tag SECTION and return the tags of type TYPE contained in
+the memory range [ADDRESS, ADDRESS + LENGTH).
+If no tags were found, return an empty vector.
+""",
+ type="gdb::byte_vector",
+ name="decode_memtag_section",
+ params=[("bfd_section *", "section"), ("int", "type"), ("CORE_ADDR", "address"), ("size_t", "length")],
+ predicate=True,
+ invalid=True,
+)
+
Method(
comment="""
Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 882b9057b1a..1d19f51f21d 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -874,6 +874,32 @@ 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);
+/* Given a bfd OBFD, segment ADDRESS and SIZE, create a memory tag section to be dumped to a core file */
+
+extern bool gdbarch_create_memtag_section_p (struct gdbarch *gdbarch);
+
+typedef asection * (gdbarch_create_memtag_section_ftype) (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size);
+extern asection * gdbarch_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size);
+extern void set_gdbarch_create_memtag_section (struct gdbarch *gdbarch, gdbarch_create_memtag_section_ftype *create_memtag_section);
+
+/* Given a memory tag section OSEC, fill OSEC's contents with the appropriate tag data */
+
+extern bool gdbarch_fill_memtag_section_p (struct gdbarch *gdbarch);
+
+typedef bool (gdbarch_fill_memtag_section_ftype) (struct gdbarch *gdbarch, asection *osec);
+extern bool gdbarch_fill_memtag_section (struct gdbarch *gdbarch, asection *osec);
+extern void set_gdbarch_fill_memtag_section (struct gdbarch *gdbarch, gdbarch_fill_memtag_section_ftype *fill_memtag_section);
+
+/* Decode a memory tag SECTION and return the tags of type TYPE contained in
+ the memory range [ADDRESS, ADDRESS + LENGTH).
+ If no tags were found, return an empty vector. */
+
+extern bool gdbarch_decode_memtag_section_p (struct gdbarch *gdbarch);
+
+typedef gdb::byte_vector (gdbarch_decode_memtag_section_ftype) (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length);
+extern gdb::byte_vector gdbarch_decode_memtag_section (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length);
+extern void set_gdbarch_decode_memtag_section (struct gdbarch *gdbarch, gdbarch_decode_memtag_section_ftype *decode_memtag_section);
+
/* 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.c b/gdb/gdbarch.c
index a588bdef61a..f5dbacb14e7 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -171,6 +171,9 @@ 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_section_ftype *create_memtag_section;
+ gdbarch_fill_memtag_section_ftype *fill_memtag_section;
+ gdbarch_decode_memtag_section_ftype *decode_memtag_section;
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;
@@ -527,6 +530,9 @@ 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_section, has predicate. */
+ /* Skip verify of fill_memtag_section, has predicate. */
+ /* Skip verify of decode_memtag_section, 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. */
@@ -1096,6 +1102,24 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: find_memory_regions = <%s>\n",
host_address_to_string (gdbarch->find_memory_regions));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_create_memtag_section_p() = %d\n",
+ gdbarch_create_memtag_section_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: create_memtag_section = <%s>\n",
+ host_address_to_string (gdbarch->create_memtag_section));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_fill_memtag_section_p() = %d\n",
+ gdbarch_fill_memtag_section_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: fill_memtag_section = <%s>\n",
+ host_address_to_string (gdbarch->fill_memtag_section));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_decode_memtag_section_p() = %d\n",
+ gdbarch_decode_memtag_section_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: decode_memtag_section = <%s>\n",
+ host_address_to_string (gdbarch->decode_memtag_section));
gdb_printf (file,
"gdbarch_dump: gdbarch_core_xfer_shared_libraries_p() = %d\n",
gdbarch_core_xfer_shared_libraries_p (gdbarch));
@@ -3744,6 +3768,78 @@ set_gdbarch_find_memory_regions (struct gdbarch *gdbarch,
gdbarch->find_memory_regions = find_memory_regions;
}
+bool
+gdbarch_create_memtag_section_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->create_memtag_section != NULL;
+}
+
+asection *
+gdbarch_create_memtag_section (struct gdbarch *gdbarch, bfd *obfd, CORE_ADDR address, size_t size)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->create_memtag_section != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_create_memtag_section called\n");
+ return gdbarch->create_memtag_section (gdbarch, obfd, address, size);
+}
+
+void
+set_gdbarch_create_memtag_section (struct gdbarch *gdbarch,
+ gdbarch_create_memtag_section_ftype create_memtag_section)
+{
+ gdbarch->create_memtag_section = create_memtag_section;
+}
+
+bool
+gdbarch_fill_memtag_section_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->fill_memtag_section != NULL;
+}
+
+bool
+gdbarch_fill_memtag_section (struct gdbarch *gdbarch, asection *osec)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->fill_memtag_section != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_fill_memtag_section called\n");
+ return gdbarch->fill_memtag_section (gdbarch, osec);
+}
+
+void
+set_gdbarch_fill_memtag_section (struct gdbarch *gdbarch,
+ gdbarch_fill_memtag_section_ftype fill_memtag_section)
+{
+ gdbarch->fill_memtag_section = fill_memtag_section;
+}
+
+bool
+gdbarch_decode_memtag_section_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->decode_memtag_section != NULL;
+}
+
+gdb::byte_vector
+gdbarch_decode_memtag_section (struct gdbarch *gdbarch, bfd_section *section, int type, CORE_ADDR address, size_t length)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->decode_memtag_section != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_decode_memtag_section called\n");
+ return gdbarch->decode_memtag_section (gdbarch, section, type, address, length);
+}
+
+void
+set_gdbarch_decode_memtag_section (struct gdbarch *gdbarch,
+ gdbarch_decode_memtag_section_ftype decode_memtag_section)
+{
+ gdbarch->decode_memtag_section = decode_memtag_section;
+}
+
bool
gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch)
{
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 4e728a06e7e..8a83ed320cf 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -42,6 +42,7 @@
#include "gcore.h"
#include "gcore-elf.h"
#include "solib-svr4.h"
+#include "memtag.h"
#include <ctype.h>
#include <unordered_map>
@@ -1320,6 +1321,7 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write,
int exec, int modified,
+ bool memory_tagged,
const char *filename,
void *data);
@@ -1470,10 +1472,11 @@ parse_smaps_data (const char *data,
return smaps;
}
-/* See linux-tdep.h. */
+/* Helper that checks if an address is in a memory tag page for a live
+ process. */
-bool
-linux_address_in_memtag_page (CORE_ADDR address)
+static bool
+linux_process_address_in_memtag_page (CORE_ADDR address)
{
if (current_inferior ()->fake_pid_p)
return false;
@@ -1505,6 +1508,30 @@ linux_address_in_memtag_page (CORE_ADDR address)
return false;
}
+/* Helper that checks if an address is in a memory tag page for a core file
+ process. */
+
+static bool
+linux_core_file_address_in_memtag_page (CORE_ADDR address)
+{
+ if (core_bfd == nullptr)
+ return false;
+
+ memtag_section_info info;
+ return get_next_core_memtag_section (core_bfd, nullptr, address, info);
+}
+
+/* See linux-tdep.h. */
+
+bool
+linux_address_in_memtag_page (CORE_ADDR address)
+{
+ if (!target_has_execution ())
+ return linux_core_file_address_in_memtag_page (address);
+
+ return linux_process_address_in_memtag_page (address);
+}
+
/* List memory regions in the inferior for a corefile. */
static int
@@ -1593,6 +1620,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
map.offset, map.inode, map.read, map.write, map.exec,
1, /* MODIFIED is true because we want to dump
the mapping. */
+ map.vmflags.memory_tagging != 0,
map.filename.c_str (), obfd);
}
}
@@ -1621,12 +1649,14 @@ static int
linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write, int exec, int modified,
+ bool memory_tagged,
const char *filename, void *arg)
{
struct linux_find_memory_regions_data *data
= (struct linux_find_memory_regions_data *) arg;
- return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+ return data->func (vaddr, size, read, write, exec, modified, memory_tagged,
+ data->obfd);
}
/* A variant of linux_find_memory_regions_full that is suitable as the
@@ -1675,6 +1705,7 @@ static int
linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
ULONGEST offset, ULONGEST inode,
int read, int write, int exec, int modified,
+ bool memory_tagged,
const char *filename, void *data)
{
struct linux_make_mappings_data *map_data
diff --git a/gdb/memtag.c b/gdb/memtag.c
new file mode 100644
index 00000000000..af86137c49d
--- /dev/null
+++ b/gdb/memtag.c
@@ -0,0 +1,61 @@
+/* GDB generic memory tagging functions.
+
+ Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "memtag.h"
+#include "bfd.h"
+
+/* See memtag.h */
+
+bool
+get_next_core_memtag_section (bfd *abfd, asection *section,
+ CORE_ADDR address, memtag_section_info &info)
+{
+ /* If the caller provided no SECTION to start from, search from the
+ beginning. */
+ if (section == nullptr)
+ section = bfd_get_section_by_name (abfd, "memtag");
+
+ /* Go through all the memtag sections and figure out if ADDRESS
+ falls within one of the memory ranges that contain tags. */
+ while (section != nullptr)
+ {
+ size_t memtag_range_size = section->rawsize;
+ size_t tags_size = bfd_section_size (section);
+
+ /* Empty memory range and empty tag dump should not happen. */
+ gdb_assert (memtag_range_size != 0);
+ gdb_assert (tags_size != 0);
+
+ CORE_ADDR start_address = bfd_section_vma (section);
+ CORE_ADDR end_address = start_address + memtag_range_size;
+
+ /* Is the address within [start_address, end_address)? */
+ if (address >= start_address
+ && address < end_address)
+ {
+ info.start_address = start_address;
+ info.end_address = end_address;
+ info.memtag_section = section;
+ return true;
+ }
+ section = bfd_get_next_section_by_name (abfd, section);
+ }
+ return false;
+}
diff --git a/gdb/memtag.h b/gdb/memtag.h
new file mode 100644
index 00000000000..fe908c1e5e3
--- /dev/null
+++ b/gdb/memtag.h
@@ -0,0 +1,50 @@
+/* GDB generic memory tagging definitions.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef MEMTAG_H
+#define MEMTAG_H
+
+#include "bfd.h"
+
+struct memtag_section_info
+{
+ /* The start address of the tagged memory range. */
+ CORE_ADDR start_address;
+ /* The final address of the tagged memory range. */
+ CORE_ADDR end_address;
+ /* The section containing tags for the memory range
+ [start_address, end_address). */
+ asection *memtag_section;
+};
+
+/* Helper function to walk through memory tag sections in a core file.
+
+ Return TRUE if there is a "memtag" section containing ADDRESS. Return FALSE
+ otherwise.
+
+ If SECTION is provided, search from that section onwards. If SECTION is
+ nullptr, then start a new search.
+
+ If a "memtag" section containing ADDRESS is found, fill INFO with data
+ about such section. Otherwise leave it unchanged. */
+
+bool get_next_core_memtag_section (bfd *abfd, asection *section,
+ CORE_ADDR address,
+ memtag_section_info &info);
+
+#endif /* MEMTAG_H */
diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
new file mode 100644
index 00000000000..b20ebcff424
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.c
@@ -0,0 +1,93 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Exercise AArch64's Memory Tagging Extension with tagged pointers. */
+
+/* This test was based on the documentation for the AArch64 Memory Tagging
+ Extension from the Linux Kernel, found in the sources in
+ Documentation/arm64/memory-tagging-extension.rst. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+
+/* From arch/arm64/include/uapi/asm/hwcap.h */
+#define HWCAP2_MTE (1 << 18)
+
+/* From arch/arm64/include/uapi/asm/mman.h */
+#define PROT_MTE 0x20
+
+/* From include/uapi/linux/prctl.h */
+#define PR_SET_TAGGED_ADDR_CTRL 55
+#define PR_GET_TAGGED_ADDR_CTRL 56
+#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+#define PR_MTE_TCF_SHIFT 1
+#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
+#define PR_MTE_TAG_SHIFT 3
+
+void
+access_memory (unsigned char *tagged_ptr)
+{
+ tagged_ptr[0] = 'a';
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned char *tagged_ptr;
+ unsigned long page_sz = sysconf (_SC_PAGESIZE);
+ unsigned long hwcap2 = getauxval(AT_HWCAP2);
+
+ /* Bail out if MTE is not supported. */
+ if (!(hwcap2 & HWCAP2_MTE))
+ return 1;
+
+ /* Enable the tagged address ABI, synchronous MTE tag check faults and
+ allow all non-zero tags in the randomly generated set. */
+ if (prctl (PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
+ | (0xfffe << PR_MTE_TAG_SHIFT),
+ 0, 0, 0))
+ {
+ perror ("prctl () failed");
+ return 1;
+ }
+
+ /* Create a mapping that will have PROT_MTE set. */
+ tagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (tagged_ptr == MAP_FAILED)
+ {
+ perror ("mmap () failed");
+ return 1;
+ }
+
+ /* Enable MTE on the above anonymous mmap. */
+ if (mprotect (tagged_ptr, page_sz, PROT_READ | PROT_WRITE | PROT_MTE))
+ {
+ perror ("mprotect () failed");
+ return 1;
+ }
+
+ access_memory (tagged_ptr);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
new file mode 100644
index 00000000000..8a19c4b449e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-mte-gcore.exp
@@ -0,0 +1,107 @@
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test generating and reading a core file with MTE memory tags.
+
+if {![is_aarch64_target]} {
+ verbose "Skipping ${gdb_test_file_name}."
+ return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+# Targets that don't support memory tagging should not execute the
+# runtime memory tagging tests.
+if {![supports_memtag]} {
+ unsupported "memory tagging unsupported"
+ return -1
+}
+
+gdb_breakpoint "access_memory"
+
+if [gdb_continue "access_memory"] {
+ return -1
+}
+
+# Set each tag granule to a different tag value, from 0x0 to 0xf.
+set atag_msg "Allocation tag\\(s\\) updated successfully\."
+for {set i 15} {$i >= 0} {incr i -1} {
+ set index [expr [expr 15 - $i] * 16]
+ set tag [format "%02x" $i]
+ gdb_test "memory-tag set-allocation-tag &tagged_ptr\[$index\] 1 $tag" \
+ $atag_msg \
+ "set memory tag of &tagged_ptr\[$index\] to $tag"
+}
+
+# Run until a crash and confirm GDB displays memory tag violation
+# information.
+gdb_test "continue" \
+ [multi_line \
+ "Program received signal SIGSEGV, Segmentation fault" \
+ "Memory tag violation while accessing address $hex" \
+ "Allocation tag $hex" \
+ "Logical tag $hex\." \
+ "$hex in access_memory \\(.*\\) at .*" \
+ ".*tagged_ptr\\\[0\\\] = 'a';"] \
+ "display tag violation information for live process"
+
+# Generate the core file.
+set core_filename [standard_output_file "$testfile.core"]
+set core_generated [gdb_gcore_cmd "$core_filename" "generate core file"]
+
+if { !$core_generated } {
+ return -1
+}
+
+clean_restart $binfile
+
+# Load the core file and make sure we see the tag violation fault
+# information.
+gdb_test "core $core_filename" \
+ [multi_line \
+ "Core was generated by.*\." \
+ "Program terminated with signal SIGSEGV, Segmentation fault" \
+ "Memory tag violation while accessing address $hex" \
+ "Allocation tag 0xf" \
+ "Logical tag 0x0\." \
+ "#0.*$hex in access_memory \\(.*\\) at .*" \
+ ".*tagged_ptr\\\[0\\\] = 'a';"] \
+ "core file shows tag violation information"
+
+# Make sure we have the tag_ctl register.
+gdb_test "info register tag_ctl" \
+ "tag_ctl.*$hex.*${::decimal}" \
+ "tag_ctl is available"
+
+# Check if the tag granules have the expected values. If they do, that
+# means the core file saved the tags properly and GDB has read them
+# correctly.
+for {set i 15} {$i >= 0} {incr i -1} {
+ set index [expr [expr 15 - $i] * 16]
+ set tag [format "%x" $i]
+ gdb_test "memory-tag print-allocation-tag &tagged_ptr\[$index\]" \
+ "= 0x$tag" \
+ "memory tag of &tagged_ptr\[$index\] is correct"
+}
--
2.25.1
next prev parent reply other threads:[~2022-04-22 13:30 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-31 14:03 Luis Machado
2022-04-21 15:20 ` [PATCH, v2] " Luis Machado
2022-04-21 15:52 ` Eli Zaretskii
2022-04-22 8:12 ` Luis Machado
2022-04-22 8:30 ` Eli Zaretskii
2022-04-22 8:37 ` Luis Machado
2022-04-22 8:43 ` Eli Zaretskii
2022-04-22 8:44 ` Luis Machado
2022-04-22 13:27 ` [PATCH 1/2] " Luis Machado
2022-04-22 13:33 ` Eli Zaretskii
2022-04-22 13:30 ` Luis Machado [this message]
2022-05-03 21:56 ` [PATCH, v4] " Luis Machado
2022-05-12 10:36 ` Luis Machado
2022-05-18 12:46 ` Luis Machado
2022-05-18 13:58 ` John Baldwin
2022-05-23 9:50 ` Luis Machado
2022-05-23 9:49 ` Luis Machado
2022-06-06 9:28 ` Luis Machado
2022-06-06 9:42 ` Kuan-Ying Lee
2022-06-06 9:47 ` Luis Machado
2022-06-06 9:54 ` Kuan-Ying Lee
2022-06-06 10:49 ` Eli Zaretskii
2022-06-22 9:04 ` Luis Machado
2022-06-27 14:51 ` Pedro Alves
2022-07-11 10:13 ` Luis Machado
2022-07-11 10:57 ` [PATCH] [AArch64,v5] " Luis Machado
2022-07-18 13:54 ` Pedro Alves
2022-07-19 14:25 ` Luis Machado
-- strict thread matches above, loose matches on Subject: below --
2021-05-26 14:08 [PATCH,v2] [AArch64] " Luis Machado
2021-05-31 14:15 ` [PATCH,v3][AArch64] " Luis Machado
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220422133014.22973-1-luis.machado@arm.com \
--to=luis.machado@arm.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).