aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@linaro.org>2020-06-19 17:33:13 -0300
committerLuis Machado <luis.machado@linaro.org>2021-03-24 14:53:56 -0300
commit4601818e8c06bb8a5bf4b63fa527c69d3f81c6f0 (patch)
treea8650e0d1beb52fdf709a0198be63a61d29f4b49 /gdb
parent3f3bd8b8c14d844533b70b25c7f1a8cbdbac2639 (diff)
downloadgdb-4601818e8c06bb8a5bf4b63fa527c69d3f81c6f0.zip
gdb-4601818e8c06bb8a5bf4b63fa527c69d3f81c6f0.tar.gz
gdb-4601818e8c06bb8a5bf4b63fa527c69d3f81c6f0.tar.bz2
AArch64: Implement memory tagging target methods for AArch64
The patch implements the memory tagging target hooks for AArch64, so we can handle MTE. gdb/ChangeLog: 2021-03-24 Luis Machado <luis.machado@linaro.org> * Makefile.in (ALL_64_TARGET_OBS): Add arch/aarch64-mte-linux.o. (HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h and nat/aarch64-mte-linux-ptrace.h. * aarch64-linux-nat.c: Include nat/aarch64-mte-linux-ptrace.h. (aarch64_linux_nat_target) <supports_memory_tagging>: New method override. <fetch_memtags>: New method override. <store_memtags>: New method override. (aarch64_linux_nat_target::supports_memory_tagging): New method. (aarch64_linux_nat_target::fetch_memtags): New method. (aarch64_linux_nat_target::store_memtags): New method. * arch/aarch64-mte-linux.c: New file. * arch/aarch64-mte-linux.h: Include gdbsupport/common-defs.h. (AARCH64_MTE_GRANULE_SIZE): Define. (aarch64_memtag_type): New enum. (aarch64_mte_get_tag_granules): New prototype. * configure.nat (NATDEPFILES): Add nat/aarch64-mte-linux-ptrace.o. * configure.tgt (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o. * nat/aarch64-mte-linux-ptrace.c: New file. * nat/aarch64-mte-linux-ptrace.h: New file.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog23
-rw-r--r--gdb/Makefile.in1
-rw-r--r--gdb/aarch64-linux-nat.c50
-rw-r--r--gdb/arch/aarch64-mte-linux.c38
-rw-r--r--gdb/arch/aarch64-mte-linux.h19
-rw-r--r--gdb/configure.nat3
-rw-r--r--gdb/configure.tgt1
-rw-r--r--gdb/nat/aarch64-mte-linux-ptrace.c210
-rw-r--r--gdb/nat/aarch64-mte-linux-ptrace.h17
9 files changed, 361 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index bf7f19d..2302c21 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,28 @@
2021-03-24 Luis Machado <luis.machado@linaro.org>
+ * Makefile.in (ALL_64_TARGET_OBS): Add arch/aarch64-mte-linux.o.
+ (HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h and
+ nat/aarch64-mte-linux-ptrace.h.
+ * aarch64-linux-nat.c: Include nat/aarch64-mte-linux-ptrace.h.
+ (aarch64_linux_nat_target) <supports_memory_tagging>: New method
+ override.
+ <fetch_memtags>: New method override.
+ <store_memtags>: New method override.
+ (aarch64_linux_nat_target::supports_memory_tagging): New method.
+ (aarch64_linux_nat_target::fetch_memtags): New method.
+ (aarch64_linux_nat_target::store_memtags): New method.
+ * arch/aarch64-mte-linux.c: New file.
+ * arch/aarch64-mte-linux.h: Include gdbsupport/common-defs.h.
+ (AARCH64_MTE_GRANULE_SIZE): Define.
+ (aarch64_memtag_type): New enum.
+ (aarch64_mte_get_tag_granules): New prototype.
+ * configure.nat (NATDEPFILES): Add nat/aarch64-mte-linux-ptrace.o.
+ * configure.tgt (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o.
+ * nat/aarch64-mte-linux-ptrace.c: New file.
+ * nat/aarch64-mte-linux-ptrace.h: New file.
+
+2021-03-24 Luis Machado <luis.machado@linaro.org>
+
* Makefile.in (HFILES_NO_SRCDIR): Add nat/aarch64-mte-linux-ptrace.h.
* nat/aarch64-mte-linux-ptrace.h: New file.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7943a3c..3318c1a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -699,6 +699,7 @@ ALL_64_TARGET_OBS = \
amd64-windows-tdep.o \
arch/aarch64.o \
arch/aarch64-insn.o \
+ arch/aarch64-mte-linux.o \
arch/amd64.o \
ia64-linux-tdep.o \
ia64-tdep.o \
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index fe3ba44..ae8db29 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -52,6 +52,8 @@
#include "arch/aarch64-mte-linux.h"
+#include "nat/aarch64-mte-linux-ptrace.h"
+
#ifndef TRAP_HWBKPT
#define TRAP_HWBKPT 0x0004
#endif
@@ -102,6 +104,16 @@ public:
override;
struct gdbarch *thread_architecture (ptid_t) override;
+
+ bool supports_memory_tagging () override;
+
+ /* Read memory allocation tags from memory via PTRACE. */
+ bool fetch_memtags (CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags, int type) override;
+
+ /* Write allocation tags to memory via PTRACE. */
+ bool store_memtags (CORE_ADDR address, size_t len,
+ const gdb::byte_vector &tags, int type) override;
};
static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -1054,6 +1066,44 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
return gdbarch_find_by_info (info);
}
+/* Implement the "supports_memory_tagging" target_ops method. */
+
+bool
+aarch64_linux_nat_target::supports_memory_tagging ()
+{
+ return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0;
+}
+
+/* Implement the "fetch_memtags" target_ops method. */
+
+bool
+aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags, int type)
+{
+ int tid = get_ptrace_pid (inferior_ptid);
+
+ /* Allocation tags? */
+ if (type == static_cast<int> (aarch64_memtag_type::mte_allocation))
+ return aarch64_mte_fetch_memtags (tid, address, len, tags);
+
+ return false;
+}
+
+/* Implement the "store_memtags" target_ops method. */
+
+bool
+aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
+ const gdb::byte_vector &tags, int type)
+{
+ int tid = get_ptrace_pid (inferior_ptid);
+
+ /* Allocation tags? */
+ if (type == static_cast<int> (aarch64_memtag_type::mte_allocation))
+ return aarch64_mte_store_memtags (tid, address, len, tags);
+
+ return false;
+}
+
/* Define AArch64 maintenance commands. */
static void
diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
new file mode 100644
index 0000000..3d72b8d
--- /dev/null
+++ b/gdb/arch/aarch64-mte-linux.c
@@ -0,0 +1,38 @@
+/* Common Linux target-dependent functionality for AArch64 MTE
+
+ Copyright (C) 2021 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 "arch/aarch64-mte-linux.h"
+
+/* See arch/aarch64-mte-linux.h */
+
+size_t
+aarch64_mte_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, granule_size);
+
+ /* We always have at least 1 granule. */
+ return 1 + (e_addr - s_addr) / granule_size;
+}
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index 7c259b8..88bd8d0 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -20,6 +20,8 @@
#ifndef ARCH_AARCH64_LINUX_H
#define ARCH_AARCH64_LINUX_H
+#include "gdbsupport/common-defs.h"
+
/* Feature check for Memory Tagging Extension. */
#ifndef HWCAP2_MTE
#define HWCAP2_MTE (1 << 18)
@@ -28,4 +30,21 @@
/* The MTE regset consists of a single 64-bit register. */
#define AARCH64_LINUX_SIZEOF_MTE 8
+/* We have one tag per 16 bytes of memory. */
+#define AARCH64_MTE_GRANULE_SIZE 16
+
+/* Memory tag types for AArch64. */
+enum class aarch64_memtag_type
+{
+ /* MTE logical tag contained in pointers. */
+ mte_logical = 0,
+ /* MTE allocation tag stored in memory tag granules. */
+ mte_allocation
+};
+
+/* Return the number of tag granules in the memory range
+ [ADDR, ADDR + LEN) given GRANULE_SIZE. */
+extern size_t aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
+ size_t granule_size);
+
#endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 2869759..e34cccf 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -236,7 +236,8 @@ case ${gdb_host} in
NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \
aarch32-linux-nat.o nat/aarch64-linux-hw-point.o \
nat/aarch64-linux.o \
- nat/aarch64-sve-linux-ptrace.o"
+ nat/aarch64-sve-linux-ptrace.o \
+ nat/aarch64-mte-linux-ptrace.o"
;;
arc)
# Host: ARC based machine running GNU/Linux
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 9102067..3519e9c 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -125,6 +125,7 @@ aarch64*-*-freebsd*)
aarch64*-*-linux*)
# Target: AArch64 linux
gdb_target_obs="aarch64-linux-tdep.o arch/aarch64.o\
+ arch/aarch64-mte-linux.o \
arch/arm.o arch/arm-linux.o arch/arm-get-next-pcs.o \
arm-tdep.o arm-linux-tdep.o \
glibc-tdep.o linux-tdep.o solib-svr4.o \
diff --git a/gdb/nat/aarch64-mte-linux-ptrace.c b/gdb/nat/aarch64-mte-linux-ptrace.c
new file mode 100644
index 0000000..47f4ab6
--- /dev/null
+++ b/gdb/nat/aarch64-mte-linux-ptrace.c
@@ -0,0 +1,210 @@
+/* Common Linux native ptrace code for AArch64 MTE.
+
+ Copyright (C) 2021 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 "gdbsupport/common-defs.h"
+#include "gdbsupport/byte-vector.h"
+
+#include "arch/aarch64.h"
+#include "arch/aarch64-mte-linux.h"
+#include "nat/aarch64-linux.h"
+#include "nat/aarch64-mte-linux-ptrace.h"
+
+#include "linux-ptrace.h"
+#include <sys/uio.h>
+
+/* Helper function to display various possible errors when reading
+ MTE tags. */
+
+static void ATTRIBUTE_NORETURN
+aarch64_mte_linux_peek_error (int error)
+{
+ switch (error)
+ {
+ case EIO:
+ perror_with_name (_("PEEKMTETAGS not supported"));
+ break;
+ case EFAULT:
+ perror_with_name (_("Couldn't fetch allocation tags"));
+ break;
+ case EOPNOTSUPP:
+ perror_with_name (_("PROT_ME not enabled for requested address"));
+ default:
+ perror_with_name (_("Unknown MTE error"));
+ break;
+ }
+}
+
+/* Helper function to display various possible errors when writing
+ MTE tags. */
+
+static void ATTRIBUTE_NORETURN
+aarch64_mte_linux_poke_error (int error)
+{
+ switch (error)
+ {
+ case EIO:
+ perror_with_name (_("POKEMTETAGS not supported"));
+ break;
+ case EFAULT:
+ perror_with_name (_("Couldn't store allocation tags"));
+ break;
+ case EOPNOTSUPP:
+ perror_with_name (_("PROT_ME not enabled for requested address"));
+ default:
+ perror_with_name (_("Unknown MTE error"));
+ break;
+ }
+}
+
+/* Helper to prepare a vector of tags to be passed on to the kernel. The
+ main purpose of this function is to optimize the number of calls to
+ ptrace if we're writing too many tags at once, like a pattern fill
+ request.
+
+ Return a vector of tags of up to MAX_SIZE size, containing the tags that
+ must be passed on to the kernel, extracted from TAGS, starting at POS.
+ GRANULES is the number of tag granules to be modified. */
+
+static gdb::byte_vector
+prepare_tag_vector (size_t granules, const gdb::byte_vector &tags, size_t pos,
+ size_t max_size)
+{
+ gdb::byte_vector t;
+
+ if (granules == 0)
+ return t;
+
+ gdb_assert (tags.size () > 0 && max_size > 0);
+
+ if (granules > AARCH64_MTE_TAGS_MAX_SIZE)
+ t.resize (AARCH64_MTE_TAGS_MAX_SIZE);
+ else
+ t.resize (granules);
+
+ size_t tag_count = tags.size ();
+
+ for (size_t i = 0; i < t.size (); i++)
+ t[i] = tags[(pos + i) % tag_count];
+
+ return t;
+}
+
+/* See nat/aarch64-mte-linux-ptrace.h */
+
+bool
+aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags)
+{
+ size_t ntags = aarch64_mte_get_tag_granules (address, len,
+ AARCH64_MTE_GRANULE_SIZE);
+
+ /* If the memory range contains no tags, nothing left to do. */
+ if (ntags == 0)
+ return true;
+
+ gdb_byte tagbuf[ntags];
+
+ struct iovec iovec;
+ iovec.iov_base = tagbuf;
+ iovec.iov_len = ntags;
+
+ tags.clear ();
+ bool done_reading = false;
+
+ /* The kernel may return less tags than we requested. Loop until we've read
+ all the requested tags or until we get an error. */
+ while (!done_reading)
+ {
+ /* Attempt to read ntags allocation tags from the kernel. */
+ if (ptrace (PTRACE_PEEKMTETAGS, tid, address, &iovec) < 0)
+ aarch64_mte_linux_peek_error (errno);
+
+ /* Make sure the kernel returned at least one tag. */
+ if (iovec.iov_len <= 0)
+ {
+ tags.clear ();
+ return false;
+ }
+
+ /* Copy the tags the kernel returned. */
+ for (size_t i = 0; i < iovec.iov_len; i++)
+ tags.push_back (tagbuf[i]);
+
+ /* Are we done reading tags? */
+ if (tags.size () == ntags)
+ done_reading = true;
+ else
+ {
+ address += iovec.iov_len * AARCH64_MTE_GRANULE_SIZE;
+ iovec.iov_len = ntags - iovec.iov_len;
+ }
+ }
+ return true;
+}
+
+/* See nat/aarch64-mte-linux-ptrace.h */
+
+bool
+aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
+ const gdb::byte_vector &tags)
+{
+ if (tags.size () == 0)
+ return true;
+
+ /* Get the number of tags we need to write. */
+ size_t ntags = aarch64_mte_get_tag_granules (address, len,
+ AARCH64_MTE_GRANULE_SIZE);
+
+ /* If the memory range contains no tags, nothing left to do. */
+ if (ntags == 0)
+ return true;
+
+ bool done_writing = false;
+ size_t tags_written = 0;
+
+ /* Write all the tags, AARCH64_MTE_TAGS_MAX_SIZE blocks at a time. */
+ while (!done_writing)
+ {
+ gdb::byte_vector t = prepare_tag_vector (ntags - tags_written, tags,
+ tags_written,
+ AARCH64_MTE_TAGS_MAX_SIZE);
+
+ struct iovec iovec;
+ iovec.iov_base = t.data ();
+ iovec.iov_len = t.size ();
+
+ /* Request the kernel to update the allocation tags. */
+ if (ptrace (PTRACE_POKEMTETAGS, tid, address, &iovec) < 0)
+ aarch64_mte_linux_poke_error (errno);
+
+ /* Make sure the kernel wrote at least one tag. */
+ if (iovec.iov_len <= 0)
+ return false;
+
+ tags_written += iovec.iov_len;
+
+ /* Are we done writing tags? */
+ if (tags_written == ntags)
+ done_writing = true;
+ else
+ address += iovec.iov_len * AARCH64_MTE_GRANULE_SIZE;
+ }
+
+ return true;
+}
diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
index 65ac141..f8c203b 100644
--- a/gdb/nat/aarch64-mte-linux-ptrace.h
+++ b/gdb/nat/aarch64-mte-linux-ptrace.h
@@ -30,4 +30,21 @@
#define PTRACE_POKEMTETAGS 34
#endif
+/* Maximum number of tags to pass at once to the kernel. */
+#define AARCH64_MTE_TAGS_MAX_SIZE 4096
+
+/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN)
+ into TAGS.
+
+ Returns true if successful and false otherwise. */
+extern bool aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+ gdb::byte_vector &tags);
+
+/* Write the allocation tags contained in TAGS into the memory range
+ [ADDRESS, ADDRESS + LEN).
+
+ Returns true if successful and false otherwise. */
+extern bool aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
+ const gdb::byte_vector &tags);
+
#endif /* NAT_AARCH64_MTE_LINUX_PTRACE_H */