public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Luis Machado <luis.machado@linaro.org>
To: gdb-patches@sourceware.org
Subject: [PATCH v6 12/25] AArch64: Implement memory tagging target methods for AArch64
Date: Mon, 22 Mar 2021 10:21:06 -0300	[thread overview]
Message-ID: <20210322132120.1202230-13-luis.machado@linaro.org> (raw)
In-Reply-To: <20210322132120.1202230-1-luis.machado@linaro.org>

Updates on v6:

- Handle case of address range that contains no tag granules.
- Fixed formatting issues.
- Fixed copyright years.

Updates on v4:

- Update naming and attributes of the functions.
- Call get_ptrace_pid.
- Misc fixes to formatting.
- Use enum instead of magic integers.

Updates on v2:

- Added type parameter to the target method implementations.

--

The patch implements the memory tagging target hooks for AArch64, so we
can handle MTE.

gdb/ChangeLog:

YYYY-MM-DD  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.
---
 gdb/Makefile.in                    |   1 +
 gdb/aarch64-linux-nat.c            |  50 +++++++
 gdb/arch/aarch64-mte-linux.c       |  38 ++++++
 gdb/arch/aarch64-mte-linux.h       |  19 +++
 gdb/configure.nat                  |   3 +-
 gdb/configure.tgt                  |   1 +
 gdb/nat/aarch64-mte-linux-ptrace.c | 210 +++++++++++++++++++++++++++++
 gdb/nat/aarch64-mte-linux-ptrace.h |  17 +++
 8 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 gdb/arch/aarch64-mte-linux.c
 create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7943a3c0d5a..3318c1a5215 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 fe3ba44c553..ae8db2988c2 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 @@ class aarch64_linux_nat_target final : public linux_nat_target
     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 00000000000..3d72b8db308
--- /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 7c259b8a4a4..88bd8d03cfb 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 286975966da..e34cccffd98 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 91020678bf0..3519e9c2f3b 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 00000000000..47f4ab68d1b
--- /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 65ac1415e55..f8c203bc05e 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 */
-- 
2.25.1


  parent reply	other threads:[~2021-03-22 13:21 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-22 13:20 [PATCH v6 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
2021-03-22 13:20 ` [PATCH v6 01/25] New target methods for memory tagging support Luis Machado
2021-03-23 21:22   ` Simon Marchi
2021-03-22 13:20 ` [PATCH v6 02/25] New gdbarch memory tagging hooks Luis Machado
2021-03-22 13:20 ` [PATCH v6 03/25] Add GDB-side remote target support for memory tagging Luis Machado
2021-03-22 13:20 ` [PATCH v6 04/25] Unit testing for GDB-side remote memory tagging handling Luis Machado
2021-03-22 13:20 ` [PATCH v6 05/25] GDBserver remote packet support for memory tagging Luis Machado
2021-03-22 13:21 ` [PATCH v6 06/25] Unit tests for gdbserver memory tagging remote packets Luis Machado
2021-03-22 13:21 ` [PATCH v6 07/25] Documentation for " Luis Machado
2021-03-22 17:47   ` Eli Zaretskii
2021-03-22 13:21 ` [PATCH v6 08/25] AArch64: Add MTE CPU feature check support Luis Machado
2021-03-22 13:21 ` [PATCH v6 09/25] AArch64: Add target description/feature for MTE registers Luis Machado
2021-03-22 13:21 ` [PATCH v6 10/25] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
2021-03-22 13:21 ` [PATCH v6 11/25] AArch64: Add MTE ptrace requests Luis Machado
2021-03-22 13:21 ` Luis Machado [this message]
2021-03-22 13:21 ` [PATCH v6 13/25] Convert char array to std::string in linux_find_memory_regions_full Luis Machado
2021-03-22 13:21 ` [PATCH v6 14/25] Refactor parsing of /proc/<pid>/smaps Luis Machado
2021-03-23 21:28   ` Simon Marchi
2021-03-22 13:21 ` [PATCH v6 15/25] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
2021-03-23 21:32   ` Simon Marchi
2021-03-22 13:21 ` [PATCH v6 16/25] AArch64: Add unit testing for logical tag set/get operations Luis Machado
2022-01-31 14:34   ` Simon Marchi
2021-03-22 13:21 ` [PATCH v6 17/25] AArch64: Report tag violation error information Luis Machado
2021-03-22 13:21 ` [PATCH v6 18/25] AArch64: Add gdbserver MTE support Luis Machado
2021-03-22 13:21 ` [PATCH v6 19/25] AArch64: Add MTE register set support for core files Luis Machado
2021-03-22 13:21 ` [PATCH v6 20/25] New memory-tag commands Luis Machado
2021-03-22 13:21 ` [PATCH v6 21/25] Documentation for the new mtag commands Luis Machado
2021-03-22 17:49   ` Eli Zaretskii
2021-03-22 13:21 ` [PATCH v6 22/25] Extend "x" and "print" commands to support memory tagging Luis Machado
2021-03-22 13:21 ` [PATCH v6 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
2021-03-22 17:51   ` Eli Zaretskii
2021-03-22 13:21 ` [PATCH v6 24/25] Add NEWS entry Luis Machado
2021-03-22 17:51   ` Eli Zaretskii
2021-03-22 17:52     ` Luis Machado
2021-03-22 13:21 ` [PATCH v6 25/25] Add memory tagging testcases Luis Machado
2021-03-23 22:50 ` [PATCH v6 00/25] Memory Tagging Support + AArch64 Linux implementation Simon Marchi
2021-03-24 18:18   ` 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=20210322132120.1202230-13-luis.machado@linaro.org \
    --to=luis.machado@linaro.org \
    --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).