aboutsummaryrefslogtreecommitdiff
path: root/gdb/arch
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@arm.com>2022-03-31 11:42:35 +0100
committerLuis Machado <luis.machado@arm.com>2022-07-19 15:24:31 +0100
commit68cffbbd4406b4efe1aa6e18460b1d7ca02549f1 (patch)
treef8a61526011db5bf0c60314f38de6fc48cd82ca0 /gdb/arch
parentd0ff5ca959df91dcef16ec57154ff199fad5a4e4 (diff)
downloadbinutils-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.zip
binutils-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.tar.gz
binutils-68cffbbd4406b4efe1aa6e18460b1d7ca02549f1.tar.bz2
[AArch64] MTE corefile support
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_AARCH64_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)
Diffstat (limited to 'gdb/arch')
-rw-r--r--gdb/arch/aarch64-mte-linux.c56
-rw-r--r--gdb/arch/aarch64-mte-linux.h10
2 files changed, 66 insertions, 0 deletions
diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
index fc7a8cc..3af6f36 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 fed91bb..0771ef7 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. */
+extern 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. */
+extern void aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first);
+
#endif /* ARCH_AARCH64_MTE_LINUX_H */