public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
@ 2020-11-09 17:04 Luis Machado
  2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
                   ` (24 more replies)
  0 siblings, 25 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Here's v3 of this patch series.

Memory tagging improves memory safety by tagging various parts of memory and
raising exceptions when the allocation tag (the one associated with a range of
memory addresses) does not match the logical tag contained in a pointer that is
used to access the memory area.

We already have an implementation of such a mechanism for sparc64 (ADI), but
it is target-specific and not exposed to the rest of GDB. This series aims to
make the infrastructure available to other targets that may wish to support
their specific memory tagging approaches. For AArch64 Linux this is called
MTE (Memory Tagging Extensions).

The series is split into a set that deals with generic changes to GDB's
infrastructure (target methods, gdbarch hooks and remote packets), a set that
implements support for AArch64 Linux and one last set that implements new
commands, updates the documentation and adds tests.

The goal is to make it so the architecture independent parts of GDB don't
need to interpret tag formats, given the formats are likely different
for each architecture.  For this reason, GDB will handle tags as a sequence of
bytes and will not assume a particular format.

The architecture-specific code can handle the sequence of bytes appropriately.

Luis Machado (24):
  New target methods for memory tagging support
  New gdbarch memory tagging hooks
  Add GDB-side remote target support for memory tagging
  Unit testing for GDB-side remote memory tagging handling
  GDBserver remote packet support for memory tagging
  Unit tests for gdbserver memory tagging remote packets
  Documentation for memory tagging remote packets
  AArch64: Add MTE CPU feature check support
  AArch64: Add target description/feature for MTE registers
  AArch64: Add MTE register set support for GDB and gdbserver
  AArch64: Add MTE ptrace requests
  AArch64: Implement memory tagging target methods for AArch64
  Refactor parsing of /proc/<pid>/smaps
  AArch64: Implement the memory tagging gdbarch hooks
  AArch64: Add unit testing for logical tag set/get operations
  AArch64: Report tag violation error information
  AArch64: Add gdbserver MTE support
  AArch64: Add MTE register set support for core files
  New mtag commands
  Documentation for the new mtag commands
  Extend "x" and "print" commands to support memory tagging
  Document new "x" and "print" memory tagging extensions
  Add NEWS entry.
  Add memory tagging testcases

 gdb/Makefile.in                        |   3 +
 gdb/NEWS                               |  32 ++
 gdb/aarch64-linux-nat.c                | 129 ++++++-
 gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
 gdb/aarch64-linux-tdep.h               |   3 +
 gdb/aarch64-tdep.c                     |  40 ++-
 gdb/aarch64-tdep.h                     |  12 +-
 gdb/arch-utils.c                       |  50 +++
 gdb/arch-utils.h                       |  23 ++
 gdb/arch/aarch64-mte-linux.c           |  70 ++++
 gdb/arch/aarch64-mte-linux.h           |  66 ++++
 gdb/arch/aarch64.c                     |   7 +-
 gdb/arch/aarch64.h                     |   7 +-
 gdb/configure.nat                      |   3 +-
 gdb/configure.tgt                      |   1 +
 gdb/doc/gdb.texinfo                    | 215 +++++++++++-
 gdb/features/Makefile                  |   1 +
 gdb/features/aarch64-mte.c             |  14 +
 gdb/features/aarch64-mte.xml           |  11 +
 gdb/gdbarch.c                          | 137 ++++++++
 gdb/gdbarch.h                          |  53 +++
 gdb/gdbarch.sh                         |  36 ++
 gdb/linux-tdep.c                       | 358 ++++++++++++-------
 gdb/linux-tdep.h                       |   4 +
 gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
 gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
 gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
 gdb/remote.c                           | 232 ++++++++++++
 gdb/target-delegates.c                 |  84 +++++
 gdb/target.h                           |  37 ++
 gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
 gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
 gdb/testsuite/gdb.base/memtag.c        |  22 ++
 gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
 gdb/testsuite/lib/gdb.exp              |  16 +
 gdb/valprint.h                         |   1 +
 gdbserver/Makefile.in                  |   1 +
 gdbserver/configure.srv                |   2 +
 gdbserver/linux-aarch64-ipa.cc         |   8 +-
 gdbserver/linux-aarch64-low.cc         |  97 ++++-
 gdbserver/linux-aarch64-tdesc.cc       |  10 +-
 gdbserver/linux-aarch64-tdesc.h        |   3 +-
 gdbserver/remote-utils.cc              |  43 ++-
 gdbserver/remote-utils.h               |   7 +-
 gdbserver/server.cc                    | 245 +++++++++++++
 gdbserver/server.h                     |   3 +
 gdbserver/target.cc                    |  20 ++
 gdbserver/target.h                     |  17 +
 gdbsupport/rsp-low.cc                  |   2 +-
 include/elf/common.h                   |   3 +
 50 files changed, 3536 insertions(+), 186 deletions(-)
 create mode 100644 gdb/arch/aarch64-mte-linux.c
 create mode 100644 gdb/arch/aarch64-mte-linux.h
 create mode 100644 gdb/features/aarch64-mte.c
 create mode 100644 gdb/features/aarch64-mte.xml
 create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
 create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
 create mode 100644 gdb/testsuite/gdb.base/memtag.c
 create mode 100644 gdb/testsuite/gdb.base/memtag.exp

-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 01/24] New target methods for memory tagging support
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25  4:26   ` Simon Marchi
  2020-12-25  5:08   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 02/24] New gdbarch memory tagging hooks Luis Machado
                   ` (23 subsequent siblings)
  24 siblings, 2 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v3:

- Updated the code documentation for the fetch_memtags and store_memtags
  methods.

Updates on v2:

- Added type parameter to fetch_memtags/store_memtags hooks.

--

This patch starts adding some of the generic pieces to accomodate memory
tagging.

We have three new target methods:

- supports_memory_tagging: Checks if the target supports memory tagging. This
  defaults to false for targets that don't support memory tagging.

- fetch_memtags: Fetches the allocation tags associated with a particular
  memory range [address, address + length).

  The default is to return 0 without returning any tags. This should only
  be called if memory tagging is supported.

- store_memtags: Stores a set of allocation tags for a particular memory
  range [address, address + length).

  The default is to return 0. This should only
  be called if memory tagging is supported.

It also adds a control option for enabling/disabling memory tagging
manually: set memory-tagging on/off.

The default is "on", with GDB making its use conditional to the
architecture supporting memory tagging.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* printcmd.c (memtag): New static global.
	(show_memtag): New function.
	(_initialize_printcmd): Add set/show memory-tagging command.
	* remote.c (remote_target) <supports_memory_tagging>: New method
	override.
	<fetch_memtags>: New method override.
	<store_memtags>: New method override.
	(remote_target::supports_memory_tagging): New method.
	(remote_target::fetch_memtags): New method.
	(remote_target::store_memtags): New method.
	* target-delegates.c
	(dummy_target) <supports_memory_tagging>: New method override.
	<fetch_memtags>: New method override.
	<store_memtags>: New method override.
	(debug_target) <supports_memory_tagging>: New method override.
	<fetch_memtags>: New method override.
	<store_memtags>: New method override.
	(target_ops::supports_memory_tagging): New method.
	(target_ops::fetch_memtags): New method.
	(target_ops::store_memtags): New method.
	(dummy_target::supports_memory_tagging): New method.
	(dummy_target::fetch_memtags): New method.
	(dummy_target::store_memtags): New method.
	(debug_target::supports_memory_tagging): New method.
	(debug_target::fetch_memtags): New method.
	(debug_target::store_memtags): New method.
	* target.h (struct target_ops) <supports_memory_tagging>: New virtual
	method.
	<fetch_memtags>: New virtual method.
	<store_memtags>: New virtual method.
	(target_supports_memory_tagging): Define.
	(target_fetch_memtags): Define.
	(target_store_memtags): Define.
---
 gdb/printcmd.c         | 28 ++++++++++++++
 gdb/remote.c           | 36 ++++++++++++++++++
 gdb/target-delegates.c | 84 ++++++++++++++++++++++++++++++++++++++++++
 gdb/target.h           | 37 +++++++++++++++++++
 4 files changed, 185 insertions(+)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f7186c296a..28451612ab 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -84,6 +84,24 @@ static CORE_ADDR last_examine_address;
 
 static value_ref_ptr last_examine_value;
 
+/* If TRUE (default), and the architecture supports it, GDB will attempt to use
+   the memory tagging infrastructure to validate certain memory accesses.  It
+   will also report memory tag violations alongside a SIGSEGV signal.
+
+   If FALSE, GDB will not use memory tagging in any way, and debugging will work
+   in the standard way.  */
+static bool memtag = true;
+
+static void
+show_memtag (struct ui_file *file, int from_tty,
+	     struct cmd_list_element *c,
+	     const char *value)
+{
+  fprintf_filtered (file,
+		    _("Use of memory tagging infrastructure is \"%s\".\n"),
+		    value);
+}
+
 /* Largest offset between a symbolic value and an address, that will be
    printed as `0x1234 <symbol+offset>'.  */
 
@@ -2893,4 +2911,14 @@ Construct a GDB command and then evaluate it.\n\
 Usage: eval \"format string\", ARG1, ARG2, ARG3, ..., ARGN\n\
 Convert the arguments to a string as \"printf\" would, but then\n\
 treat this string as a command line, and evaluate it."));
+
+  add_setshow_boolean_cmd ("memory-tagging", class_support,
+			   &memtag, _("\
+Set whether the debugger should use memory tagging infrastructure."), _("\
+Show whether the debugger should use memory tagging infrastructure."), _("\
+If on, gdb will attempt to validate memory tags and will warn the user if\n\
+certain operations have illegal tags."),
+			    NULL,
+			    show_memtag,
+			    &setlist, &showlist);
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index 71f814efb3..2686de3501 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -686,6 +686,16 @@ class remote_target : public process_stratum_target
   int remove_exec_catchpoint (int) override;
   enum exec_direction_kind execution_direction () override;
 
+  bool supports_memory_tagging () override;
+
+  /* Read memory tags via the qMemTags packet  */
+  int fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+
+  /* Write allocation tags via the QMemTags packet.  */
+  int store_memtags (CORE_ADDR address, size_t len,
+		     const gdb::byte_vector &tags, int type) override;
+
 public: /* Remote specific methods.  */
 
   void remote_download_command_source (int num, ULONGEST addr,
@@ -14389,6 +14399,32 @@ set_range_stepping (const char *ignore_args, int from_tty,
     }
 }
 
+/* Implement the "supports_memory_tagging" target_ops method.  */
+
+bool
+remote_target::supports_memory_tagging ()
+{
+  return false;
+}
+
+/* Implement the "fetch_memtags" target_ops method.  */
+
+int
+remote_target::fetch_memtags (CORE_ADDR address, size_t len,
+			      gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
+/* Implement the "store_memtags" target_ops method.  */
+
+int
+remote_target::store_memtags (CORE_ADDR address, size_t len,
+			      const gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
 void _initialize_remote ();
 void
 _initialize_remote ()
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 437b19b858..fbebc8b4ce 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -173,6 +173,11 @@ struct dummy_target : public target_ops
   const struct frame_unwind *get_tailcall_unwinder () override;
   void prepare_to_generate_core () override;
   void done_generating_core () override;
+  bool supports_memory_tagging () override;
+  int fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+  int store_memtags (CORE_ADDR address, size_t len,
+		     const gdb::byte_vector &tags, int type) override;
 };
 
 struct debug_target : public target_ops
@@ -344,6 +349,11 @@ struct debug_target : public target_ops
   const struct frame_unwind *get_tailcall_unwinder () override;
   void prepare_to_generate_core () override;
   void done_generating_core () override;
+  bool supports_memory_tagging () override;
+  int fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+  int store_memtags (CORE_ADDR address, size_t len,
+		     const gdb::byte_vector &tags, int type) override;
 };
 
 void
@@ -4413,3 +4423,77 @@ debug_target::done_generating_core ()
   fputs_unfiltered (")\n", gdb_stdlog);
 }
 
+bool
+target_ops::supports_memory_tagging ()
+{
+  return this->beneath ()->supports_memory_tagging ();
+}
+
+int
+target_ops::fetch_memtags (CORE_ADDR address, size_t len,
+			   gdb::byte_vector &tags, int type)
+{
+  return this->beneath ()->fetch_memtags (address, len, tags, type);
+}
+
+int
+target_ops::store_memtags (CORE_ADDR address, size_t len,
+			   const gdb::byte_vector &tags, int type)
+{
+  return this->beneath ()->store_memtags (address, len, tags, type);
+}
+
+bool
+dummy_target::supports_memory_tagging ()
+{
+  return false;
+}
+
+int
+dummy_target::fetch_memtags (CORE_ADDR address, size_t len,
+			     gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
+int
+dummy_target::store_memtags (CORE_ADDR address, size_t len,
+			     const gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
+bool
+debug_target::supports_memory_tagging ()
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->supports_memory_tagging (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->supports_memory_tagging ();
+  fprintf_unfiltered (gdb_stdlog, "<- %s->supports_memory_tagging (", this->beneath ()->shortname ());
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
+int
+debug_target::fetch_memtags (CORE_ADDR address, size_t len,
+			     gdb::byte_vector &tags, int type)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->fetch_memtags (...)\n", this->beneath ()->shortname ());
+  int result = this->beneath ()->fetch_memtags (address, len, tags, type);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->fetch_memtags (", this->beneath ()->shortname ());
+  fputs_unfiltered (")\n", gdb_stdlog);
+  return result;
+}
+
+int
+debug_target::store_memtags (CORE_ADDR address, size_t len,
+			     const gdb::byte_vector &tags, int type)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->store_memtags (...)\n", this->beneath ()->shortname ());
+  int result = this->beneath ()->store_memtags (address, len, tags, type);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->store_memtags (", this->beneath ()->shortname ());
+  fputs_unfiltered (")\n", gdb_stdlog);
+  return result;
+}
diff --git a/gdb/target.h b/gdb/target.h
index 416b8089fa..3bc958a406 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1260,6 +1260,34 @@ struct target_ops
     /* Cleanup after generating a core file.  */
     virtual void done_generating_core ()
       TARGET_DEFAULT_IGNORE ();
+
+    /* Returns true if the target supports memory tagging.  */
+    virtual bool supports_memory_tagging ()
+      TARGET_DEFAULT_RETURN (false);
+
+    /* Return the allocated memory tags of type TYPE associated with
+       [ADDRESS, ADDRESS + LEN) in TAGS.
+
+       LEN is the number of bytes in the memory range.  TAGS is a vector of
+       bytes containing the tags found in the above memory range.
+
+       It is up to the architecture/target to interpret the bytes in the TAGS
+       vector and read the tags appropriately.  */
+    virtual int fetch_memtags (CORE_ADDR address, size_t len,
+			       gdb::byte_vector &tags, int type)
+      TARGET_DEFAULT_IGNORE ();
+
+    /* Write the allocation tags of type TYPE contained in TAGS to the memory
+       range [ADDRESS, ADDRESS + LEN).
+
+       LEN is the number of bytes in the memory range.  TAGS is a vector of
+       bytes containing the tags to be stored to the memory range.
+
+       It is up to the architecture/target to interpret the bytes in the TAGS
+       vector and store them appropriately.  */
+    virtual int store_memtags (CORE_ADDR address, size_t len,
+			       const gdb::byte_vector &tags, int type)
+      TARGET_DEFAULT_IGNORE ();
   };
 
 /* Deleter for std::unique_ptr.  See comments in
@@ -2312,6 +2340,15 @@ extern gdb::unique_xmalloc_ptr<char> target_fileio_read_stralloc
 #define target_augmented_libraries_svr4_read() \
   (current_top_target ()->augmented_libraries_svr4_read) ()
 
+#define target_supports_memory_tagging() \
+  ((current_top_target ()->supports_memory_tagging) ())
+
+#define target_fetch_memtags(address, len, tags, type) \
+  (current_top_target ()->fetch_memtags) ((address), (len), (tags), (type))
+
+#define target_store_memtags(address, len, tags, type) \
+  (current_top_target ()->store_memtags) ((address), (len), (tags), (type))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)					\
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 02/24] New gdbarch memory tagging hooks
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25  4:40   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 03/24] Add GDB-side remote target support for memory tagging Luis Machado
                   ` (22 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

We need some new gdbarch hooks to help us manipulate memory tags without having
to have GDB calls the target methods directly.

This patch adds the following hooks:

gdbarch_memtag_to_string
--
Returns a printable string corresponding to the tag.

gdbarch_tagged_address_p
--
Checks if a particular address is protected with memory tagging.

gdbarch_memtag_mismatch_p
--
Checks if there is a mismatch between the logical tag of a pointer and the
allocation tag.

gdbarch_set_memtags:
--
Sets either the allocation tag or the logical tag for a particular value.

gdbarch_get_memtag:
--
Gets either the allocation tag or the logical tag for a particular value.

gdbarch_granule_size
--
Sets the memory tag granule size, which represents the number of bytes a
particular allocation tag covers. For example, this is 16 bytes for
AArch64's MTE.

I've used struct value as opposed to straight CORE_ADDR so other architectures
can use the infrastructure without having to rely on fixed types.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* arch-utils.c (default_memtag_to_string, +default_tagged_address_p)
	(default_memtag_mismatch_p, default_set_memtags)
	(default_get_memtag): New functions.
	* arch-utils.h (default_memtag_to_string, default_tagged_address_p)
	(default_memtag_mismatch_p, default_set_memtags)
	(default_get_memtag): New prototypes.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
	* gdbarch.sh (memtag_to_string, tagged_address_p, memtag_mismatch_p)
	(set_memtags, get_memtag, memtag_granule_size): New gdbarch hooks.
	(enum memtag_type): New enum.
---
 gdb/arch-utils.c |  50 +++++++++++++++++
 gdb/arch-utils.h |  23 ++++++++
 gdb/gdbarch.c    | 137 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/gdbarch.h    |  53 ++++++++++++++++++
 gdb/gdbarch.sh   |  36 +++++++++++++
 5 files changed, 299 insertions(+)

diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index e50df82091..10064759b2 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -77,6 +77,56 @@ legacy_register_sim_regno (struct gdbarch *gdbarch, int regnum)
     return LEGACY_SIM_REGNO_IGNORE;
 }
 
+
+/* See arch-utils.h */
+
+std::string
+default_memtag_to_string (struct gdbarch *gdbarch, struct value *address,
+			  enum memtag_type tag_type)
+{
+  /* By default, assume the address is untagged.  */
+  return "";
+}
+
+/* See arch-utils.h */
+
+bool
+default_tagged_address_p (struct gdbarch *gdbarch, struct value *address)
+{
+  /* By default, assume the address is untagged.  */
+  return false;
+}
+
+/* See arch-utils.h */
+
+bool
+default_memtag_mismatch_p (struct gdbarch *gdbarch, struct value *address)
+{
+  /* By default, assume there is no mismatch.  */
+  return false;
+}
+
+/* See arch-utils.h */
+
+int
+default_set_memtags (struct gdbarch *gdbarch, struct value *address,
+		     size_t length, const gdb::byte_vector &tags,
+		     enum memtag_type tag_type)
+{
+  /* By default, return 0;  */
+  return 0;
+}
+
+/* See arch-utils.h */
+
+struct value *
+default_get_memtag (struct gdbarch *gdbarch, struct value *address,
+		    enum memtag_type tag_type)
+{
+  /* By default, return no tag.  */
+  return NULL;
+}
+
 CORE_ADDR
 generic_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 7eea838ac3..375432e9d5 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -132,6 +132,29 @@ extern const struct floatformat **
   default_floatformat_for_type (struct gdbarch *gdbarch,
 				const char *name, int len);
 
+/* Default implementation of gdbarch_tagged_address_p.  */
+extern std::string default_memtag_to_string (struct gdbarch *gdbarch,
+					     struct value *address,
+					     enum memtag_type tag_type);
+
+/* Default implementation of gdbarch_tagged_address_p.  */
+bool default_tagged_address_p (struct gdbarch *gdbarch, struct value *address);
+
+/* Default implementation of gdbarch_memtag_mismatch_p.  */
+extern bool default_memtag_mismatch_p (struct gdbarch *gdbarch,
+				       struct value *address);
+
+/* Default implementation of gdbarch_set_memtags.  */
+int default_set_memtags (struct gdbarch *gdbarch,
+			 struct value *address, size_t length,
+			 const gdb::byte_vector &tags,
+			 enum memtag_type tag_type);
+
+/* Default implementation of gdbarch_get_memtag.  */
+struct value *default_get_memtag (struct gdbarch *gdbarch,
+				  struct value *address,
+				  enum memtag_type tag_type);
+
 extern CORE_ADDR generic_skip_trampoline_code (struct frame_info *frame,
 					       CORE_ADDR pc);
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 0b43ae434e..2f1d835428 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -253,6 +253,12 @@ struct gdbarch
   gdbarch_convert_from_func_ptr_addr_ftype *convert_from_func_ptr_addr;
   gdbarch_addr_bits_remove_ftype *addr_bits_remove;
   int significant_addr_bit;
+  gdbarch_memtag_to_string_ftype *memtag_to_string;
+  gdbarch_tagged_address_p_ftype *tagged_address_p;
+  gdbarch_memtag_mismatch_p_ftype *memtag_mismatch_p;
+  gdbarch_set_memtags_ftype *set_memtags;
+  gdbarch_get_memtag_ftype *get_memtag;
+  CORE_ADDR memtag_granule_size;
   gdbarch_software_single_step_ftype *software_single_step;
   gdbarch_single_step_through_delay_ftype *single_step_through_delay;
   gdbarch_print_insn_ftype *print_insn;
@@ -430,6 +436,11 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr;
   gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity;
   gdbarch->addr_bits_remove = core_addr_identity;
+  gdbarch->memtag_to_string = default_memtag_to_string;
+  gdbarch->tagged_address_p = default_tagged_address_p;
+  gdbarch->memtag_mismatch_p = default_memtag_mismatch_p;
+  gdbarch->set_memtags = default_set_memtags;
+  gdbarch->get_memtag = default_get_memtag;
   gdbarch->print_insn = default_print_insn;
   gdbarch->skip_trampoline_code = generic_skip_trampoline_code;
   gdbarch->skip_solib_resolver = generic_skip_solib_resolver;
@@ -623,6 +634,12 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of convert_from_func_ptr_addr, invalid_p == 0 */
   /* Skip verify of addr_bits_remove, invalid_p == 0 */
   /* Skip verify of significant_addr_bit, invalid_p == 0 */
+  /* Skip verify of memtag_to_string, invalid_p == 0 */
+  /* Skip verify of tagged_address_p, invalid_p == 0 */
+  /* Skip verify of memtag_mismatch_p, invalid_p == 0 */
+  /* Skip verify of set_memtags, invalid_p == 0 */
+  /* Skip verify of get_memtag, invalid_p == 0 */
+  /* Skip verify of memtag_granule_size, invalid_p == 0 */
   /* Skip verify of software_single_step, has predicate.  */
   /* Skip verify of single_step_through_delay, has predicate.  */
   /* Skip verify of print_insn, invalid_p == 0 */
@@ -1068,6 +1085,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: get_longjmp_target = <%s>\n",
                       host_address_to_string (gdbarch->get_longjmp_target));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: get_memtag = <%s>\n",
+                      host_address_to_string (gdbarch->get_memtag));
   fprintf_unfiltered (file,
                       "gdbarch_dump: get_pc_address_flags = <%s>\n",
                       host_address_to_string (gdbarch->get_pc_address_flags));
@@ -1197,6 +1217,15 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: memory_remove_breakpoint = <%s>\n",
                       host_address_to_string (gdbarch->memory_remove_breakpoint));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: memtag_granule_size = %s\n",
+                      core_addr_to_string_nz (gdbarch->memtag_granule_size));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: memtag_mismatch_p = <%s>\n",
+                      host_address_to_string (gdbarch->memtag_mismatch_p));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: memtag_to_string = <%s>\n",
+                      host_address_to_string (gdbarch->memtag_to_string));
   fprintf_unfiltered (file,
                       "gdbarch_dump: num_pseudo_regs = %s\n",
                       plongest (gdbarch->num_pseudo_regs));
@@ -1350,6 +1379,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: sdb_reg_to_regnum = <%s>\n",
                       host_address_to_string (gdbarch->sdb_reg_to_regnum));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: set_memtags = <%s>\n",
+                      host_address_to_string (gdbarch->set_memtags));
   fprintf_unfiltered (file,
                       "gdbarch_dump: short_bit = %s\n",
                       plongest (gdbarch->short_bit));
@@ -1458,6 +1490,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: syscalls_info = %s\n",
                       host_address_to_string (gdbarch->syscalls_info));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: tagged_address_p = <%s>\n",
+                      host_address_to_string (gdbarch->tagged_address_p));
   fprintf_unfiltered (file,
                       "gdbarch_dump: target_desc = %s\n",
                       host_address_to_string (gdbarch->target_desc));
@@ -3263,6 +3298,108 @@ set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch,
   gdbarch->significant_addr_bit = significant_addr_bit;
 }
 
+std::string
+gdbarch_memtag_to_string (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->memtag_to_string != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_to_string called\n");
+  return gdbarch->memtag_to_string (gdbarch, address, tag_type);
+}
+
+void
+set_gdbarch_memtag_to_string (struct gdbarch *gdbarch,
+                              gdbarch_memtag_to_string_ftype memtag_to_string)
+{
+  gdbarch->memtag_to_string = memtag_to_string;
+}
+
+bool
+gdbarch_tagged_address_p (struct gdbarch *gdbarch, struct value *address)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->tagged_address_p != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_tagged_address_p called\n");
+  return gdbarch->tagged_address_p (gdbarch, address);
+}
+
+void
+set_gdbarch_tagged_address_p (struct gdbarch *gdbarch,
+                              gdbarch_tagged_address_p_ftype tagged_address_p)
+{
+  gdbarch->tagged_address_p = tagged_address_p;
+}
+
+bool
+gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, struct value *address)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->memtag_mismatch_p != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_mismatch_p called\n");
+  return gdbarch->memtag_mismatch_p (gdbarch, address);
+}
+
+void
+set_gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch,
+                               gdbarch_memtag_mismatch_p_ftype memtag_mismatch_p)
+{
+  gdbarch->memtag_mismatch_p = memtag_mismatch_p;
+}
+
+int
+gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->set_memtags != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_set_memtags called\n");
+  return gdbarch->set_memtags (gdbarch, address, length, tags, tag_type);
+}
+
+void
+set_gdbarch_set_memtags (struct gdbarch *gdbarch,
+                         gdbarch_set_memtags_ftype set_memtags)
+{
+  gdbarch->set_memtags = set_memtags;
+}
+
+struct value *
+gdbarch_get_memtag (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->get_memtag != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_get_memtag called\n");
+  return gdbarch->get_memtag (gdbarch, address, tag_type);
+}
+
+void
+set_gdbarch_get_memtag (struct gdbarch *gdbarch,
+                        gdbarch_get_memtag_ftype get_memtag)
+{
+  gdbarch->get_memtag = get_memtag;
+}
+
+CORE_ADDR
+gdbarch_memtag_granule_size (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  /* Skip verify of memtag_granule_size, invalid_p == 0 */
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_granule_size called\n");
+  return gdbarch->memtag_granule_size;
+}
+
+void
+set_gdbarch_memtag_granule_size (struct gdbarch *gdbarch,
+                                 CORE_ADDR memtag_granule_size)
+{
+  gdbarch->memtag_granule_size = memtag_granule_size;
+}
+
 bool
 gdbarch_software_single_step_p (struct gdbarch *gdbarch)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index b620bb25b9..48228b5169 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -115,6 +115,18 @@ enum function_call_return_method
   return_method_struct,
 };
 
+enum memtag_type
+{
+  /* Logical tag, the tag that is stored in unused bits of a pointer to a
+     virtual address.  */
+  tag_logical = 0,
+
+  /* Allocation tag, the tag that is associated with every granule of memory in
+     the physical address space.  Allocation tags are used to validate memory
+     accesses via pointers containing logical tags.  */
+  tag_allocation,
+};
+
 
 
 /* The following are pre-initialized by GDBARCH.  */
@@ -710,6 +722,47 @@ extern void set_gdbarch_addr_bits_remove (struct gdbarch *gdbarch, gdbarch_addr_
 extern int gdbarch_significant_addr_bit (struct gdbarch *gdbarch);
 extern void set_gdbarch_significant_addr_bit (struct gdbarch *gdbarch, int significant_addr_bit);
 
+/* Return a string representation of the memory tag TYPE of ADDRESS.
+   If no tag is associated with such an address, return the empty string. */
+
+typedef std::string (gdbarch_memtag_to_string_ftype) (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type);
+extern std::string gdbarch_memtag_to_string (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type);
+extern void set_gdbarch_memtag_to_string (struct gdbarch *gdbarch, gdbarch_memtag_to_string_ftype *memtag_to_string);
+
+/* Return true if ADDRESS contains a tag and false otherwise. */
+
+typedef bool (gdbarch_tagged_address_p_ftype) (struct gdbarch *gdbarch, struct value *address);
+extern bool gdbarch_tagged_address_p (struct gdbarch *gdbarch, struct value *address);
+extern void set_gdbarch_tagged_address_p (struct gdbarch *gdbarch, gdbarch_tagged_address_p_ftype *tagged_address_p);
+
+/* Return true if the tag from ADDRESS does not match the memory tag for that
+   particular address.  Return false otherwise. */
+
+typedef bool (gdbarch_memtag_mismatch_p_ftype) (struct gdbarch *gdbarch, struct value *address);
+extern bool gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, struct value *address);
+extern void set_gdbarch_memtag_mismatch_p (struct gdbarch *gdbarch, gdbarch_memtag_mismatch_p_ftype *memtag_mismatch_p);
+
+/* Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS
+   Return 0 if successful and non-zero otherwise. */
+
+typedef int (gdbarch_set_memtags_ftype) (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type);
+extern int gdbarch_set_memtags (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type);
+extern void set_gdbarch_set_memtags (struct gdbarch *gdbarch, gdbarch_set_memtags_ftype *set_memtags);
+
+/* Return the tag portion of ADDRESS, assuming ADDRESS is tagged. */
+
+typedef struct value * (gdbarch_get_memtag_ftype) (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type);
+extern struct value * gdbarch_get_memtag (struct gdbarch *gdbarch, struct value *address, enum memtag_type tag_type);
+extern void set_gdbarch_get_memtag (struct gdbarch *gdbarch, gdbarch_get_memtag_ftype *get_memtag);
+
+/* memtag_granule_size is the size of the allocation tag granule, for
+   architectures that support memory tagging.
+   This is 0 for architectures that do not support memory tagging.
+   For a non-zero value, this represents the number of bytes of memory per tag. */
+
+extern CORE_ADDR gdbarch_memtag_granule_size (struct gdbarch *gdbarch);
+extern void set_gdbarch_memtag_granule_size (struct gdbarch *gdbarch, CORE_ADDR memtag_granule_size);
+
 /* FIXME/cagney/2001-01-18: This should be split in two.  A target method that
    indicates if the target needs software single step.  An ISA method to
    implement it.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index d27318a757..1fd3b0b4da 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -605,6 +605,30 @@ m;CORE_ADDR;addr_bits_remove;CORE_ADDR addr;addr;;core_addr_identity;;0
 # additional data associated with the address.
 v;int;significant_addr_bit;;;;;;0
 
+# Return a string representation of the memory tag TYPE of ADDRESS.
+# If no tag is associated with such an address, return the empty string.
++m;std::string;memtag_to_string;struct value *address, enum memtag_type tag_type;address, tag_type;;default_memtag_to_string;;0
+
+# Return true if ADDRESS contains a tag and false otherwise.
++m;bool;tagged_address_p;struct value *address;address;;default_tagged_address_p;;0
+
+# Return true if the tag from ADDRESS does not match the memory tag for that
+# particular address.  Return false otherwise.
++m;bool;memtag_mismatch_p;struct value *address;address;;default_memtag_mismatch_p;;0
+
+# Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS
+# Return 0 if successful and non-zero otherwise.
++m;int;set_memtags;struct value *address, size_t length, const gdb::byte_vector \&tags, enum memtag_type tag_type;address, length, tags, tag_type;;default_set_memtags;;0
+
+# Return the tag portion of ADDRESS, assuming ADDRESS is tagged.
++m;struct value *;get_memtag;struct value *address, enum memtag_type tag_type;address, tag_type;;default_get_memtag;;0
+
+# memtag_granule_size is the size of the allocation tag granule, for
+# architectures that support memory tagging.
+# This is 0 for architectures that do not support memory tagging.
+# For a non-zero value, this represents the number of bytes of memory per tag.
+v;CORE_ADDR;memtag_granule_size;;;;;;0
+
 # FIXME/cagney/2001-01-18: This should be split in two.  A target method that
 # indicates if the target needs software single step.  An ISA method to
 # implement it.
@@ -1354,6 +1378,18 @@ enum function_call_return_method
   return_method_struct,
 };
 
+enum memtag_type
+{
+  /* Logical tag, the tag that is stored in unused bits of a pointer to a
+     virtual address.  */
+  tag_logical = 0,
+
+  /* Allocation tag, the tag that is associated with every granule of memory in
+     the physical address space.  Allocation tags are used to validate memory
+     accesses via pointers containing logical tags.  */
+  tag_allocation,
+};
+
 EOF
 
 # function typedef's
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 03/24] Add GDB-side remote target support for memory tagging
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
  2020-11-09 17:04 ` [PATCH v3 02/24] New gdbarch memory tagging hooks Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25  5:08   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling Luis Machado
                   ` (21 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates for v2:

- Add type field to target hooks.
- Add type data to qMemTags and QMemTags. The packets now look like this:

qMemTags:<address>,<length>:<type>
QMemTags:<address>,<length>:<type>:<uninterpreted tag bytes>

--

This patch adds memory tagging support to GDB's remote side, with
packet string checks, new packet support and an implementation of
the two new tags methods fetch_atags and store_atags.

GDBserver needs to know how to read/write allocation tags, since that is
done via ptrace.  It doesn't need to know about logical tags.

The new packets are:

qMemTags:<address>,<length>
--

Reads tags from the address range [<address>, <address + length>)

QMemTags:<address>,<length>:<uninterpreted tag bytes>
--
Writes the tags represented by the uninterpreted bytes to the address range
[<address>, <address + length>).

The interpretation of what to do with the tag bytes is up to the arch-specific
code.

Note that these new packets consider the case of packet size overflow as an
error, given the common use case is to read/write only a few memory tags at
a time.  Having to use a couple new packets for multi-part transfers wouldn't
make sense for the little use it would have.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* remote.c (PACKET_memory_tagging_feature): New enum.
	(remote_memory_tagging_p): New function.
	(remote_protocol_features): New "memory-tagging" entry.
	(remote_target::remote_query_supported): Handle memory tagging
	support.
	(remote_target::supports_memory_tagging): Implement.
	(create_fmemtags_request, parse_fmemtags_reply)
	(create_smemtags_request): New functions.
	(remote_target::fetch_memtags): Implement.
	(remote_target::store_memtags): Implement.
	(_initialize_remote): Add new "memory-tagging-feature"
	config command.
---
 gdb/remote.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index 2686de3501..e45eef4bee 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -2104,6 +2104,10 @@ enum {
   /* Support TARGET_WAITKIND_NO_RESUMED.  */
   PACKET_no_resumed,
 
+  /* Support for memory tagging, allocation tag fetch/store
+     packets and the tag violation stop replies.  */
+  PACKET_memory_tagging_feature,
+
   PACKET_MAX
 };
 
@@ -2245,6 +2249,14 @@ remote_exec_event_p (struct remote_state *rs)
   return packet_support (PACKET_exec_event_feature) == PACKET_ENABLE;
 }
 
+/* Returns true if memory tagging is supported.  */
+
+static bool
+remote_memory_tagging_p (void)
+{
+  return packet_support (PACKET_memory_tagging_feature) == PACKET_ENABLE;
+}
+
 /* Insert fork catchpoint target routine.  If fork events are enabled
    then return success, nothing more to do.  */
 
@@ -5247,6 +5259,8 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "vContSupported", PACKET_DISABLE, remote_supported_packet, PACKET_vContSupported },
   { "QThreadEvents", PACKET_DISABLE, remote_supported_packet, PACKET_QThreadEvents },
   { "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
+  { "memory-tagging", PACKET_DISABLE, remote_supported_packet,
+    PACKET_memory_tagging_feature },
 };
 
 static char *remote_support_xml;
@@ -5341,6 +5355,10 @@ remote_target::remote_query_supported ()
       if (packet_set_cmd_state (PACKET_no_resumed) != AUTO_BOOLEAN_FALSE)
 	remote_query_supported_append (&q, "no-resumed+");
 
+      if (packet_set_cmd_state (PACKET_memory_tagging_feature)
+	  != AUTO_BOOLEAN_FALSE)
+	remote_query_supported_append (&q, "memory-tagging+");
+
       /* Keep this one last to work around a gdbserver <= 7.10 bug in
 	 the qSupported:xmlRegisters=i386 handling.  */
       if (remote_support_xml != NULL
@@ -14404,7 +14422,65 @@ set_range_stepping (const char *ignore_args, int from_tty,
 bool
 remote_target::supports_memory_tagging ()
 {
-  return false;
+  return remote_memory_tagging_p ();
+}
+
+/* Create the qMemTags packet given ADDRESS, LEN and TYPE.
+
+   Return 0 if successful, non-zero otherwise.  */
+
+static void
+create_fmemtags_request (gdb::char_vector &packet, CORE_ADDR address,
+			 size_t len, int type)
+{
+  int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
+
+  std::string request = string_printf ("qMemTags:%s,%s:%s",
+				       phex_nz (address, addr_size),
+				       phex_nz (len, sizeof (len)),
+				       phex_nz (type, sizeof (type)));
+
+  strcpy (packet.data (), request.c_str ());
+}
+
+/* Parse the qMemTags packet reply into TAGS.
+
+   Return 0 if successful, non-zero otherwise.  */
+
+static int
+parse_fmemtags_reply (gdb::char_vector &reply, gdb::byte_vector &tags)
+{
+  if (reply.empty () || reply[0] == 'E' || reply[0] != 'm')
+    return 1;
+
+  /* Copy the tag data.  */
+  tags = hex2bin (reply.data () + 1);
+
+  return 0;
+}
+
+/* Create the QMemTags packet given ADDRESS, LEN, TYPE and TAGS.
+
+   Return 0 if successful, non-zero otherwise.  */
+
+static void
+create_smemtags_request (gdb::char_vector &packet, CORE_ADDR address,
+			 size_t len, int type, const gdb::byte_vector &tags)
+{
+  int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
+
+  /* Put together the main packet, address and length.  */
+  std::string request = string_printf ("QMemTags:%s,%s:%s:",
+				       phex_nz (address, addr_size),
+				       phex_nz (len, sizeof (len)),
+				       phex_nz (type, sizeof (type)));
+  request += bin2hex (tags.data (), tags.size ());
+
+  /* Check if we have exceeded the maximum packet size.  */
+  if (packet.size () < request.length ())
+    error (_("Contents too big for packet QMemTags."));
+
+  strcpy (packet.data (), request.c_str ());
 }
 
 /* Implement the "fetch_memtags" target_ops method.  */
@@ -14413,6 +14489,19 @@ int
 remote_target::fetch_memtags (CORE_ADDR address, size_t len,
 			      gdb::byte_vector &tags, int type)
 {
+  /* Make sure the qMemTags packet is supported.  */
+  if (!remote_memory_tagging_p ())
+    gdb_assert_not_reached ("remote fetch_memtags called with packet disabled");
+
+  struct remote_state *rs = get_remote_state ();
+
+  create_fmemtags_request (rs->buf, address, len, type);
+
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  parse_fmemtags_reply (rs->buf, tags);
+
   return 0;
 }
 
@@ -14422,6 +14511,21 @@ int
 remote_target::store_memtags (CORE_ADDR address, size_t len,
 			      const gdb::byte_vector &tags, int type)
 {
+  /* Make sure the QMemTags packet is supported.  */
+  if (!remote_memory_tagging_p ())
+    gdb_assert_not_reached ("remote store_memtags called with packet disabled");
+
+  struct remote_state *rs = get_remote_state ();
+
+  create_smemtags_request (rs->buf, address, len, type, tags);
+
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  /* Verify if the request was successful.  */
+  if (packet_check_result (rs->buf.data ()) != PACKET_OK)
+    return 1;
+
   return 0;
 }
 
@@ -14824,6 +14928,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_no_resumed],
 			 "N stop reply", "no-resumed-stop-reply", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_memory_tagging_feature],
+			 "memory-tagging-feature", "memory-tagging-feature", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (2 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 03/24] Add GDB-side remote target support for memory tagging Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25  5:34   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 05/24] GDBserver remote packet support for memory tagging Luis Machado
                   ` (20 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updated in v2:

- Adjusted unit tests to cope with new type field in the remote packets.

--

Include some unit testing for the functions handling the new qMemTags and
QMemTags packets.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* remote: Include gdbsupport/selftest.h.
	(test_memory_tagging_functions): New function.
	(_initialize_remote): Register test_memory_tagging_functions.
---
 gdb/remote.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/gdb/remote.c b/gdb/remote.c
index e45eef4bee..6db7a74542 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -79,6 +79,7 @@
 #include <algorithm>
 #include <unordered_map>
 #include "async-event.h"
+#include "gdbsupport/selftest.h"
 
 /* The remote target.  */
 
@@ -14529,6 +14530,89 @@ remote_target::store_memtags (CORE_ADDR address, size_t len,
   return 0;
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+static void
+test_memory_tagging_functions (void)
+{
+  remote_target remote;
+
+  struct packet_config *config
+    = &remote_protocol_packets[PACKET_memory_tagging_feature];
+
+  /* Test memory tagging packet support.  */
+  config->support = PACKET_SUPPORT_UNKNOWN;
+  SELF_CHECK (remote.supports_memory_tagging () == false);
+  config->support = PACKET_DISABLE;
+  SELF_CHECK (remote.supports_memory_tagging () == false);
+  config->support = PACKET_ENABLE;
+  SELF_CHECK (remote.supports_memory_tagging () == true);
+
+  /* Setup testing.  */
+  gdb::char_vector packet;
+  gdb::byte_vector tags, bv;
+  std::string expected, reply;
+  packet.resize (32000);
+
+  /* Test creating a qMemTags request.  */
+
+  expected = "qMemTags:0,0:0";
+  create_fmemtags_request (packet, 0x0, 0x0, 0);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  expected = "qMemTags:deadbeef,10:1";
+  create_fmemtags_request (packet, 0xdeadbeef, 16, 1);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  /* Test parsing a qMemTags reply.  */
+
+  /* Error reply, tags vector unmodified.  */
+  reply = "E00";
+  strcpy (packet.data (), reply.c_str ());
+  tags.resize (0);
+  SELF_CHECK (parse_fmemtags_reply (packet, tags) != 0);
+  SELF_CHECK (tags.size () == 0);
+
+  /* Valid reply, tags vector updated.  */
+  tags.resize (0);
+  bv.resize (0);
+
+  for (int i = 0; i < 5; i++)
+    bv.push_back (i);
+
+  reply = "m" + bin2hex (bv.data (), bv.size ());
+  strcpy (packet.data (), reply.c_str ());
+
+  SELF_CHECK (parse_fmemtags_reply (packet, tags) == 0);
+  SELF_CHECK (tags.size () == 5);
+
+  for (int i = 0; i < 5; i++)
+    SELF_CHECK (tags[i] == i);
+
+  /* Test creating a QMemTags request.  */
+
+  /* Empty tag data.  */
+  tags.resize (0);
+  expected = "QMemTags:0,0:0:";
+  create_smemtags_request (packet, 0x0, 0x0, 0, tags);
+  SELF_CHECK (memcmp (packet.data (), expected.c_str (),
+		      expected.length ()) == 0);
+
+  /* Non-empty tag data.  */
+  tags.resize (0);
+  for (int i = 0; i < 5; i++)
+    tags.push_back (i);
+  expected = "QMemTags:deadbeef,ff:1:0001020304";
+  create_smemtags_request (packet, 0xdeadbeef, 255, 1, tags);
+  SELF_CHECK (memcmp (packet.data (), expected.c_str (),
+		      expected.length ()) == 0);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 void _initialize_remote ();
 void
 _initialize_remote ()
@@ -15042,4 +15126,9 @@ Specify \"unlimited\" to display all the characters."),
 
   /* Eventually initialize fileio.  See fileio.c */
   initialize_remote_fileio (&remote_set_cmdlist, &remote_show_cmdlist);
+
+#if GDB_SELF_TEST
+  selftests::register_test ("remote_memory_tagging",
+			    selftests::test_memory_tagging_functions);
+#endif
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 05/24] GDBserver remote packet support for memory tagging
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (3 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25  5:50   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets Luis Machado
                   ` (19 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v2:

- Update target methods to contain a tag type field.
- Update remote packet processing to parse the type field.

--

This patch adds the generic remote bits to gdbserver so it can check for memory
tagging support and handle fetch tags and store tags requests.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* remote-utils.cc (decode_m_packet_params): Renamed from ...
	(decode_m_packet): ... this, which now calls decode_m_packet_params.
	Make char * param/return const char *.
	(decode_M_packet): Use decode_m_packet_params and make char * param
	const char *.
	* remote-utils.h (decode_m_packet_params): New prototype.
	(decode_m_packet): Constify char pointers.
	(decode_M_packet): Likewise.
	* server.cc (create_fmemtags_reply, parse_smemtags_request): New
	functions.
	(handle_general_set): Handle the QMemTags packet.
	(parse_fmemtags_request): New function.
	(handle_query): Handle the qMemTags packet and advertise memory
	tagging support.
	(captured_main): Initialize memory tagging flag.
	* server.h (struct client_state): Initialize memory tagging flag.
	* target.cc (process_stratum_target::supports_memory_tagging)
	(process_stratum_target::fetch_memtags)
	(process_stratum_target::store_memtags): New methods.
	* target.h: Include gdbsupport/byte-vector.h.
	(class process_stratum_target) <supports_memory_tagging>
	<fetch_memtags, store_memtags>: New class virtual methods.
	(target_supports_memory_tagging): Define.
---
 gdbserver/remote-utils.cc |  43 ++++++-----
 gdbserver/remote-utils.h  |   7 +-
 gdbserver/server.cc       | 145 ++++++++++++++++++++++++++++++++++++++
 gdbserver/server.h        |   3 +
 gdbserver/target.cc       |  20 ++++++
 gdbserver/target.h        |  17 +++++
 6 files changed, 210 insertions(+), 25 deletions(-)

diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
index 5a6ceb1d9a..1774bfafc9 100644
--- a/gdbserver/remote-utils.cc
+++ b/gdbserver/remote-utils.cc
@@ -1304,10 +1304,14 @@ prepare_resume_reply (char *buf, ptid_t ptid,
     }
 }
 
-void
-decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr)
+/* Decode ADDR and LEN from a parameter of the form "addr,len<x>", with <x>
+   being an end marker character.  */
+
+const char *
+decode_m_packet_params (const char *from, CORE_ADDR *mem_addr_ptr,
+			unsigned int *len_ptr, const char end_marker)
 {
-  int i = 0, j = 0;
+  int i = 0;
   char ch;
   *mem_addr_ptr = *len_ptr = 0;
 
@@ -1317,39 +1321,32 @@ decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr)
       *mem_addr_ptr |= fromhex (ch) & 0x0f;
     }
 
-  for (j = 0; j < 4; j++)
+  while ((ch = from[i++]) != end_marker)
     {
-      if ((ch = from[i++]) == 0)
-	break;
       *len_ptr = *len_ptr << 4;
       *len_ptr |= fromhex (ch) & 0x0f;
     }
+
+  return from + i;
 }
 
 void
-decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
-		 unsigned char **to_p)
+decode_m_packet (const char *from, CORE_ADDR *mem_addr_ptr,
+		 unsigned int *len_ptr)
 {
-  int i = 0;
-  char ch;
-  *mem_addr_ptr = *len_ptr = 0;
-
-  while ((ch = from[i++]) != ',')
-    {
-      *mem_addr_ptr = *mem_addr_ptr << 4;
-      *mem_addr_ptr |= fromhex (ch) & 0x0f;
-    }
+  decode_m_packet_params (from, mem_addr_ptr, len_ptr, '\0');
+}
 
-  while ((ch = from[i++]) != ':')
-    {
-      *len_ptr = *len_ptr << 4;
-      *len_ptr |= fromhex (ch) & 0x0f;
-    }
+void
+decode_M_packet (const char *from, CORE_ADDR *mem_addr_ptr,
+		 unsigned int *len_ptr, unsigned char **to_p)
+{
+  from = decode_m_packet_params (from, mem_addr_ptr, len_ptr, ':');
 
   if (*to_p == NULL)
     *to_p = (unsigned char *) xmalloc (*len_ptr);
 
-  hex2bin (&from[i++], *to_p, *len_ptr);
+  hex2bin (from, *to_p, *len_ptr);
 }
 
 int
diff --git a/gdbserver/remote-utils.h b/gdbserver/remote-utils.h
index 1b31456798..4d0e1cd250 100644
--- a/gdbserver/remote-utils.h
+++ b/gdbserver/remote-utils.h
@@ -45,9 +45,12 @@ void prepare_resume_reply (char *buf, ptid_t ptid,
 
 const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start);
 void decode_address (CORE_ADDR *addrp, const char *start, int len);
-void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,
+const char *decode_m_packet_params (const char *from, CORE_ADDR *mem_addr_ptr,
+				    unsigned int *len_ptr,
+				    const char end_marker);
+void decode_m_packet (const char *from, CORE_ADDR * mem_addr_ptr,
 		      unsigned int *len_ptr);
-void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
+void decode_M_packet (const char *from, CORE_ADDR * mem_addr_ptr,
 		      unsigned int *len_ptr, unsigned char **to_p);
 int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
 		     unsigned int *len_ptr, unsigned char **to_p);
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 95db9807a9..7eddd0e01f 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -547,12 +547,71 @@ handle_btrace_conf_general_set (char *own_buf)
   return 1;
 }
 
+/* Create the qMemTags packet reply given TAGS.  */
+
+static int
+create_fmemtags_reply (char *reply, const gdb::byte_vector &tags)
+{
+  /* It is an error to pass a zero-sized tag vector.  */
+  if (tags.size () == 0)
+    return 1;
+
+  std::string packet ("m");
+
+  /* Write the tag data.  */
+  packet += bin2hex (tags.data (), tags.size ());
+
+  /* Check if the reply is too big for the packet to handle.  */
+  if (PBUFSIZ < packet.size ())
+    return 1;
+
+  strcpy (reply, packet.c_str ());
+  return 0;
+}
+
+/* Parse the QMemTags request into ADDR, LEN and TAGS.
+
+   Return 0 if successful, non-zero otherwise.  */
+
+static int
+parse_smemtags_request (char *request, CORE_ADDR *addr, size_t *len,
+			gdb::byte_vector &tags, int *type)
+{
+  if (!startswith (request, "QMemTags:"))
+    return 1;
+
+  const char *p = request + strlen ("QMemTags:");
+
+  /* Read address and length.  */
+  unsigned int length = 0;
+  p = decode_m_packet_params (p, addr, &length, ':');
+  *len = length;
+
+  /* Read the tag type.  */
+  ULONGEST tag_type = 0;
+  p = unpack_varlen_hex (p, &tag_type);
+  *type = (int) tag_type;
+
+  /* Make sure there is a colon after the type.  */
+  if (*p != ':')
+    return 1;
+
+  /* Skip the colon.  */
+  p++;
+
+  /* Read the tag data.  */
+  tags = hex2bin (p);
+
+  return 0;
+}
+
 /* Handle all of the extended 'Q' packets.  */
 
 static void
 handle_general_set (char *own_buf)
 {
   client_state &cs = get_client_state ();
+
   if (startswith (own_buf, "QPassSignals:"))
     {
       int numsigs = (int) GDB_SIGNAL_LAST, i;
@@ -903,6 +962,31 @@ handle_general_set (char *own_buf)
       return;
     }
 
+
+  /* Handle store memory tags packets.  */
+  if (startswith (own_buf, "QMemTags:")
+      && target_supports_memory_tagging ())
+    {
+      gdb::byte_vector tags;
+      CORE_ADDR addr = 0;
+      size_t len = 0;
+      int type = 0;
+
+      require_running_or_return (own_buf);
+
+      int ret = parse_smemtags_request (own_buf, &addr, &len, tags, &type);
+
+      if (ret == 0)
+	ret = the_target->store_memtags (addr, len, tags, type);
+
+      if (ret)
+	write_enn (own_buf);
+      else
+	write_ok (own_buf);
+
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -2066,6 +2150,31 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
   return (unsigned long long) crc;
 }
 
+/* Parse the qMemTags packet request into ADDR and LEN.
+
+   Return 0 if successful, non-zero otherwise.  */
+
+static int
+parse_fmemtags_request (char *request, CORE_ADDR *addr, size_t *len, int *type)
+{
+  if (!startswith (request, "qMemTags:"))
+    return 1;
+
+  const char *p = request + strlen ("qMemTags:");
+
+  /* Read address and length.  */
+  unsigned int length = 0;
+  p = decode_m_packet_params (p, addr, &length, ':');
+  *len = length;
+
+  /* Read the tag type.  */
+  ULONGEST tag_type = 0;
+  p = unpack_varlen_hex (p, &tag_type);
+  *type = (int) tag_type;
+
+  return 0;
+}
+
 /* Add supported btrace packets to BUF.  */
 
 static void
@@ -2284,6 +2393,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 		     events.  */
 		  report_no_resumed = true;
 		}
+	      else if (feature == "memory-tagging+")
+		{
+		  /* GDB supports memory tagging features.  */
+		  if (target_supports_memory_tagging ())
+		    cs.memory_tagging_feature = true;
+		}
 	      else
 		{
 		  /* Move the unknown features all together.  */
@@ -2401,6 +2516,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 
       strcat (own_buf, ";no-resumed+");
 
+      if (target_supports_memory_tagging ())
+	strcat (own_buf, ";memory-tagging+");
+
       /* Reinitialize components as needed for the new connection.  */
       hostio_handle_new_gdb_connection ();
       target_handle_new_gdb_connection ();
@@ -2593,6 +2711,32 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
   if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
     return;
 
+  /* Handle fetch memory tags packets.  */
+  if (startswith (own_buf, "qMemTags:")
+      && target_supports_memory_tagging ())
+    {
+      gdb::byte_vector tags;
+      CORE_ADDR addr = 0;
+      size_t len = 0;
+      int type = 0;
+
+      require_running_or_return (own_buf);
+
+      int ret = parse_fmemtags_request (own_buf, &addr, &len, &type);
+
+      if (ret == 0)
+	ret = the_target->fetch_memtags (addr, len, tags, type);
+
+      if (ret == 0)
+	ret = create_fmemtags_reply (own_buf, tags);
+
+      if (ret)
+	write_enn (own_buf);
+
+      *new_packet_len_p = strlen (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -3810,6 +3954,7 @@ captured_main (int argc, char *argv[])
       cs.swbreak_feature = 0;
       cs.hwbreak_feature = 0;
       cs.vCont_supported = 0;
+      cs.memory_tagging_feature = false;
 
       remote_open (port);
 
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 22228050a8..3d4a086e18 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -190,6 +190,9 @@ struct client_state
 
   int current_traceframe = -1;
 
+  /* If true, memory tagging features are supported.  */
+  bool memory_tagging_feature = false;
+
 };
 
 client_state &get_client_state ();
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index 921d26fcf7..70df911e9f 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -464,6 +464,26 @@ process_stratum_target::supports_read_offsets ()
   return false;
 }
 
+bool
+process_stratum_target::supports_memory_tagging ()
+{
+  return false;
+}
+
+int
+process_stratum_target::fetch_memtags (CORE_ADDR address, size_t len,
+				       gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
+int
+process_stratum_target::store_memtags (CORE_ADDR address, size_t len,
+				       const gdb::byte_vector &tags, int type)
+{
+  return 0;
+}
+
 int
 process_stratum_target::read_offsets (CORE_ADDR *text, CORE_ADDR *data)
 {
diff --git a/gdbserver/target.h b/gdbserver/target.h
index c2245ebfe8..e3e6b07fee 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -30,6 +30,7 @@
 #include "gdbsupport/array-view.h"
 #include "gdbsupport/btrace-common.h"
 #include <vector>
+#include "gdbsupport/byte-vector.h"
 
 struct emit_ops;
 struct buffer;
@@ -499,6 +500,19 @@ class process_stratum_target
 
   /* Return tdesc index for IPA.  */
   virtual int get_ipa_tdesc_idx ();
+
+  /* Returns true if the target supports memory tagging facilities.  */
+  virtual bool supports_memory_tagging ();
+
+  /* Return the allocated memory tags of type TYPE associated with
+     [ADDRESS, ADDRESS + LEN) in TAGS.  */
+  virtual int fetch_memtags (CORE_ADDR address, size_t len,
+			     gdb::byte_vector &tags, int type);
+
+  /* Write the allocation tags of type TYPE contained in TAGS to the
+     memory range [ADDRESS, ADDRESS + LEN).  */
+  virtual int store_memtags (CORE_ADDR address, size_t len,
+			     const gdb::byte_vector &tags, int type);
 };
 
 extern process_stratum_target *the_target;
@@ -525,6 +539,9 @@ int kill_inferior (process_info *proc);
 #define target_supports_exec_events() \
   the_target->supports_exec_events ()
 
+#define target_supports_memory_tagging() \
+  the_target->supports_memory_tagging ()
+
 #define target_handle_new_gdb_connection()		 \
   the_target->handle_new_gdb_connection ()
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (4 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 05/24] GDBserver remote packet support for memory tagging Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-25 20:13   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 07/24] Documentation for " Luis Machado
                   ` (18 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v2:

- Update unit tests to cope with additional tag type field in the remote
packets.

--

Add some unit testing to exercise the functions handling the qMemTags and
QMemTags packets as well as feature support.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* server.cc (test_memory_tagging_functions): New function.
	(captured_main): Register test_memory_tagging_functions.
---
 gdbserver/server.cc | 100 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 7eddd0e01f..6812b624f8 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -3647,6 +3647,103 @@ detach_or_kill_for_exit_cleanup ()
     }
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+static void
+test_memory_tagging_functions (void)
+{
+  /* Setup testing.  */
+  gdb::char_vector packet;
+  gdb::byte_vector tags, bv;
+  std::string expected;
+  packet.resize (32000);
+  CORE_ADDR addr;
+  size_t len;
+  int type;
+
+  /* Test parsing a qMemTags request.  */
+
+  /* Invalid request, addr len and type unchanged.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  strcpy (packet.data (), "qMemTags_wrong:0,0:0");
+  SELF_CHECK (parse_fmemtags_request (packet.data (), &addr, &len, &type) != 0);
+  SELF_CHECK (addr == 0xff && len == 255 && type == 255);
+
+  /* Valid request, addr, len and type updated.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  strcpy (packet.data (), "qMemTags:0,0:0");
+  SELF_CHECK (parse_fmemtags_request (packet.data (), &addr, &len, &type) == 0);
+  SELF_CHECK (addr == 0 && len == 0 && type == 0);
+
+  /* Valid request, addr, len and type updated.  */
+  addr = 0;
+  len = 0;
+  type = 0;
+  strcpy (packet.data (), "qMemTags:deadbeef,ff:5");
+  SELF_CHECK (parse_fmemtags_request (packet.data (), &addr, &len, &type) == 0);
+  SELF_CHECK (addr == 0xdeadbeef && len == 255 && type == 5);
+
+  /* Test creating a qMemTags reply.  */
+
+  /* Non-empty tag data.  */
+  bv.resize (0);
+
+  for (int i = 0; i < 5; i++)
+    bv.push_back (i);
+
+  expected = "m0001020304";
+  SELF_CHECK (create_fmemtags_reply (packet.data (), bv) == 0);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  /* Empty tag data (error).  */
+  bv.clear ();
+  SELF_CHECK (create_fmemtags_reply (packet.data (), bv) != 0);
+
+  /* Test parsing a QMemTags request.  */
+
+  /* Invalid request and non-empty tag data: addr, len, type and tags
+     unchanged.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  tags.resize (5);
+  strcpy (packet.data (), "QMemTags_wrong:0,0:0:0001020304");
+  SELF_CHECK (parse_smemtags_request (packet.data (), &addr, &len, tags,
+				      &type) != 0);
+  SELF_CHECK (addr == 0xff && len == 255 && type == 255 && tags.size () == 5);
+
+  /* Valid request and empty tag data: addr, len, type and tags updated.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  tags.resize (5);
+  strcpy (packet.data (), "QMemTags:0,0:0:");
+  SELF_CHECK (parse_smemtags_request (packet.data (), &addr, &len, tags,
+				      &type) == 0);
+  SELF_CHECK (addr == 0 && len == 0 && type == 0 && tags.size () == 0);
+
+  /* Valid request and non-empty tag data: addr, len, type and tags updated.  */
+  addr = 0;
+  len = 0;
+  type = 0;
+  tags.resize (0);
+  strcpy (packet.data (),
+	  "QMemTags:deadbeef,ff:5:0001020304");
+  SELF_CHECK (parse_smemtags_request (packet.data (), &addr, &len, tags,
+				      &type) == 0);
+  SELF_CHECK (addr == 0xdeadbeef && len == 255 && type == 5
+	      && tags.size () == 5);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 /* Main function.  This is called by the real "main" function,
    wrapped in a TRY_CATCH that handles any uncaught exceptions.  */
 
@@ -3664,6 +3761,9 @@ captured_main (int argc, char *argv[])
   bool selftest = false;
 #if GDB_SELF_TEST
   std::vector<const char *> selftest_filters;
+
+  selftests::register_test ("remote_memory_tagging",
+			    selftests::test_memory_tagging_functions);
 #endif
 
   current_directory = getcwd (NULL, 0);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (5 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:08   ` Eli Zaretskii
  2020-11-09 17:04 ` [PATCH v3 08/24] AArch64: Add MTE CPU feature check support Luis Machado
                   ` (17 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v3:

- Made packet description more clear.
- Fixed Misc formatting/references issues.

Updates on v2:

- Update documentation to mention the packet's type field.

--

Document the remote packet changes to support memory tagging.

gdb/doc/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* gdb.texinfo (General Query Packets): Document qMemTags and
	QMemTags.  Document the "memory-tagging" feature.
---
 gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5270156000..7593559331 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40884,6 +40884,87 @@ is a sequence of thread IDs, @var{threadid} (eight hex
 digits), from the target.  See @code{remote.c:parse_threadlist_response()}.
 @end table
 
+@item qMemTags:@var{start address},@var{length}:@var{type}
+@anchor{qMemTags}
+@cindex fetch memory tags
+@cindex @samp{qMemTags} packet
+Fetch memory tags of type @var{type} from the address range
+@w{@r{[}@var{start address}, @var{start address} + @var{length}@r{)}}.  The target
+is responsible for calculating how many tags will be returned, as this is
+architecture-specific.
+
+@var{start address} is the starting address of the memory range.
+
+@var{length} is the length, in bytes, of the memory range.
+
+@var{type} is the type of tag the request wants to fetch.  The type is a signed
+integer.
+
+Reply:
+@table @samp
+@item @var{mxx}@dots{}
+Hex encoded sequence of uninterpreted bytes, @var{xx}@dots{}, representing the
+tags found in the requested memory range.
+
+@item E @var{nn}
+An error occured.  This means that fetching of memory tags failed for some
+reason.
+
+@item @w{}
+An empty reply indicates that @samp{qMemTags} is not supported by the stub,
+although this should not happen given @value{GDBN} will only send this packet
+if the stub has advertised support for memory tagging via @samp{qSupported}.
+@end table
+
+@item QMemTags:@var{start address},@var{length}:@var{type}:@var{tag bytes}
+@anchor{QMemTags}
+@cindex store memory tags
+@cindex @samp{QMemTags} packet
+Store memory tags of type @var{type} to the address range
+@w{@r{[}@var{start address}, @var{start address} + @var{length}@r{)}}.  The target
+is responsible for interpreting the type, the tag bytes and modifying the
+memory tag granules accordingly, given this is architecture-specific.
+
+The interpretation of how many tags (@var{nt}) should be written to how many
+memory tag granules (@var{ng}) is also architecture-specific.  The behavior is
+implementation-specific, but the following is suggested.
+
+If the number of memory tags, @var{nt}, is greater than or equal to the
+number of memory tag granules, @var{ng}, only @var{ng} tags will be
+stored.
+
+If @var{nt} is less than @var{ng}, the behavior is that of a fill operation,
+and the tag bytes will be used as a pattern that will get repeated until
+@var{ng} tags are stored.
+
+@var{start address} is the starting address of the memory range.  The address
+does not have any restriction on alignment or size.
+
+@var{length} is the length, in bytes, of the memory range.
+
+@var{type} is the type of tag the request wants to fetch.  The typeis a signed
+integer.
+
+@var{tag bytes} is a sequence of hex encoded uninterpreted bytes which will be
+interpreted by the target.  Each pair of hex digits is interpreted as a
+single byte.
+
+Reply:
+@table @samp
+@item OK
+The request was successful and the memory tag granules were modified
+accordingly.
+
+@item E @var{nn}
+An error occured.  This means that modifying the memory tag granules failed
+for some reason.
+
+@item @w{}
+An empty reply indicates that @samp{QMemTags} is not supported by the stub,
+although this should not happen given @value{GDBN} will only send this packet
+if the stub has advertised support for memory tagging via @samp{qSupported}.
+@end table
+
 @item qOffsets
 @cindex section offsets, remote request
 @cindex @samp{qOffsets} packet
@@ -41551,6 +41632,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab No
 
+@item @samp{memory-tagging}
+@tab No
+@tab @samp{-}
+@tab No
+
 @end multitable
 
 These are the currently defined stub features, in more detail:
@@ -41765,6 +41851,16 @@ The remote stub understands the @samp{QThreadEvents} packet.
 @item no-resumed
 The remote stub reports the @samp{N} stop reply.
 
+
+@item memory-tagging
+The remote stub supports and implements the required memory tagging
+functionality and understands the @samp{qMemTags} (@pxref{qMemTags}) and
+@samp{QMemTags} (@pxref{QMemTags}) packets.
+
+For AArch64 GNU/Linux systems, this feature also requires access to the
+@file{/proc/@var{pid}/smaps} file so memory mapping page flags can be inspected.
+This is done via the @samp{vFile} requests.
+
 @end table
 
 @item qSymbol::
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 08/24] AArch64: Add MTE CPU feature check support
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (6 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 07/24] Documentation for " Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  0:04   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers Luis Machado
                   ` (16 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

This patch is a preparation for the next patches implementing MTE. It just adds
a HWCAP2 constant for MTE, creates a new generic arch/aarch64-mte-linux.h file
and includes that file in the source files that will use it.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* Makefile.in (HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h.
	* aarch64-linux-nat.c: Include arch/aarch64-mte-linux.h.
	* aarch64-linux-tdep.c: Likewise
	* arch/aarch64-mte-linux.h: New file.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* linux-aarch64-low.cc: Include arch/aarch64-mte-linux.h.
---
 gdb/Makefile.in                |  1 +
 gdb/aarch64-linux-nat.c        |  2 ++
 gdb/aarch64-linux-tdep.c       |  2 ++
 gdb/arch/aarch64-mte-linux.h   | 28 ++++++++++++++++++++++++++++
 gdbserver/linux-aarch64-low.cc |  1 +
 5 files changed, 34 insertions(+)
 create mode 100644 gdb/arch/aarch64-mte-linux.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c46935efaf..4fd0c1d8e5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1460,6 +1460,7 @@ HFILES_NO_SRCDIR = \
 	arch/aarch32.h \
 	arch/aarch64.h \
 	arch/aarch64-insn.h \
+	arch/aarch64-mte-linux.h \
 	arch/arc.h \
 	arch/arm.h \
 	arch/i386.h \
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 77d5863a56..260f47558b 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -50,6 +50,8 @@
 #include "gdb_proc_service.h"
 #include "arch-utils.h"
 
+#include "arch/aarch64-mte-linux.h"
+
 #ifndef TRAP_HWBKPT
 #define TRAP_HWBKPT 0x0004
 #endif
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index c9898bdafd..0fd806a5aa 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -44,6 +44,8 @@
 #include "record-full.h"
 #include "linux-record.h"
 
+#include "arch/aarch64-mte-linux.h"
+
 /* Signal frame handling.
 
       +------------+  ^
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
new file mode 100644
index 0000000000..c6a91c2db4
--- /dev/null
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -0,0 +1,28 @@
+/* Common Linux target-dependent definitions for AArch64 MTE
+
+   Copyright (C) 2020 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 ARCH_AARCH64_LINUX_H
+#define ARCH_AARCH64_LINUX_H
+
+/* Feature check for Memory Tagging Extension.  */
+#ifndef HWCAP2_MTE
+#define HWCAP2_MTE  (1 << 18)
+#endif
+
+#endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 08208ae4f4..7512aac54b 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -40,6 +40,7 @@
 
 #include "gdb_proc_service.h"
 #include "arch/aarch64.h"
+#include "arch/aarch64-mte-linux.h"
 #include "linux-aarch32-tdesc.h"
 #include "linux-aarch64-tdesc.h"
 #include "nat/aarch64-sve-linux-ptrace.h"
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (7 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 08/24] AArch64: Add MTE CPU feature check support Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  0:10   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
                   ` (15 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

This patch adds a target description and feature "mte" for aarch64.

It includes one new register, tag_ctl, that can be used to configure the
tag generation rules and sync/async modes.  It is 64-bit in size.

The patch also adjusts the code that creates the target descriptions at
runtime based on CPU feature checks.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-nat.c
	(aarch64_linux_nat_target::read_description): Take MTE flag into
	account.
	Slight refactor to hwcap flag checking.
	* aarch64-linux-tdep.c
	(aarch64_linux_core_read_description): Likewise.
	* aarch64-tdep.c (tdesc_aarch64_list): Add one more dimension for
	MTE.
	(aarch64_read_description): Add mte_p parameter and update to use it.
	Update the documentation.
	(aarch64_gdbarch_init): Update call to aarch64_read_description.
	* aarch64-tdep.h (aarch64_read_description): Add mte_p parameter.
	* arch/aarch64.c: Include ../features/aarch64-mte.c.
	(aarch64_create_target_description): Add mte_p parameter and update
	the code to use it.
	* arch/aarch64.h (aarch64_create_target_description): Add mte_p
	parameter.
	* features/Makefile (FEATURE_XMLFILES): Add aarch64-mte.xml.
	* features/aarch64-mte.c: New file, generated.
	* features/aarch64-mte.xml: New file.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* linux-aarch64-ipa.cc (get_ipa_tdesc): Update call to
	aarch64_linux_read_description.
	(initialize_low_tracepoint): Likewise.
	* linux-aarch64-low.cc (aarch64_target::low_arch_setup): Take MTE flag
	into account.
	* linux-aarch64-tdesc.cc (tdesc_aarch64_list): Add one more dimension
	for MTE.
	(aarch64_linux_read_description): Add mte_p parameter and update to
	use it.
	* linux-aarch64-tdesc.h (aarch64_linux_read_description): Add mte_p
	parameter.
---
 gdb/aarch64-linux-nat.c          |  7 +++++--
 gdb/aarch64-linux-tdep.c         |  5 ++++-
 gdb/aarch64-tdep.c               | 16 +++++++++-------
 gdb/aarch64-tdep.h               |  3 ++-
 gdb/arch/aarch64.c               |  7 ++++++-
 gdb/arch/aarch64.h               |  7 +++++--
 gdb/features/Makefile            |  1 +
 gdb/features/aarch64-mte.c       | 14 ++++++++++++++
 gdb/features/aarch64-mte.xml     | 11 +++++++++++
 gdbserver/linux-aarch64-ipa.cc   |  8 ++++----
 gdbserver/linux-aarch64-low.cc   |  6 +++++-
 gdbserver/linux-aarch64-tdesc.cc | 10 +++++-----
 gdbserver/linux-aarch64-tdesc.h  |  3 ++-
 13 files changed, 73 insertions(+), 25 deletions(-)
 create mode 100644 gdb/features/aarch64-mte.c
 create mode 100644 gdb/features/aarch64-mte.xml

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 260f47558b..1392ec440c 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -653,9 +653,12 @@ aarch64_linux_nat_target::read_description ()
     return aarch32_read_description ();
 
   CORE_ADDR hwcap = linux_get_hwcap (this);
+  CORE_ADDR hwcap2 = linux_get_hwcap2 (this);
 
-  return aarch64_read_description (aarch64_sve_get_vq (tid),
-				   hwcap & AARCH64_HWCAP_PACA);
+  bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
+  bool mte_p = hwcap2 & HWCAP2_MTE;
+
+  return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, mte_p);
 }
 
 /* Convert a native/host siginfo object, into/from the siginfo in the
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 0fd806a5aa..5f6fb42792 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -654,9 +654,12 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
 				     struct target_ops *target, bfd *abfd)
 {
   CORE_ADDR hwcap = linux_get_hwcap (target);
+  CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
 
+  bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
+  bool mte_p = hwcap2 & HWCAP2_MTE;
   return aarch64_read_description (aarch64_linux_core_read_vq (gdbarch, abfd),
-				   hwcap & AARCH64_HWCAP_PACA);
+				   pauth_p, mte_p);
 }
 
 /* Implementation of `gdbarch_stap_is_single_operand', as defined in
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 2c1d888904..846b0ba0f3 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -62,7 +62,7 @@
 #define HA_MAX_NUM_FLDS		4
 
 /* All possible aarch64 target descriptors.  */
-struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/];
+struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/][2 /* mte */];
 
 /* The standard register names, and all the valid aliases for them.  */
 static const struct
@@ -3266,21 +3266,23 @@ aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
 
 /* Get the correct target description for the given VQ value.
    If VQ is zero then it is assumed SVE is not supported.
-   (It is not possible to set VQ to zero on an SVE system).  */
+   (It is not possible to set VQ to zero on an SVE system).
+
+   MTE_P indicates the presence of the Memory Tagging Extension feature. */
 
 const target_desc *
-aarch64_read_description (uint64_t vq, bool pauth_p)
+aarch64_read_description (uint64_t vq, bool pauth_p, bool mte_p)
 {
   if (vq > AARCH64_MAX_SVE_VQ)
     error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq,
 	   AARCH64_MAX_SVE_VQ);
 
-  struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p];
+  struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p][mte_p];
 
   if (tdesc == NULL)
     {
-      tdesc = aarch64_create_target_description (vq, pauth_p);
-      tdesc_aarch64_list[vq][pauth_p] = tdesc;
+      tdesc = aarch64_create_target_description (vq, pauth_p, mte_p);
+      tdesc_aarch64_list[vq][pauth_p][mte_p] = tdesc;
     }
 
   return tdesc;
@@ -3380,7 +3382,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      value.  */
   const struct target_desc *tdesc = info.target_desc;
   if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc))
-    tdesc = aarch64_read_description (vq, false);
+    tdesc = aarch64_read_description (vq, false, false);
   gdb_assert (tdesc);
 
   feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core");
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 81ce4d84b4..6f3299f2cb 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -102,7 +102,8 @@ struct gdbarch_tdep
   }
 };
 
-const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p);
+const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p,
+					     bool mte_p);
 
 extern int aarch64_process_record (struct gdbarch *gdbarch,
 			       struct regcache *regcache, CORE_ADDR addr);
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index f89d5e014d..6c90bb36e4 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -23,11 +23,12 @@
 #include "../features/aarch64-fpu.c"
 #include "../features/aarch64-sve.c"
 #include "../features/aarch64-pauth.c"
+#include "../features/aarch64-mte.c"
 
 /* See arch/aarch64.h.  */
 
 target_desc *
-aarch64_create_target_description (uint64_t vq, bool pauth_p)
+aarch64_create_target_description (uint64_t vq, bool pauth_p, bool mte_p)
 {
   target_desc_up tdesc = allocate_target_description ();
 
@@ -47,5 +48,9 @@ aarch64_create_target_description (uint64_t vq, bool pauth_p)
   if (pauth_p)
     regnum = create_feature_aarch64_pauth (tdesc.get (), regnum);
 
+  /* Memory tagging extension registers.  */
+  if (mte_p)
+    regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
+
   return tdesc.release ();
 }
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index 857bb22b03..6b1882afcc 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -25,9 +25,12 @@
 /* Create the aarch64 target description.  A non zero VQ value indicates both
    the presence of SVE and the Vector Quotient - the number of 128bit chunks in
    an SVE Z register.  HAS_PAUTH_P indicates the presence of the PAUTH
-   feature.  */
+   feature.
 
-target_desc *aarch64_create_target_description (uint64_t vq, bool has_pauth_p);
+   MTE_P indicates the presence of the Memory Tagging Extension feature.  */
+
+target_desc *aarch64_create_target_description (uint64_t vq, bool has_pauth_p,
+						bool mte_p);
 
 /* Register numbers of various important registers.
    Note that on SVE, the Z registers reuse the V register numbers and the V
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 689603847a..bdc6c60c78 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -201,6 +201,7 @@ $(outdir)/%.dat: %.xml number-regs.xsl sort-regs.xsl gdbserver-regs.xsl
 FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-fpu.xml \
 	aarch64-pauth.xml \
+	aarch64-mte.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
 	arc/v2-core.xml \
diff --git a/gdb/features/aarch64-mte.c b/gdb/features/aarch64-mte.c
new file mode 100644
index 0000000000..883b19cd15
--- /dev/null
+++ b/gdb/features/aarch64-mte.c
@@ -0,0 +1,14 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: aarch64-mte.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_aarch64_mte (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.mte");
+  tdesc_create_reg (feature, "tag_ctl", regnum++, 0, "system", 64, "uint64");
+  return regnum;
+}
diff --git a/gdb/features/aarch64-mte.xml b/gdb/features/aarch64-mte.xml
new file mode 100644
index 0000000000..85455b13b2
--- /dev/null
+++ b/gdb/features/aarch64-mte.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2020 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.mte">
+  <reg name="tag_ctl" bitsize="64" type="uint64" group="system" save-restore="no"/>
+</feature>
diff --git a/gdbserver/linux-aarch64-ipa.cc b/gdbserver/linux-aarch64-ipa.cc
index 694dfd77df..1a47bf95d7 100644
--- a/gdbserver/linux-aarch64-ipa.cc
+++ b/gdbserver/linux-aarch64-ipa.cc
@@ -147,12 +147,12 @@ get_raw_reg (const unsigned char *raw_regs, int regnum)
 
 /* Return target_desc to use for IPA, given the tdesc index passed by
    gdbserver.  Index is ignored, since we have only one tdesc
-   at the moment.  SVE and pauth not yet supported.  */
+   at the moment.  SVE, pauth and MTE not yet supported.  */
 
 const struct target_desc *
 get_ipa_tdesc (int idx)
 {
-  return aarch64_linux_read_description (0, false);
+  return aarch64_linux_read_description (0, false, false);
 }
 
 /* Allocate buffer for the jump pads.  The branch instruction has a reach
@@ -204,6 +204,6 @@ alloc_jump_pad_buffer (size_t size)
 void
 initialize_low_tracepoint (void)
 {
-  /* SVE and pauth not yet supported.  */
-  aarch64_linux_read_description (0, false);
+  /* SVE, pauth and MTE not yet supported.  */
+  aarch64_linux_read_description (0, false, false);
 }
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 7512aac54b..60d60a4d5c 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -642,9 +642,13 @@ aarch64_target::low_arch_setup ()
     {
       uint64_t vq = aarch64_sve_get_vq (tid);
       unsigned long hwcap = linux_get_hwcap (8);
+      unsigned long hwcap2 = linux_get_hwcap2 (8);
       bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
+      /* MTE is AArch64-only.  */
+      bool mte_p = hwcap2 & HWCAP2_MTE;
 
-      current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p);
+      current_process ()->tdesc
+	= aarch64_linux_read_description (vq, pauth_p, mte_p);
     }
   else
     current_process ()->tdesc = aarch32_linux_read_description ();
diff --git a/gdbserver/linux-aarch64-tdesc.cc b/gdbserver/linux-aarch64-tdesc.cc
index 897fbb43bd..3c5233d1fb 100644
--- a/gdbserver/linux-aarch64-tdesc.cc
+++ b/gdbserver/linux-aarch64-tdesc.cc
@@ -27,22 +27,22 @@
 #include <inttypes.h>
 
 /* All possible aarch64 target descriptors.  */
-struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/];
+struct target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/][2 /* mte */];
 
 /* Create the aarch64 target description.  */
 
 const target_desc *
-aarch64_linux_read_description (uint64_t vq, bool pauth_p)
+aarch64_linux_read_description (uint64_t vq, bool pauth_p, bool mte_p)
 {
   if (vq > AARCH64_MAX_SVE_VQ)
     error (_("VQ is %" PRIu64 ", maximum supported value is %d"), vq,
 	   AARCH64_MAX_SVE_VQ);
 
-  struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p];
+  struct target_desc *tdesc = tdesc_aarch64_list[vq][pauth_p][mte_p];
 
   if (tdesc == NULL)
     {
-      tdesc = aarch64_create_target_description (vq, pauth_p);
+      tdesc = aarch64_create_target_description (vq, pauth_p, mte_p);
 
       static const char *expedite_regs_aarch64[] = { "x29", "sp", "pc", NULL };
       static const char *expedite_regs_aarch64_sve[] = { "x29", "sp", "pc",
@@ -53,7 +53,7 @@ aarch64_linux_read_description (uint64_t vq, bool pauth_p)
       else
 	init_target_desc (tdesc, expedite_regs_aarch64_sve);
 
-      tdesc_aarch64_list[vq][pauth_p] = tdesc;
+      tdesc_aarch64_list[vq][pauth_p][mte_p] = tdesc;
     }
 
   return tdesc;
diff --git a/gdbserver/linux-aarch64-tdesc.h b/gdbserver/linux-aarch64-tdesc.h
index 0165e633d4..09d42970a9 100644
--- a/gdbserver/linux-aarch64-tdesc.h
+++ b/gdbserver/linux-aarch64-tdesc.h
@@ -20,6 +20,7 @@
 #ifndef GDBSERVER_LINUX_AARCH64_TDESC_H
 #define GDBSERVER_LINUX_AARCH64_TDESC_H
 
-const target_desc * aarch64_linux_read_description (uint64_t vq, bool pauth_p);
+const target_desc * aarch64_linux_read_description (uint64_t vq, bool pauth_p,
+						    bool mte_p);
 
 #endif /* GDBSERVER_LINUX_AARCH64_TDESC_H */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (8 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  0:17   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 11/24] AArch64: Add MTE ptrace requests Luis Machado
                   ` (14 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

AArch64 MTE support in the Linux kernel exposes a new register
through ptrace.  This patch adds the required code to support it.

include/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* elf/common.h (NT_ARM_TAGGED_ADDR_CTRL): Define.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-nat.c (fetch_mteregs_from_thread): New function.
	(store_mteregs_to_thread): New function.
	(aarch64_linux_nat_target::fetch_registers): Update to call
	fetch_mteregs_from_thread.
	(aarch64_linux_nat_target::store_registers): Update to call
	store_mteregs_to_thread.
	* aarch64-tdep.c (aarch64_mte_register_names): New struct.
	(aarch64_cannot_store_register): Handle MTE registers.
	(aarch64_gdbarch_init): Initialize and setup MTE registers.
	* aarch64-tdep.h (gdbarch_tdep) <mte_reg_base>: New field.
	<has_mte>: New method.
	* arch/aarch64-linux.h (AARCH64_LINUX_SIZEOF_MTE): Define.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* linux-aarch64-low.cc (aarch64_fill_mteregset): New function.
	(aarch64_store_mteregset): New function.
	(aarch64_regsets): Add MTE register set entry.
	(aarch64_sve_regsets): Add MTE register set entry.
---
 gdb/aarch64-linux-nat.c        | 70 ++++++++++++++++++++++++++++++++++
 gdb/aarch64-tdep.c             | 24 ++++++++++++
 gdb/aarch64-tdep.h             |  9 +++++
 gdb/arch/aarch64-mte-linux.h   |  3 ++
 gdbserver/linux-aarch64-low.cc | 29 ++++++++++++++
 include/elf/common.h           |  3 ++
 6 files changed, 138 insertions(+)

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 1392ec440c..dea34da669 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -461,6 +461,60 @@ fetch_pauth_masks_from_thread (struct regcache *regcache)
 			&pauth_regset[1]);
 }
 
+/* Fill GDB's register array with the MTE register values from
+   the current thread.  */
+
+static void
+fetch_mteregs_from_thread (struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+  int regno = tdep->mte_reg_base;
+
+  gdb_assert (regno != -1);
+
+  uint64_t tag_ctl = 0;
+  struct iovec iovec;
+
+  iovec.iov_base = &tag_ctl;
+  iovec.iov_len = sizeof (tag_ctl);
+
+  int tid = regcache->ptid ().lwp ();
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL,
+		&iovec) != 0)
+      perror_with_name (_("unable to fetch MTE registers."));
+
+  regcache->raw_supply (regno, &tag_ctl);
+}
+
+/* Store to the current thread the valid MTE register set in the GDB's
+   register array.  */
+
+static void
+store_mteregs_to_thread (struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+  int regno = tdep->mte_reg_base;
+
+  gdb_assert (regno != -1);
+
+  uint64_t tag_ctl = 0;
+
+  if (REG_VALID != regcache->get_register_status (regno))
+    return;
+
+  regcache->raw_collect (regno, (char *) &tag_ctl);
+
+  struct iovec iovec;
+
+  iovec.iov_base = &tag_ctl;
+  iovec.iov_len = sizeof (tag_ctl);
+
+  int tid = regcache->ptid ().lwp ();
+  if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL,
+	      &iovec) != 0)
+    perror_with_name (_("unable to store MTE registers."));
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
@@ -479,6 +533,9 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
 
       if (tdep->has_pauth ())
 	fetch_pauth_masks_from_thread (regcache);
+
+      if (tdep->has_mte ())
+	fetch_mteregs_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
@@ -493,6 +550,11 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
 	  || regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
 	fetch_pauth_masks_from_thread (regcache);
     }
+
+  /* Fetch individual MTE registers.  */
+  if (tdep->has_mte ()
+      && (regno == tdep->mte_reg_base))
+    fetch_mteregs_from_thread (regcache);
 }
 
 /* Implement the "store_registers" target_ops method.  */
@@ -510,6 +572,9 @@ aarch64_linux_nat_target::store_registers (struct regcache *regcache,
 	store_sveregs_to_thread (regcache);
       else
 	store_fpregs_to_thread (regcache);
+
+      if (tdep->has_mte ())
+	store_mteregs_to_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     store_gregs_to_thread (regcache);
@@ -517,6 +582,11 @@ aarch64_linux_nat_target::store_registers (struct regcache *regcache,
     store_sveregs_to_thread (regcache);
   else
     store_fpregs_to_thread (regcache);
+
+  /* Store MTE registers.  */
+  if (tdep->has_mte ()
+      && (regno == tdep->mte_reg_base))
+    store_mteregs_to_thread (regcache);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 846b0ba0f3..d76c233eed 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -176,6 +176,12 @@ static const char *const aarch64_pauth_register_names[] =
   "pauth_cmask"
 };
 
+static const char *const aarch64_mte_register_names[] =
+{
+  /* Tag Control Register.  */
+  "tag_ctl"
+};
+
 /* AArch64 prologue cache structure.  */
 struct aarch64_prologue_cache
 {
@@ -3352,6 +3358,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   bool valid_p = true;
   int i, num_regs = 0, num_pseudo_regs = 0;
   int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
+  int first_mte_regnum = -1;
 
   /* Use the vector length passed via the target info.  Here -1 is used for no
      SVE, and 0 is unset.  If unset then use the vector length from the existing
@@ -3389,6 +3396,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
   feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
   feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
+  const struct tdesc_feature *feature_mte
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte");
 
   if (feature_core == nullptr)
     return nullptr;
@@ -3459,6 +3468,20 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       num_pseudo_regs += 1;	/* Count RA_STATE pseudo register.  */
     }
 
+  /* Add the MTE registers.  */
+  if (feature_mte != NULL)
+    {
+      first_mte_regnum = num_regs;
+      /* Validate the descriptor provides the mandatory MTE registers and
+	 allocate their numbers.  */
+      for (i = 0; i < ARRAY_SIZE (aarch64_mte_register_names); i++)
+	valid_p &= tdesc_numbered_register (feature_mte, tdesc_data.get (),
+					    first_mte_regnum + i,
+					    aarch64_mte_register_names[i]);
+
+      num_regs += i;
+    }
+
   if (!valid_p)
     return nullptr;
 
@@ -3476,6 +3499,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
 				: pauth_ra_state_offset + num_regs;
+  tdep->mte_reg_base = first_mte_regnum;
 
   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 6f3299f2cb..f221c6125f 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -100,6 +100,15 @@ struct gdbarch_tdep
   {
     return pauth_reg_base != -1;
   }
+
+  /* First MTE register.  This is -1 if no MTE registers are available.  */
+  int mte_reg_base;
+
+  /* Returns true if the target supports MTE.  */
+  bool has_mte () const
+  {
+    return mte_reg_base != -1;
+  }
 };
 
 const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p,
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index c6a91c2db4..4124e80543 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -25,4 +25,7 @@
 #define HWCAP2_MTE  (1 << 18)
 #endif
 
+/* The MTE regset consists of a single 64-bit register.  */
+#define AARCH64_LINUX_SIZEOF_MTE 8
+
 #endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 60d60a4d5c..22485d9466 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -261,6 +261,29 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
 		   &pauth_regset[1]);
 }
 
+/* Fill BUF with the MTE registers from the regcache.  */
+
+static void
+aarch64_fill_mteregset (struct regcache *regcache, void *buf)
+{
+  uint64_t *mte_regset = (uint64_t *) buf;
+  int mte_base = find_regno (regcache->tdesc, "tag_ctl");
+
+  collect_register (regcache, mte_base, mte_regset);
+}
+
+/* Store the MTE registers to regcache.  */
+
+static void
+aarch64_store_mteregset (struct regcache *regcache, const void *buf)
+{
+  uint64_t *mte_regset = (uint64_t *) buf;
+  int mte_base = find_regno (regcache->tdesc, "tag_ctl");
+
+  /* Tag Control register */
+  supply_register (regcache, mte_base, mte_regset);
+}
+
 bool
 aarch64_target::low_supports_breakpoints ()
 {
@@ -684,6 +707,9 @@ static struct regset_info aarch64_regsets[] =
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
     AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
     NULL, aarch64_store_pauthregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL,
+    AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, aarch64_fill_mteregset,
+    aarch64_store_mteregset },
   NULL_REGSET
 };
 
@@ -713,6 +739,9 @@ static struct regset_info aarch64_sve_regsets[] =
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
     AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
     NULL, aarch64_store_pauthregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL,
+    AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, aarch64_fill_mteregset,
+    aarch64_store_mteregset },
   NULL_REGSET
 };
 
diff --git a/include/elf/common.h b/include/elf/common.h
index fc672de9f2..334e9e301f 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -660,6 +660,9 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARM_PAC_MASK	0x406		/* AArch pointer authentication code masks */
 					/*   note name must be "LINUX".  */
+#define NT_ARM_TAGGED_ADDR_CTRL	0x409	/* AArch64 tagged address control
+					   (prctl()) */
+					/*   note name must be "LINUX".  */
 #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
 					/*   note name must be "LINUX".  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 11/24] AArch64: Add MTE ptrace requests
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (9 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  0:19   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

This patch adds the required ptrace request definitions into a new include
file that will be used by the next patches.

They are PTRACE_PEEKMTETAGS and PTRACE_POKEMTETAGS.

gdb/ChangeLog:

YYYY-MM-DD  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.
---
 gdb/Makefile.in                    |  1 +
 gdb/nat/aarch64-mte-linux-ptrace.h | 33 ++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)
 create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4fd0c1d8e5..4f08beea44 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1497,6 +1497,7 @@ HFILES_NO_SRCDIR = \
 	nat/aarch64-linux.h \
 	nat/aarch64-linux-hw-point.h \
 	nat/aarch64-sve-linux-ptrace.h \
+	nat/aarch64-mte-linux-ptrace.h \
 	nat/amd64-linux-siginfo.h \
 	nat/gdb_ptrace.h \
 	nat/gdb_thread_db.h \
diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
new file mode 100644
index 0000000000..099b6440ca
--- /dev/null
+++ b/gdb/nat/aarch64-mte-linux-ptrace.h
@@ -0,0 +1,33 @@
+/* Common native Linux definitions for AArch64 MTE.
+
+   Copyright (C) 2018-2020 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 NAT_AARCH64_MTE_LINUX_PTRACE_H
+#define NAT_AARCH64_MTE_LINUX_PTRACE_H
+
+/* MTE allocation tag access */
+
+#ifndef PTRACE_PEEKMTETAGS
+#define PTRACE_PEEKMTETAGS	  33
+#endif
+
+#ifndef PTRACE_POKEMTETAGS
+#define PTRACE_POKEMTETAGS	  34
+#endif
+
+#endif /* NAT_AARCH64_MTE_LINUX_PTRACE_H */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (10 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 11/24] AArch64: Add MTE ptrace requests Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  0:33   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps Luis Machado
                   ` (12 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

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.
	(MTE_GRANULE_SIZE): Define.
	(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       |  34 +++++
 gdb/arch/aarch64-mte-linux.h       |  10 ++
 gdb/configure.nat                  |   3 +-
 gdb/configure.tgt                  |   1 +
 gdb/nat/aarch64-mte-linux-ptrace.c | 200 +++++++++++++++++++++++++++++
 gdb/nat/aarch64-mte-linux-ptrace.h |  17 +++
 8 files changed, 315 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 4f08beea44..452e21b2b2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -693,6 +693,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 dea34da669..4edf5a0454 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.  */
+  int fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+
+  /* Write allocation tags to memory via PTRACE.  */
+  int 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;
@@ -1050,6 +1062,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.  */
+
+int
+aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
+					 gdb::byte_vector &tags, int type)
+{
+  int tid = inferior_ptid.lwp ();
+
+  /* Allocation tags?  */
+  if (type == 1)
+    return aarch64_mte_fetch_memtags (tid, address, len, tags);
+
+  return 1;
+}
+
+/* Implement the "store_memtags" target_ops method.  */
+
+int
+aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
+					 const gdb::byte_vector &tags, int type)
+{
+  int tid = inferior_ptid.lwp ();
+
+  /* Allocation tags?  */
+  if (type == 1)
+    return aarch64_mte_store_memtags (tid, address, len, tags);
+
+  return 1;
+}
+
 /* 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 0000000000..ee162aef19
--- /dev/null
+++ b/gdb/arch/aarch64-mte-linux.c
@@ -0,0 +1,34 @@
+/* Common Linux target-dependent functionality for AArch64 MTE
+
+   Copyright (C) 2020 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
+get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
+{
+  /* 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 4124e80543..e555f0af19 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,12 @@
 /* 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 MTE_GRANULE_SIZE 16
+
+/* Return the number of tag granules in the memory range
+   [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
+extern size_t 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 ef2218f0b8..f973cc7f9b 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"
 		;;
 	    arm)
 		# Host: ARM based machine running GNU/Linux
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 6e03983874..1c7a8919db 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 0000000000..f92028176d
--- /dev/null
+++ b/gdb/nat/aarch64-mte-linux-ptrace.c
@@ -0,0 +1,200 @@
+/* Common Linux native ptrace code for AArch64 MTE.
+
+   Copyright (C) 2020 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
+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
+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)
+    {
+      t.clear ();
+      return t;
+    }
+
+  gdb_assert (tags.size () > 0 && max_size > 0);
+
+  if (granules > TAGS_MAX_SIZE)
+    t.resize (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 */
+
+int
+aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+			   gdb::byte_vector &tags)
+{
+  size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE);
+  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 1;
+	}
+
+      /* 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 * MTE_GRANULE_SIZE;
+	  iovec.iov_len = ntags - iovec.iov_len;
+	}
+    }
+  return 0;
+}
+
+/* See nat/aarch64-mte-linux-ptrace.h */
+
+int
+aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
+			   const gdb::byte_vector &tags)
+{
+  if (tags.size () == 0)
+    return 0;
+
+  /* Get the number of tags we need to write.  */
+  size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE);
+  bool done_writing = false;
+  size_t tags_written = 0;
+
+  /* Write all the tags, TAGS_MAX_SIZE blocks at a time.  */
+  while (!done_writing)
+    {
+      gdb::byte_vector t = prepare_tag_vector (ntags - tags_written, tags,
+					       tags_written, 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 1;
+
+      tags_written += iovec.iov_len;
+
+      /* Are we done writing tags?  */
+      if (tags_written == ntags)
+	done_writing = true;
+      else
+	address += iovec.iov_len * MTE_GRANULE_SIZE;
+    }
+
+  return 0;
+}
diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
index 099b6440ca..7ba6f014f6 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 TAGS_MAX_SIZE 4096
+
+/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN)
+   into TAGS.
+
+   Return 0 if successful and non-zero otherwise.  */
+extern int aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+				      gdb::byte_vector &tags);
+
+/* Write the TAGS allocation tags to the memory range
+   [ADDRESS, ADDRESS + LEN).
+
+   Return 0 if successful and non-zero otherwise.  */
+extern int 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.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (11 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  6:36   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
                   ` (11 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

The Linux kernel exposes the information about MTE-protected pages via the
proc filesystem, more specifically through the smaps file.

What we're looking for is a mapping with the 'mt' flag, which tells us that
mapping was created with a PROT_MTE flag and, thus, is capable of using memory
tagging.

We already parse that file for other purposes (core file
generation/filtering), so this patch refactors the code to make the parsing
of the smaps file reusable for memory tagging.

The function linux_address_in_memtag_page uses the refactored code to allow
querying for memory tag support in a particular address, and it gets used in the
next patch.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* linux-tdep.c (struct smaps_vmflags) <memory_tagging>: New flag
	bit.
	(struct smaps_data): New struct.
	(decode_vmflags): Handle the 'mt' flag.
	(parse_smaps_data): New function, refactored from
	linux_find_memory_regions_full.
	(linux_address_in_memtag_page): New function.
	(linux_find_memory_regions_full): Refactor into parse_smaps_data.
	* linux-tdep.h (linux_address_in_memtag_page): New prototype.
---
 gdb/linux-tdep.c | 358 +++++++++++++++++++++++++++++++----------------
 gdb/linux-tdep.h |   4 +
 2 files changed, 241 insertions(+), 121 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index bacb61398f..91bdcc133b 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -86,8 +86,33 @@ struct smaps_vmflags
     /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
 
     unsigned int shared_mapping : 1;
+
+    /* Memory map has memory tagging enabled.  */
+
+    unsigned int memory_tagging : 1;
   };
 
+/* Data structure that holds the information contained in the
+   /proc/<pid>/smaps file.  */
+
+struct smaps_data
+{
+  ULONGEST start_address;
+  ULONGEST end_address;
+  std::string filename;
+  struct smaps_vmflags vmflags;
+  bool read;
+  bool write;
+  bool exec;
+  bool priv;
+  bool has_anonymous;
+  bool mapping_anon_p;
+  bool mapping_file_p;
+
+  ULONGEST inode;
+  ULONGEST offset;
+};
+
 /* Whether to take the /proc/PID/coredump_filter into account when
    generating a corefile.  */
 
@@ -472,6 +497,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
 	v->exclude_coredump = 1;
       else if (strcmp (s, "sh") == 0)
 	v->shared_mapping = 1;
+      else if (strcmp (s, "mt") == 0)
+	v->memory_tagging = 1;
     }
 }
 
@@ -1267,6 +1294,184 @@ typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
 					const char *filename,
 					ULONGEST addr,
 					ULONGEST offset);
+/* Helper function to parse the contents of /proc/<pid>/smaps into a data
+   structure, for easy access.
+
+   DATA is the contents of the smaps file.  The parsed contents are stored
+   into the SMAPS vector.  */
+
+static int
+parse_smaps_data (const char *data,
+		  std::vector<struct smaps_data> &smaps,
+		  const char *mapsfilename)
+{
+  char *line, *t;
+
+  gdb_assert (data != nullptr);
+
+  smaps.clear ();
+
+  line = strtok_r ((char *) data, "\n", &t);
+
+  while (line != NULL)
+    {
+      ULONGEST addr, endaddr, offset, inode;
+      const char *permissions, *device, *filename;
+      struct smaps_vmflags v;
+      size_t permissions_len, device_len;
+      int read, write, exec, priv;
+      int has_anonymous = 0;
+      int mapping_anon_p;
+      int mapping_file_p;
+
+      memset (&v, 0, sizeof (v));
+      read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+		    &offset, &device, &device_len, &inode, &filename);
+      mapping_anon_p = mapping_is_anonymous_p (filename);
+      /* If the mapping is not anonymous, then we can consider it
+	 to be file-backed.  These two states (anonymous or
+	 file-backed) seem to be exclusive, but they can actually
+	 coexist.  For example, if a file-backed mapping has
+	 "Anonymous:" pages (see more below), then the Linux
+	 kernel will dump this mapping when the user specified
+	 that she only wants anonymous mappings in the corefile
+	 (*even* when she explicitly disabled the dumping of
+	 file-backed mappings).  */
+      mapping_file_p = !mapping_anon_p;
+
+      /* Decode permissions.  */
+      read = (memchr (permissions, 'r', permissions_len) != 0);
+      write = (memchr (permissions, 'w', permissions_len) != 0);
+      exec = (memchr (permissions, 'x', permissions_len) != 0);
+      /* 'private' here actually means VM_MAYSHARE, and not
+	 VM_SHARED.  In order to know if a mapping is really
+	 private or not, we must check the flag "sh" in the
+	 VmFlags field.  This is done by decode_vmflags.  However,
+	 if we are using a Linux kernel released before the commit
+	 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	 not have the VmFlags there.  In this case, there is
+	 really no way to know if we are dealing with VM_SHARED,
+	 so we just assume that VM_MAYSHARE is enough.  */
+      priv = memchr (permissions, 'p', permissions_len) != 0;
+
+      /* Try to detect if region should be dumped by parsing smaps
+	 counters.  */
+      for (line = strtok_r (NULL, "\n", &t);
+	   line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	   line = strtok_r (NULL, "\n", &t))
+	{
+	  char keyword[64 + 1];
+
+	  if (sscanf (line, "%64s", keyword) != 1)
+	    {
+	      warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
+	      break;
+	    }
+
+	  if (strcmp (keyword, "Anonymous:") == 0)
+	    {
+	      /* Older Linux kernels did not support the
+		 "Anonymous:" counter.  Check it here.  */
+	      has_anonymous = 1;
+	    }
+	  else if (strcmp (keyword, "VmFlags:") == 0)
+	    decode_vmflags (line, &v);
+
+	  if (strcmp (keyword, "AnonHugePages:") == 0
+	      || strcmp (keyword, "Anonymous:") == 0)
+	    {
+	      unsigned long number;
+
+	      if (sscanf (line, "%*s%lu", &number) != 1)
+		{
+		  warning (_("Error parsing {s,}maps file '%s' number"),
+			   mapsfilename);
+		  break;
+		}
+	      if (number > 0)
+		{
+		  /* Even if we are dealing with a file-backed
+		     mapping, if it contains anonymous pages we
+		     consider it to be *also* an anonymous
+		     mapping, because this is what the Linux
+		     kernel does:
+
+		     // Dump segments that have been written to.
+		     if (vma->anon_vma && FILTER(ANON_PRIVATE))
+		       goto whole;
+
+		    Note that if the mapping is already marked as
+		    file-backed (i.e., mapping_file_p is
+		    non-zero), then this is a special case, and
+		    this mapping will be dumped either when the
+		    user wants to dump file-backed *or* anonymous
+		    mappings.  */
+		  mapping_anon_p = 1;
+		}
+	    }
+	}
+      /* Save the smaps entry to the vector.  */
+	struct smaps_data map;
+	std::string fname (filename);
+
+	map.start_address = addr;
+	map.end_address = endaddr;
+	map.filename = fname;
+	map.vmflags = v;
+	map.read = read? true : false;
+	map.write = write? true : false;
+	map.exec = exec? true : false;
+	map.priv = priv? true : false;
+	map.has_anonymous = has_anonymous;
+	map.mapping_anon_p = mapping_anon_p? true : false;
+	map.mapping_file_p = mapping_file_p? true : false;
+	map.offset = offset;
+	map.inode = inode;
+
+	smaps.emplace_back (map);
+    }
+
+  return 0;
+}
+
+/* See linux-tdep.h.  */
+
+bool
+linux_address_in_memtag_page (CORE_ADDR address)
+{
+  if (current_inferior ()->fake_pid_p)
+    return false;
+
+  pid_t pid = current_inferior ()->pid;
+
+  std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
+
+  gdb::unique_xmalloc_ptr<char> data
+    = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
+
+  if (data == nullptr)
+    return false;
+
+  std::vector<struct smaps_data> smaps;
+
+  /* Parse the contents of smaps into a vector.  */
+  parse_smaps_data (data.get (), smaps, smaps_file.c_str ());
+
+  if (!smaps.empty ())
+    {
+      for (struct smaps_data map : smaps)
+	{
+	  /* 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;
+	}
+    }
+
+  return false;
+}
 
 /* List memory regions in the inferior for a corefile.  */
 
@@ -1276,8 +1481,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				linux_find_memory_region_ftype *func,
 				void *obfd)
 {
-  char mapsfilename[100];
-  char coredumpfilter_name[100];
+  std::string coredumpfilter_name;
   pid_t pid;
   /* Default dump behavior of coredump_filter (0x33), according to
      Documentation/filesystems/proc.txt from the Linux kernel
@@ -1295,10 +1499,9 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 
   if (use_coredump_filter)
     {
-      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
-		 "/proc/%d/coredump_filter", pid);
+      coredumpfilter_name = string_printf ("/proc/%d/coredump_filter", pid);
       gdb::unique_xmalloc_ptr<char> coredumpfilterdata
-	= target_fileio_read_stralloc (NULL, coredumpfilter_name);
+	= target_fileio_read_stralloc (NULL, coredumpfilter_name.c_str ());
       if (coredumpfilterdata != NULL)
 	{
 	  unsigned int flags;
@@ -1308,125 +1511,39 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 	}
     }
 
-  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
+  std::string mapsfilename = string_printf ("/proc/%d/smaps", pid);
   gdb::unique_xmalloc_ptr<char> data
-    = target_fileio_read_stralloc (NULL, mapsfilename);
+    = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
   if (data == NULL)
     {
       /* Older Linux kernels did not support /proc/PID/smaps.  */
-      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
-      data = target_fileio_read_stralloc (NULL, mapsfilename);
+      mapsfilename = string_printf ("/proc/%d/maps", pid);
+      data = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
     }
 
-  if (data != NULL)
-    {
-      char *line, *t;
-
-      line = strtok_r (data.get (), "\n", &t);
-      while (line != NULL)
-	{
-	  ULONGEST addr, endaddr, offset, inode;
-	  const char *permissions, *device, *filename;
-	  struct smaps_vmflags v;
-	  size_t permissions_len, device_len;
-	  int read, write, exec, priv;
-	  int has_anonymous = 0;
-	  int should_dump_p = 0;
-	  int mapping_anon_p;
-	  int mapping_file_p;
-
-	  memset (&v, 0, sizeof (v));
-	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
-			&offset, &device, &device_len, &inode, &filename);
-	  mapping_anon_p = mapping_is_anonymous_p (filename);
-	  /* If the mapping is not anonymous, then we can consider it
-	     to be file-backed.  These two states (anonymous or
-	     file-backed) seem to be exclusive, but they can actually
-	     coexist.  For example, if a file-backed mapping has
-	     "Anonymous:" pages (see more below), then the Linux
-	     kernel will dump this mapping when the user specified
-	     that she only wants anonymous mappings in the corefile
-	     (*even* when she explicitly disabled the dumping of
-	     file-backed mappings).  */
-	  mapping_file_p = !mapping_anon_p;
-
-	  /* Decode permissions.  */
-	  read = (memchr (permissions, 'r', permissions_len) != 0);
-	  write = (memchr (permissions, 'w', permissions_len) != 0);
-	  exec = (memchr (permissions, 'x', permissions_len) != 0);
-	  /* 'private' here actually means VM_MAYSHARE, and not
-	     VM_SHARED.  In order to know if a mapping is really
-	     private or not, we must check the flag "sh" in the
-	     VmFlags field.  This is done by decode_vmflags.  However,
-	     if we are using a Linux kernel released before the commit
-	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
-	     not have the VmFlags there.  In this case, there is
-	     really no way to know if we are dealing with VM_SHARED,
-	     so we just assume that VM_MAYSHARE is enough.  */
-	  priv = memchr (permissions, 'p', permissions_len) != 0;
-
-	  /* Try to detect if region should be dumped by parsing smaps
-	     counters.  */
-	  for (line = strtok_r (NULL, "\n", &t);
-	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
-	       line = strtok_r (NULL, "\n", &t))
-	    {
-	      char keyword[64 + 1];
+  if (data == nullptr)
+    return 1;
 
-	      if (sscanf (line, "%64s", keyword) != 1)
-		{
-		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
-		  break;
-		}
+  std::vector<struct smaps_data> smaps;
 
-	      if (strcmp (keyword, "Anonymous:") == 0)
-		{
-		  /* Older Linux kernels did not support the
-		     "Anonymous:" counter.  Check it here.  */
-		  has_anonymous = 1;
-		}
-	      else if (strcmp (keyword, "VmFlags:") == 0)
-		decode_vmflags (line, &v);
+  /* Parse the contents of smaps into a vector.  */
+  parse_smaps_data (data.get (), smaps, mapsfilename.c_str ());
 
-	      if (strcmp (keyword, "AnonHugePages:") == 0
-		  || strcmp (keyword, "Anonymous:") == 0)
-		{
-		  unsigned long number;
-
-		  if (sscanf (line, "%*s%lu", &number) != 1)
-		    {
-		      warning (_("Error parsing {s,}maps file '%s' number"),
-			       mapsfilename);
-		      break;
-		    }
-		  if (number > 0)
-		    {
-		      /* Even if we are dealing with a file-backed
-			 mapping, if it contains anonymous pages we
-			 consider it to be *also* an anonymous
-			 mapping, because this is what the Linux
-			 kernel does:
-
-			 // Dump segments that have been written to.
-			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
-			 	goto whole;
-
-			 Note that if the mapping is already marked as
-			 file-backed (i.e., mapping_file_p is
-			 non-zero), then this is a special case, and
-			 this mapping will be dumped either when the
-			 user wants to dump file-backed *or* anonymous
-			 mappings.  */
-		      mapping_anon_p = 1;
-		    }
-		}
-	    }
+  if (!smaps.empty ())
+    {
+      for (struct smaps_data map : smaps)
+	{
+	  int should_dump_p = 0;
 
-	  if (has_anonymous)
-	    should_dump_p = should_dump_mapping_p (filterflags, &v, priv,
-						   mapping_anon_p,
-						   mapping_file_p,
-						   filename, addr, offset);
+	  if (map.has_anonymous)
+	    should_dump_p
+	      = should_dump_mapping_p (filterflags, &map.vmflags,
+				       map.priv,
+				       map.mapping_anon_p,
+				       map.mapping_file_p,
+				       map.filename.c_str (),
+				       map.start_address,
+				       map.offset);
 	  else
 	    {
 	      /* Older Linux kernels did not support the "Anonymous:" counter.
@@ -1436,16 +1553,15 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 
 	  /* Invoke the callback function to create the corefile segment.  */
 	  if (should_dump_p)
-	    func (addr, endaddr - addr, offset, inode,
-		  read, write, exec, 1, /* MODIFIED is true because we
-					   want to dump the mapping.  */
-		  filename, obfd);
+	    func (map.start_address, map.end_address - map.start_address,
+		  map.offset, map.inode, map.read, map.write, map.exec,
+		  1, /* MODIFIED is true because we want to dump
+			the mapping.  */
+		  map.filename.c_str (), obfd);
 	}
-
-      return 0;
     }
 
-  return 1;
+  return 0;
 }
 
 /* A structure for passing information through
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 91c28738f5..32c9c03835 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -41,6 +41,10 @@ DEF_ENUM_FLAGS_TYPE (enum linux_siginfo_extra_field_values,
 struct type *linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch,
 						 linux_siginfo_extra_fields);
 
+ /* Return true if ADDRESS is within the boundaries of a page mapped with
+   memory tagging protection.  */
+bool linux_address_in_memtag_page (CORE_ADDR address);
+
 typedef char *(*linux_collect_thread_registers_ftype) (const struct regcache *,
 						       ptid_t,
 						       bfd *, char *, int *,
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (12 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26  6:52   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 15/24] AArch64: Add unit testing for logical tag set/get operations Luis Machado
                   ` (10 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v2:

- Update target methods to contain a tag type parameter.

--

This patch implements the memory tagging gdbarch hooks for AArch64, for
the MTE feature.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-tdep.c: Include target.h, arch-utils.h, value.h.
	(aarch64_linux_get_atag, aarch64_linux_tagged_address_p)
	(aarch64_linux_memtag_mismatch_p, aarch64_linux_set_memtags)
	(aarch64_linux_get_memtag, aarch64_linux_memtag_to_string): New
	functions.
	(aarch64_linux_init_abi): Initialize MTE-related gdbarch hooks.
	* arch/aarch64-mte-linux.c (make_ltag_bits, make_ltag)
	(aarch64_linux_set_ltag, aarch64_linux_get_ltag): New functions.
	* arch/aarch64-mte-linux.h (MTE_LOGICAL_TAG_START_BIT)
	(MTE_LOGICAL_MAX_VALUE): Define.
	(make_ltag_bits, make_ltag, aarch64_linux_set_ltag)
	(aarch64_linux_get_ltag): New prototype.
---
 gdb/aarch64-linux-tdep.c     | 212 +++++++++++++++++++++++++++++++++++
 gdb/arch/aarch64-mte-linux.c |  36 ++++++
 gdb/arch/aarch64-mte-linux.h |  19 ++++
 3 files changed, 267 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 5f6fb42792..00c4f45035 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -30,6 +30,7 @@
 #include "symtab.h"
 #include "tramp-frame.h"
 #include "trad-frame.h"
+#include "target.h"
 #include "target/target.h"
 
 #include "regcache.h"
@@ -46,6 +47,9 @@
 
 #include "arch/aarch64-mte-linux.h"
 
+#include "arch-utils.h"
+#include "value.h"
+
 /* Signal frame handling.
 
       +------------+  ^
@@ -1437,6 +1441,189 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
   return {};
 }
 
+/* Helper to get the allocation tag from a 64-bit ADDRESS.
+
+   Return 0 for success and non-zero otherwise.  */
+
+static int
+aarch64_linux_get_atag (CORE_ADDR address, CORE_ADDR *tag)
+{
+  gdb::byte_vector tags;
+
+  /* Attempt to fetch the allocation tag.  */
+  if (target_fetch_memtags (address, 0, tags, tag_allocation) != 0)
+    return 1;
+
+  /* Only one tag should've been returned.  Make sure we got exactly that.  */
+  gdb_assert (tags.size () == 1);
+
+  /* Although our tags are 4 bits in size, they are stored in a
+     byte.  */
+  *tag = tags[0];
+
+  return 0;
+}
+
+/* Implement the tagged_address_p gdbarch method.  */
+
+static bool
+aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, struct value *address)
+{
+  gdb_assert (address != nullptr);
+
+  CORE_ADDR addr = value_as_address (address);
+
+  /* Remove the top byte for the memory range check.  */
+  addr = address_significant (gdbarch, addr);
+
+  /* Check if the page that contains ADDRESS is mapped with PROT_MTE.  */
+  if (!linux_address_in_memtag_page (addr))
+    return false;
+
+  /* We have a valid tag in the top byte of the 64-bit address.  */
+  return true;
+}
+
+/* Implement the memtag_mismatch_p gdbarch method.  */
+
+static bool
+aarch64_linux_memtag_mismatch_p (struct gdbarch *gdbarch,
+				 struct value *address)
+{
+  gdb_assert (address != nullptr);
+
+  /* Make sure we are dealing with a tagged address to begin with.  */
+  if (!aarch64_linux_tagged_address_p (gdbarch, address))
+    return false;
+
+  CORE_ADDR addr = value_as_address (address);
+
+  /* Fetch the allocation tag for ADDRESS.  */
+  CORE_ADDR atag = 0;
+
+  if (aarch64_linux_get_atag (addr, &atag) != 0)
+    return false;
+
+  /* Fetch the logical tag for ADDRESS.  */
+  gdb_byte ltag = aarch64_linux_get_ltag (addr);
+
+  /* Are the tags the same?  */
+  if (ltag == atag)
+    return false;
+
+  return true;
+}
+
+/* Implement the set_memtags gdbarch method.  */
+
+static int
+aarch64_linux_set_memtags (struct gdbarch *gdbarch, struct value *address,
+			   size_t length, const gdb::byte_vector &tags,
+			   enum memtag_type tag_type)
+{
+  if (tags.empty ())
+    return 0;
+
+  gdb_assert (address != nullptr);
+
+  CORE_ADDR addr = value_as_address (address);
+
+  /* Set the logical tag or the allocation tag.  */
+  if (tag_type == tag_logical)
+    {
+      /* When setting logical tags, we don't care about the length, since
+	 we are only setting a single logical tag.  */
+      addr = aarch64_linux_set_ltag (addr, tags[0]);
+
+      /* Update the value's content with the tag.  */
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      gdb_byte *srcbuf = value_contents_raw (address);
+      store_unsigned_integer (srcbuf, sizeof (addr), byte_order, addr);
+    }
+  else
+    {
+      /* Make sure we are dealing with a tagged address to begin with.  */
+      if (!aarch64_linux_tagged_address_p (gdbarch, address))
+	return 1;
+
+      /* With G being the number of tag granules and N the number of tags
+	 passed in, we can have the following cases:
+
+	 1 - G == N: Store all the N tags to memory.
+
+	 2 - G < N : Warn about having more tags than granules, but write G
+		     tags.
+
+	 3 - G > N : This is a "fill tags" operation.  We should use the tags
+		     as a pattern to fill the granules repeatedly until we have
+		     written G tags to memory.
+      */
+
+      size_t g = get_tag_granules (addr, length, MTE_GRANULE_SIZE);
+      size_t n = tags.size ();
+
+      if (g < n)
+	{
+	  warning (_("Got more tags than memory granules.  Tags will be "
+		     "truncated."));
+	}
+      else if (g > n)
+	warning (_("Using tag pattern to fill memory range."));
+
+      if (target_store_memtags (addr, length, tags, tag_allocation) != 0)
+	return 1;
+    }
+  return 0;
+}
+
+/* Implement the get_memtag gdbarch method.  */
+
+static struct value *
+aarch64_linux_get_memtag (struct gdbarch *gdbarch, struct value *address,
+			  enum memtag_type tag_type)
+{
+  gdb_assert (address != nullptr);
+
+  CORE_ADDR addr = value_as_address (address);
+  CORE_ADDR tag = 0;
+
+  /* Get the logical tag or the allocation tag.  */
+  if (tag_type == tag_logical)
+    tag = aarch64_linux_get_ltag (addr);
+  else
+    {
+      /* Make sure we are dealing with a tagged address to begin with.  */
+      if (!aarch64_linux_tagged_address_p (gdbarch, address))
+	return nullptr;
+
+      if (aarch64_linux_get_atag (addr, &tag) != 0)
+	return nullptr;
+    }
+
+  /* Convert the tag to a value.  */
+  return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
+			      tag);
+}
+
+/* Implement the memtag_to_string gdbarch method.  */
+
+static std::string
+aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
+				struct value *address,
+				enum memtag_type tag_type)
+{
+  gdb_assert (address != nullptr);
+
+  struct value *v_tag = aarch64_linux_get_memtag (gdbarch, address, tag_type);
+
+  if (v_tag == nullptr && tag_allocation)
+    error (_("Error getting tag from target"));
+
+  CORE_ADDR tag = value_as_address (v_tag);
+
+  return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1494,6 +1681,31 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
      data associated with the address.  */
   set_gdbarch_significant_addr_bit (gdbarch, 56);
 
+  /* MTE-specific settings and hooks.  */
+  if (tdep->has_mte ())
+    {
+      /* Register a hook for checking if an address is tagged or not.  */
+      set_gdbarch_tagged_address_p (gdbarch, aarch64_linux_tagged_address_p);
+
+      /* Register a hook for checking if there is a memory tag mismatch.  */
+      set_gdbarch_memtag_mismatch_p (gdbarch,
+				     aarch64_linux_memtag_mismatch_p);
+
+      /* Register a hook for setting the logical/allocation tags for
+	 a range of addresses.  */
+      set_gdbarch_set_memtags (gdbarch, aarch64_linux_set_memtags);
+
+      /* Register a hook for extracting the logical/allocation tag from an
+	 address.  */
+      set_gdbarch_get_memtag (gdbarch, aarch64_linux_get_memtag);
+
+      /* Set the allocation tag granule size to 16 bytes.  */
+      set_gdbarch_memtag_granule_size (gdbarch, MTE_GRANULE_SIZE);
+
+      /* Register a hook for converting a memory tag to a string.  */
+      set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
+    }
+
   /* Initialize the aarch64_linux_record_tdep.  */
   /* These values are the size of the type that will be used in a system
      call.  They are obtained from Linux Kernel source.  */
diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
index ee162aef19..5c02e5ef5b 100644
--- a/gdb/arch/aarch64-mte-linux.c
+++ b/gdb/arch/aarch64-mte-linux.c
@@ -32,3 +32,39 @@ get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
   /* We always have at least 1 granule.  */
   return 1 + (e_addr - s_addr) / granule_size;
 }
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+make_ltag_bits (CORE_ADDR value)
+{
+  return value & MTE_LOGICAL_MAX_VALUE;
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+make_ltag (CORE_ADDR value)
+{
+  return make_ltag_bits (value) << MTE_LOGICAL_TAG_START_BIT;
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+aarch64_linux_set_ltag (CORE_ADDR address, CORE_ADDR tag)
+{
+  /* Remove the existing tag.  */
+  address &= ~make_ltag (MTE_LOGICAL_MAX_VALUE);
+
+  /* Return the new tagged address.  */
+  return address | make_ltag (tag);
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+aarch64_linux_get_ltag (CORE_ADDR address)
+{
+  return make_ltag_bits (address >> MTE_LOGICAL_TAG_START_BIT);
+}
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index e555f0af19..5c5783f28b 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -32,10 +32,29 @@
 
 /* We have one tag per 16 bytes of memory.  */
 #define MTE_GRANULE_SIZE 16
+#define MTE_LOGICAL_TAG_START_BIT   56
+#define MTE_LOGICAL_MAX_VALUE	    0xf
 
 /* Return the number of tag granules in the memory range
    [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
 extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
 				size_t granule_size);
 
+/* Return the 4-bit tag made from VALUE.  */
+extern CORE_ADDR make_ltag_bits (CORE_ADDR value);
+
+/* Return the 4-bit tag that can be OR-ed to an address.  */
+extern CORE_ADDR make_ltag (CORE_ADDR value);
+
+/* Helper to set the logical TAG for a 64-bit ADDRESS.
+
+   It is always possible to set the logical tag.  */
+extern CORE_ADDR aarch64_linux_set_ltag (CORE_ADDR address,
+					 CORE_ADDR tag);
+
+/* Helper to get the logical tag from a 64-bit ADDRESS.
+
+   It is always possible to get the logical tag.  */
+extern CORE_ADDR aarch64_linux_get_ltag (CORE_ADDR address);
+
 #endif /* ARCH_AARCH64_LINUX_H */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 15/24] AArch64: Add unit testing for logical tag set/get operations
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (13 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:04 ` [PATCH v3 16/24] AArch64: Report tag violation error information Luis Machado
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Add some unit testing to exercise setting/getting logical tags in the
AArch64 implementation.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-tdep.c: Include gdbsupport/selftest.h.
	(aarch64_linux_ltag_tests): New function.
	(_initialize_aarch64_linux_tdep): Register aarch64_linux_ltag_tests.
---
 gdb/aarch64-linux-tdep.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 00c4f45035..39b1790263 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -50,6 +50,8 @@
 #include "arch-utils.h"
 #include "value.h"
 
+#include "gdbsupport/selftest.h"
+
 /* Signal frame handling.
 
       +------------+  ^
@@ -1882,10 +1884,39 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_gcc_target_options (gdbarch, aarch64_linux_gcc_target_options);
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Verify functions to read and write logical tags.  */
+
+static void
+aarch64_linux_ltag_tests (void)
+{
+  /* We have 4 bits of tags, but we test writing all the bits of the top
+     byte of address.  */
+  for (int i = 0; i < 1 << 8; i++)
+    {
+      CORE_ADDR addr = ((CORE_ADDR) i << 56) | 0xdeadbeef;
+      SELF_CHECK (aarch64_linux_get_ltag (addr) == (i & 0xf));
+
+      addr = aarch64_linux_set_ltag (0xdeadbeef, i);
+      SELF_CHECK (addr = ((CORE_ADDR) (i & 0xf) << 56) | 0xdeadbeef);
+    }
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 void _initialize_aarch64_linux_tdep ();
 void
 _initialize_aarch64_linux_tdep ()
 {
   gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
 			  aarch64_linux_init_abi);
+
+#if GDB_SELF_TEST
+  selftests::register_test ("aarch64-linux-tagged-address",
+			    selftests::aarch64_linux_ltag_tests);
+#endif
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (14 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 15/24] AArch64: Add unit testing for logical tag set/get operations Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-16 15:43   ` David Spickett
  2020-12-26 22:23   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 17/24] AArch64: Add gdbserver MTE support Luis Machado
                   ` (8 subsequent siblings)
  24 siblings, 2 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
information can be obtained through the siginfo data structure.

For AArch64 the Linux kernel may expose the fault address and tag
information, if we have a synchronous event. Otherwise there is
no fault address available.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-tdep.c
	(aarch64_linux_report_signal_info): New function.
	(aarch64_linux_init_abi): Register
	aarch64_linux_report_signal_info as the report_signal_info hook.
	* arch/aarch64-linux.h (SEGV_MTEAERR): Define.
	(SEGV_MTESERR): Define.
---
 gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
 gdb/arch/aarch64-mte-linux.h |  6 ++++
 2 files changed, 70 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 39b1790263..70e180e1cb 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
   return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
 }
 
+/* AArch64 Linux implementation of the report_signal_info gdbarch
+   hook.  Displays information about possible memory tag violations.  */
+
+static void
+aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
+				  struct ui_out *uiout,
+				  enum gdb_signal siggnal)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
+    return;
+
+  CORE_ADDR fault_addr = 0;
+  long si_code = 0;
+
+  try
+    {
+      /* Sigcode tells us if the segfault is actually a memory tag
+	 violation.  */
+      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
+
+      fault_addr
+	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
+    }
+  catch (const gdb_exception &exception)
+    {
+      return;
+    }
+
+  /* If this is not a memory tag violation, just return.  */
+  if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR)
+    return;
+
+  uiout->text ("\n");
+
+  uiout->field_string ("sigcode-meaning", _("Memory tag violation"));
+
+  /* For synchronous faults, show additional information.  */
+  if (si_code == SEGV_MTESERR)
+    {
+      uiout->text (_(" while accessing address "));
+      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
+      uiout->text ("\n");
+
+      CORE_ADDR atag;
+      if (aarch64_linux_get_atag (fault_addr, &atag) != 0)
+	uiout->text (_("Allocation tag unavailable"));
+      else
+	{
+	  uiout->text (_("Allocation tag "));
+	  uiout->field_core_addr ("allocation-tag", gdbarch, atag);
+	}
+    }
+  else
+    {
+      uiout->text ("\n");
+      uiout->text (_("Fault address unavailable"));
+    }
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1706,6 +1767,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
       /* Register a hook for converting a memory tag to a string.  */
       set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
+
+      set_gdbarch_report_signal_info (gdbarch,
+				      aarch64_linux_report_signal_info);
     }
 
   /* Initialize the aarch64_linux_record_tdep.  */
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index 5c5783f28b..a5a980ed49 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -35,6 +35,12 @@
 #define MTE_LOGICAL_TAG_START_BIT   56
 #define MTE_LOGICAL_MAX_VALUE	    0xf
 
+/* Memory tagging definitions.  */
+#ifndef SEGV_MTEAERR
+# define SEGV_MTEAERR 8
+# define SEGV_MTESERR 9
+#endif
+
 /* Return the number of tag granules in the memory range
    [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
 extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 17/24] AArch64: Add gdbserver MTE support
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (15 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 16/24] AArch64: Report tag violation error information Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-26 22:30   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 18/24] AArch64: Add MTE register set support for core files Luis Machado
                   ` (7 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Updates on v2:

- Updated target methods to contain a tag type parameter.

--

Adds the AArch64-specific memory tagging support (MTE) by implementing the
required hooks and checks for GDBserver.

gdbserver/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* Makefile.in (SFILES): Add /../gdb/nat/aarch64-mte-linux-ptrace.c.
	* configure.srv (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o and
	nat/aarch64-mte-linux-ptrace.o.
	* linux-aarch64-low.cc: Include nat/aarch64-mte-linux-ptrace.h.
	(class aarch64_target) <supports_memory_tagging>
	<fetch_memtags, store_memtags>: New method overrides.
	(aarch64_target::supports_memory_tagging)
	(aarch64_target::fetch_memtags)
	(aarch64_target::store_memtags): New methods.
---
 gdbserver/Makefile.in          |  1 +
 gdbserver/configure.srv        |  2 ++
 gdbserver/linux-aarch64-low.cc | 61 ++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
index 1969ed0ec3..45b605c3b5 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -221,6 +221,7 @@ SFILES = \
 	$(srcdir)/../gdb/arch/ppc-linux-common.c \
 	$(srcdir)/../gdb/arch/riscv.c \
 	$(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \
+	$(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \
 	$(srcdir)/../gdb/nat/linux-btrace.c \
 	$(srcdir)/../gdb/nat/linux-namespaces.c \
 	$(srcdir)/../gdb/nat/linux-osdata.c \
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 833ad27c4c..0bbd990758 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -52,8 +52,10 @@ case "${gdbserver_host}" in
 			srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o"
 			srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o"
 			srv_tgtobj="$srv_tgtobj arch/aarch64.o"
+			srv_tgtobj="$srv_tgtobj arch/aarch64-mte-linux.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o"
 			srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o"
+			srv_tgtobj="$srv_tgtobj nat/aarch64-mte-linux-ptrace.o"
 			srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 22485d9466..2c6de1903b 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -44,12 +44,17 @@
 #include "linux-aarch32-tdesc.h"
 #include "linux-aarch64-tdesc.h"
 #include "nat/aarch64-sve-linux-ptrace.h"
+#include "nat/aarch64-mte-linux-ptrace.h"
 #include "tdesc.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
 
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
 /* Linux target op definitions for the AArch64 architecture.  */
 
 class aarch64_target : public linux_process_target
@@ -82,6 +87,14 @@ public:
 
   struct emit_ops *emit_ops () override;
 
+  bool supports_memory_tagging () override;
+
+  int fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+
+  int store_memtags (CORE_ADDR address, size_t len,
+		     const gdb::byte_vector &tags, int type) override;
+
 protected:
 
   void low_arch_setup () override;
@@ -3201,6 +3214,54 @@ aarch64_target::breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
     return arm_breakpoint_kind_from_current_state (pcptr);
 }
 
+/* Returns true if memory tagging is supported.  */
+bool
+aarch64_target::supports_memory_tagging ()
+{
+  if (current_thread == NULL)
+    {
+      /* We don't have any processes running, so don't attempt to
+	 use linux_get_hwcap2 as it will try to fetch the current
+	 thread id.  Instead, just fetch the auxv from the self
+	 PID.  */
+#ifdef HAVE_GETAUXVAL
+      return (getauxval (AT_HWCAP2) & HWCAP2_MTE) != 0;
+#else
+      return true;
+#endif
+    }
+
+  return (linux_get_hwcap2 (8) & HWCAP2_MTE) != 0;
+}
+
+int
+aarch64_target::fetch_memtags (CORE_ADDR address, size_t len,
+			       gdb::byte_vector &tags, int type)
+{
+  /* Allocation tags are per-process, so any tid is fine.  */
+  int tid = lwpid_of (current_thread);
+
+  /* Allocation tag?  */
+  if (type == 1)
+    return aarch64_mte_fetch_memtags (tid, address, len, tags);
+
+  return 1;
+}
+
+int
+aarch64_target::store_memtags (CORE_ADDR address, size_t len,
+			       const gdb::byte_vector &tags, int type)
+{
+  /* Allocation tags are per-process, so any tid is fine.  */
+  int tid = lwpid_of (current_thread);
+
+  /* Allocation tag?  */
+  if (type == 1)
+    return aarch64_mte_store_memtags (tid, address, len, tags);
+
+  return 1;
+}
+
 /* The linux target ops object.  */
 
 linux_process_target *the_linux_target = &the_aarch64_target;
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 18/24] AArch64: Add MTE register set support for core files
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (16 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 17/24] AArch64: Add gdbserver MTE support Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:04 ` [PATCH v3 19/24] New mtag commands Luis Machado
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

This patch handles the tagged_addr_ctrl register that is exported when
generating a core file.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-tdep.c
	(aarch64_linux_iterate_over_regset_sections): Handle MTE register set.
	* aarch64-linux-tdep.h (AARCH64_LINUX_SIZEOF_MTE_REGSET): Define.
---
 gdb/aarch64-linux-tdep.c | 20 ++++++++++++++++++++
 gdb/aarch64-linux-tdep.h |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 70e180e1cb..4f27f5551d 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -651,6 +651,26 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  AARCH64_LINUX_SIZEOF_PAUTH, &aarch64_linux_pauth_regset,
 	  "pauth registers", cb_data);
     }
+
+  /* Handle MTE registers.  */
+  if (tdep->has_mte ())
+    {
+      /* Create this on the fly in order to handle the variable location.  */
+      const struct regcache_map_entry mte_regmap[] =
+	{
+	  { 1, tdep->mte_reg_base, 4},
+	  { 0 }
+	};
+
+      const struct regset aarch64_linux_mte_regset =
+	{
+	  mte_regmap, regcache_supply_regset, regcache_collect_regset
+	};
+
+      cb (".reg-aarch-mte", AARCH64_LINUX_SIZEOF_MTE_REGSET,
+	  AARCH64_LINUX_SIZEOF_MTE_REGSET, &aarch64_linux_mte_regset,
+	  "MTE registers", cb_data);
+    }
 }
 
 /* Implement the "core_read_description" gdbarch method.  */
diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
index a7094bb7c0..2495379d5b 100644
--- a/gdb/aarch64-linux-tdep.h
+++ b/gdb/aarch64-linux-tdep.h
@@ -36,6 +36,9 @@
 /* The pauth regset consists of 2 X sized registers.  */
 #define AARCH64_LINUX_SIZEOF_PAUTH (2 * X_REGISTER_SIZE)
 
+/* The MTE regset consists of a 32-bit register.  */
+#define AARCH64_LINUX_SIZEOF_MTE_REGSET (4)
+
 extern const struct regset aarch64_linux_gregset;
 extern const struct regset aarch64_linux_fpregset;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 19/24] New mtag commands
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (17 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 18/24] AArch64: Add MTE register set support for core files Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-12-27  3:32   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 20/24] Documentation for the new " Luis Machado
                   ` (5 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Add new commands under the "mtag" prefix to allow users to inspect, modify and
check memory tags in different ways.

The available subcommands are the following:

- mtag showltag <expression>: Shows the logical tag for a particular address.

- mtag withltag <expression> <tag>: Prints the address tagged with the logical
  tag <tag>.

- mtag showatag <expression>: Shows the allocation tag for a particular address.

- mtag setatag <expression> <length> <tags>: Sets one or more allocation tags to
  the specified tags.

- mtag check <expression>: Check if the logical tag in <address> matches its
  allocation tag.

These commands make use of the memory tagging gdbarch methods, and are still
available, but disabled, when memory tagging is not supported by the
architecture.

I've pondered about a way to make these commands invisible when memory tagging
is not available, but given the check is at runtime (and support may come and go
based on a process' configuration), that is a bit too late in the process to
either not include the commands or get rid of them.

Ideas are welcome.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* printcmd.c: Include gdbsupport/rsp-low.h.
	(mtaglist): New static global.
	(process_print_command_args): Factored out of
	print_command_1.
	(print_command_1): Use process_print_command_args.
	(show_addr_not_tagged, show_memtag_unsupported, mtag_command)
	(mtag_showtag_command, mtag_showltag_command, mtag_showatag_command)
	(parse_withltag_input, mtag_withltag_command, parse_setatag_input)
	(mtag_setatag_command, mtag_check_command): New functions.
	(_initialize_printcmd): Add "mtag" prefix and subcommands.

gdbsupport/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* rsp-low.cc (fromhex): Change error message text to not be
	RSP-specific.
---
 gdb/printcmd.c        | 359 ++++++++++++++++++++++++++++++++++++++++--
 gdbsupport/rsp-low.cc |   2 +-
 2 files changed, 348 insertions(+), 13 deletions(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 28451612ab..6949678235 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -53,6 +53,11 @@
 #include "source.h"
 #include "gdbsupport/byte-vector.h"
 #include "gdbsupport/gdb_optional.h"
+#include "gdbsupport/rsp-low.h"
+
+/* Chain containing all defined mtag subcommands.  */
+
+struct cmd_list_element *mtaglist;
 
 /* Last specified output format.  */
 
@@ -1219,31 +1224,38 @@ print_value (value *val, const value_print_options &opts)
   annotate_value_history_end ();
 }
 
-/* Implementation of the "print" and "call" commands.  */
+/* Helper for parsing arguments for print_command_1.  */
 
-static void
-print_command_1 (const char *args, int voidprint)
+static struct value *
+process_print_command_args (const char *args, value_print_options *print_opts)
 {
-  struct value *val;
-  value_print_options print_opts;
-
-  get_user_print_options (&print_opts);
+  get_user_print_options (print_opts);
   /* Override global settings with explicit options, if any.  */
-  auto group = make_value_print_options_def_group (&print_opts);
+  auto group = make_value_print_options_def_group (print_opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group);
 
-  print_command_parse_format (&args, "print", &print_opts);
+  print_command_parse_format (&args, "print", print_opts);
 
   const char *exp = args;
 
   if (exp != nullptr && *exp)
     {
       expression_up expr = parse_expression (exp);
-      val = evaluate_expression (expr.get ());
+      return evaluate_expression (expr.get ());
     }
-  else
-    val = access_value_history (0);
+
+  return access_value_history (0);
+}
+
+/* Implementation of the "print" and "call" commands.  */
+
+static void
+print_command_1 (const char *args, int voidprint)
+{
+  value_print_options print_opts;
+
+  struct value *val = process_print_command_args (args, &print_opts);
 
   if (voidprint || (val && value_type (val) &&
 		    value_type (val)->code () != TYPE_CODE_VOID))
@@ -2711,6 +2723,273 @@ eval_command (const char *arg, int from_tty)
   execute_command (expanded.c_str (), from_tty);
 }
 
+/* Convenience function for error checking in mtag commands.  */
+
+static void
+show_addr_not_tagged (CORE_ADDR address)
+{
+  error (_("Address %s not in a region mapped with a memory tagging flag."),
+	 paddress (target_gdbarch (), address));
+}
+
+/* Convenience function for error checking in mtag commands.  */
+
+static void
+show_memtag_unsupported (void)
+{
+  error (_("Memory tagging not supported or disabled by the current"
+	   " architecture."));
+}
+
+/* Implement the "mtag" prefix command.  */
+
+static void
+mtag_command (const char *arg, int from_tty)
+{
+  help_list (mtaglist, "mtag ", all_commands, gdb_stdout);
+}
+
+/* Helper for showltag and showatag.  */
+
+static void
+mtag_showtag_command (const char *args, enum memtag_type tag_type)
+{
+  if (args == nullptr)
+    error_no_arg (_("address or pointer"));
+
+  /* Parse args into a value.  If the value is a pointer or an address,
+     then fetch the logical or allocation tag.  */
+  value_print_options print_opts;
+
+  struct value *val = process_print_command_args (args, &print_opts);
+
+  /* If the address is not in a region memory mapped with a memory tagging
+     flag, it is no use trying to access/manipulate its allocation tag.
+
+     It is OK to manipulate the logical tag though.  */
+  if (tag_type == tag_allocation
+      && !gdbarch_tagged_address_p (target_gdbarch (), val))
+    show_addr_not_tagged (value_as_address (val));
+
+  std::string tag = gdbarch_memtag_to_string (target_gdbarch (),
+					      val, tag_type);
+  if (tag.empty ())
+    printf_filtered (_("%s tag unavailable.\n"),
+		     tag_type == tag_logical? "Logical" : "Allocation");
+
+  struct value *v_tag = process_print_command_args (tag.c_str (),
+						    &print_opts);
+  print_opts.output_format = 'x';
+  print_value (v_tag, print_opts);
+}
+
+/* Implement the "mtag showltag" command.  */
+
+static void
+mtag_showltag_command (const char *args, int from_tty)
+{
+  if (!memtag || !target_supports_memory_tagging ())
+    show_memtag_unsupported ();
+
+  mtag_showtag_command (args, tag_logical);
+}
+
+/* Implement the "mtag showatag" command.  */
+
+static void
+mtag_showatag_command (const char *args, int from_tty)
+{
+  if (!memtag || !target_supports_memory_tagging ())
+    show_memtag_unsupported ();
+
+  mtag_showtag_command (args, tag_allocation);
+}
+
+/* Parse ARGS and extract ADDR and TAG.
+   ARGS should have format <expression> <tag bytes>.  */
+
+static void
+parse_withltag_input (const char *args, struct value **val,
+		      gdb::byte_vector &tags, value_print_options *print_opts)
+{
+  /* Given <expression> can be reasonably complex, we parse things backwards
+     so we can isolate the <tag bytes> portion.  */
+
+  /* Fetch the address.  */
+  std::string s_address = extract_string_maybe_quoted (&args);
+
+  /* Parse the address into a value.  */
+  *val = process_print_command_args (s_address.c_str (), print_opts);
+
+  /* Fetch the tag bytes.  */
+  std::string s_tag = extract_string_maybe_quoted (&args);
+
+  /* Validate the input.  */
+  if (s_address.empty () || s_tag.empty ())
+    error (_("Missing arguments."));
+
+  if (s_tag.length () % 2)
+    error (_("Error parsing tags argument. The tag should be 2 digits."));
+
+  tags = hex2bin (s_tag.c_str ());
+}
+
+/* Implement the "mtag withltag" command.  */
+
+static void
+mtag_withltag_command (const char *args, int from_tty)
+{
+  if (!memtag || !target_supports_memory_tagging ())
+    show_memtag_unsupported ();
+
+  if (args == nullptr)
+    error_no_arg (_("<address> <tag>"));
+
+  gdb::byte_vector tags;
+  struct value *val;
+  value_print_options print_opts;
+
+  /* Parse the input.  */
+  parse_withltag_input (args, &val, tags, &print_opts);
+
+  /* Setting the logical tag is just a local operation that does not touch
+     any memory from the target.  Given an input value, we modify the value
+     to include the appropriate tag.
+
+     For this reason we need to cast the argument value to a
+     (void *) pointer.  This is so we have the right the for the gdbarch
+     hook to manipulate the value and insert the tag.
+
+     Otherwise, this would fail if, for example, GDB parsed the argument value
+     into an int-sized value and the pointer value has a type of greater
+     length.  */
+
+  /* Cast to (void *).  */
+  val = value_cast (builtin_type (target_gdbarch ())->builtin_data_ptr,
+		    val);
+
+  if (gdbarch_set_memtags (target_gdbarch (), val, 0, tags,
+			   tag_logical) != 0)
+    printf_filtered (_("Could not update the logical tag data.\n"));
+  else
+    {
+      /* Always print it in hex format.  */
+      print_opts.output_format = 'x';
+      print_value (val, print_opts);
+    }
+}
+
+/* Parse ARGS and extract ADDR, LENGTH and TAGS.  */
+
+static void
+parse_setatag_input (const char *args, struct value **val, size_t *length,
+		     gdb::byte_vector &tags)
+{
+  /* Fetch the address.  */
+  std::string s_address = extract_string_maybe_quoted (&args);
+
+  /* Parse the address into a value.  */
+  value_print_options print_opts;
+  *val = process_print_command_args (s_address.c_str (), &print_opts);
+
+  /* Fetch the length.  */
+  std::string s_length = extract_string_maybe_quoted (&args);
+
+  /* Fetch the tag bytes.  */
+  std::string s_tags = extract_string_maybe_quoted (&args);
+
+  /* Validate the input.  */
+  if (s_address.empty () || s_length.empty () || s_tags.empty ())
+    error (_("Missing arguments."));
+
+  errno = 0;
+  *length = strtoulst (s_length.c_str (), NULL, 10);
+  if (errno != 0)
+    error (_("Error parsing length argument."));
+
+  if (s_tags.length () % 2)
+    error (_("Error parsing tags argument. Tags should be 2 digits per byte."));
+
+  tags = hex2bin (s_tags.c_str ());
+
+  /* If the address is not in a region memory mapped with a memory tagging
+     flag, it is no use trying to access/manipulate its allocation tag.  */
+  if (!gdbarch_tagged_address_p (target_gdbarch (), *val))
+    show_addr_not_tagged (value_as_address (*val));
+}
+
+/* Implement the "mtag setatag" command.
+   ARGS should be in the format <address> <length> <tags>.  */
+
+static void
+mtag_setatag_command (const char *args, int from_tty)
+{
+  if (!memtag || !target_supports_memory_tagging ())
+    show_memtag_unsupported ();
+
+  if (args == nullptr)
+    error_no_arg (_("<starting address> <length> <tag bytes>"));
+
+  gdb::byte_vector tags;
+  size_t length = 0;
+  struct value *val;
+
+  /* Parse the input.  */
+  parse_setatag_input (args, &val, &length, tags);
+
+  if (gdbarch_set_memtags (target_gdbarch (), val, length, tags,
+			   tag_allocation) != 0)
+    printf_filtered (_("Could not update the allocation tag(s).\n"));
+  else
+    printf_filtered (_("Allocation tag(s) updated successfully.\n"));
+}
+
+/* Implement the "mtag check" command.  */
+
+static void
+mtag_check_command (const char *args, int from_tty)
+{
+  if (!memtag || !target_supports_memory_tagging ())
+    show_memtag_unsupported ();
+
+  if (args == nullptr)
+    error (_("Argument required (address or pointer)"));
+
+  /* Parse the expression into a value.  If the value is an address or
+     pointer, then check its logical tag against the allocation tag.  */
+  value_print_options print_opts;
+
+  struct value *val = process_print_command_args (args, &print_opts);
+
+  /* If the address is not in a region memory mapped with a memory tagging
+     flag, it is no use trying to access/manipulate its allocation tag.  */
+  if (!gdbarch_tagged_address_p (target_gdbarch (), val))
+    show_addr_not_tagged (value_as_address (val));
+
+  CORE_ADDR addr = value_as_address (val);
+
+  /* If memory tagging validation is on, check if the tag is valid.  */
+  if (gdbarch_memtag_mismatch_p (target_gdbarch (), val))
+    {
+      std::string ltag = gdbarch_memtag_to_string (target_gdbarch (),
+						   val, tag_logical);
+      std::string atag = gdbarch_memtag_to_string (target_gdbarch (),
+						   val, tag_allocation);
+
+      printf_filtered (_("Logical tag (%s) does not match"
+			 " the allocation tag (%s) for address %s.\n"),
+		       ltag.c_str (), atag.c_str (),
+		       paddress (target_gdbarch (), addr));
+    }
+  else
+    {
+      std::string ltag = gdbarch_memtag_to_string (target_gdbarch (),
+						   val, tag_logical);
+      printf_filtered (_("Memory tags for address %s match (%s).\n"),
+		       paddress (target_gdbarch (), addr), ltag.c_str ());
+    }
+}
+
 void _initialize_printcmd ();
 void
 _initialize_printcmd ()
@@ -2921,4 +3200,60 @@ certain operations have illegal tags."),
 			    NULL,
 			    show_memtag,
 			    &setlist, &showlist);
+
+  /* Memory tagging commands.  */
+  add_prefix_cmd ("mtag", class_vars, mtag_command, _("\
+Generic command for showing and manipulating memory tag properties."),
+		  &mtaglist, "mtag ", 0, &cmdlist);
+  add_cmd ("showltag", class_vars, mtag_showltag_command,
+	   ("Show the logical tag for an address.\n\
+Usage: mtag showltag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will show the logical tag associated with <address>.  The tag\n\
+interpretation is architecture-specific."),
+	   &mtaglist);
+  add_cmd ("showatag", class_vars, mtag_showatag_command,
+	   _("Show the allocation tag for an address.\n\
+Usage: mtag showatag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will show the allocation tag associated with <address>.  The tag\n\
+interpretation is architecture-specific."),
+	   &mtaglist);
+  add_cmd ("withltag", class_vars, mtag_withltag_command,
+	   _("Set the logical tag for an address.\n\
+Usage: mtag withltag <address> <tag>\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+<tag> is a sequence of hex bytes that will be interpreted by the\n\
+architecture as a single memory tag.\n\
+GDB will set the logical tag for <address> to <tag>, and will show the\n\
+resulting address with the updated tag."),
+	   &mtaglist);
+  add_cmd ("setatag", class_vars, mtag_setatag_command,
+	   _("Set the allocation tag for an address.\n\
+Usage: mtag setatag <address> <length> <tag_bytes>\n\
+<address> is an expression that evaluates to a pointer or memory address\n\
+<length> is the number of bytes that will get added to <address> to calculate\n\
+the memory range.\n\
+<tag bytes> is a sequence of hex bytes that will be interpreted by the\n\
+architecture as one or more memory tags.\n\
+Sets the tags of the memory range [<address>, <address> + <length>)\n\
+to the specified tag bytes.\n\
+\n\
+If the number of tags is greater than or equal to the number of tag granules\n\
+in the [<address>, <address> + <length) range, only the tags up to the\n\
+number of tag granules will be stored.\n\
+\n\
+If the number of tags is less than the number of tag granules, then the\n\
+command is a fill operation.  The tag bytes are interpreted as a pattern\n\
+that will get repeated until the number of tag granules in the memory range\n\
+[<address>, <address> + <length>] is stored to."),
+	   &mtaglist);
+  add_cmd ("check", class_vars, mtag_check_command,
+	   _("Validate the logical tag against the allocation tag.\n\
+Usage: mtag check <address>\n\
+<address> is an expression that evaluates to a pointer or memory address\n\
+GDB will fetch the logical and allocation tags for <address> and will\n\
+compare them for equality.  If the tags do not match, GDB will show\n\
+additional information about the mismatch."),
+	   &mtaglist);
 }
diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc
index 9bb16605dd..90b51dbb18 100644
--- a/gdbsupport/rsp-low.cc
+++ b/gdbsupport/rsp-low.cc
@@ -32,7 +32,7 @@ fromhex (int a)
   else if (a >= 'A' && a <= 'F')
     return a - 'A' + 10;
   else
-    error (_("Reply contains invalid hex digit %d"), a);
+    error (_("Invalid hex digit %d"), a);
 }
 
 /* See rsp-low.h.  */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 20/24] Documentation for the new mtag commands
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (18 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 19/24] New mtag commands Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:11   ` Eli Zaretskii
  2020-11-09 17:04 ` [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging Luis Machado
                   ` (4 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Document the new "mtag" command prefix and all of its subcommands.

gdb/doc/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* gdb.texinfo (Memory Tagging): New subsection and node.
	(AArch64 Memory Tagging Extension): New subsection.
---
 gdb/doc/gdb.texinfo | 95 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7593559331..e826775755 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10932,6 +10932,66 @@ target supports computing the CRC checksum of a block of memory
 (@pxref{qCRC packet}).
 @end table
 
+@node Memory Tagging
+@subsection Memory Tagging
+
+Memory tagging is a memory protection technology that uses a pair of tags to
+validate memory accesses through pointers.  The tags are integer values
+usually comprised of a few bits, depending on the architecture.
+
+There are two types of tags that are used in this setup: logical and
+allocation.  A logical tag is stored in the pointers themselves, usually at the
+higher bits of the pointers.  An allocation tag is the tag associated
+with particular ranges of memory in the physical address space, against which
+the logical tags from pointers are compared.
+
+The pointer tag (logical tag) must match the memory tag (allocation tag)
+for the memory access to be valid.  If the logical tag does not match the
+allocation tag, that will raise a memory violation.
+
+Allocation tags cover multiple contiguous bytes of physical memory.  This
+range of bytes is called a memory tag granule and is architecture-specific.
+For example,  AArch64 has a tag granule of 16 bytes, meaning each allocation
+tag spans 16 bytes of memory.
+
+If the underlying architecture supports memory tagging, like AArch64 MTE
+or SPARC ADI do,  @value{GDBN} can make use of it to validate addresses and
+pointers against memory allocation tags.
+
+A command prefix of @code{mtag} gives access to the various memory tagging
+commands.
+
+The @code{mtag} commands are the following:
+
+@table @code
+@kindex mtag showltag
+@item mtag showltag @var{address_expression}
+Show the logical tag stored at the address given by @var{address_expression}.
+@kindex mtag withltag
+@item mtag withltag @var{address_expression} @var{tag_bytes}
+Print the address given by @var{address_expression}, augmented with a logical
+tag of @var{tag_bytes}.
+@kindex mtag showatag
+@item mtag showatag @var{address_expression}
+Show the allocation tag associated with the memory address given by
+@var{address_expression}.
+@kindex mtag setatag
+@item mtag setatag @var{starting_address} @var{length} @var{tag_bytes}
+Set the allocation tag(s) for memory range @r{[}@var{starting_address},
+@var{starting_address} + @var{length}@r{)} to @var{tag_bytes}.
+@kindex mtag check
+@item mtag check @var{address_expression}
+Check that the logical tag stored at the address given by
+@var{address_expression} matches the allocation tag for the same address.
+
+This essentially emulates the hardware validation that is done when tagged
+memory is accessed through a pointer, but does not cause a memory fault as
+it would during hardware validation.
+
+It can be used to inspect potential memory tagging violations in the running
+process, before any faults get triggered.
+@end table
+
 @node Auto Display
 @section Automatic Display
 @cindex automatic display
@@ -25017,6 +25077,41 @@ When GDB prints a backtrace, any addresses that required unmasking will be
 postfixed with the marker [PAC].  When using the MI, this is printed as part
 of the @code{addr_flags} field.
 
+@subsubsection AArch64 Memory Tagging Extension.
+@cindex AArch64 Memory Tagging Extension.
+
+When @value{GDBN} is debugging the AArch64 architecture, the program is
+using the v8.5-A feature Memory Tagging Extension (MTE) and there is support
+in the kernel for MTE, @value{GDBN} will make memory tagging functionality
+available for inspection and editing of logical and allocation tags.
+@xref{Memory Tagging}.
+
+To aid debugging, @value{GDBN} will output additional information when SIGSEGV
+signals are generated as a result of memory tag failures.
+
+If the tag violation is synchronous, the following will be shown:
+
+@smallexample
+Program received signal SIGSEGV, Segmentation fault
+Memory tag violation while accessing address 0x0000fffff7ff8000
+Allocation tag 0x0000000000000001.
+@end smallexample
+
+If the tag violation is asynchronous, the fault address is not available.
+In this case @value{GDBN} will show the following:
+
+@smallexample
+Program received signal SIGSEGV, Segmentation fault
+Memory tag violation
+Fault address unavailable.
+@end smallexample
+
+A special register, @code{tag_ctl}, is made available through the
+@code{org.gnu.gdb.aarch64.mte} feature.  This register exposes some
+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.
+
 @node i386
 @subsection x86 Architecture-specific Issues
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (19 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 20/24] Documentation for the new " Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:14   ` Eli Zaretskii
  2020-12-27  4:18   ` Simon Marchi
  2020-11-09 17:04 ` [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions Luis Machado
                   ` (3 subsequent siblings)
  24 siblings, 2 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Extend the "x" and "print" commands to make use of memory tagging
functionality, if supported by the architecture.

The "print" command will point out any possible tag mismatches it finds
when dealing with pointers, in case such a pointer is tagged.  No additional
modifiers are needed.

Suppose we have a pointer "p" with value 0x1234 (logical tag 0x0) and that we
have an allocation tag of 0x1 for that particular area of memory. This is the
expected output:

(gdb) p/x p
Logical tag (0x0) does not match the allocation tag (0x1).
$1 = 0x1234

The "x" command has a new 'm' modifier that will enable displaying of
allocation tags alongside the data dump.  It will display one allocation
tag per line.

AArch64 has a tag granule of 16 bytes, which means we can have one tag for
every 16 bytes of memory. In this case, this is what the "x" command will
display with the new 'm' modifier:

(gdb) x/32bxm p
<Allocation Tag 0x1 for range [0x1230,0x1240)>
0x1234:	0x01	0x02	0x00	0x00	0x00	0x00	0x00	0x00
0x123c:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
<Allocation Tag 0x1 for range [0x1240,0x1250)>
0x1244:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x124c:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00

(gdb) x/4gxm a
<Allocation Tag 0x1 for range [0x1230,0x1240)>
0x1234:	0x0000000000000201	0x0000000000000000
<Allocation Tag 0x1 for range [0x1240,0x1250)>
0x1244:	0x0000000000000000	0x0000000000000000

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* printcmd.c (decode_format): Handle the 'm' modifier.
	(do_examine): Display allocation tags when required/supported.
	(should_validate_memtags): New function.
	(print_command_1): Display memory tag mismatches.
	* valprint.h (struct format_data) <print_tags>: New field.
---
 gdb/printcmd.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/valprint.h |  1 +
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 6949678235..38b51c64ab 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -54,6 +54,7 @@
 #include "gdbsupport/byte-vector.h"
 #include "gdbsupport/gdb_optional.h"
 #include "gdbsupport/rsp-low.h"
+#include "infrun.h"		/* For memtag setting.  */
 
 /* Chain containing all defined mtag subcommands.  */
 
@@ -210,6 +211,7 @@ decode_format (const char **string_ptr, int oformat, int osize)
   val.size = '?';
   val.count = 1;
   val.raw = 0;
+  val.print_tags = false;
 
   if (*p == '-')
     {
@@ -232,6 +234,11 @@ decode_format (const char **string_ptr, int oformat, int osize)
 	  val.raw = 1;
 	  p++;
 	}
+      else if (*p == 'm')
+	{
+	  val.print_tags = true;
+	  p++;
+	}
       else if (*p >= 'a' && *p <= 'z')
 	val.format = *p++;
       else
@@ -1116,12 +1123,47 @@ do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
       need_to_update_next_address = 1;
     }
 
+  /* Whether we need to print the memory tag information for the current
+     address range.  */
+  bool print_range_tag = true;
+  uint32_t gsize = gdbarch_memtag_granule_size (gdbarch);
+
   /* Print as many objects as specified in COUNT, at most maxelts per line,
      with the address of the next one at the start of each line.  */
 
   while (count > 0)
     {
       QUIT;
+
+      CORE_ADDR tag_laddr = 0, tag_haddr = 0;
+
+      /* Print the memory tag information if requested.  */
+      if (fmt.print_tags && print_range_tag && memtag
+	  && target_supports_memory_tagging ())
+	{
+	  tag_laddr = align_down (next_address, gsize);
+	  tag_haddr = align_down (next_address + gsize, gsize);
+
+	  struct value *v_addr
+	    = value_from_ulongest (builtin_type (gdbarch)->builtin_data_ptr,
+				   tag_laddr);
+
+	  if (gdbarch_tagged_address_p (target_gdbarch (), v_addr))
+	    {
+	      std::string atag = gdbarch_memtag_to_string (gdbarch, v_addr,
+							   tag_allocation);
+
+	      if (!atag.empty ())
+		{
+		  printf_filtered (_("<Allocation Tag %s for range [%s,%s)>\n"),
+				   atag.c_str (),
+				   paddress (gdbarch, tag_laddr),
+				   paddress (gdbarch, tag_haddr));
+		}
+	    }
+	  print_range_tag = false;
+	}
+
       if (format == 'i')
 	fputs_filtered (pc_prefix (next_address), gdb_stdout);
       print_address (next_gdbarch, next_address, gdb_stdout);
@@ -1152,6 +1194,11 @@ do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
 	  /* Display any branch delay slots following the final insn.  */
 	  if (format == 'i' && count == 1)
 	    count += branch_delay_insns;
+
+	  /* Update the tag range based on the current address being
+	     processed.  */
+	  if (tag_haddr <= next_address)
+	      print_range_tag = true;
 	}
       printf_filtered ("\n");
     }
@@ -1224,6 +1271,26 @@ print_value (value *val, const value_print_options &opts)
   annotate_value_history_end ();
 }
 
+/* Returns true if memory tags should be validated.  False otherwise.  */
+
+static bool
+should_validate_memtags (struct value *value)
+{
+  if (memtag && target_supports_memory_tagging ()
+      && gdbarch_tagged_address_p (target_gdbarch (), value))
+    {
+      gdb_assert (value && value_type (value));
+
+      enum type_code code = value_type (value)->code ();
+
+      return (code == TYPE_CODE_PTR
+	      || code == TYPE_CODE_REF
+	      || code == TYPE_CODE_METHODPTR
+	      || code == TYPE_CODE_MEMBERPTR);
+    }
+  return false;
+}
+
 /* Helper for parsing arguments for print_command_1.  */
 
 static struct value *
@@ -1259,7 +1326,21 @@ print_command_1 (const char *args, int voidprint)
 
   if (voidprint || (val && value_type (val) &&
 		    value_type (val)->code () != TYPE_CODE_VOID))
-    print_value (val, print_opts);
+    {
+      /* If memory tagging validation is on, check if the tag is valid.  */
+      if (should_validate_memtags (val)
+	  && gdbarch_memtag_mismatch_p (target_gdbarch (), val))
+	{
+	  std::string ltag = gdbarch_memtag_to_string (target_gdbarch (),
+						       val, tag_logical);
+	  std::string atag = gdbarch_memtag_to_string (target_gdbarch (),
+						       val, tag_allocation);
+	  printf_filtered (_("Logical tag (%s) does not match the "
+			     "allocation tag (%s).\n"),
+			   ltag.c_str (), atag.c_str ());
+	}
+      print_value (val, print_opts);
+    }
 }
 
 /* See valprint.h.  */
diff --git a/gdb/valprint.h b/gdb/valprint.h
index ef9ebfa84f..fca58ad084 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -255,6 +255,7 @@ struct format_data
     int count;
     char format;
     char size;
+    bool print_tags;
 
     /* True if the value should be printed raw -- that is, bypassing
        python-based formatters.  */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (20 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:16   ` Eli Zaretskii
  2020-11-09 17:04 ` [PATCH v3 23/24] Add NEWS entry Luis Machado
                   ` (2 subsequent siblings)
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Document the changes to the "print" and "x" commands to support memory
tagging.

gdb/doc/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* gdb.texinfo (Data): Document memory tagging changes to the "print"
	command.
	(Examining Memory): Document memory tagging changes to the "x"
	command.
	(Memory Tagging): Update with more information on changes to the "x"
	and "print" commands.
---
 gdb/doc/gdb.texinfo | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e826775755..37d35316e0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10019,6 +10019,10 @@ If you omit @var{expr}, @value{GDBN} displays the last value again (from the
 conveniently inspect the same value in an alternative format.
 @end table
 
+If the architecture supports memory tagging, the @code{print} command will
+display pointer/memory tag mismatches if what is being printed is a pointer
+or reference type. @xref{Memory Tagging}.
+
 A more low-level way of examining data is with the @code{x} command.
 It examines data in memory at a specified address and prints it in a
 specified format.  @xref{Memory, ,Examining Memory}.
@@ -10786,7 +10790,8 @@ number is specified, memory is examined backward from @var{addr}.
 @item @var{f}, the display format
 The display format is one of the formats used by @code{print}
 (@samp{x}, @samp{d}, @samp{u}, @samp{o}, @samp{t}, @samp{a}, @samp{c},
-@samp{f}, @samp{s}), and in addition @samp{i} (for machine instructions).
+@samp{f}, @samp{s}), @samp{i} (for machine instructions) and
+@samp{m} (for displaying memory tags).
 The default is @samp{x} (hexadecimal) initially.  The default changes
 each time you use either @code{x} or @code{print}.
 
@@ -10881,6 +10886,22 @@ counter is shown with a @code{=>} marker. For example:
    0x804838c <main+24>: call   0x80482d4 <puts@@plt>
 @end smallexample
 
+If the architecture supports memory tagging, the tags can be displayed by
+using @samp{m}.  @xref{Memory Tagging}.
+
+The information will be displayed once per granule size
+(the amount of bytes a particular memory tag covers).  For example, AArch64
+has a granule size of 16 bytes, so it will display a tag every 16 bytes.
+
+Due to the way @value{GDBN} prints information with the @code{x} command (not
+aligned to a particular boundary), the tag information will refer to the
+initial address displayed on a particular line.  If a memory tag boundary
+is crossed in the middle of a line displayed by the @code{x} command, it
+will be displayed on the next line.
+
+The @samp{m} format doesn't affect any other specified formats that were
+passed to the @code{x} command.
+
 @cindex @code{$_}, @code{$__}, and value history
 The addresses and contents printed by the @code{x} command are not saved
 in the value history because there is often too much of them and they
@@ -10958,8 +10979,9 @@ If the underlying architecture supports memory tagging, like AArch64 MTE
 or SPARC ADI do,  @value{GDBN} can make use of it to validate addresses and
 pointers against memory allocation tags.
 
-A command prefix of @code{mtag} gives access to the various memory tagging
-commands.
+The @code{print} (@pxref{Data}) and @code{x} (@pxref{Memory}) commands will
+display tag information when appropriate, and a command prefix of @code{mtag}
+gives access to the various memory tagging commands.
 
 The @code{mtag} commands are the following:
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 23/24] Add NEWS entry.
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (21 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-09 17:19   ` Eli Zaretskii
  2020-11-09 17:04 ` [PATCH v3 24/24] Add memory tagging testcases Luis Machado
  2020-11-16 13:48 ` [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  24 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Mention the new packets and memory tagging features.

gdb/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* NEWS: Mention memory tagging changes.
---
 gdb/NEWS | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index 3e08aee7c6..55af85528d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -51,6 +51,19 @@ condition [-force] N COND
 
 *** Changes in GDB 10
 
+* GDB now supports general memory tagging functionality if the underlying
+  architecture supports the proper primitives and hooks.  Currently this is
+  enabled only for AArch64 MTE.
+
+  This includes additional information when the inferior crashes with a
+  SIGSEGV caused by a memory tag violation.
+
+* The "x" command supports the 'm' modifier to display allocation tags for
+  a particular memory range.
+
+* The "print" command displays memory tag mismatches for addresses and
+  pointers, if memory tagging is supported by the architecture.
+
 * There are new feature names for ARC targets: "org.gnu.gdb.arc.core"
   and "org.gnu.gdb.arc.aux".  The old names are still supported but
   must be considered obsolete.  They will be deprecated after some
@@ -133,8 +146,27 @@ condition [-force] N COND
 * On Windows targets, it is now possible to debug 32-bit programs with a
   64-bit GDB.
 
+* New remote packets
+
+qMemTags
+  Request the remote to send allocation tags for a particular memory range.
+QMemTags
+  Request the remote to store the specified allocation tags to the requested
+  memory range.
+
 * New commands
 
+mtag showltag ADDRESS
+  Show the logical tag for ADDRESS.
+mtag withltag ADDRESS TAG
+  Set the logical tag for ADDRESS to TAG.
+mtag showatag ADDRESS
+  Show the allocation tag for ADDRESS.
+mtag setatag ADDRESS LENGTH TAGS
+  Set the allocation tag for [ADDRESS, ADDRESS + LENGTH) to TAGS.
+mtag check ADDRESS
+  Validate that ADDRESS' logical tag matches the allocation tag.
+
 set exec-file-mismatch -- Set exec-file-mismatch handling (ask|warn|off).
 show exec-file-mismatch -- Show exec-file-mismatch handling (ask|warn|off).
   Set or show the option 'exec-file-mismatch'.  When GDB attaches to a
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* [PATCH v3 24/24] Add memory tagging testcases
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (22 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 23/24] Add NEWS entry Luis Machado
@ 2020-11-09 17:04 ` Luis Machado
  2020-11-16 15:47   ` David Spickett
  2020-12-27  4:36   ` Simon Marchi
  2020-11-16 13:48 ` [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  24 siblings, 2 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Add an AArch64-specific test and a more generic memory tagging test that
other architectures can run.

Even though architectures not supporting memory tagging can run the memory
tagging tests, the runtime check will make the tests bail out early, as it
would make no sense to proceed without proper support.

It is also tricky to do any further runtime tests for memory tagging, given
we'd need to deal with tags, and those are arch-specific.  Therefore the
test in gdb.base is more of a smoke test.

If an architecture wants to implement memory tagging, then it makes sense to
have tests within gdb.arch instead.

gdb/testsuite/ChangeLog:

YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>

	* gdb.arch/aarch64-mte.c: New file.
	* gdb.arch/aarch64-mte.exp: New test.
	* gdb.base/memtag.c: New file.
	* gdb.base/memtag.exp: New test.
	* lib/gdb.exp (supports_memtag): New function.
---
 gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 +++++++
 gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 +++++++++++++++++++++++++
 gdb/testsuite/gdb.base/memtag.c        |  22 ++
 gdb/testsuite/gdb.base/memtag.exp      |  64 +++++
 gdb/testsuite/lib/gdb.exp              |  16 ++
 5 files changed, 580 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
 create mode 100644 gdb/testsuite/gdb.base/memtag.c
 create mode 100644 gdb/testsuite/gdb.base/memtag.exp

diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.c b/gdb/testsuite/gdb.arch/aarch64-mte.c
new file mode 100644
index 0000000000..f6fb4cca67
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-mte.c
@@ -0,0 +1,107 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2020 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_NONE		(0UL << PR_MTE_TCF_SHIFT)
+#define PR_MTE_TCF_SYNC		(1UL << PR_MTE_TCF_SHIFT)
+#define PR_MTE_TCF_ASYNC	(2UL << PR_MTE_TCF_SHIFT)
+#define PR_MTE_TCF_MASK		(3UL << PR_MTE_TCF_SHIFT)
+#define PR_MTE_TAG_SHIFT	3
+#define PR_MTE_TAG_MASK		(0xffffUL << PR_MTE_TAG_SHIFT)
+
+void
+access_memory (unsigned char *tagged_ptr, unsigned char *untagged_ptr)
+{
+  tagged_ptr[0] = 'a';
+}
+
+int
+main (int argc, char **argv)
+{
+  unsigned char *tagged_ptr;
+  unsigned char *untagged_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;
+    }
+
+  /* Create another mapping that won't have PROT_MTE set.  */
+  untagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
+		       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (untagged_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, untagged_ptr);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.exp b/gdb/testsuite/gdb.arch/aarch64-mte.exp
new file mode 100644
index 0000000000..39dba493fb
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-mte.exp
@@ -0,0 +1,371 @@
+# Copyright (C) 2020 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/>.
+
+# Test a binary with address signing works regardless of whether the target
+# supports pauth instructions.  On non pauth systems, all pauth instructions
+# are treated as nops.
+
+global hex
+global decimal
+
+# Return TAG in hex format with no leading zeroes.
+proc get_hex_tag { tag } {
+    return [format "%x" $tag]
+}
+
+# Return TAG in the NN format where N is 4 bits of the byte.
+proc get_tag_nn { tag } {
+    return [format "%02x" $tag]
+}
+
+# Return the address of PTR with a tag of TAG.
+proc get_tagged_ptr { tag ptr } {
+  set addr [get_hexadecimal_valueof $ptr -1]
+  return [get_valueof "/x" \
+	      "${addr} & (0xf0ffffffffffffff) | ((unsigned long) ${tag} << 56)" \
+	      "0" "fetch pointer ${ptr} with tag ${tag}"]
+}
+
+# Return the logical TAG from PTR.
+proc get_ltag_from_ptr { ptr } {
+  set addr [get_hexadecimal_valueof $ptr -1]
+  return [get_valueof "/x" "${addr} >> 56 & 0xf" -1 \
+		      "fetch tag from pointer ${ptr}"]
+}
+
+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]} {
+    untested "memory tagging unsupported"
+    return -1
+}
+
+gdb_breakpoint "access_memory"
+
+if [gdb_continue "access_memory"] {
+    fail "could not run to tagged memory test function"
+    return -1
+}
+
+# Fetch a known pointer to an area mapped with PROT_MTE.
+set tagged_ptr_symbol "tagged_ptr"
+set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
+
+if {$tagged_ptr_addr == -1} {
+    untested "unexpected pointer or tag value"
+    return -1
+}
+
+# Fetch a known pointer to an area not mapped with PROT_MTE.
+set untagged_ptr_symbol "untagged_ptr"
+set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
+
+if {$untagged_ptr_addr == -1} {
+    untested "unexpected pointer or tag value"
+    return -1
+}
+
+with_test_prefix "literals" {
+    # Test inspecting an allocation tag from a pointer to a memory area that
+    # is not mapped with PROT_MTE.
+    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
+    gdb_test "mtag showatag ${untagged_ptr_addr}" $msg \
+	     "mtag showatag with an untagged address"
+
+    gdb_test "mtag setatag ${untagged_ptr_addr} 0 00" $msg \
+	     "mtag setatag with an untagged address"
+
+    set addr_tagged 0
+    set addr_tagged_valid 0
+
+    # Test setting and showing the logical tags for a literal address.
+    for {set i 0} {$i < 32} {incr i} {
+	with_test_prefix "tag ${i}" {
+	    set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
+	}
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "mtag showltag ${addr_tagged}" \
+		 " = 0x${tag_hexnz}" \
+		 "showltag with tag ${i}"
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "mtag withltag ${addr_tagged} ${tag_hexnn}" \
+		 " = \\(void \\*\\) ${addr_tagged}" \
+		 "withltag with tag ${i}"
+    }
+
+    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
+    # Test setting and showing the allocation tags.
+    for {set i 0} {$i < 32} {incr i} {
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
+		 $setatag_msg \
+		 "setatag with tag ${i}"
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "mtag showatag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \
+		 "showatag with tag ${i}"
+    }
+
+    # Test tag mismatches.
+    with_test_prefix "tag mismatches" {
+	for {set i 0} {$i < 32} {incr i} {
+
+	    # Set the allocation tag to a known value.
+	    set tag_hexnn [get_tag_nn $i]
+	    gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
+		     $setatag_msg \
+		     "setatag with tag ${i}"
+
+	    set atag_hexnz [get_hex_tag [expr $i % 16]]
+
+	    # Validate that the logical tag matches the allocation tag.
+	    with_test_prefix "tag ${i}" {
+		set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
+	    }
+
+	    gdb_test "mtag check ${addr_tagged}" \
+		     "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
+		     "check match with tag ${i}"
+
+	    # Get a pointer with the logical tag that does not match the
+	    # allocation tag.
+	    set ltag [expr $i + 1]
+	    with_test_prefix "fetch mismatch tag ${i}" {
+		set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
+	    }
+
+	    # Validate that the logical tag does not match the allocation
+	    # tag.
+	    set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
+	    gdb_test "mtag check ${addr_tagged}" \
+		     "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
+		     "check mismatch with tag ${i}"
+	}
+    }
+}
+
+with_test_prefix "symbolic" {
+    # Test inspecting an allocation tag from a pointer to a memory area that
+    # is not mapped with PROT_MTE.
+    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
+    gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
+	     "mtag showatag with an untagged address"
+
+    gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
+	     "mtag setatag with an untagged address"
+
+    # Test setting and showing the logical tags for a literal address.
+    for {set i 0} {$i < 32} {incr i} {
+	set addr_tagged 0
+
+	with_test_prefix "tag ${i}" {
+	    set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
+	    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
+			       "update value of symbol ${tagged_ptr_symbol}"
+	}
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "mtag showltag ${tagged_ptr_symbol}" \
+		 " = 0x${tag_hexnz}" \
+		 "showltag with tag ${i}"
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
+		 " = \\(void \\*\\) ${addr_tagged}" \
+		 "withltag with tag ${i}"
+    }
+
+    # Reset the tagged ptr to its original value
+    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
+		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
+
+    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
+    # Test setting and showing the allocation tags.
+    for {set i 0} {$i < 32} {incr i} {
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
+		 $setatag_msg \
+		 "setatag with tag ${i}"
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
+		 "showatag with tag ${i}"
+    }
+
+    # Test tag mismatches.
+    with_test_prefix "tag mismatches" {
+	for {set i 0} {$i < 32} {incr i} {
+
+	    # Set the allocation tag to a known value (0).
+	    set tag_hexnn [get_tag_nn $i]
+	    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
+		     $setatag_msg \
+		     "setatag with tag ${i}"
+
+	    set atag_hexnz [get_hex_tag [expr $i % 16]]
+
+	    # Validate that the logical tag matches the allocation tag.
+	    with_test_prefix "tag ${i}" {
+		set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
+	    }
+
+	    with_test_prefix "tag ${i}" {
+		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
+				   "set ${tagged_ptr_symbol} to a matching logical tag"
+	    }
+
+	    gdb_test "mtag check ${tagged_ptr_symbol}" \
+		     "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
+		     "check match with tag ${i}"
+
+	    # Get a pointer with the logical tag that does not match the
+	    # allocation tag.
+	    set ltag [expr $i + 1]
+	    with_test_prefix "fetch mismatch tag ${i}" {
+		set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
+	    }
+
+	    with_test_prefix "tag ${i}" {
+		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
+				   "set ${tagged_ptr_symbol} to a mismatching logical tag"
+	    }
+
+	    # Validate that the logical tag does not match the allocation
+	    # tag.
+	    set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
+	    gdb_test "mtag check ${tagged_ptr_symbol}" \
+		     "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
+		     "check mismatch with tag ${i}"
+	}
+    # Reset the tagged ptr to its original value
+    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
+		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
+    }
+}
+
+# Test the memory tagging extensions for the "print" command.
+with_test_prefix "print command" {
+    set untagged_ptr [get_tagged_ptr 0 ${tagged_ptr_addr}]
+
+    with_test_prefix "fetch ltag" {
+	set ltag [get_ltag_from_ptr ${tagged_ptr_addr}]
+    }
+
+    if {$ltag == -1} {
+	untested "unexpected tag value"
+	return -1
+    }
+
+    set atag [expr [expr $ltag + 1] % 16]
+    set atag_hexnn [get_tag_nn $atag]
+
+    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${atag_hexnn}" \
+	     $setatag_msg \
+	     "make atag and ltag different"
+
+    set atag_hexnz [get_hex_tag $atag]
+    gdb_test "p/x ${tagged_ptr_symbol}" \
+	[multi_line \
+	    "Logical tag \\(${ltag}\\) does not match the allocation tag \\(0x${atag_hexnz}\\)\." \
+	    "\\\$\[0-9\]+ = ${untagged_ptr}"] \
+	    "show tag mismatch"
+}
+
+# Test the memory tagging extensions for the "x" command.
+with_test_prefix "x command" {
+
+    # Check if the allocation tags match what we expect.
+    gdb_test "x/gxm ${tagged_ptr_symbol}" \
+	[multi_line \
+	    "<Allocation Tag $hex for range \\\[$hex,$hex\\)>" \
+	    "$hex:\[ \t\]+$hex"] \
+	"outputs tag information"
+
+    # Also make sure no tag information is output for memory areas without
+    # PROT_MTE mappings.
+    gdb_test "x/gxm ${untagged_ptr_symbol}" \
+	     "$hex:\[ \t\]+$hex" \
+	     "does not output tag information"
+}
+
+# Validate the presence of the MTE registers.
+foreach reg {"tag_ctl" } {
+    gdb_test "info registers $reg" \
+	     "$reg\[ \t\]+$hex\[ \t\]+$decimal" \
+	     "register $reg available"
+}
+
+# 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\." \
+	"$hex in access_memory \\(.*\\) at .*" \
+	".*tagged_ptr\\\[0\\\] = 'a';"] \
+	 "display tag violation information"
+
+# Restart to execute the async tag fault test.
+with_test_prefix "async" {
+    if ![runto_main] {
+	untested "could not run to main"
+	return -1
+    }
+
+    gdb_breakpoint "access_memory"
+
+    if [gdb_continue "access_memory"] {
+	fail "could not run to tagged memory test function"
+	return -1
+    }
+
+    # Force a tag fault.
+    gdb_test "mtag setatag tagged_ptr 0 05" \
+	     $setatag_msg \
+	     "make atag and ltag different"
+
+    # Force the tag fault to be async.
+    gdb_test_no_output "set \$tag_ctl=0x7fff5" "set tag_ctl to async"
+
+    # Run until a crash and confirm GDB displays memory tag violation
+    # information for async mode
+    gdb_test "continue" \
+	[multi_line \
+	    "Program received signal SIGSEGV, Segmentation fault" \
+	    "Memory tag violation" \
+	    "Fault address unavailable\." \
+	    "$hex in .* \\(.*\\) .*"] \
+	    "display tag violation information"
+}
diff --git a/gdb/testsuite/gdb.base/memtag.c b/gdb/testsuite/gdb.base/memtag.c
new file mode 100644
index 0000000000..63a42ae278
--- /dev/null
+++ b/gdb/testsuite/gdb.base/memtag.c
@@ -0,0 +1,22 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2020 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/>.  */
+
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/memtag.exp b/gdb/testsuite/gdb.base/memtag.exp
new file mode 100644
index 0000000000..484a78e828
--- /dev/null
+++ b/gdb/testsuite/gdb.base/memtag.exp
@@ -0,0 +1,64 @@
+# Copyright 2020 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/>.
+
+# Smoke testing for the various memory tagging commands in GDB.
+
+set u_msg "Memory tagging not supported or disabled by the current architecture\."
+
+standard_testfile
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
+    return -1
+}
+
+if {[target_info gdb_protocol] == "extended-remote"} {
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
+}
+
+# Test commands without running the program.
+with_test_prefix "before program execution" {
+    # These commands should all fails without a running program.
+    foreach subcmd {"withltag" "showltag" "setatag" "showatag" "check"} {
+	gdb_test "mtag $subcmd" $u_msg
+    }
+}
+
+clean_restart $testfile
+
+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]} {
+    untested "memory tagging unsupported"
+    return -1
+}
+
+# With the program running, try to use the memory tagging commands.
+with_test_prefix "during program execution" {
+    set msg "Argument required \\(address or pointer\\)\."
+
+    # Test the various mtag commands again.
+    gdb_test "mtag showltag" $msg
+    gdb_test "mtag showatag" $msg
+    gdb_test "mtag withltag" "Argument required \\(<address> <tag>\\)\."
+    gdb_test "mtag setatag" \
+	     "Argument required \\(<starting address> <length> <tag bytes>\\)\."
+    gdb_test "mtag check" $msg
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 55154db6a5..347704ce0a 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
     }
 }
 
+# Return 1 if memory tagging is supported at runtime, otherwise return 0.
+
+proc supports_memtag {} {
+    global gdb_prompt
+
+    gdb_test_multiple "mtag check" "" {
+	-re "Memory tagging not supported or disabled by the current architecture\..*$gdb_prompt $" {
+	  return 0
+	}
+	-re "Argument required \\(address or pointer\\).*$gdb_prompt $" {
+	    return 1
+	}
+    }
+    return 0
+}
+
 # Return 1 if the target supports hardware single stepping.
 
 proc can_hardware_single_step {} {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-09 17:04 ` [PATCH v3 07/24] Documentation for " Luis Machado
@ 2020-11-09 17:08   ` Eli Zaretskii
  2020-11-16 15:44     ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Eli Zaretskii @ 2020-11-09 17:08 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, david.spickett

> Date: Mon,  9 Nov 2020 14:04:18 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> Cc: david.spickett@linaro.org
> 
> gdb/doc/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* gdb.texinfo (General Query Packets): Document qMemTags and
> 	QMemTags.  Document the "memory-tagging" feature.
> ---
>  gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 96 insertions(+)

OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 20/24] Documentation for the new mtag commands
  2020-11-09 17:04 ` [PATCH v3 20/24] Documentation for the new " Luis Machado
@ 2020-11-09 17:11   ` Eli Zaretskii
  0 siblings, 0 replies; 96+ messages in thread
From: Eli Zaretskii @ 2020-11-09 17:11 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, david.spickett

> Date: Mon,  9 Nov 2020 14:04:31 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> Cc: david.spickett@linaro.org
> 
> Document the new "mtag" command prefix and all of its subcommands.
> 
> gdb/doc/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* gdb.texinfo (Memory Tagging): New subsection and node.
> 	(AArch64 Memory Tagging Extension): New subsection.
> ---
>  gdb/doc/gdb.texinfo | 95 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 95 insertions(+)

Thanks, this part is OK.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-11-09 17:04 ` [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging Luis Machado
@ 2020-11-09 17:14   ` Eli Zaretskii
  2020-11-09 17:20     ` Luis Machado
  2020-12-27  4:18   ` Simon Marchi
  1 sibling, 1 reply; 96+ messages in thread
From: Eli Zaretskii @ 2020-11-09 17:14 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, david.spickett

> Date: Mon,  9 Nov 2020 14:04:32 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> Cc: david.spickett@linaro.org
> 
> Suppose we have a pointer "p" with value 0x1234 (logical tag 0x0) and that we
> have an allocation tag of 0x1 for that particular area of memory. This is the
> expected output:
> 
> (gdb) p/x p
> Logical tag (0x0) does not match the allocation tag (0x1).
> $1 = 0x1234

If the tags did match, GDB would have also printed the contents of the
memory pointed to by p, right?  At least with pointer to 'char *'
strings it would.  Does GDB still print the contents if the tags don't
match?  If it doesn't, it should say something like "Cannot access
memory at NNNN: logical tag doesn't match".

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions
  2020-11-09 17:04 ` [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions Luis Machado
@ 2020-11-09 17:16   ` Eli Zaretskii
  0 siblings, 0 replies; 96+ messages in thread
From: Eli Zaretskii @ 2020-11-09 17:16 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, david.spickett

> Date: Mon,  9 Nov 2020 14:04:33 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> Cc: david.spickett@linaro.org
> 
> Document the changes to the "print" and "x" commands to support memory
> tagging.
> 
> gdb/doc/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* gdb.texinfo (Data): Document memory tagging changes to the "print"
> 	command.
> 	(Examining Memory): Document memory tagging changes to the "x"
> 	command.
> 	(Memory Tagging): Update with more information on changes to the "x"
> 	and "print" commands.
> ---
>  gdb/doc/gdb.texinfo | 28 +++++++++++++++++++++++++---
>  1 file changed, 25 insertions(+), 3 deletions(-)

This part is OK, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 23/24] Add NEWS entry.
  2020-11-09 17:04 ` [PATCH v3 23/24] Add NEWS entry Luis Machado
@ 2020-11-09 17:19   ` Eli Zaretskii
  2020-11-09 17:22     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Eli Zaretskii @ 2020-11-09 17:19 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, david.spickett

> Date: Mon,  9 Nov 2020 14:04:34 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> Cc: david.spickett@linaro.org
> 
> +* GDB now supports general memory tagging functionality if the underlying
> +  architecture supports the proper primitives and hooks.  Currently this is
> +  enabled only for AArch64 MTE.
> +
> +  This includes additional information when the inferior crashes with a
> +  SIGSEGV caused by a memory tag violation.
> +
> +* The "x" command supports the 'm' modifier to display allocation tags for
> +  a particular memory range.
> +
> +* The "print" command displays memory tag mismatches for addresses and
> +  pointers, if memory tagging is supported by the architecture.

The "This includes" part should include the other 2 items as well, I
presume?  So I suggest to reword:

  This includes:

    - Additional information when the inferior crashes ...
    - A new modifier 'm' for the "x" command, which ...
    - Display of memory tag mismatches by "print" ...

Thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-11-09 17:14   ` Eli Zaretskii
@ 2020-11-09 17:20     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:20 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, david.spickett

On 11/9/20 2:14 PM, Eli Zaretskii wrote:
>> Date: Mon,  9 Nov 2020 14:04:32 -0300
>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>> Cc: david.spickett@linaro.org
>>
>> Suppose we have a pointer "p" with value 0x1234 (logical tag 0x0) and that we
>> have an allocation tag of 0x1 for that particular area of memory. This is the
>> expected output:
>>
>> (gdb) p/x p
>> Logical tag (0x0) does not match the allocation tag (0x1).
>> $1 = 0x1234
> 
> If the tags did match, GDB would have also printed the contents of the
> memory pointed to by p, right?  At least with pointer to 'char *'
> strings it would.  Does GDB still print the contents if the tags don't
> match?  If it doesn't, it should say something like "Cannot access
> memory at NNNN: logical tag doesn't match".
> 

Yes. GDB should print the contents just like before. I don't think we 
should prevent the debugger from printing the pointer/contents even if 
there is a tag mismatch.

The tag mismatch part is a warning so users know that something is off 
(and may cause memory faults).

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 23/24] Add NEWS entry.
  2020-11-09 17:19   ` Eli Zaretskii
@ 2020-11-09 17:22     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-09 17:22 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, david.spickett

On 11/9/20 2:19 PM, Eli Zaretskii wrote:
>> Date: Mon,  9 Nov 2020 14:04:34 -0300
>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>> Cc: david.spickett@linaro.org
>>
>> +* GDB now supports general memory tagging functionality if the underlying
>> +  architecture supports the proper primitives and hooks.  Currently this is
>> +  enabled only for AArch64 MTE.
>> +
>> +  This includes additional information when the inferior crashes with a
>> +  SIGSEGV caused by a memory tag violation.
>> +
>> +* The "x" command supports the 'm' modifier to display allocation tags for
>> +  a particular memory range.
>> +
>> +* The "print" command displays memory tag mismatches for addresses and
>> +  pointers, if memory tagging is supported by the architecture.
> 
> The "This includes" part should include the other 2 items as well, I
> presume?  So I suggest to reword:
> 
>    This includes:
> 
>      - Additional information when the inferior crashes ...
>      - A new modifier 'm' for the "x" command, which ...
>      - Display of memory tag mismatches by "print" ...
> 

That makes sense. Fixed now. Thanks!

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (23 preceding siblings ...)
  2020-11-09 17:04 ` [PATCH v3 24/24] Add memory tagging testcases Luis Machado
@ 2020-11-16 13:48 ` Luis Machado
  2020-11-16 14:37   ` Alan Hayward
  2020-11-23 16:08   ` Luis Machado
  24 siblings, 2 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-16 13:48 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Ping?

FTR, I'm aiming at having this ready for GDB 11.

On 11/9/20 2:04 PM, Luis Machado wrote:
> Here's v3 of this patch series.
> 
> Memory tagging improves memory safety by tagging various parts of memory and
> raising exceptions when the allocation tag (the one associated with a range of
> memory addresses) does not match the logical tag contained in a pointer that is
> used to access the memory area.
> 
> We already have an implementation of such a mechanism for sparc64 (ADI), but
> it is target-specific and not exposed to the rest of GDB. This series aims to
> make the infrastructure available to other targets that may wish to support
> their specific memory tagging approaches. For AArch64 Linux this is called
> MTE (Memory Tagging Extensions).
> 
> The series is split into a set that deals with generic changes to GDB's
> infrastructure (target methods, gdbarch hooks and remote packets), a set that
> implements support for AArch64 Linux and one last set that implements new
> commands, updates the documentation and adds tests.
> 
> The goal is to make it so the architecture independent parts of GDB don't
> need to interpret tag formats, given the formats are likely different
> for each architecture.  For this reason, GDB will handle tags as a sequence of
> bytes and will not assume a particular format.
> 
> The architecture-specific code can handle the sequence of bytes appropriately.
> 
> Luis Machado (24):
>    New target methods for memory tagging support
>    New gdbarch memory tagging hooks
>    Add GDB-side remote target support for memory tagging
>    Unit testing for GDB-side remote memory tagging handling
>    GDBserver remote packet support for memory tagging
>    Unit tests for gdbserver memory tagging remote packets
>    Documentation for memory tagging remote packets
>    AArch64: Add MTE CPU feature check support
>    AArch64: Add target description/feature for MTE registers
>    AArch64: Add MTE register set support for GDB and gdbserver
>    AArch64: Add MTE ptrace requests
>    AArch64: Implement memory tagging target methods for AArch64
>    Refactor parsing of /proc/<pid>/smaps
>    AArch64: Implement the memory tagging gdbarch hooks
>    AArch64: Add unit testing for logical tag set/get operations
>    AArch64: Report tag violation error information
>    AArch64: Add gdbserver MTE support
>    AArch64: Add MTE register set support for core files
>    New mtag commands
>    Documentation for the new mtag commands
>    Extend "x" and "print" commands to support memory tagging
>    Document new "x" and "print" memory tagging extensions
>    Add NEWS entry.
>    Add memory tagging testcases
> 
>   gdb/Makefile.in                        |   3 +
>   gdb/NEWS                               |  32 ++
>   gdb/aarch64-linux-nat.c                | 129 ++++++-
>   gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>   gdb/aarch64-linux-tdep.h               |   3 +
>   gdb/aarch64-tdep.c                     |  40 ++-
>   gdb/aarch64-tdep.h                     |  12 +-
>   gdb/arch-utils.c                       |  50 +++
>   gdb/arch-utils.h                       |  23 ++
>   gdb/arch/aarch64-mte-linux.c           |  70 ++++
>   gdb/arch/aarch64-mte-linux.h           |  66 ++++
>   gdb/arch/aarch64.c                     |   7 +-
>   gdb/arch/aarch64.h                     |   7 +-
>   gdb/configure.nat                      |   3 +-
>   gdb/configure.tgt                      |   1 +
>   gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>   gdb/features/Makefile                  |   1 +
>   gdb/features/aarch64-mte.c             |  14 +
>   gdb/features/aarch64-mte.xml           |  11 +
>   gdb/gdbarch.c                          | 137 ++++++++
>   gdb/gdbarch.h                          |  53 +++
>   gdb/gdbarch.sh                         |  36 ++
>   gdb/linux-tdep.c                       | 358 ++++++++++++-------
>   gdb/linux-tdep.h                       |   4 +
>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>   gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
>   gdb/remote.c                           | 232 ++++++++++++
>   gdb/target-delegates.c                 |  84 +++++
>   gdb/target.h                           |  37 ++
>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>   gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>   gdb/testsuite/lib/gdb.exp              |  16 +
>   gdb/valprint.h                         |   1 +
>   gdbserver/Makefile.in                  |   1 +
>   gdbserver/configure.srv                |   2 +
>   gdbserver/linux-aarch64-ipa.cc         |   8 +-
>   gdbserver/linux-aarch64-low.cc         |  97 ++++-
>   gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>   gdbserver/linux-aarch64-tdesc.h        |   3 +-
>   gdbserver/remote-utils.cc              |  43 ++-
>   gdbserver/remote-utils.h               |   7 +-
>   gdbserver/server.cc                    | 245 +++++++++++++
>   gdbserver/server.h                     |   3 +
>   gdbserver/target.cc                    |  20 ++
>   gdbserver/target.h                     |  17 +
>   gdbsupport/rsp-low.cc                  |   2 +-
>   include/elf/common.h                   |   3 +
>   50 files changed, 3536 insertions(+), 186 deletions(-)
>   create mode 100644 gdb/arch/aarch64-mte-linux.c
>   create mode 100644 gdb/arch/aarch64-mte-linux.h
>   create mode 100644 gdb/features/aarch64-mte.c
>   create mode 100644 gdb/features/aarch64-mte.xml
>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-11-16 13:48 ` [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
@ 2020-11-16 14:37   ` Alan Hayward
  2020-11-23 16:08   ` Luis Machado
  1 sibling, 0 replies; 96+ messages in thread
From: Alan Hayward @ 2020-11-16 14:37 UTC (permalink / raw)
  To: Luis Machado
  Cc: gdb-patches\@sourceware.org, jhb@freebsd.org, david.spickett, nd

I’m happy with this series now. Specifically, the AArch64 parts are fine.


Alan.

> On 16 Nov 2020, at 13:48, Luis Machado <luis.machado@linaro.org> wrote:
> 
> Ping?
> 
> FTR, I'm aiming at having this ready for GDB 11.
> 
> On 11/9/20 2:04 PM, Luis Machado wrote:
>> Here's v3 of this patch series.
>> Memory tagging improves memory safety by tagging various parts of memory and
>> raising exceptions when the allocation tag (the one associated with a range of
>> memory addresses) does not match the logical tag contained in a pointer that is
>> used to access the memory area.
>> We already have an implementation of such a mechanism for sparc64 (ADI), but
>> it is target-specific and not exposed to the rest of GDB. This series aims to
>> make the infrastructure available to other targets that may wish to support
>> their specific memory tagging approaches. For AArch64 Linux this is called
>> MTE (Memory Tagging Extensions).
>> The series is split into a set that deals with generic changes to GDB's
>> infrastructure (target methods, gdbarch hooks and remote packets), a set that
>> implements support for AArch64 Linux and one last set that implements new
>> commands, updates the documentation and adds tests.
>> The goal is to make it so the architecture independent parts of GDB don't
>> need to interpret tag formats, given the formats are likely different
>> for each architecture.  For this reason, GDB will handle tags as a sequence of
>> bytes and will not assume a particular format.
>> The architecture-specific code can handle the sequence of bytes appropriately.
>> Luis Machado (24):
>>   New target methods for memory tagging support
>>   New gdbarch memory tagging hooks
>>   Add GDB-side remote target support for memory tagging
>>   Unit testing for GDB-side remote memory tagging handling
>>   GDBserver remote packet support for memory tagging
>>   Unit tests for gdbserver memory tagging remote packets
>>   Documentation for memory tagging remote packets
>>   AArch64: Add MTE CPU feature check support
>>   AArch64: Add target description/feature for MTE registers
>>   AArch64: Add MTE register set support for GDB and gdbserver
>>   AArch64: Add MTE ptrace requests
>>   AArch64: Implement memory tagging target methods for AArch64
>>   Refactor parsing of /proc/<pid>/smaps
>>   AArch64: Implement the memory tagging gdbarch hooks
>>   AArch64: Add unit testing for logical tag set/get operations
>>   AArch64: Report tag violation error information
>>   AArch64: Add gdbserver MTE support
>>   AArch64: Add MTE register set support for core files
>>   New mtag commands
>>   Documentation for the new mtag commands
>>   Extend "x" and "print" commands to support memory tagging
>>   Document new "x" and "print" memory tagging extensions
>>   Add NEWS entry.
>>   Add memory tagging testcases
>>  gdb/Makefile.in                        |   3 +
>>  gdb/NEWS                               |  32 ++
>>  gdb/aarch64-linux-nat.c                | 129 ++++++-
>>  gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>>  gdb/aarch64-linux-tdep.h               |   3 +
>>  gdb/aarch64-tdep.c                     |  40 ++-
>>  gdb/aarch64-tdep.h                     |  12 +-
>>  gdb/arch-utils.c                       |  50 +++
>>  gdb/arch-utils.h                       |  23 ++
>>  gdb/arch/aarch64-mte-linux.c           |  70 ++++
>>  gdb/arch/aarch64-mte-linux.h           |  66 ++++
>>  gdb/arch/aarch64.c                     |   7 +-
>>  gdb/arch/aarch64.h                     |   7 +-
>>  gdb/configure.nat                      |   3 +-
>>  gdb/configure.tgt                      |   1 +
>>  gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>>  gdb/features/Makefile                  |   1 +
>>  gdb/features/aarch64-mte.c             |  14 +
>>  gdb/features/aarch64-mte.xml           |  11 +
>>  gdb/gdbarch.c                          | 137 ++++++++
>>  gdb/gdbarch.h                          |  53 +++
>>  gdb/gdbarch.sh                         |  36 ++
>>  gdb/linux-tdep.c                       | 358 ++++++++++++-------
>>  gdb/linux-tdep.h                       |   4 +
>>  gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>>  gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>>  gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
>>  gdb/remote.c                           | 232 ++++++++++++
>>  gdb/target-delegates.c                 |  84 +++++
>>  gdb/target.h                           |  37 ++
>>  gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>>  gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>>  gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>  gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>>  gdb/testsuite/lib/gdb.exp              |  16 +
>>  gdb/valprint.h                         |   1 +
>>  gdbserver/Makefile.in                  |   1 +
>>  gdbserver/configure.srv                |   2 +
>>  gdbserver/linux-aarch64-ipa.cc         |   8 +-
>>  gdbserver/linux-aarch64-low.cc         |  97 ++++-
>>  gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>>  gdbserver/linux-aarch64-tdesc.h        |   3 +-
>>  gdbserver/remote-utils.cc              |  43 ++-
>>  gdbserver/remote-utils.h               |   7 +-
>>  gdbserver/server.cc                    | 245 +++++++++++++
>>  gdbserver/server.h                     |   3 +
>>  gdbserver/target.cc                    |  20 ++
>>  gdbserver/target.h                     |  17 +
>>  gdbsupport/rsp-low.cc                  |   2 +-
>>  include/elf/common.h                   |   3 +
>>  50 files changed, 3536 insertions(+), 186 deletions(-)
>>  create mode 100644 gdb/arch/aarch64-mte-linux.c
>>  create mode 100644 gdb/arch/aarch64-mte-linux.h
>>  create mode 100644 gdb/features/aarch64-mte.c
>>  create mode 100644 gdb/features/aarch64-mte.xml
>>  create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>>  create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>  create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>  create mode 100644 gdb/testsuite/gdb.base/memtag.exp


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-11-09 17:04 ` [PATCH v3 16/24] AArch64: Report tag violation error information Luis Machado
@ 2020-11-16 15:43   ` David Spickett
  2020-11-16 16:45     ` Luis Machado
  2020-12-26 22:23   ` Simon Marchi
  1 sibling, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-16 15:43 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, alan.hayward, John Baldwin

> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
> +                                 struct ui_out *uiout,
> +                                 enum gdb_signal siggnal)

siggnal -> signal

Also a nit about the formatting.

Copying from 20/24 of v3:
> +Memory tag violation while accessing address 0x0000fffff7ff8000
> +Allocation tag 0x0000000000000001.

(I'm guessing the code to print the "Allocation tag" line lives here
in some part)

Would it make more sense to either not align the tag value to
anything, or to align it to the size of the architecture's tag? Which
would be 4 bits in this case so the same either way.

On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
>
> Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
> information can be obtained through the siginfo data structure.
>
> For AArch64 the Linux kernel may expose the fault address and tag
> information, if we have a synchronous event. Otherwise there is
> no fault address available.
>
> gdb/ChangeLog:
>
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>
>         * aarch64-linux-tdep.c
>         (aarch64_linux_report_signal_info): New function.
>         (aarch64_linux_init_abi): Register
>         aarch64_linux_report_signal_info as the report_signal_info hook.
>         * arch/aarch64-linux.h (SEGV_MTEAERR): Define.
>         (SEGV_MTESERR): Define.
> ---
>  gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
>  gdb/arch/aarch64-mte-linux.h |  6 ++++
>  2 files changed, 70 insertions(+)
>
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 39b1790263..70e180e1cb 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
>    return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
>  }
>
> +/* AArch64 Linux implementation of the report_signal_info gdbarch
> +   hook.  Displays information about possible memory tag violations.  */
> +
> +static void
> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
> +                                 struct ui_out *uiout,
> +                                 enum gdb_signal siggnal)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
> +    return;
> +
> +  CORE_ADDR fault_addr = 0;
> +  long si_code = 0;
> +
> +  try
> +    {
> +      /* Sigcode tells us if the segfault is actually a memory tag
> +        violation.  */
> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
> +
> +      fault_addr
> +       = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> +    }
> +  catch (const gdb_exception &exception)
> +    {
> +      return;
> +    }
> +
> +  /* If this is not a memory tag violation, just return.  */
> +  if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR)
> +    return;
> +
> +  uiout->text ("\n");
> +
> +  uiout->field_string ("sigcode-meaning", _("Memory tag violation"));
> +
> +  /* For synchronous faults, show additional information.  */
> +  if (si_code == SEGV_MTESERR)
> +    {
> +      uiout->text (_(" while accessing address "));
> +      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
> +      uiout->text ("\n");
> +
> +      CORE_ADDR atag;
> +      if (aarch64_linux_get_atag (fault_addr, &atag) != 0)
> +       uiout->text (_("Allocation tag unavailable"));
> +      else
> +       {
> +         uiout->text (_("Allocation tag "));
> +         uiout->field_core_addr ("allocation-tag", gdbarch, atag);
> +       }
> +    }
> +  else
> +    {
> +      uiout->text ("\n");
> +      uiout->text (_("Fault address unavailable"));
> +    }
> +}
> +
>  static void
>  aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>  {
> @@ -1706,6 +1767,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>
>        /* Register a hook for converting a memory tag to a string.  */
>        set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
> +
> +      set_gdbarch_report_signal_info (gdbarch,
> +                                     aarch64_linux_report_signal_info);
>      }
>
>    /* Initialize the aarch64_linux_record_tdep.  */
> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
> index 5c5783f28b..a5a980ed49 100644
> --- a/gdb/arch/aarch64-mte-linux.h
> +++ b/gdb/arch/aarch64-mte-linux.h
> @@ -35,6 +35,12 @@
>  #define MTE_LOGICAL_TAG_START_BIT   56
>  #define MTE_LOGICAL_MAX_VALUE      0xf
>
> +/* Memory tagging definitions.  */
> +#ifndef SEGV_MTEAERR
> +# define SEGV_MTEAERR 8
> +# define SEGV_MTESERR 9
> +#endif
> +
>  /* Return the number of tag granules in the memory range
>     [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
>  extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-09 17:08   ` Eli Zaretskii
@ 2020-11-16 15:44     ` David Spickett
  2020-11-16 16:04       ` David Spickett
  2020-11-16 16:49       ` Luis Machado
  0 siblings, 2 replies; 96+ messages in thread
From: David Spickett @ 2020-11-16 15:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Luis Machado, gdb-patches

Minor thing, there is a missing space here in "typeis".

> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> +integer.

On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>
> > Date: Mon,  9 Nov 2020 14:04:18 -0300
> > From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> > Cc: david.spickett@linaro.org
> >
> > gdb/doc/ChangeLog:
> >
> > YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >
> >       * gdb.texinfo (General Query Packets): Document qMemTags and
> >       QMemTags.  Document the "memory-tagging" feature.
> > ---
> >  gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 96 insertions(+)
>
> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 24/24] Add memory tagging testcases
  2020-11-09 17:04 ` [PATCH v3 24/24] Add memory tagging testcases Luis Machado
@ 2020-11-16 15:47   ` David Spickett
  2020-11-16 16:51     ` Luis Machado
  2020-12-27  4:36   ` Simon Marchi
  1 sibling, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-16 15:47 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, alan.hayward, John Baldwin

(I've just skimmed through so not a review in any real way)

In gdb/testsuite/gdb.arch/aarch64-mte.exp:
+# Test a binary with address signing works regardless of whether the target
+# supports pauth instructions.  On non pauth systems, all pauth instructions
+# are treated as nops.

I assume this was left over from the original test file you adapted,
it doesn't apply to MTE.

On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
>
> Add an AArch64-specific test and a more generic memory tagging test that
> other architectures can run.
>
> Even though architectures not supporting memory tagging can run the memory
> tagging tests, the runtime check will make the tests bail out early, as it
> would make no sense to proceed without proper support.
>
> It is also tricky to do any further runtime tests for memory tagging, given
> we'd need to deal with tags, and those are arch-specific.  Therefore the
> test in gdb.base is more of a smoke test.
>
> If an architecture wants to implement memory tagging, then it makes sense to
> have tests within gdb.arch instead.
>
> gdb/testsuite/ChangeLog:
>
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>
>         * gdb.arch/aarch64-mte.c: New file.
>         * gdb.arch/aarch64-mte.exp: New test.
>         * gdb.base/memtag.c: New file.
>         * gdb.base/memtag.exp: New test.
>         * lib/gdb.exp (supports_memtag): New function.
> ---
>  gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 +++++++
>  gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 +++++++++++++++++++++++++
>  gdb/testsuite/gdb.base/memtag.c        |  22 ++
>  gdb/testsuite/gdb.base/memtag.exp      |  64 +++++
>  gdb/testsuite/lib/gdb.exp              |  16 ++
>  5 files changed, 580 insertions(+)
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>  create mode 100644 gdb/testsuite/gdb.base/memtag.c
>  create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>
> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.c b/gdb/testsuite/gdb.arch/aarch64-mte.c
> new file mode 100644
> index 0000000000..f6fb4cca67
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.c
> @@ -0,0 +1,107 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2020 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_NONE                (0UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_SYNC                (1UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_ASYNC       (2UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_MASK                (3UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TAG_SHIFT       3
> +#define PR_MTE_TAG_MASK                (0xffffUL << PR_MTE_TAG_SHIFT)
> +
> +void
> +access_memory (unsigned char *tagged_ptr, unsigned char *untagged_ptr)
> +{
> +  tagged_ptr[0] = 'a';
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> +  unsigned char *tagged_ptr;
> +  unsigned char *untagged_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;
> +    }
> +
> +  /* Create another mapping that won't have PROT_MTE set.  */
> +  untagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
> +                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +  if (untagged_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, untagged_ptr);
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.exp b/gdb/testsuite/gdb.arch/aarch64-mte.exp
> new file mode 100644
> index 0000000000..39dba493fb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.exp
> @@ -0,0 +1,371 @@
> +# Copyright (C) 2020 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/>.
> +
> +# Test a binary with address signing works regardless of whether the target
> +# supports pauth instructions.  On non pauth systems, all pauth instructions
> +# are treated as nops.
> +
> +global hex
> +global decimal
> +
> +# Return TAG in hex format with no leading zeroes.
> +proc get_hex_tag { tag } {
> +    return [format "%x" $tag]
> +}
> +
> +# Return TAG in the NN format where N is 4 bits of the byte.
> +proc get_tag_nn { tag } {
> +    return [format "%02x" $tag]
> +}
> +
> +# Return the address of PTR with a tag of TAG.
> +proc get_tagged_ptr { tag ptr } {
> +  set addr [get_hexadecimal_valueof $ptr -1]
> +  return [get_valueof "/x" \
> +             "${addr} & (0xf0ffffffffffffff) | ((unsigned long) ${tag} << 56)" \
> +             "0" "fetch pointer ${ptr} with tag ${tag}"]
> +}
> +
> +# Return the logical TAG from PTR.
> +proc get_ltag_from_ptr { ptr } {
> +  set addr [get_hexadecimal_valueof $ptr -1]
> +  return [get_valueof "/x" "${addr} >> 56 & 0xf" -1 \
> +                     "fetch tag from pointer ${ptr}"]
> +}
> +
> +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]} {
> +    untested "memory tagging unsupported"
> +    return -1
> +}
> +
> +gdb_breakpoint "access_memory"
> +
> +if [gdb_continue "access_memory"] {
> +    fail "could not run to tagged memory test function"
> +    return -1
> +}
> +
> +# Fetch a known pointer to an area mapped with PROT_MTE.
> +set tagged_ptr_symbol "tagged_ptr"
> +set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
> +
> +if {$tagged_ptr_addr == -1} {
> +    untested "unexpected pointer or tag value"
> +    return -1
> +}
> +
> +# Fetch a known pointer to an area not mapped with PROT_MTE.
> +set untagged_ptr_symbol "untagged_ptr"
> +set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
> +
> +if {$untagged_ptr_addr == -1} {
> +    untested "unexpected pointer or tag value"
> +    return -1
> +}
> +
> +with_test_prefix "literals" {
> +    # Test inspecting an allocation tag from a pointer to a memory area that
> +    # is not mapped with PROT_MTE.
> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
> +    gdb_test "mtag showatag ${untagged_ptr_addr}" $msg \
> +            "mtag showatag with an untagged address"
> +
> +    gdb_test "mtag setatag ${untagged_ptr_addr} 0 00" $msg \
> +            "mtag setatag with an untagged address"
> +
> +    set addr_tagged 0
> +    set addr_tagged_valid 0
> +
> +    # Test setting and showing the logical tags for a literal address.
> +    for {set i 0} {$i < 32} {incr i} {
> +       with_test_prefix "tag ${i}" {
> +           set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +       }
> +
> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
> +       gdb_test "mtag showltag ${addr_tagged}" \
> +                " = 0x${tag_hexnz}" \
> +                "showltag with tag ${i}"
> +
> +       set tag_hexnn [get_tag_nn $i]
> +       gdb_test "mtag withltag ${addr_tagged} ${tag_hexnn}" \
> +                " = \\(void \\*\\) ${addr_tagged}" \
> +                "withltag with tag ${i}"
> +    }
> +
> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
> +    # Test setting and showing the allocation tags.
> +    for {set i 0} {$i < 32} {incr i} {
> +
> +       set tag_hexnn [get_tag_nn $i]
> +       gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
> +                $setatag_msg \
> +                "setatag with tag ${i}"
> +
> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
> +       gdb_test "mtag showatag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \
> +                "showatag with tag ${i}"
> +    }
> +
> +    # Test tag mismatches.
> +    with_test_prefix "tag mismatches" {
> +       for {set i 0} {$i < 32} {incr i} {
> +
> +           # Set the allocation tag to a known value.
> +           set tag_hexnn [get_tag_nn $i]
> +           gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
> +                    $setatag_msg \
> +                    "setatag with tag ${i}"
> +
> +           set atag_hexnz [get_hex_tag [expr $i % 16]]
> +
> +           # Validate that the logical tag matches the allocation tag.
> +           with_test_prefix "tag ${i}" {
> +               set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +           }
> +
> +           gdb_test "mtag check ${addr_tagged}" \
> +                    "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
> +                    "check match with tag ${i}"
> +
> +           # Get a pointer with the logical tag that does not match the
> +           # allocation tag.
> +           set ltag [expr $i + 1]
> +           with_test_prefix "fetch mismatch tag ${i}" {
> +               set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
> +           }
> +
> +           # Validate that the logical tag does not match the allocation
> +           # tag.
> +           set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
> +           gdb_test "mtag check ${addr_tagged}" \
> +                    "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
> +                    "check mismatch with tag ${i}"
> +       }
> +    }
> +}
> +
> +with_test_prefix "symbolic" {
> +    # Test inspecting an allocation tag from a pointer to a memory area that
> +    # is not mapped with PROT_MTE.
> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
> +    gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
> +            "mtag showatag with an untagged address"
> +
> +    gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
> +            "mtag setatag with an untagged address"
> +
> +    # Test setting and showing the logical tags for a literal address.
> +    for {set i 0} {$i < 32} {incr i} {
> +       set addr_tagged 0
> +
> +       with_test_prefix "tag ${i}" {
> +           set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +           gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +                              "update value of symbol ${tagged_ptr_symbol}"
> +       }
> +
> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
> +       gdb_test "mtag showltag ${tagged_ptr_symbol}" \
> +                " = 0x${tag_hexnz}" \
> +                "showltag with tag ${i}"
> +
> +       set tag_hexnn [get_tag_nn $i]
> +       gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
> +                " = \\(void \\*\\) ${addr_tagged}" \
> +                "withltag with tag ${i}"
> +    }
> +
> +    # Reset the tagged ptr to its original value
> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> +                      "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> +
> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
> +    # Test setting and showing the allocation tags.
> +    for {set i 0} {$i < 32} {incr i} {
> +
> +       set tag_hexnn [get_tag_nn $i]
> +       gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> +                $setatag_msg \
> +                "setatag with tag ${i}"
> +
> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
> +       gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
> +                "showatag with tag ${i}"
> +    }
> +
> +    # Test tag mismatches.
> +    with_test_prefix "tag mismatches" {
> +       for {set i 0} {$i < 32} {incr i} {
> +
> +           # Set the allocation tag to a known value (0).
> +           set tag_hexnn [get_tag_nn $i]
> +           gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> +                    $setatag_msg \
> +                    "setatag with tag ${i}"
> +
> +           set atag_hexnz [get_hex_tag [expr $i % 16]]
> +
> +           # Validate that the logical tag matches the allocation tag.
> +           with_test_prefix "tag ${i}" {
> +               set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +           }
> +
> +           with_test_prefix "tag ${i}" {
> +               gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +                                  "set ${tagged_ptr_symbol} to a matching logical tag"
> +           }
> +
> +           gdb_test "mtag check ${tagged_ptr_symbol}" \
> +                    "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
> +                    "check match with tag ${i}"
> +
> +           # Get a pointer with the logical tag that does not match the
> +           # allocation tag.
> +           set ltag [expr $i + 1]
> +           with_test_prefix "fetch mismatch tag ${i}" {
> +               set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
> +           }
> +
> +           with_test_prefix "tag ${i}" {
> +               gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +                                  "set ${tagged_ptr_symbol} to a mismatching logical tag"
> +           }
> +
> +           # Validate that the logical tag does not match the allocation
> +           # tag.
> +           set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
> +           gdb_test "mtag check ${tagged_ptr_symbol}" \
> +                    "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
> +                    "check mismatch with tag ${i}"
> +       }
> +    # Reset the tagged ptr to its original value
> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> +                      "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> +    }
> +}
> +
> +# Test the memory tagging extensions for the "print" command.
> +with_test_prefix "print command" {
> +    set untagged_ptr [get_tagged_ptr 0 ${tagged_ptr_addr}]
> +
> +    with_test_prefix "fetch ltag" {
> +       set ltag [get_ltag_from_ptr ${tagged_ptr_addr}]
> +    }
> +
> +    if {$ltag == -1} {
> +       untested "unexpected tag value"
> +       return -1
> +    }
> +
> +    set atag [expr [expr $ltag + 1] % 16]
> +    set atag_hexnn [get_tag_nn $atag]
> +
> +    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${atag_hexnn}" \
> +            $setatag_msg \
> +            "make atag and ltag different"
> +
> +    set atag_hexnz [get_hex_tag $atag]
> +    gdb_test "p/x ${tagged_ptr_symbol}" \
> +       [multi_line \
> +           "Logical tag \\(${ltag}\\) does not match the allocation tag \\(0x${atag_hexnz}\\)\." \
> +           "\\\$\[0-9\]+ = ${untagged_ptr}"] \
> +           "show tag mismatch"
> +}
> +
> +# Test the memory tagging extensions for the "x" command.
> +with_test_prefix "x command" {
> +
> +    # Check if the allocation tags match what we expect.
> +    gdb_test "x/gxm ${tagged_ptr_symbol}" \
> +       [multi_line \
> +           "<Allocation Tag $hex for range \\\[$hex,$hex\\)>" \
> +           "$hex:\[ \t\]+$hex"] \
> +       "outputs tag information"
> +
> +    # Also make sure no tag information is output for memory areas without
> +    # PROT_MTE mappings.
> +    gdb_test "x/gxm ${untagged_ptr_symbol}" \
> +            "$hex:\[ \t\]+$hex" \
> +            "does not output tag information"
> +}
> +
> +# Validate the presence of the MTE registers.
> +foreach reg {"tag_ctl" } {
> +    gdb_test "info registers $reg" \
> +            "$reg\[ \t\]+$hex\[ \t\]+$decimal" \
> +            "register $reg available"
> +}
> +
> +# 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\." \
> +       "$hex in access_memory \\(.*\\) at .*" \
> +       ".*tagged_ptr\\\[0\\\] = 'a';"] \
> +        "display tag violation information"
> +
> +# Restart to execute the async tag fault test.
> +with_test_prefix "async" {
> +    if ![runto_main] {
> +       untested "could not run to main"
> +       return -1
> +    }
> +
> +    gdb_breakpoint "access_memory"
> +
> +    if [gdb_continue "access_memory"] {
> +       fail "could not run to tagged memory test function"
> +       return -1
> +    }
> +
> +    # Force a tag fault.
> +    gdb_test "mtag setatag tagged_ptr 0 05" \
> +            $setatag_msg \
> +            "make atag and ltag different"
> +
> +    # Force the tag fault to be async.
> +    gdb_test_no_output "set \$tag_ctl=0x7fff5" "set tag_ctl to async"
> +
> +    # Run until a crash and confirm GDB displays memory tag violation
> +    # information for async mode
> +    gdb_test "continue" \
> +       [multi_line \
> +           "Program received signal SIGSEGV, Segmentation fault" \
> +           "Memory tag violation" \
> +           "Fault address unavailable\." \
> +           "$hex in .* \\(.*\\) .*"] \
> +           "display tag violation information"
> +}
> diff --git a/gdb/testsuite/gdb.base/memtag.c b/gdb/testsuite/gdb.base/memtag.c
> new file mode 100644
> index 0000000000..63a42ae278
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/memtag.c
> @@ -0,0 +1,22 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2020 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/>.  */
> +
> +int
> +main (int argc, char **argv)
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/memtag.exp b/gdb/testsuite/gdb.base/memtag.exp
> new file mode 100644
> index 0000000000..484a78e828
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/memtag.exp
> @@ -0,0 +1,64 @@
> +# Copyright 2020 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/>.
> +
> +# Smoke testing for the various memory tagging commands in GDB.
> +
> +set u_msg "Memory tagging not supported or disabled by the current architecture\."
> +
> +standard_testfile
> +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
> +    return -1
> +}
> +
> +if {[target_info gdb_protocol] == "extended-remote"} {
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"
> +}
> +
> +# Test commands without running the program.
> +with_test_prefix "before program execution" {
> +    # These commands should all fails without a running program.
> +    foreach subcmd {"withltag" "showltag" "setatag" "showatag" "check"} {
> +       gdb_test "mtag $subcmd" $u_msg
> +    }
> +}
> +
> +clean_restart $testfile
> +
> +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]} {
> +    untested "memory tagging unsupported"
> +    return -1
> +}
> +
> +# With the program running, try to use the memory tagging commands.
> +with_test_prefix "during program execution" {
> +    set msg "Argument required \\(address or pointer\\)\."
> +
> +    # Test the various mtag commands again.
> +    gdb_test "mtag showltag" $msg
> +    gdb_test "mtag showatag" $msg
> +    gdb_test "mtag withltag" "Argument required \\(<address> <tag>\\)\."
> +    gdb_test "mtag setatag" \
> +            "Argument required \\(<starting address> <length> <tag bytes>\\)\."
> +    gdb_test "mtag check" $msg
> +}
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 55154db6a5..347704ce0a 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
>      }
>  }
>
> +# Return 1 if memory tagging is supported at runtime, otherwise return 0.
> +
> +proc supports_memtag {} {
> +    global gdb_prompt
> +
> +    gdb_test_multiple "mtag check" "" {
> +       -re "Memory tagging not supported or disabled by the current architecture\..*$gdb_prompt $" {
> +         return 0
> +       }
> +       -re "Argument required \\(address or pointer\\).*$gdb_prompt $" {
> +           return 1
> +       }
> +    }
> +    return 0
> +}
> +
>  # Return 1 if the target supports hardware single stepping.
>
>  proc can_hardware_single_step {} {
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-16 15:44     ` David Spickett
@ 2020-11-16 16:04       ` David Spickett
  2020-11-16 17:22         ` Luis Machado
  2020-11-16 16:49       ` Luis Machado
  1 sibling, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-16 16:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Luis Machado, gdb-patches

Also with regard to the "type" field.

> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> +integer.

(typo aside) Is this field architecture specific and will there be a
list of these type numbers documented anywhere? (or already is)
For example would 1 on AArch64 be MTE, and on <other arch> be <other
tag type>. Or would that <other tag type> be 2.

My assumption has been that it is the latter and that a value means a
kind of tagging extension. So for example 1=MTE rather than
1= mte logical and 2 = mte allocation. Correct me if I am wrong there.

A page like:
https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds

Or just a short note, given that there's only one type right now.

Also, I may have suggested the type be a string at some point. However
based on examples like the link above
I don't see much advantage to it apart from making packet dumps easier
to read. Just wanted to close the loop on that
if I didn't before.



On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>
> Minor thing, there is a missing space here in "typeis".
>
> > +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> > +integer.
>
> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >
> > > Date: Mon,  9 Nov 2020 14:04:18 -0300
> > > From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> > > Cc: david.spickett@linaro.org
> > >
> > > gdb/doc/ChangeLog:
> > >
> > > YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> > >
> > >       * gdb.texinfo (General Query Packets): Document qMemTags and
> > >       QMemTags.  Document the "memory-tagging" feature.
> > > ---
> > >  gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 96 insertions(+)
> >
> > OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-11-16 15:43   ` David Spickett
@ 2020-11-16 16:45     ` Luis Machado
  2020-11-17  9:36       ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-16 16:45 UTC (permalink / raw)
  To: David Spickett; +Cc: gdb-patches, alan.hayward, John Baldwin

On 11/16/20 12:43 PM, David Spickett wrote:
>> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>> +                                 struct ui_out *uiout,
>> +                                 enum gdb_signal siggnal)
> 
> siggnal -> signal
> 

This is a GDB-ism. The hook itself is named like that. I don't like the 
name, but I thought I'd leave it the same just to keep it standard.

> Also a nit about the formatting.
> 
> Copying from 20/24 of v3:
>> +Memory tag violation while accessing address 0x0000fffff7ff8000
>> +Allocation tag 0x0000000000000001.
> 
> (I'm guessing the code to print the "Allocation tag" line lives here
> in some part)
> 
> Would it make more sense to either not align the tag value to
> anything, or to align it to the size of the architecture's tag? Which
> would be 4 bits in this case so the same either way.

We could print it without leading zeroes. That may make things a bit 
more compact. Would that work?

> 
> On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
>> information can be obtained through the siginfo data structure.
>>
>> For AArch64 the Linux kernel may expose the fault address and tag
>> information, if we have a synchronous event. Otherwise there is
>> no fault address available.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>>          * aarch64-linux-tdep.c
>>          (aarch64_linux_report_signal_info): New function.
>>          (aarch64_linux_init_abi): Register
>>          aarch64_linux_report_signal_info as the report_signal_info hook.
>>          * arch/aarch64-linux.h (SEGV_MTEAERR): Define.
>>          (SEGV_MTESERR): Define.
>> ---
>>   gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
>>   gdb/arch/aarch64-mte-linux.h |  6 ++++
>>   2 files changed, 70 insertions(+)
>>
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index 39b1790263..70e180e1cb 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
>>     return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
>>   }
>>
>> +/* AArch64 Linux implementation of the report_signal_info gdbarch
>> +   hook.  Displays information about possible memory tag violations.  */
>> +
>> +static void
>> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>> +                                 struct ui_out *uiout,
>> +                                 enum gdb_signal siggnal)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
>> +    return;
>> +
>> +  CORE_ADDR fault_addr = 0;
>> +  long si_code = 0;
>> +
>> +  try
>> +    {
>> +      /* Sigcode tells us if the segfault is actually a memory tag
>> +        violation.  */
>> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
>> +
>> +      fault_addr
>> +       = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
>> +    }
>> +  catch (const gdb_exception &exception)
>> +    {
>> +      return;
>> +    }
>> +
>> +  /* If this is not a memory tag violation, just return.  */
>> +  if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR)
>> +    return;
>> +
>> +  uiout->text ("\n");
>> +
>> +  uiout->field_string ("sigcode-meaning", _("Memory tag violation"));
>> +
>> +  /* For synchronous faults, show additional information.  */
>> +  if (si_code == SEGV_MTESERR)
>> +    {
>> +      uiout->text (_(" while accessing address "));
>> +      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
>> +      uiout->text ("\n");
>> +
>> +      CORE_ADDR atag;
>> +      if (aarch64_linux_get_atag (fault_addr, &atag) != 0)
>> +       uiout->text (_("Allocation tag unavailable"));
>> +      else
>> +       {
>> +         uiout->text (_("Allocation tag "));
>> +         uiout->field_core_addr ("allocation-tag", gdbarch, atag);
>> +       }
>> +    }
>> +  else
>> +    {
>> +      uiout->text ("\n");
>> +      uiout->text (_("Fault address unavailable"));
>> +    }
>> +}
>> +
>>   static void
>>   aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>>   {
>> @@ -1706,6 +1767,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>>
>>         /* Register a hook for converting a memory tag to a string.  */
>>         set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
>> +
>> +      set_gdbarch_report_signal_info (gdbarch,
>> +                                     aarch64_linux_report_signal_info);
>>       }
>>
>>     /* Initialize the aarch64_linux_record_tdep.  */
>> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
>> index 5c5783f28b..a5a980ed49 100644
>> --- a/gdb/arch/aarch64-mte-linux.h
>> +++ b/gdb/arch/aarch64-mte-linux.h
>> @@ -35,6 +35,12 @@
>>   #define MTE_LOGICAL_TAG_START_BIT   56
>>   #define MTE_LOGICAL_MAX_VALUE      0xf
>>
>> +/* Memory tagging definitions.  */
>> +#ifndef SEGV_MTEAERR
>> +# define SEGV_MTEAERR 8
>> +# define SEGV_MTESERR 9
>> +#endif
>> +
>>   /* Return the number of tag granules in the memory range
>>      [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
>>   extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
>> --
>> 2.17.1
>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-16 15:44     ` David Spickett
  2020-11-16 16:04       ` David Spickett
@ 2020-11-16 16:49       ` Luis Machado
  1 sibling, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-16 16:49 UTC (permalink / raw)
  To: David Spickett, Eli Zaretskii; +Cc: gdb-patches

On 11/16/20 12:44 PM, David Spickett wrote:
> Minor thing, there is a missing space here in "typeis".
> 

Thanks for catching that. Fixed now.

>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>> +integer.
> 
> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>
>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>> Cc: david.spickett@linaro.org
>>>
>>> gdb/doc/ChangeLog:
>>>
>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>
>>>        * gdb.texinfo (General Query Packets): Document qMemTags and
>>>        QMemTags.  Document the "memory-tagging" feature.
>>> ---
>>>   gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 96 insertions(+)
>>
>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 24/24] Add memory tagging testcases
  2020-11-16 15:47   ` David Spickett
@ 2020-11-16 16:51     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-11-16 16:51 UTC (permalink / raw)
  To: David Spickett; +Cc: gdb-patches, alan.hayward, John Baldwin

On 11/16/20 12:47 PM, David Spickett wrote:
> (I've just skimmed through so not a review in any real way)
> 
> In gdb/testsuite/gdb.arch/aarch64-mte.exp:
> +# Test a binary with address signing works regardless of whether the target
> +# supports pauth instructions.  On non pauth systems, all pauth instructions
> +# are treated as nops.
> 
> I assume this was left over from the original test file you adapted,
> it doesn't apply to MTE.
> 

Indeed. Fixed now.

> On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> Add an AArch64-specific test and a more generic memory tagging test that
>> other architectures can run.
>>
>> Even though architectures not supporting memory tagging can run the memory
>> tagging tests, the runtime check will make the tests bail out early, as it
>> would make no sense to proceed without proper support.
>>
>> It is also tricky to do any further runtime tests for memory tagging, given
>> we'd need to deal with tags, and those are arch-specific.  Therefore the
>> test in gdb.base is more of a smoke test.
>>
>> If an architecture wants to implement memory tagging, then it makes sense to
>> have tests within gdb.arch instead.
>>
>> gdb/testsuite/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>>          * gdb.arch/aarch64-mte.c: New file.
>>          * gdb.arch/aarch64-mte.exp: New test.
>>          * gdb.base/memtag.c: New file.
>>          * gdb.base/memtag.exp: New test.
>>          * lib/gdb.exp (supports_memtag): New function.
>> ---
>>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 +++++++
>>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 +++++++++++++++++++++++++
>>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>   gdb/testsuite/gdb.base/memtag.exp      |  64 +++++
>>   gdb/testsuite/lib/gdb.exp              |  16 ++
>>   5 files changed, 580 insertions(+)
>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>>
>> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.c b/gdb/testsuite/gdb.arch/aarch64-mte.c
>> new file mode 100644
>> index 0000000000..f6fb4cca67
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.c
>> @@ -0,0 +1,107 @@
>> +/* This test program is part of GDB, the GNU debugger.
>> +
>> +   Copyright 2020 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_NONE                (0UL << PR_MTE_TCF_SHIFT)
>> +#define PR_MTE_TCF_SYNC                (1UL << PR_MTE_TCF_SHIFT)
>> +#define PR_MTE_TCF_ASYNC       (2UL << PR_MTE_TCF_SHIFT)
>> +#define PR_MTE_TCF_MASK                (3UL << PR_MTE_TCF_SHIFT)
>> +#define PR_MTE_TAG_SHIFT       3
>> +#define PR_MTE_TAG_MASK                (0xffffUL << PR_MTE_TAG_SHIFT)
>> +
>> +void
>> +access_memory (unsigned char *tagged_ptr, unsigned char *untagged_ptr)
>> +{
>> +  tagged_ptr[0] = 'a';
>> +}
>> +
>> +int
>> +main (int argc, char **argv)
>> +{
>> +  unsigned char *tagged_ptr;
>> +  unsigned char *untagged_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;
>> +    }
>> +
>> +  /* Create another mapping that won't have PROT_MTE set.  */
>> +  untagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
>> +                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
>> +  if (untagged_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, untagged_ptr);
>> +
>> +  return 0;
>> +}
>> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.exp b/gdb/testsuite/gdb.arch/aarch64-mte.exp
>> new file mode 100644
>> index 0000000000..39dba493fb
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.exp
>> @@ -0,0 +1,371 @@
>> +# Copyright (C) 2020 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/>.
>> +
>> +# Test a binary with address signing works regardless of whether the target
>> +# supports pauth instructions.  On non pauth systems, all pauth instructions
>> +# are treated as nops.
>> +
>> +global hex
>> +global decimal
>> +
>> +# Return TAG in hex format with no leading zeroes.
>> +proc get_hex_tag { tag } {
>> +    return [format "%x" $tag]
>> +}
>> +
>> +# Return TAG in the NN format where N is 4 bits of the byte.
>> +proc get_tag_nn { tag } {
>> +    return [format "%02x" $tag]
>> +}
>> +
>> +# Return the address of PTR with a tag of TAG.
>> +proc get_tagged_ptr { tag ptr } {
>> +  set addr [get_hexadecimal_valueof $ptr -1]
>> +  return [get_valueof "/x" \
>> +             "${addr} & (0xf0ffffffffffffff) | ((unsigned long) ${tag} << 56)" \
>> +             "0" "fetch pointer ${ptr} with tag ${tag}"]
>> +}
>> +
>> +# Return the logical TAG from PTR.
>> +proc get_ltag_from_ptr { ptr } {
>> +  set addr [get_hexadecimal_valueof $ptr -1]
>> +  return [get_valueof "/x" "${addr} >> 56 & 0xf" -1 \
>> +                     "fetch tag from pointer ${ptr}"]
>> +}
>> +
>> +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]} {
>> +    untested "memory tagging unsupported"
>> +    return -1
>> +}
>> +
>> +gdb_breakpoint "access_memory"
>> +
>> +if [gdb_continue "access_memory"] {
>> +    fail "could not run to tagged memory test function"
>> +    return -1
>> +}
>> +
>> +# Fetch a known pointer to an area mapped with PROT_MTE.
>> +set tagged_ptr_symbol "tagged_ptr"
>> +set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
>> +
>> +if {$tagged_ptr_addr == -1} {
>> +    untested "unexpected pointer or tag value"
>> +    return -1
>> +}
>> +
>> +# Fetch a known pointer to an area not mapped with PROT_MTE.
>> +set untagged_ptr_symbol "untagged_ptr"
>> +set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
>> +
>> +if {$untagged_ptr_addr == -1} {
>> +    untested "unexpected pointer or tag value"
>> +    return -1
>> +}
>> +
>> +with_test_prefix "literals" {
>> +    # Test inspecting an allocation tag from a pointer to a memory area that
>> +    # is not mapped with PROT_MTE.
>> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
>> +    gdb_test "mtag showatag ${untagged_ptr_addr}" $msg \
>> +            "mtag showatag with an untagged address"
>> +
>> +    gdb_test "mtag setatag ${untagged_ptr_addr} 0 00" $msg \
>> +            "mtag setatag with an untagged address"
>> +
>> +    set addr_tagged 0
>> +    set addr_tagged_valid 0
>> +
>> +    # Test setting and showing the logical tags for a literal address.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +       with_test_prefix "tag ${i}" {
>> +           set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +       }
>> +
>> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +       gdb_test "mtag showltag ${addr_tagged}" \
>> +                " = 0x${tag_hexnz}" \
>> +                "showltag with tag ${i}"
>> +
>> +       set tag_hexnn [get_tag_nn $i]
>> +       gdb_test "mtag withltag ${addr_tagged} ${tag_hexnn}" \
>> +                " = \\(void \\*\\) ${addr_tagged}" \
>> +                "withltag with tag ${i}"
>> +    }
>> +
>> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
>> +    # Test setting and showing the allocation tags.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +
>> +       set tag_hexnn [get_tag_nn $i]
>> +       gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
>> +                $setatag_msg \
>> +                "setatag with tag ${i}"
>> +
>> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +       gdb_test "mtag showatag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \
>> +                "showatag with tag ${i}"
>> +    }
>> +
>> +    # Test tag mismatches.
>> +    with_test_prefix "tag mismatches" {
>> +       for {set i 0} {$i < 32} {incr i} {
>> +
>> +           # Set the allocation tag to a known value.
>> +           set tag_hexnn [get_tag_nn $i]
>> +           gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
>> +                    $setatag_msg \
>> +                    "setatag with tag ${i}"
>> +
>> +           set atag_hexnz [get_hex_tag [expr $i % 16]]
>> +
>> +           # Validate that the logical tag matches the allocation tag.
>> +           with_test_prefix "tag ${i}" {
>> +               set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +           }
>> +
>> +           gdb_test "mtag check ${addr_tagged}" \
>> +                    "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
>> +                    "check match with tag ${i}"
>> +
>> +           # Get a pointer with the logical tag that does not match the
>> +           # allocation tag.
>> +           set ltag [expr $i + 1]
>> +           with_test_prefix "fetch mismatch tag ${i}" {
>> +               set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
>> +           }
>> +
>> +           # Validate that the logical tag does not match the allocation
>> +           # tag.
>> +           set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
>> +           gdb_test "mtag check ${addr_tagged}" \
>> +                    "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
>> +                    "check mismatch with tag ${i}"
>> +       }
>> +    }
>> +}
>> +
>> +with_test_prefix "symbolic" {
>> +    # Test inspecting an allocation tag from a pointer to a memory area that
>> +    # is not mapped with PROT_MTE.
>> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
>> +    gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
>> +            "mtag showatag with an untagged address"
>> +
>> +    gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
>> +            "mtag setatag with an untagged address"
>> +
>> +    # Test setting and showing the logical tags for a literal address.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +       set addr_tagged 0
>> +
>> +       with_test_prefix "tag ${i}" {
>> +           set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +           gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +                              "update value of symbol ${tagged_ptr_symbol}"
>> +       }
>> +
>> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +       gdb_test "mtag showltag ${tagged_ptr_symbol}" \
>> +                " = 0x${tag_hexnz}" \
>> +                "showltag with tag ${i}"
>> +
>> +       set tag_hexnn [get_tag_nn $i]
>> +       gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
>> +                " = \\(void \\*\\) ${addr_tagged}" \
>> +                "withltag with tag ${i}"
>> +    }
>> +
>> +    # Reset the tagged ptr to its original value
>> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
>> +                      "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
>> +
>> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
>> +    # Test setting and showing the allocation tags.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +
>> +       set tag_hexnn [get_tag_nn $i]
>> +       gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
>> +                $setatag_msg \
>> +                "setatag with tag ${i}"
>> +
>> +       set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +       gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
>> +                "showatag with tag ${i}"
>> +    }
>> +
>> +    # Test tag mismatches.
>> +    with_test_prefix "tag mismatches" {
>> +       for {set i 0} {$i < 32} {incr i} {
>> +
>> +           # Set the allocation tag to a known value (0).
>> +           set tag_hexnn [get_tag_nn $i]
>> +           gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
>> +                    $setatag_msg \
>> +                    "setatag with tag ${i}"
>> +
>> +           set atag_hexnz [get_hex_tag [expr $i % 16]]
>> +
>> +           # Validate that the logical tag matches the allocation tag.
>> +           with_test_prefix "tag ${i}" {
>> +               set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +           }
>> +
>> +           with_test_prefix "tag ${i}" {
>> +               gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +                                  "set ${tagged_ptr_symbol} to a matching logical tag"
>> +           }
>> +
>> +           gdb_test "mtag check ${tagged_ptr_symbol}" \
>> +                    "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
>> +                    "check match with tag ${i}"
>> +
>> +           # Get a pointer with the logical tag that does not match the
>> +           # allocation tag.
>> +           set ltag [expr $i + 1]
>> +           with_test_prefix "fetch mismatch tag ${i}" {
>> +               set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
>> +           }
>> +
>> +           with_test_prefix "tag ${i}" {
>> +               gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +                                  "set ${tagged_ptr_symbol} to a mismatching logical tag"
>> +           }
>> +
>> +           # Validate that the logical tag does not match the allocation
>> +           # tag.
>> +           set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
>> +           gdb_test "mtag check ${tagged_ptr_symbol}" \
>> +                    "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
>> +                    "check mismatch with tag ${i}"
>> +       }
>> +    # Reset the tagged ptr to its original value
>> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
>> +                      "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
>> +    }
>> +}
>> +
>> +# Test the memory tagging extensions for the "print" command.
>> +with_test_prefix "print command" {
>> +    set untagged_ptr [get_tagged_ptr 0 ${tagged_ptr_addr}]
>> +
>> +    with_test_prefix "fetch ltag" {
>> +       set ltag [get_ltag_from_ptr ${tagged_ptr_addr}]
>> +    }
>> +
>> +    if {$ltag == -1} {
>> +       untested "unexpected tag value"
>> +       return -1
>> +    }
>> +
>> +    set atag [expr [expr $ltag + 1] % 16]
>> +    set atag_hexnn [get_tag_nn $atag]
>> +
>> +    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${atag_hexnn}" \
>> +            $setatag_msg \
>> +            "make atag and ltag different"
>> +
>> +    set atag_hexnz [get_hex_tag $atag]
>> +    gdb_test "p/x ${tagged_ptr_symbol}" \
>> +       [multi_line \
>> +           "Logical tag \\(${ltag}\\) does not match the allocation tag \\(0x${atag_hexnz}\\)\." \
>> +           "\\\$\[0-9\]+ = ${untagged_ptr}"] \
>> +           "show tag mismatch"
>> +}
>> +
>> +# Test the memory tagging extensions for the "x" command.
>> +with_test_prefix "x command" {
>> +
>> +    # Check if the allocation tags match what we expect.
>> +    gdb_test "x/gxm ${tagged_ptr_symbol}" \
>> +       [multi_line \
>> +           "<Allocation Tag $hex for range \\\[$hex,$hex\\)>" \
>> +           "$hex:\[ \t\]+$hex"] \
>> +       "outputs tag information"
>> +
>> +    # Also make sure no tag information is output for memory areas without
>> +    # PROT_MTE mappings.
>> +    gdb_test "x/gxm ${untagged_ptr_symbol}" \
>> +            "$hex:\[ \t\]+$hex" \
>> +            "does not output tag information"
>> +}
>> +
>> +# Validate the presence of the MTE registers.
>> +foreach reg {"tag_ctl" } {
>> +    gdb_test "info registers $reg" \
>> +            "$reg\[ \t\]+$hex\[ \t\]+$decimal" \
>> +            "register $reg available"
>> +}
>> +
>> +# 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\." \
>> +       "$hex in access_memory \\(.*\\) at .*" \
>> +       ".*tagged_ptr\\\[0\\\] = 'a';"] \
>> +        "display tag violation information"
>> +
>> +# Restart to execute the async tag fault test.
>> +with_test_prefix "async" {
>> +    if ![runto_main] {
>> +       untested "could not run to main"
>> +       return -1
>> +    }
>> +
>> +    gdb_breakpoint "access_memory"
>> +
>> +    if [gdb_continue "access_memory"] {
>> +       fail "could not run to tagged memory test function"
>> +       return -1
>> +    }
>> +
>> +    # Force a tag fault.
>> +    gdb_test "mtag setatag tagged_ptr 0 05" \
>> +            $setatag_msg \
>> +            "make atag and ltag different"
>> +
>> +    # Force the tag fault to be async.
>> +    gdb_test_no_output "set \$tag_ctl=0x7fff5" "set tag_ctl to async"
>> +
>> +    # Run until a crash and confirm GDB displays memory tag violation
>> +    # information for async mode
>> +    gdb_test "continue" \
>> +       [multi_line \
>> +           "Program received signal SIGSEGV, Segmentation fault" \
>> +           "Memory tag violation" \
>> +           "Fault address unavailable\." \
>> +           "$hex in .* \\(.*\\) .*"] \
>> +           "display tag violation information"
>> +}
>> diff --git a/gdb/testsuite/gdb.base/memtag.c b/gdb/testsuite/gdb.base/memtag.c
>> new file mode 100644
>> index 0000000000..63a42ae278
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/memtag.c
>> @@ -0,0 +1,22 @@
>> +/* This test program is part of GDB, the GNU debugger.
>> +
>> +   Copyright 2020 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/>.  */
>> +
>> +int
>> +main (int argc, char **argv)
>> +{
>> +  return 0;
>> +}
>> diff --git a/gdb/testsuite/gdb.base/memtag.exp b/gdb/testsuite/gdb.base/memtag.exp
>> new file mode 100644
>> index 0000000000..484a78e828
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/memtag.exp
>> @@ -0,0 +1,64 @@
>> +# Copyright 2020 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/>.
>> +
>> +# Smoke testing for the various memory tagging commands in GDB.
>> +
>> +set u_msg "Memory tagging not supported or disabled by the current architecture\."
>> +
>> +standard_testfile
>> +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
>> +    return -1
>> +}
>> +
>> +if {[target_info gdb_protocol] == "extended-remote"} {
>> +    # Make sure we're disconnected, in case we're testing with an
>> +    # extended-remote board, therefore already connected.
>> +    gdb_test "disconnect" ".*"
>> +}
>> +
>> +# Test commands without running the program.
>> +with_test_prefix "before program execution" {
>> +    # These commands should all fails without a running program.
>> +    foreach subcmd {"withltag" "showltag" "setatag" "showatag" "check"} {
>> +       gdb_test "mtag $subcmd" $u_msg
>> +    }
>> +}
>> +
>> +clean_restart $testfile
>> +
>> +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]} {
>> +    untested "memory tagging unsupported"
>> +    return -1
>> +}
>> +
>> +# With the program running, try to use the memory tagging commands.
>> +with_test_prefix "during program execution" {
>> +    set msg "Argument required \\(address or pointer\\)\."
>> +
>> +    # Test the various mtag commands again.
>> +    gdb_test "mtag showltag" $msg
>> +    gdb_test "mtag showatag" $msg
>> +    gdb_test "mtag withltag" "Argument required \\(<address> <tag>\\)\."
>> +    gdb_test "mtag setatag" \
>> +            "Argument required \\(<starting address> <length> <tag bytes>\\)\."
>> +    gdb_test "mtag check" $msg
>> +}
>> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
>> index 55154db6a5..347704ce0a 100644
>> --- a/gdb/testsuite/lib/gdb.exp
>> +++ b/gdb/testsuite/lib/gdb.exp
>> @@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
>>       }
>>   }
>>
>> +# Return 1 if memory tagging is supported at runtime, otherwise return 0.
>> +
>> +proc supports_memtag {} {
>> +    global gdb_prompt
>> +
>> +    gdb_test_multiple "mtag check" "" {
>> +       -re "Memory tagging not supported or disabled by the current architecture\..*$gdb_prompt $" {
>> +         return 0
>> +       }
>> +       -re "Argument required \\(address or pointer\\).*$gdb_prompt $" {
>> +           return 1
>> +       }
>> +    }
>> +    return 0
>> +}
>> +
>>   # Return 1 if the target supports hardware single stepping.
>>
>>   proc can_hardware_single_step {} {
>> --
>> 2.17.1
>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-16 16:04       ` David Spickett
@ 2020-11-16 17:22         ` Luis Machado
  2020-11-17 10:05           ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-16 17:22 UTC (permalink / raw)
  To: David Spickett, Eli Zaretskii; +Cc: gdb-patches



On 11/16/20 1:04 PM, David Spickett wrote:
> Also with regard to the "type" field.
> 
>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>> +integer.
> 
> (typo aside) Is this field architecture specific and will there be a
> list of these type numbers documented anywhere? (or already is)
> For example would 1 on AArch64 be MTE, and on <other arch> be <other
> tag type>. Or would that <other tag type> be 2.
> 
> My assumption has been that it is the latter and that a value means a
> kind of tagging extension. So for example 1=MTE rather than
> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.

Right now the design makes these types architecture-specific. It would 
be nice to have more documentation about them, for sure.

But there's one catch right now. The user-visible commands know about 
two types of tags (logical and allocation). The native/remote side of 
GDB only sees one type, the allocation one, as it doesn't make sense to 
ask the native/remote target about logical tags.

This is slightly messy and, in my opinion, should be an implementation 
detail.

So, in summary... We have a couple generic tag types GDB knows about: 
logical and allocation.

Those types get translated to an arch/a target-specific type when they 
cross the native/remote target boundary.

In theory we could have generic tag types 1 and 2 in generic code, but 
tag type 2 gets translated to type 1 in a remote packet.

Maybe we could improve this a little.

> 
> A page like:
> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> 
> Or just a short note, given that there's only one type right now.

Yes, that would be nice to expand for the tag types.

> 
> Also, I may have suggested the type be a string at some point. However
> based on examples like the link above
> I don't see much advantage to it apart from making packet dumps easier
> to read. Just wanted to close the loop on that
> if I didn't before.

I don't have a strong preference here. I'm just forwarding the tag type 
from generic code.

If we want to pass strings, we will need a gdbarch hook that maps a type 
to a string in the remote target layer.

Otherwise we'd need to standardize on particular tag type names across 
different architectures, like "hw memory tag", "sw memory tag", 
"capability tag" etc.

> 
> 
> 
> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>>
>> Minor thing, there is a missing space here in "typeis".
>>
>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>> +integer.
>>
>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>>
>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>>> Cc: david.spickett@linaro.org
>>>>
>>>> gdb/doc/ChangeLog:
>>>>
>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>>
>>>>        * gdb.texinfo (General Query Packets): Document qMemTags and
>>>>        QMemTags.  Document the "memory-tagging" feature.
>>>> ---
>>>>   gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>>   1 file changed, 96 insertions(+)
>>>
>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-11-16 16:45     ` Luis Machado
@ 2020-11-17  9:36       ` David Spickett
  0 siblings, 0 replies; 96+ messages in thread
From: David Spickett @ 2020-11-17  9:36 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches, alan.hayward, John Baldwin

> This is a GDB-ism. The hook itself is named like that. I don't like the name, but I thought I'd leave it the same just to keep it standard.

Fair enough.

> We could print it without leading zeroes. That may make things a bit more compact. Would that work?

Sounds good to me.

On Mon, 16 Nov 2020 at 16:46, Luis Machado <luis.machado@linaro.org> wrote:
>
> On 11/16/20 12:43 PM, David Spickett wrote:
> >> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
> >> +                                 struct ui_out *uiout,
> >> +                                 enum gdb_signal siggnal)
> >
> > siggnal -> signal
> >
>
> This is a GDB-ism. The hook itself is named like that. I don't like the
> name, but I thought I'd leave it the same just to keep it standard.
>
> > Also a nit about the formatting.
> >
> > Copying from 20/24 of v3:
> >> +Memory tag violation while accessing address 0x0000fffff7ff8000
> >> +Allocation tag 0x0000000000000001.
> >
> > (I'm guessing the code to print the "Allocation tag" line lives here
> > in some part)
> >
> > Would it make more sense to either not align the tag value to
> > anything, or to align it to the size of the architecture's tag? Which
> > would be 4 bits in this case so the same either way.
>
> We could print it without leading zeroes. That may make things a bit
> more compact. Would that work?
>
> >
> > On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
> >>
> >> Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
> >> information can be obtained through the siginfo data structure.
> >>
> >> For AArch64 the Linux kernel may expose the fault address and tag
> >> information, if we have a synchronous event. Otherwise there is
> >> no fault address available.
> >>
> >> gdb/ChangeLog:
> >>
> >> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>
> >>          * aarch64-linux-tdep.c
> >>          (aarch64_linux_report_signal_info): New function.
> >>          (aarch64_linux_init_abi): Register
> >>          aarch64_linux_report_signal_info as the report_signal_info hook.
> >>          * arch/aarch64-linux.h (SEGV_MTEAERR): Define.
> >>          (SEGV_MTESERR): Define.
> >> ---
> >>   gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
> >>   gdb/arch/aarch64-mte-linux.h |  6 ++++
> >>   2 files changed, 70 insertions(+)
> >>
> >> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> >> index 39b1790263..70e180e1cb 100644
> >> --- a/gdb/aarch64-linux-tdep.c
> >> +++ b/gdb/aarch64-linux-tdep.c
> >> @@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
> >>     return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
> >>   }
> >>
> >> +/* AArch64 Linux implementation of the report_signal_info gdbarch
> >> +   hook.  Displays information about possible memory tag violations.  */
> >> +
> >> +static void
> >> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
> >> +                                 struct ui_out *uiout,
> >> +                                 enum gdb_signal siggnal)
> >> +{
> >> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> >> +
> >> +  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
> >> +    return;
> >> +
> >> +  CORE_ADDR fault_addr = 0;
> >> +  long si_code = 0;
> >> +
> >> +  try
> >> +    {
> >> +      /* Sigcode tells us if the segfault is actually a memory tag
> >> +        violation.  */
> >> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
> >> +
> >> +      fault_addr
> >> +       = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> >> +    }
> >> +  catch (const gdb_exception &exception)
> >> +    {
> >> +      return;
> >> +    }
> >> +
> >> +  /* If this is not a memory tag violation, just return.  */
> >> +  if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR)
> >> +    return;
> >> +
> >> +  uiout->text ("\n");
> >> +
> >> +  uiout->field_string ("sigcode-meaning", _("Memory tag violation"));
> >> +
> >> +  /* For synchronous faults, show additional information.  */
> >> +  if (si_code == SEGV_MTESERR)
> >> +    {
> >> +      uiout->text (_(" while accessing address "));
> >> +      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
> >> +      uiout->text ("\n");
> >> +
> >> +      CORE_ADDR atag;
> >> +      if (aarch64_linux_get_atag (fault_addr, &atag) != 0)
> >> +       uiout->text (_("Allocation tag unavailable"));
> >> +      else
> >> +       {
> >> +         uiout->text (_("Allocation tag "));
> >> +         uiout->field_core_addr ("allocation-tag", gdbarch, atag);
> >> +       }
> >> +    }
> >> +  else
> >> +    {
> >> +      uiout->text ("\n");
> >> +      uiout->text (_("Fault address unavailable"));
> >> +    }
> >> +}
> >> +
> >>   static void
> >>   aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> >>   {
> >> @@ -1706,6 +1767,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> >>
> >>         /* Register a hook for converting a memory tag to a string.  */
> >>         set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
> >> +
> >> +      set_gdbarch_report_signal_info (gdbarch,
> >> +                                     aarch64_linux_report_signal_info);
> >>       }
> >>
> >>     /* Initialize the aarch64_linux_record_tdep.  */
> >> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
> >> index 5c5783f28b..a5a980ed49 100644
> >> --- a/gdb/arch/aarch64-mte-linux.h
> >> +++ b/gdb/arch/aarch64-mte-linux.h
> >> @@ -35,6 +35,12 @@
> >>   #define MTE_LOGICAL_TAG_START_BIT   56
> >>   #define MTE_LOGICAL_MAX_VALUE      0xf
> >>
> >> +/* Memory tagging definitions.  */
> >> +#ifndef SEGV_MTEAERR
> >> +# define SEGV_MTEAERR 8
> >> +# define SEGV_MTESERR 9
> >> +#endif
> >> +
> >>   /* Return the number of tag granules in the memory range
> >>      [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
> >>   extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
> >> --
> >> 2.17.1
> >>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-16 17:22         ` Luis Machado
@ 2020-11-17 10:05           ` David Spickett
  2020-11-17 12:01             ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-17 10:05 UTC (permalink / raw)
  To: Luis Machado; +Cc: Eli Zaretskii, gdb-patches

> Right now the design makes these types architecture-specific.

This works too, in fact it matches the breakpoint types example better that way.

> But there's one catch right now. The user-visible commands know about
> two types of tags (logical and allocation). The native/remote side of
> GDB only sees one type, the allocation one, as it doesn't make sense to
> ask the native/remote target about logical tags.
>
> This is slightly messy and, in my opinion, should be an implementation
> detail.

Tell me if I have this right.

In gdb in overall you have these two types but the server only uses
one of them, the allocation tag type.
So only the allocation tag type will ever go over the protocol. (for
MTE at least)

Given that, if we assume that "mte allocation" type is 1. A future
AArch64 kind of memory tagging could allocate 2 and on for its tag
types.
Something like:
AArch64 Memory Tag types -
  0 : MTE logical (which is internal only, reserved but documented as
unused, or left out completely?)
  1 : MTE allocation (the one we use at present)
  2: <future tagging> logical tag (because maybe there is some server
component for this kind of tagging extension?)
  3: <future tagging> allocation tag

The reason I want to clarify is that I understood the type to
differentiate tagging technologies, not the kind of tag within them.
(the type tells you MTE vs <future tag type> instead of allocation vs logical)
The use case being what if you have MTE and <future tag type> active
in the same target and I want to set an MTE allocation tag,
how can the server tell them apart?

If the type numbers overlap between tagging technologies, we can't
tell them apart.
However if they encode what extension they are for and the
logical/allocation type (as in the example above) then we can.

A lot of that is probably academic given there's one relevant type but
we can at least document the intent of the field.
E.g. "these types are global to AArch64 so new types should not
overlap existing ones"

> Otherwise we'd need to standardize on particular tag type names across
> different architectures, like "hw memory tag", "sw memory tag",
> "capability tag" etc.

Well I was thinking of type more as a single value like "mte". Anyway
I'm fine with the integer route.

On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
>
>
>
> On 11/16/20 1:04 PM, David Spickett wrote:
> > Also with regard to the "type" field.
> >
> >> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >> +integer.
> >
> > (typo aside) Is this field architecture specific and will there be a
> > list of these type numbers documented anywhere? (or already is)
> > For example would 1 on AArch64 be MTE, and on <other arch> be <other
> > tag type>. Or would that <other tag type> be 2.
> >
> > My assumption has been that it is the latter and that a value means a
> > kind of tagging extension. So for example 1=MTE rather than
> > 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
>
> Right now the design makes these types architecture-specific. It would
> be nice to have more documentation about them, for sure.
>
> But there's one catch right now. The user-visible commands know about
> two types of tags (logical and allocation). The native/remote side of
> GDB only sees one type, the allocation one, as it doesn't make sense to
> ask the native/remote target about logical tags.
>
> This is slightly messy and, in my opinion, should be an implementation
> detail.
>
> So, in summary... We have a couple generic tag types GDB knows about:
> logical and allocation.
>
> Those types get translated to an arch/a target-specific type when they
> cross the native/remote target boundary.
>
> In theory we could have generic tag types 1 and 2 in generic code, but
> tag type 2 gets translated to type 1 in a remote packet.
>
> Maybe we could improve this a little.
>
> >
> > A page like:
> > https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> >
> > Or just a short note, given that there's only one type right now.
>
> Yes, that would be nice to expand for the tag types.
>
> >
> > Also, I may have suggested the type be a string at some point. However
> > based on examples like the link above
> > I don't see much advantage to it apart from making packet dumps easier
> > to read. Just wanted to close the loop on that
> > if I didn't before.
>
> I don't have a strong preference here. I'm just forwarding the tag type
> from generic code.
>
> If we want to pass strings, we will need a gdbarch hook that maps a type
> to a string in the remote target layer.
>
> Otherwise we'd need to standardize on particular tag type names across
> different architectures, like "hw memory tag", "sw memory tag",
> "capability tag" etc.
>
> >
> >
> >
> > On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
> >>
> >> Minor thing, there is a missing space here in "typeis".
> >>
> >>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>> +integer.
> >>
> >> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >>>
> >>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
> >>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> >>>> Cc: david.spickett@linaro.org
> >>>>
> >>>> gdb/doc/ChangeLog:
> >>>>
> >>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>>>
> >>>>        * gdb.texinfo (General Query Packets): Document qMemTags and
> >>>>        QMemTags.  Document the "memory-tagging" feature.
> >>>> ---
> >>>>   gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >>>>   1 file changed, 96 insertions(+)
> >>>
> >>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 10:05           ` David Spickett
@ 2020-11-17 12:01             ` Luis Machado
  2020-11-17 12:29               ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-17 12:01 UTC (permalink / raw)
  To: David Spickett; +Cc: Eli Zaretskii, gdb-patches

Hi,

On 11/17/20 7:05 AM, David Spickett wrote:
>> Right now the design makes these types architecture-specific.
> 
> This works too, in fact it matches the breakpoint types example better that way.
> 
>> But there's one catch right now. The user-visible commands know about
>> two types of tags (logical and allocation). The native/remote side of
>> GDB only sees one type, the allocation one, as it doesn't make sense to
>> ask the native/remote target about logical tags.
>>
>> This is slightly messy and, in my opinion, should be an implementation
>> detail.
> 
> Tell me if I have this right.
> 
> In gdb in overall you have these two types but the server only uses
> one of them, the allocation tag type.
> So only the allocation tag type will ever go over the protocol. (for
> MTE at least)

That's correct. Only GDB knows about logical tags. Those don't make 
their way to the remote via the remote protocol.

> 
> Given that, if we assume that "mte allocation" type is 1. A future
> AArch64 kind of memory tagging could allocate 2 and on for its tag
> types.
> Something like:
> AArch64 Memory Tag types -
>    0 : MTE logical (which is internal only, reserved but documented as
> unused, or left out completely?)
>    1 : MTE allocation (the one we use at present)
>    2: <future tagging> logical tag (because maybe there is some server
> component for this kind of tagging extension?)
>    3: <future tagging> allocation tag
> 
> The reason I want to clarify is that I understood the type to
> differentiate tagging technologies, not the kind of tag within them.
> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
> The use case being what if you have MTE and <future tag type> active
> in the same target and I want to set an MTE allocation tag,
> how can the server tell them apart?

Right. The type is really telling you what specific kind of tag you are 
requesting, not the technology. So it may be perfectly valid to request 
a MTE logical tag from the remote target, but the remote target doesn't 
know how to reply to that at the moment (nor does it make much sense, IMO).

The tag types don't overlap at the moment, given they are an ENUM in 
generic code. So the server will tell them apart by their values.

> 
> If the type numbers overlap between tagging technologies, we can't
> tell them apart.
> However if they encode what extension they are for and the
> logical/allocation type (as in the example above) then we can.
> 
> A lot of that is probably academic given there's one relevant type but
> we can at least document the intent of the field.
> E.g. "these types are global to AArch64 so new types should not
> overlap existing ones"

I suppose. I chose to have generic ENUM's without specific references to 
MTE for that reason. Architectures can use logical/allocation tags as 
they see fit, but the ENUM values will not overlap.

We need to support the UI as well, so there needs to be some generic 
definitions so commands can query different tag types.

> 
>> Otherwise we'd need to standardize on particular tag type names across
>> different architectures, like "hw memory tag", "sw memory tag",
>> "capability tag" etc.
> 
> Well I was thinking of type more as a single value like "mte". Anyway
> I'm fine with the integer route.

Though we don't have a use for requesting logical tags from the remote 
targets, it is possible to support that. Passing "mte" or any other 
technology name would close that option.

If, for example, we decide to have a dumb GDB client and a smart 
GDBserver (unlikely at this point), then it would make sense to pass 
down logical tag requests I think. I just want to keep that option open 
if someone wants to do it, or if some other type of tag shows up that 
would require such support.

> 
> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
>>
>>
>>
>> On 11/16/20 1:04 PM, David Spickett wrote:
>>> Also with regard to the "type" field.
>>>
>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>> +integer.
>>>
>>> (typo aside) Is this field architecture specific and will there be a
>>> list of these type numbers documented anywhere? (or already is)
>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
>>> tag type>. Or would that <other tag type> be 2.
>>>
>>> My assumption has been that it is the latter and that a value means a
>>> kind of tagging extension. So for example 1=MTE rather than
>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
>>
>> Right now the design makes these types architecture-specific. It would
>> be nice to have more documentation about them, for sure.
>>
>> But there's one catch right now. The user-visible commands know about
>> two types of tags (logical and allocation). The native/remote side of
>> GDB only sees one type, the allocation one, as it doesn't make sense to
>> ask the native/remote target about logical tags.
>>
>> This is slightly messy and, in my opinion, should be an implementation
>> detail.
>>
>> So, in summary... We have a couple generic tag types GDB knows about:
>> logical and allocation.
>>
>> Those types get translated to an arch/a target-specific type when they
>> cross the native/remote target boundary.
>>
>> In theory we could have generic tag types 1 and 2 in generic code, but
>> tag type 2 gets translated to type 1 in a remote packet.
>>
>> Maybe we could improve this a little.
>>
>>>
>>> A page like:
>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
>>>
>>> Or just a short note, given that there's only one type right now.
>>
>> Yes, that would be nice to expand for the tag types.
>>
>>>
>>> Also, I may have suggested the type be a string at some point. However
>>> based on examples like the link above
>>> I don't see much advantage to it apart from making packet dumps easier
>>> to read. Just wanted to close the loop on that
>>> if I didn't before.
>>
>> I don't have a strong preference here. I'm just forwarding the tag type
>> from generic code.
>>
>> If we want to pass strings, we will need a gdbarch hook that maps a type
>> to a string in the remote target layer.
>>
>> Otherwise we'd need to standardize on particular tag type names across
>> different architectures, like "hw memory tag", "sw memory tag",
>> "capability tag" etc.
>>
>>>
>>>
>>>
>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>>>>
>>>> Minor thing, there is a missing space here in "typeis".
>>>>
>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>> +integer.
>>>>
>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>>>>
>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>>>>> Cc: david.spickett@linaro.org
>>>>>>
>>>>>> gdb/doc/ChangeLog:
>>>>>>
>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>>>>
>>>>>>         * gdb.texinfo (General Query Packets): Document qMemTags and
>>>>>>         QMemTags.  Document the "memory-tagging" feature.
>>>>>> ---
>>>>>>    gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>>>>    1 file changed, 96 insertions(+)
>>>>>
>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 12:01             ` Luis Machado
@ 2020-11-17 12:29               ` David Spickett
  2020-11-17 14:44                 ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-17 12:29 UTC (permalink / raw)
  To: Luis Machado; +Cc: Eli Zaretskii, gdb-patches

> Right. The type is really telling you what specific kind of tag you are
> requesting, not the technology. So it may be perfectly valid to request
> a MTE logical tag from the remote target, but the remote target doesn't
> know how to reply to that at the moment (nor does it make much sense, IMO).
>
> The tag types don't overlap at the moment, given they are an ENUM in
> generic code. So the server will tell them apart by their values.

Ok but my concern here is that there are two aspects to type. (which I
probably confused earlier tbf)

1. logical vs allocation
2. MTE vs <future tagging technology>

So we have three scenarios:
1. Server uses type to decide between logical and allocation
2. Server uses type to decide between MTE and <future tagging technology>
3. The combination of the two, should a system have both technologies

What I want to avoid is a two step process:
1. Somehow select tagging technology you want to interact with
2. You send memtag packets with the logical vs allocation "type"

Which would be needed if the protocol "type" is just allocation vs
logical. If the "type" includes the technology
then we can do it in one step.

So I prefer:
0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
allocation, 3 = future tag form (not logical/allocation) etc...
Over:
0 = logical, 1 = allocation, 2 = future term for other tag form etc...

I see the need for the second form in gdb internally, but my concern
is only with the protocol side.

> I just want to keep that option open
> if someone wants to do it, or if some other type of tag shows up that
> would require such support.

I hadn't thought of that. I agree that type should include that too.

On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
>
> Hi,
>
> On 11/17/20 7:05 AM, David Spickett wrote:
> >> Right now the design makes these types architecture-specific.
> >
> > This works too, in fact it matches the breakpoint types example better that way.
> >
> >> But there's one catch right now. The user-visible commands know about
> >> two types of tags (logical and allocation). The native/remote side of
> >> GDB only sees one type, the allocation one, as it doesn't make sense to
> >> ask the native/remote target about logical tags.
> >>
> >> This is slightly messy and, in my opinion, should be an implementation
> >> detail.
> >
> > Tell me if I have this right.
> >
> > In gdb in overall you have these two types but the server only uses
> > one of them, the allocation tag type.
> > So only the allocation tag type will ever go over the protocol. (for
> > MTE at least)
>
> That's correct. Only GDB knows about logical tags. Those don't make
> their way to the remote via the remote protocol.
>
> >
> > Given that, if we assume that "mte allocation" type is 1. A future
> > AArch64 kind of memory tagging could allocate 2 and on for its tag
> > types.
> > Something like:
> > AArch64 Memory Tag types -
> >    0 : MTE logical (which is internal only, reserved but documented as
> > unused, or left out completely?)
> >    1 : MTE allocation (the one we use at present)
> >    2: <future tagging> logical tag (because maybe there is some server
> > component for this kind of tagging extension?)
> >    3: <future tagging> allocation tag
> >
> > The reason I want to clarify is that I understood the type to
> > differentiate tagging technologies, not the kind of tag within them.
> > (the type tells you MTE vs <future tag type> instead of allocation vs logical)
> > The use case being what if you have MTE and <future tag type> active
> > in the same target and I want to set an MTE allocation tag,
> > how can the server tell them apart?
>
> Right. The type is really telling you what specific kind of tag you are
> requesting, not the technology. So it may be perfectly valid to request
> a MTE logical tag from the remote target, but the remote target doesn't
> know how to reply to that at the moment (nor does it make much sense, IMO).
>
> The tag types don't overlap at the moment, given they are an ENUM in
> generic code. So the server will tell them apart by their values.
>
> >
> > If the type numbers overlap between tagging technologies, we can't
> > tell them apart.
> > However if they encode what extension they are for and the
> > logical/allocation type (as in the example above) then we can.
> >
> > A lot of that is probably academic given there's one relevant type but
> > we can at least document the intent of the field.
> > E.g. "these types are global to AArch64 so new types should not
> > overlap existing ones"
>
> I suppose. I chose to have generic ENUM's without specific references to
> MTE for that reason. Architectures can use logical/allocation tags as
> they see fit, but the ENUM values will not overlap.
>
> We need to support the UI as well, so there needs to be some generic
> definitions so commands can query different tag types.
>
> >
> >> Otherwise we'd need to standardize on particular tag type names across
> >> different architectures, like "hw memory tag", "sw memory tag",
> >> "capability tag" etc.
> >
> > Well I was thinking of type more as a single value like "mte". Anyway
> > I'm fine with the integer route.
>
> Though we don't have a use for requesting logical tags from the remote
> targets, it is possible to support that. Passing "mte" or any other
> technology name would close that option.
>
> If, for example, we decide to have a dumb GDB client and a smart
> GDBserver (unlikely at this point), then it would make sense to pass
> down logical tag requests I think. I just want to keep that option open
> if someone wants to do it, or if some other type of tag shows up that
> would require such support.
>
> >
> > On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
> >>
> >>
> >>
> >> On 11/16/20 1:04 PM, David Spickett wrote:
> >>> Also with regard to the "type" field.
> >>>
> >>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>> +integer.
> >>>
> >>> (typo aside) Is this field architecture specific and will there be a
> >>> list of these type numbers documented anywhere? (or already is)
> >>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
> >>> tag type>. Or would that <other tag type> be 2.
> >>>
> >>> My assumption has been that it is the latter and that a value means a
> >>> kind of tagging extension. So for example 1=MTE rather than
> >>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
> >>
> >> Right now the design makes these types architecture-specific. It would
> >> be nice to have more documentation about them, for sure.
> >>
> >> But there's one catch right now. The user-visible commands know about
> >> two types of tags (logical and allocation). The native/remote side of
> >> GDB only sees one type, the allocation one, as it doesn't make sense to
> >> ask the native/remote target about logical tags.
> >>
> >> This is slightly messy and, in my opinion, should be an implementation
> >> detail.
> >>
> >> So, in summary... We have a couple generic tag types GDB knows about:
> >> logical and allocation.
> >>
> >> Those types get translated to an arch/a target-specific type when they
> >> cross the native/remote target boundary.
> >>
> >> In theory we could have generic tag types 1 and 2 in generic code, but
> >> tag type 2 gets translated to type 1 in a remote packet.
> >>
> >> Maybe we could improve this a little.
> >>
> >>>
> >>> A page like:
> >>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> >>>
> >>> Or just a short note, given that there's only one type right now.
> >>
> >> Yes, that would be nice to expand for the tag types.
> >>
> >>>
> >>> Also, I may have suggested the type be a string at some point. However
> >>> based on examples like the link above
> >>> I don't see much advantage to it apart from making packet dumps easier
> >>> to read. Just wanted to close the loop on that
> >>> if I didn't before.
> >>
> >> I don't have a strong preference here. I'm just forwarding the tag type
> >> from generic code.
> >>
> >> If we want to pass strings, we will need a gdbarch hook that maps a type
> >> to a string in the remote target layer.
> >>
> >> Otherwise we'd need to standardize on particular tag type names across
> >> different architectures, like "hw memory tag", "sw memory tag",
> >> "capability tag" etc.
> >>
> >>>
> >>>
> >>>
> >>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
> >>>>
> >>>> Minor thing, there is a missing space here in "typeis".
> >>>>
> >>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>> +integer.
> >>>>
> >>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >>>>>
> >>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
> >>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> >>>>>> Cc: david.spickett@linaro.org
> >>>>>>
> >>>>>> gdb/doc/ChangeLog:
> >>>>>>
> >>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>>>>>
> >>>>>>         * gdb.texinfo (General Query Packets): Document qMemTags and
> >>>>>>         QMemTags.  Document the "memory-tagging" feature.
> >>>>>> ---
> >>>>>>    gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >>>>>>    1 file changed, 96 insertions(+)
> >>>>>
> >>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 12:29               ` David Spickett
@ 2020-11-17 14:44                 ` Luis Machado
  2020-11-17 15:16                   ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-17 14:44 UTC (permalink / raw)
  To: David Spickett; +Cc: Eli Zaretskii, gdb-patches

On 11/17/20 9:29 AM, David Spickett wrote:
>> Right. The type is really telling you what specific kind of tag you are
>> requesting, not the technology. So it may be perfectly valid to request
>> a MTE logical tag from the remote target, but the remote target doesn't
>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>
>> The tag types don't overlap at the moment, given they are an ENUM in
>> generic code. So the server will tell them apart by their values.
> 
> Ok but my concern here is that there are two aspects to type. (which I
> probably confused earlier tbf)
> 
> 1. logical vs allocation
> 2. MTE vs <future tagging technology>
> 
> So we have three scenarios:
> 1. Server uses type to decide between logical and allocation

Right now 0 maps to logical and 1 maps to allocation for all 
architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE 
allocation.

But, if more tag types are supported in the future, we will need to map 
types to logical, allocation or something else.

> 2. Server uses type to decide between MTE and <future tagging technology>

Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet 
supported). In the future, if there are more tagging technologies, we 
will need to provide a mapping from tag types to tag technology.

> 3. The combination of the two, should a system have both technologies

In this case, we will use two mappings: type to tag type and type to tag 
technology.

> 
> What I want to avoid is a two step process:
> 1. Somehow select tagging technology you want to interact with
> 2. You send memtag packets with the logical vs allocation "type"
> 
> Which would be needed if the protocol "type" is just allocation vs
> logical. If the "type" includes the technology
> then we can do it in one step.

Right now you can infer the technology and logical/allocation from the 
type. There is no need for a two step process. I don't anticipate a need 
for that in the future either, as long as we prevent the tag type ENUM 
from having overlapping values.

> 
> So I prefer:
> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> allocation, 3 = future tag form (not logical/allocation) etc...

So this is wrong, as the remote/native side won't be able to tell both 
definitions of type "1" apart.

> Over:
> 0 = logical, 1 = allocation, 2 = future term for other tag form etc...

This is correct in my view. Everything is unique.

The complicating factor here is that generic code/UI needs to use a 
generic tag type so all architectures supporting memory tagging can use 
the commands out of the box.

For AArch64, tag_logical/tag_allocation means MTE logical/MTE 
allocation. For SPARC ADI, this means whatever their tagging mechanism is.

If we turn tag_logical into mte_logical, SPARC ADI won't be able to use 
that. We will, again, need a mapping.

If we want to address this and make it a bit more flexible, then we will 
need to let architectures define their own tag type values. Then generic 
code will have to go through an arch-specific hook to fetch the tag type.

Would that address your concerns?

> 
> I see the need for the second form in gdb internally, but my concern
> is only with the protocol side.

As long as GDB sends a unique tag type identifier (non-overlapping 
values), we will be able to tell them apart from the remote side.

> 
>> I just want to keep that option open
>> if someone wants to do it, or if some other type of tag shows up that
>> would require such support.
> 
> I hadn't thought of that. I agree that type should include that too.
> 
> On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> Hi,
>>
>> On 11/17/20 7:05 AM, David Spickett wrote:
>>>> Right now the design makes these types architecture-specific.
>>>
>>> This works too, in fact it matches the breakpoint types example better that way.
>>>
>>>> But there's one catch right now. The user-visible commands know about
>>>> two types of tags (logical and allocation). The native/remote side of
>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>> ask the native/remote target about logical tags.
>>>>
>>>> This is slightly messy and, in my opinion, should be an implementation
>>>> detail.
>>>
>>> Tell me if I have this right.
>>>
>>> In gdb in overall you have these two types but the server only uses
>>> one of them, the allocation tag type.
>>> So only the allocation tag type will ever go over the protocol. (for
>>> MTE at least)
>>
>> That's correct. Only GDB knows about logical tags. Those don't make
>> their way to the remote via the remote protocol.
>>
>>>
>>> Given that, if we assume that "mte allocation" type is 1. A future
>>> AArch64 kind of memory tagging could allocate 2 and on for its tag
>>> types.
>>> Something like:
>>> AArch64 Memory Tag types -
>>>     0 : MTE logical (which is internal only, reserved but documented as
>>> unused, or left out completely?)
>>>     1 : MTE allocation (the one we use at present)
>>>     2: <future tagging> logical tag (because maybe there is some server
>>> component for this kind of tagging extension?)
>>>     3: <future tagging> allocation tag
>>>
>>> The reason I want to clarify is that I understood the type to
>>> differentiate tagging technologies, not the kind of tag within them.
>>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
>>> The use case being what if you have MTE and <future tag type> active
>>> in the same target and I want to set an MTE allocation tag,
>>> how can the server tell them apart?
>>
>> Right. The type is really telling you what specific kind of tag you are
>> requesting, not the technology. So it may be perfectly valid to request
>> a MTE logical tag from the remote target, but the remote target doesn't
>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>
>> The tag types don't overlap at the moment, given they are an ENUM in
>> generic code. So the server will tell them apart by their values.
>>
>>>
>>> If the type numbers overlap between tagging technologies, we can't
>>> tell them apart.
>>> However if they encode what extension they are for and the
>>> logical/allocation type (as in the example above) then we can.
>>>
>>> A lot of that is probably academic given there's one relevant type but
>>> we can at least document the intent of the field.
>>> E.g. "these types are global to AArch64 so new types should not
>>> overlap existing ones"
>>
>> I suppose. I chose to have generic ENUM's without specific references to
>> MTE for that reason. Architectures can use logical/allocation tags as
>> they see fit, but the ENUM values will not overlap.
>>
>> We need to support the UI as well, so there needs to be some generic
>> definitions so commands can query different tag types.
>>
>>>
>>>> Otherwise we'd need to standardize on particular tag type names across
>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>> "capability tag" etc.
>>>
>>> Well I was thinking of type more as a single value like "mte". Anyway
>>> I'm fine with the integer route.
>>
>> Though we don't have a use for requesting logical tags from the remote
>> targets, it is possible to support that. Passing "mte" or any other
>> technology name would close that option.
>>
>> If, for example, we decide to have a dumb GDB client and a smart
>> GDBserver (unlikely at this point), then it would make sense to pass
>> down logical tag requests I think. I just want to keep that option open
>> if someone wants to do it, or if some other type of tag shows up that
>> would require such support.
>>
>>>
>>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
>>>>
>>>>
>>>>
>>>> On 11/16/20 1:04 PM, David Spickett wrote:
>>>>> Also with regard to the "type" field.
>>>>>
>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>> +integer.
>>>>>
>>>>> (typo aside) Is this field architecture specific and will there be a
>>>>> list of these type numbers documented anywhere? (or already is)
>>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
>>>>> tag type>. Or would that <other tag type> be 2.
>>>>>
>>>>> My assumption has been that it is the latter and that a value means a
>>>>> kind of tagging extension. So for example 1=MTE rather than
>>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
>>>>
>>>> Right now the design makes these types architecture-specific. It would
>>>> be nice to have more documentation about them, for sure.
>>>>
>>>> But there's one catch right now. The user-visible commands know about
>>>> two types of tags (logical and allocation). The native/remote side of
>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>> ask the native/remote target about logical tags.
>>>>
>>>> This is slightly messy and, in my opinion, should be an implementation
>>>> detail.
>>>>
>>>> So, in summary... We have a couple generic tag types GDB knows about:
>>>> logical and allocation.
>>>>
>>>> Those types get translated to an arch/a target-specific type when they
>>>> cross the native/remote target boundary.
>>>>
>>>> In theory we could have generic tag types 1 and 2 in generic code, but
>>>> tag type 2 gets translated to type 1 in a remote packet.
>>>>
>>>> Maybe we could improve this a little.
>>>>
>>>>>
>>>>> A page like:
>>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
>>>>>
>>>>> Or just a short note, given that there's only one type right now.
>>>>
>>>> Yes, that would be nice to expand for the tag types.
>>>>
>>>>>
>>>>> Also, I may have suggested the type be a string at some point. However
>>>>> based on examples like the link above
>>>>> I don't see much advantage to it apart from making packet dumps easier
>>>>> to read. Just wanted to close the loop on that
>>>>> if I didn't before.
>>>>
>>>> I don't have a strong preference here. I'm just forwarding the tag type
>>>> from generic code.
>>>>
>>>> If we want to pass strings, we will need a gdbarch hook that maps a type
>>>> to a string in the remote target layer.
>>>>
>>>> Otherwise we'd need to standardize on particular tag type names across
>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>> "capability tag" etc.
>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>>>>>>
>>>>>> Minor thing, there is a missing space here in "typeis".
>>>>>>
>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>>> +integer.
>>>>>>
>>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>>>>>>
>>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>>>>>>> Cc: david.spickett@linaro.org
>>>>>>>>
>>>>>>>> gdb/doc/ChangeLog:
>>>>>>>>
>>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>>>>>>
>>>>>>>>          * gdb.texinfo (General Query Packets): Document qMemTags and
>>>>>>>>          QMemTags.  Document the "memory-tagging" feature.
>>>>>>>> ---
>>>>>>>>     gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>     1 file changed, 96 insertions(+)
>>>>>>>
>>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 14:44                 ` Luis Machado
@ 2020-11-17 15:16                   ` David Spickett
  2020-11-17 17:29                     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-17 15:16 UTC (permalink / raw)
  To: Luis Machado; +Cc: Eli Zaretskii, gdb-patches

> Right now you can infer the technology and logical/allocation from the
> type. There is no need for a two step process. I don't anticipate a need
> for that in the future either, as long as we prevent the tag type ENUM
> from having overlapping values.

Right, so to not overlap, a value of that tag type ENUM must be a
combination of technology and tag...kind. (words are hard)
E.g. MTE logical tag, <future tech> allocation tag , <other tech> strange tag

So if <future AArch64 tag technology> were to also have "logical" and
"allocation" tags, they would be new type values, yes?
0 = MTE logical
1 = MTE allocation
2 = <future AArch64 tag technology> logical
3 = <future AArch64 tag technology> allocation

Because if they are still 0 and 1, they overlap and you can't tell MTE
and <future AArch64 tag technology> apart.

I get that at the user interface layer you have some mapping back to a
set of generic types, talking just about the
packet contents.

> So this is wrong, as the remote/native side won't be able to tell both
> definitions of type "1" apart.

Sorry that was a typo. Should be:
0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
allocation, 3 = future tag form (not logical/allocation) etc...
(basically what I restated above)

> If we want to address this and make it a bit more flexible, then we will
> need to let architectures define their own tag type values. Then generic
> code will have to go through an arch-specific hook to fetch the tag type.

> Would that address your concerns?

I think so. I thought of this working like the breakpoint types I
referenced. Breakpoint type 1 for MIPS isn't in any way the same as
type 1 for Arm etc.
(ok they might be similar but the docs make it clear that the list of
types is per architecture)

> As long as GDB sends a unique tag type identifier (non-overlapping
> values), we will be able to tell them apart from the remote side.

Yes but depending on how those IDs are allocated we may only be able
to tell logical vs allocation not MTE vs CHERI vs <future whatever>.

On Tue, 17 Nov 2020 at 14:44, Luis Machado <luis.machado@linaro.org> wrote:
>
> On 11/17/20 9:29 AM, David Spickett wrote:
> >> Right. The type is really telling you what specific kind of tag you are
> >> requesting, not the technology. So it may be perfectly valid to request
> >> a MTE logical tag from the remote target, but the remote target doesn't
> >> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>
> >> The tag types don't overlap at the moment, given they are an ENUM in
> >> generic code. So the server will tell them apart by their values.
> >
> > Ok but my concern here is that there are two aspects to type. (which I
> > probably confused earlier tbf)
> >
> > 1. logical vs allocation
> > 2. MTE vs <future tagging technology>
> >
> > So we have three scenarios:
> > 1. Server uses type to decide between logical and allocation
>
> Right now 0 maps to logical and 1 maps to allocation for all
> architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE
> allocation.
>
> But, if more tag types are supported in the future, we will need to map
> types to logical, allocation or something else.
>
> > 2. Server uses type to decide between MTE and <future tagging technology>
>
> Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet
> supported). In the future, if there are more tagging technologies, we
> will need to provide a mapping from tag types to tag technology.
>
> > 3. The combination of the two, should a system have both technologies
>
> In this case, we will use two mappings: type to tag type and type to tag
> technology.
>
> >
> > What I want to avoid is a two step process:
> > 1. Somehow select tagging technology you want to interact with
> > 2. You send memtag packets with the logical vs allocation "type"
> >
> > Which would be needed if the protocol "type" is just allocation vs
> > logical. If the "type" includes the technology
> > then we can do it in one step.
>
> Right now you can infer the technology and logical/allocation from the
> type. There is no need for a two step process. I don't anticipate a need
> for that in the future either, as long as we prevent the tag type ENUM
> from having overlapping values.
>
> >
> > So I prefer:
> > 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> > allocation, 3 = future tag form (not logical/allocation) etc...
>
> So this is wrong, as the remote/native side won't be able to tell both
> definitions of type "1" apart.
>
> > Over:
> > 0 = logical, 1 = allocation, 2 = future term for other tag form etc...
>
> This is correct in my view. Everything is unique.
>
> The complicating factor here is that generic code/UI needs to use a
> generic tag type so all architectures supporting memory tagging can use
> the commands out of the box.
>
> For AArch64, tag_logical/tag_allocation means MTE logical/MTE
> allocation. For SPARC ADI, this means whatever their tagging mechanism is.
>
> If we turn tag_logical into mte_logical, SPARC ADI won't be able to use
> that. We will, again, need a mapping.
>
> If we want to address this and make it a bit more flexible, then we will
> need to let architectures define their own tag type values. Then generic
> code will have to go through an arch-specific hook to fetch the tag type.
>
> Would that address your concerns?
>
> >
> > I see the need for the second form in gdb internally, but my concern
> > is only with the protocol side.
>
> As long as GDB sends a unique tag type identifier (non-overlapping
> values), we will be able to tell them apart from the remote side.
>
> >
> >> I just want to keep that option open
> >> if someone wants to do it, or if some other type of tag shows up that
> >> would require such support.
> >
> > I hadn't thought of that. I agree that type should include that too.
> >
> > On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
> >>
> >> Hi,
> >>
> >> On 11/17/20 7:05 AM, David Spickett wrote:
> >>>> Right now the design makes these types architecture-specific.
> >>>
> >>> This works too, in fact it matches the breakpoint types example better that way.
> >>>
> >>>> But there's one catch right now. The user-visible commands know about
> >>>> two types of tags (logical and allocation). The native/remote side of
> >>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>> ask the native/remote target about logical tags.
> >>>>
> >>>> This is slightly messy and, in my opinion, should be an implementation
> >>>> detail.
> >>>
> >>> Tell me if I have this right.
> >>>
> >>> In gdb in overall you have these two types but the server only uses
> >>> one of them, the allocation tag type.
> >>> So only the allocation tag type will ever go over the protocol. (for
> >>> MTE at least)
> >>
> >> That's correct. Only GDB knows about logical tags. Those don't make
> >> their way to the remote via the remote protocol.
> >>
> >>>
> >>> Given that, if we assume that "mte allocation" type is 1. A future
> >>> AArch64 kind of memory tagging could allocate 2 and on for its tag
> >>> types.
> >>> Something like:
> >>> AArch64 Memory Tag types -
> >>>     0 : MTE logical (which is internal only, reserved but documented as
> >>> unused, or left out completely?)
> >>>     1 : MTE allocation (the one we use at present)
> >>>     2: <future tagging> logical tag (because maybe there is some server
> >>> component for this kind of tagging extension?)
> >>>     3: <future tagging> allocation tag
> >>>
> >>> The reason I want to clarify is that I understood the type to
> >>> differentiate tagging technologies, not the kind of tag within them.
> >>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
> >>> The use case being what if you have MTE and <future tag type> active
> >>> in the same target and I want to set an MTE allocation tag,
> >>> how can the server tell them apart?
> >>
> >> Right. The type is really telling you what specific kind of tag you are
> >> requesting, not the technology. So it may be perfectly valid to request
> >> a MTE logical tag from the remote target, but the remote target doesn't
> >> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>
> >> The tag types don't overlap at the moment, given they are an ENUM in
> >> generic code. So the server will tell them apart by their values.
> >>
> >>>
> >>> If the type numbers overlap between tagging technologies, we can't
> >>> tell them apart.
> >>> However if they encode what extension they are for and the
> >>> logical/allocation type (as in the example above) then we can.
> >>>
> >>> A lot of that is probably academic given there's one relevant type but
> >>> we can at least document the intent of the field.
> >>> E.g. "these types are global to AArch64 so new types should not
> >>> overlap existing ones"
> >>
> >> I suppose. I chose to have generic ENUM's without specific references to
> >> MTE for that reason. Architectures can use logical/allocation tags as
> >> they see fit, but the ENUM values will not overlap.
> >>
> >> We need to support the UI as well, so there needs to be some generic
> >> definitions so commands can query different tag types.
> >>
> >>>
> >>>> Otherwise we'd need to standardize on particular tag type names across
> >>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>> "capability tag" etc.
> >>>
> >>> Well I was thinking of type more as a single value like "mte". Anyway
> >>> I'm fine with the integer route.
> >>
> >> Though we don't have a use for requesting logical tags from the remote
> >> targets, it is possible to support that. Passing "mte" or any other
> >> technology name would close that option.
> >>
> >> If, for example, we decide to have a dumb GDB client and a smart
> >> GDBserver (unlikely at this point), then it would make sense to pass
> >> down logical tag requests I think. I just want to keep that option open
> >> if someone wants to do it, or if some other type of tag shows up that
> >> would require such support.
> >>
> >>>
> >>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 11/16/20 1:04 PM, David Spickett wrote:
> >>>>> Also with regard to the "type" field.
> >>>>>
> >>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>> +integer.
> >>>>>
> >>>>> (typo aside) Is this field architecture specific and will there be a
> >>>>> list of these type numbers documented anywhere? (or already is)
> >>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
> >>>>> tag type>. Or would that <other tag type> be 2.
> >>>>>
> >>>>> My assumption has been that it is the latter and that a value means a
> >>>>> kind of tagging extension. So for example 1=MTE rather than
> >>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
> >>>>
> >>>> Right now the design makes these types architecture-specific. It would
> >>>> be nice to have more documentation about them, for sure.
> >>>>
> >>>> But there's one catch right now. The user-visible commands know about
> >>>> two types of tags (logical and allocation). The native/remote side of
> >>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>> ask the native/remote target about logical tags.
> >>>>
> >>>> This is slightly messy and, in my opinion, should be an implementation
> >>>> detail.
> >>>>
> >>>> So, in summary... We have a couple generic tag types GDB knows about:
> >>>> logical and allocation.
> >>>>
> >>>> Those types get translated to an arch/a target-specific type when they
> >>>> cross the native/remote target boundary.
> >>>>
> >>>> In theory we could have generic tag types 1 and 2 in generic code, but
> >>>> tag type 2 gets translated to type 1 in a remote packet.
> >>>>
> >>>> Maybe we could improve this a little.
> >>>>
> >>>>>
> >>>>> A page like:
> >>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> >>>>>
> >>>>> Or just a short note, given that there's only one type right now.
> >>>>
> >>>> Yes, that would be nice to expand for the tag types.
> >>>>
> >>>>>
> >>>>> Also, I may have suggested the type be a string at some point. However
> >>>>> based on examples like the link above
> >>>>> I don't see much advantage to it apart from making packet dumps easier
> >>>>> to read. Just wanted to close the loop on that
> >>>>> if I didn't before.
> >>>>
> >>>> I don't have a strong preference here. I'm just forwarding the tag type
> >>>> from generic code.
> >>>>
> >>>> If we want to pass strings, we will need a gdbarch hook that maps a type
> >>>> to a string in the remote target layer.
> >>>>
> >>>> Otherwise we'd need to standardize on particular tag type names across
> >>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>> "capability tag" etc.
> >>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
> >>>>>>
> >>>>>> Minor thing, there is a missing space here in "typeis".
> >>>>>>
> >>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>>> +integer.
> >>>>>>
> >>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >>>>>>>
> >>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
> >>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> >>>>>>>> Cc: david.spickett@linaro.org
> >>>>>>>>
> >>>>>>>> gdb/doc/ChangeLog:
> >>>>>>>>
> >>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>>>>>>>
> >>>>>>>>          * gdb.texinfo (General Query Packets): Document qMemTags and
> >>>>>>>>          QMemTags.  Document the "memory-tagging" feature.
> >>>>>>>> ---
> >>>>>>>>     gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >>>>>>>>     1 file changed, 96 insertions(+)
> >>>>>>>
> >>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 15:16                   ` David Spickett
@ 2020-11-17 17:29                     ` Luis Machado
  2020-11-18 10:39                       ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-17 17:29 UTC (permalink / raw)
  To: David Spickett; +Cc: Eli Zaretskii, gdb-patches

On 11/17/20 12:16 PM, David Spickett wrote:
>> Right now you can infer the technology and logical/allocation from the
>> type. There is no need for a two step process. I don't anticipate a need
>> for that in the future either, as long as we prevent the tag type ENUM
>> from having overlapping values.
> 
> Right, so to not overlap, a value of that tag type ENUM must be a
> combination of technology and tag...kind. (words are hard)
> E.g. MTE logical tag, <future tech> allocation tag , <other tech> strange tag

Why? It only needs to be a unique value that represents a unique 
combination. See below.

> 
> So if <future AArch64 tag technology> were to also have "logical" and
> "allocation" tags, they would be new type values, yes?
> 0 = MTE logical
> 1 = MTE allocation
> 2 = <future AArch64 tag technology> logical
> 3 = <future AArch64 tag technology> allocation
> 
> Because if they are still 0 and 1, they overlap and you can't tell MTE
> and <future AArch64 tag technology> apart.

I think there is some confusion here. Let me try to clarify.

Yes, we currently only have tag types 0 and 1 (AArch64's MTE and SPARC 
ADI technologies, logical/allocation kind). If we add more tag 
technologies, we will also add new code/commands that will pass the 
appropriate tag types down to the target/remote layer.

For example, if we end up supporting capability tags as a new type of 
tag (say, type 2, given we already have 0 and 1) , we will have to 
modify the code to handle that. It will be either a new command or new 
code to handle it.

The target/remote layer will only see unique numbers 0, 1 and 2.

For AArch64, these numbers would mean the following:

0 - MTE logical
1 - MTE allocation
2 - Capability

For SPARC ADI, the following:

0 - ADI logical
1 - ADI allocation
2 - Unknown/Invalid

> 
> I get that at the user interface layer you have some mapping back to a
> set of generic types, talking just about the
> packet contents.
> 
>> So this is wrong, as the remote/native side won't be able to tell both
>> definitions of type "1" apart.
> 
> Sorry that was a typo. Should be:
> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> allocation, 3 = future tag form (not logical/allocation) etc...
> (basically what I restated above)

I think the typo is still there.

You meant 0,1,2 3 and 4, right?

But I see what you mean. Even though the tag type name is "tag_logical" 
right now, the implementation choice is to interpret that as MTE for 
AArch64 and ADI for SPARC. Same thing for "tag_allocation".

The rationale for having these two generic tag types ("tag_logical" and 
"tag_allocation") is that this technology may be common to multiple 
architectures (AArch64 and SPARC right now).

Personally, I don't think having 4 type enums (mte_logical, 
mte_allocation, adi_logical and adi_allocation) would be better. That 
would require extra code for a similar technology. So, just to pass 
down, say, mte_logical instead of adi_logical, when those are in fact 
the same kind of tag/technology.

Does that make sense?

> 
>> If we want to address this and make it a bit more flexible, then we will
>> need to let architectures define their own tag type values. Then generic
>> code will have to go through an arch-specific hook to fetch the tag type.
> 
>> Would that address your concerns?
> 
> I think so. I thought of this working like the breakpoint types I
> referenced. Breakpoint type 1 for MIPS isn't in any way the same as
> type 1 for Arm etc.
> (ok they might be similar but the docs make it clear that the list of
> types is per architecture)
> 

I think the situation is similar here. I opted to group similar things 
together in the type names.

mte_allocation is similar to adi_allocation, but they're different in 
that mte_allocation has granule size 16, while adi_allocation has 
granule size 64.

mte_logical is exactly the same as adi_logical. They are both 4 bits in 
size.

>> As long as GDB sends a unique tag type identifier (non-overlapping
>> values), we will be able to tell them apart from the remote side.
> 
> Yes but depending on how those IDs are allocated we may only be able
> to tell logical vs allocation not MTE vs CHERI vs <future whatever>.
> 
> On Tue, 17 Nov 2020 at 14:44, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> On 11/17/20 9:29 AM, David Spickett wrote:
>>>> Right. The type is really telling you what specific kind of tag you are
>>>> requesting, not the technology. So it may be perfectly valid to request
>>>> a MTE logical tag from the remote target, but the remote target doesn't
>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>>>
>>>> The tag types don't overlap at the moment, given they are an ENUM in
>>>> generic code. So the server will tell them apart by their values.
>>>
>>> Ok but my concern here is that there are two aspects to type. (which I
>>> probably confused earlier tbf)
>>>
>>> 1. logical vs allocation
>>> 2. MTE vs <future tagging technology>
>>>
>>> So we have three scenarios:
>>> 1. Server uses type to decide between logical and allocation
>>
>> Right now 0 maps to logical and 1 maps to allocation for all
>> architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE
>> allocation.
>>
>> But, if more tag types are supported in the future, we will need to map
>> types to logical, allocation or something else.
>>
>>> 2. Server uses type to decide between MTE and <future tagging technology>
>>
>> Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet
>> supported). In the future, if there are more tagging technologies, we
>> will need to provide a mapping from tag types to tag technology.
>>
>>> 3. The combination of the two, should a system have both technologies
>>
>> In this case, we will use two mappings: type to tag type and type to tag
>> technology.
>>
>>>
>>> What I want to avoid is a two step process:
>>> 1. Somehow select tagging technology you want to interact with
>>> 2. You send memtag packets with the logical vs allocation "type"
>>>
>>> Which would be needed if the protocol "type" is just allocation vs
>>> logical. If the "type" includes the technology
>>> then we can do it in one step.
>>
>> Right now you can infer the technology and logical/allocation from the
>> type. There is no need for a two step process. I don't anticipate a need
>> for that in the future either, as long as we prevent the tag type ENUM
>> from having overlapping values.
>>
>>>
>>> So I prefer:
>>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
>>> allocation, 3 = future tag form (not logical/allocation) etc...
>>
>> So this is wrong, as the remote/native side won't be able to tell both
>> definitions of type "1" apart.
>>
>>> Over:
>>> 0 = logical, 1 = allocation, 2 = future term for other tag form etc...
>>
>> This is correct in my view. Everything is unique.
>>
>> The complicating factor here is that generic code/UI needs to use a
>> generic tag type so all architectures supporting memory tagging can use
>> the commands out of the box.
>>
>> For AArch64, tag_logical/tag_allocation means MTE logical/MTE
>> allocation. For SPARC ADI, this means whatever their tagging mechanism is.
>>
>> If we turn tag_logical into mte_logical, SPARC ADI won't be able to use
>> that. We will, again, need a mapping.
>>
>> If we want to address this and make it a bit more flexible, then we will
>> need to let architectures define their own tag type values. Then generic
>> code will have to go through an arch-specific hook to fetch the tag type.
>>
>> Would that address your concerns?
>>
>>>
>>> I see the need for the second form in gdb internally, but my concern
>>> is only with the protocol side.
>>
>> As long as GDB sends a unique tag type identifier (non-overlapping
>> values), we will be able to tell them apart from the remote side.
>>
>>>
>>>> I just want to keep that option open
>>>> if someone wants to do it, or if some other type of tag shows up that
>>>> would require such support.
>>>
>>> I hadn't thought of that. I agree that type should include that too.
>>>
>>> On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
>>>>
>>>> Hi,
>>>>
>>>> On 11/17/20 7:05 AM, David Spickett wrote:
>>>>>> Right now the design makes these types architecture-specific.
>>>>>
>>>>> This works too, in fact it matches the breakpoint types example better that way.
>>>>>
>>>>>> But there's one catch right now. The user-visible commands know about
>>>>>> two types of tags (logical and allocation). The native/remote side of
>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>>>> ask the native/remote target about logical tags.
>>>>>>
>>>>>> This is slightly messy and, in my opinion, should be an implementation
>>>>>> detail.
>>>>>
>>>>> Tell me if I have this right.
>>>>>
>>>>> In gdb in overall you have these two types but the server only uses
>>>>> one of them, the allocation tag type.
>>>>> So only the allocation tag type will ever go over the protocol. (for
>>>>> MTE at least)
>>>>
>>>> That's correct. Only GDB knows about logical tags. Those don't make
>>>> their way to the remote via the remote protocol.
>>>>
>>>>>
>>>>> Given that, if we assume that "mte allocation" type is 1. A future
>>>>> AArch64 kind of memory tagging could allocate 2 and on for its tag
>>>>> types.
>>>>> Something like:
>>>>> AArch64 Memory Tag types -
>>>>>      0 : MTE logical (which is internal only, reserved but documented as
>>>>> unused, or left out completely?)
>>>>>      1 : MTE allocation (the one we use at present)
>>>>>      2: <future tagging> logical tag (because maybe there is some server
>>>>> component for this kind of tagging extension?)
>>>>>      3: <future tagging> allocation tag
>>>>>
>>>>> The reason I want to clarify is that I understood the type to
>>>>> differentiate tagging technologies, not the kind of tag within them.
>>>>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
>>>>> The use case being what if you have MTE and <future tag type> active
>>>>> in the same target and I want to set an MTE allocation tag,
>>>>> how can the server tell them apart?
>>>>
>>>> Right. The type is really telling you what specific kind of tag you are
>>>> requesting, not the technology. So it may be perfectly valid to request
>>>> a MTE logical tag from the remote target, but the remote target doesn't
>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>>>
>>>> The tag types don't overlap at the moment, given they are an ENUM in
>>>> generic code. So the server will tell them apart by their values.
>>>>
>>>>>
>>>>> If the type numbers overlap between tagging technologies, we can't
>>>>> tell them apart.
>>>>> However if they encode what extension they are for and the
>>>>> logical/allocation type (as in the example above) then we can.
>>>>>
>>>>> A lot of that is probably academic given there's one relevant type but
>>>>> we can at least document the intent of the field.
>>>>> E.g. "these types are global to AArch64 so new types should not
>>>>> overlap existing ones"
>>>>
>>>> I suppose. I chose to have generic ENUM's without specific references to
>>>> MTE for that reason. Architectures can use logical/allocation tags as
>>>> they see fit, but the ENUM values will not overlap.
>>>>
>>>> We need to support the UI as well, so there needs to be some generic
>>>> definitions so commands can query different tag types.
>>>>
>>>>>
>>>>>> Otherwise we'd need to standardize on particular tag type names across
>>>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>>>> "capability tag" etc.
>>>>>
>>>>> Well I was thinking of type more as a single value like "mte". Anyway
>>>>> I'm fine with the integer route.
>>>>
>>>> Though we don't have a use for requesting logical tags from the remote
>>>> targets, it is possible to support that. Passing "mte" or any other
>>>> technology name would close that option.
>>>>
>>>> If, for example, we decide to have a dumb GDB client and a smart
>>>> GDBserver (unlikely at this point), then it would make sense to pass
>>>> down logical tag requests I think. I just want to keep that option open
>>>> if someone wants to do it, or if some other type of tag shows up that
>>>> would require such support.
>>>>
>>>>>
>>>>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 11/16/20 1:04 PM, David Spickett wrote:
>>>>>>> Also with regard to the "type" field.
>>>>>>>
>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>>>> +integer.
>>>>>>>
>>>>>>> (typo aside) Is this field architecture specific and will there be a
>>>>>>> list of these type numbers documented anywhere? (or already is)
>>>>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
>>>>>>> tag type>. Or would that <other tag type> be 2.
>>>>>>>
>>>>>>> My assumption has been that it is the latter and that a value means a
>>>>>>> kind of tagging extension. So for example 1=MTE rather than
>>>>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
>>>>>>
>>>>>> Right now the design makes these types architecture-specific. It would
>>>>>> be nice to have more documentation about them, for sure.
>>>>>>
>>>>>> But there's one catch right now. The user-visible commands know about
>>>>>> two types of tags (logical and allocation). The native/remote side of
>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>>>> ask the native/remote target about logical tags.
>>>>>>
>>>>>> This is slightly messy and, in my opinion, should be an implementation
>>>>>> detail.
>>>>>>
>>>>>> So, in summary... We have a couple generic tag types GDB knows about:
>>>>>> logical and allocation.
>>>>>>
>>>>>> Those types get translated to an arch/a target-specific type when they
>>>>>> cross the native/remote target boundary.
>>>>>>
>>>>>> In theory we could have generic tag types 1 and 2 in generic code, but
>>>>>> tag type 2 gets translated to type 1 in a remote packet.
>>>>>>
>>>>>> Maybe we could improve this a little.
>>>>>>
>>>>>>>
>>>>>>> A page like:
>>>>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
>>>>>>>
>>>>>>> Or just a short note, given that there's only one type right now.
>>>>>>
>>>>>> Yes, that would be nice to expand for the tag types.
>>>>>>
>>>>>>>
>>>>>>> Also, I may have suggested the type be a string at some point. However
>>>>>>> based on examples like the link above
>>>>>>> I don't see much advantage to it apart from making packet dumps easier
>>>>>>> to read. Just wanted to close the loop on that
>>>>>>> if I didn't before.
>>>>>>
>>>>>> I don't have a strong preference here. I'm just forwarding the tag type
>>>>>> from generic code.
>>>>>>
>>>>>> If we want to pass strings, we will need a gdbarch hook that maps a type
>>>>>> to a string in the remote target layer.
>>>>>>
>>>>>> Otherwise we'd need to standardize on particular tag type names across
>>>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>>>> "capability tag" etc.
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>>>>>>>>
>>>>>>>> Minor thing, there is a missing space here in "typeis".
>>>>>>>>
>>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>>>>> +integer.
>>>>>>>>
>>>>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>>>>>>>>
>>>>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>>>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>>>>>>>>> Cc: david.spickett@linaro.org
>>>>>>>>>>
>>>>>>>>>> gdb/doc/ChangeLog:
>>>>>>>>>>
>>>>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>>>>>>>>
>>>>>>>>>>           * gdb.texinfo (General Query Packets): Document qMemTags and
>>>>>>>>>>           QMemTags.  Document the "memory-tagging" feature.
>>>>>>>>>> ---
>>>>>>>>>>      gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>      1 file changed, 96 insertions(+)
>>>>>>>>>
>>>>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-17 17:29                     ` Luis Machado
@ 2020-11-18 10:39                       ` David Spickett
  2020-11-18 10:56                         ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: David Spickett @ 2020-11-18 10:39 UTC (permalink / raw)
  To: Luis Machado; +Cc: Eli Zaretskii, gdb-patches

> I think the typo is still there.
>
> You meant 0,1,2 3 and 4, right?

Sorry, long day. That is what I meant.

> But I see what you mean. Even though the tag type name is "tag_logical"
> right now, the implementation choice is to interpret that as MTE for
> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
>
> The rationale for having these two generic tag types ("tag_logical" and
> "tag_allocation") is that this technology may be common to multiple
> architectures (AArch64 and SPARC right now).
>
> Personally, I don't think having 4 type enums (mte_logical,
> mte_allocation, adi_logical and adi_allocation) would be better. That
> would require extra code for a similar technology. So, just to pass
> down, say, mte_logical instead of adi_logical, when those are in fact
> the same kind of tag/technology.
>
> Does that make sense?

Yes it does. I'm not suggesting a combined type enum for all architectures.

>  The rationale for having these two generic tag types ("tag_logical" and
> "tag_allocation") is that this technology may be common to multiple
> architectures (AArch64 and SPARC right now).

I think it's sketchy to think of logical and allocation as anything more than
"concepts".

On a user interface level yes. logical tags come from pointers, that's the nice
way of summarising them. And you can have common code to show them in
common ways.

Server side though the allocation tags for MTE and the allocation
tags for <future aarch64 tagging> could/will have different interfaces
to read them.
(even if it is just a ptrace enum)
So the protocol needs to know the difference. (within the same architecture)

See below...

> For AArch64, these numbers would mean the following:
>
> 0 - MTE logical
> 1 - MTE allocation
> 2 - Capability
>
> For SPARC ADI, the following:
>
> 0 - ADI logical
> 1 - ADI allocation
> 2 - Unknown/Invalid

My concern is what happens when <future aarch64 tagging> comes in. Assume that:
* it also has tags referred to as logical and allocation
* it can be present alongside MTE in the same process/debug target
* the interface to read the allocation tags is different (aka it's a
different code path)

If you say well, <future aarch64 tagging> allocation tag is an
allocation tag like any other,
then the server gets "hey read me an allocation tag". But for what?
MTE or <future aarch64 tagging>?

If you add these new <future aarch64 tagging> tags as new enum values like:
0 - MTE logical
1 - MTE allocation
2 - Capability
3 - <future aarch64 tagging> logical
4 - <future aarch64 tagging> allocation

Then the server gets "hey read me a <future aarch64 tagging> allocation tag".

There's an argument to be made that this isn't a real problem and
might never happen,
and if it did you could add some kind of priming packet. "I'm going to
read MTE", "read me an allocation tag".
qMemTagsEX, whatever.

I just think you could avoid that right now by encoding the type in
the way I suggested.
(again, in the protocol, clients can map it however they want to reuse code)

I'll try to summarise where I'm at:

Grouping similar tag kinds (as in 0 = logical for SPARC ADI and 0 =
logical for MTE also) doesn't bother me.
We've got plenty of ints to go around and yes it does help the client
share some code.

As long as, within the same architecture (aarch64 here), the server
can tell MTE from <future aarch64 tagging>.
If we document the intent of the "type" field in the protocol I think
that fixes this, since the use case is academic at this point.
I suggest something like:
"This type value is per architecture and each value encodes the
architecture specific tagging technology used (e.g MTE) and the tag
kind (e.g. logical or allocation)."
<followed by a table for aarch64>

If it makes sense to say "Architectures that want to add memory
tagging support may choose to overlap with existing values from other
architectures to reuse existing commands..." then great.
We've made the intent clear.

This leaves the door open for SPARC ADI to do as you suggested and
overlap their logical/allocation with aarch64 mte and reuse the
existing code.
But it also confirms that <future aarch64 tagging> will get new type
values regardless of whether it has things called logical/allocation
tags.
So that servers can tell them apart.

This means your code in these patches doesn't need to change at all.
Right now we have the convenience of lining up the logical/allocation
kinds and if that
changes in future then the clients can change. (for example we add a
mapping from aarch64 tag types back to the smaller generic list of tag
types)

Which is a lot of words to ask for a small docs addition, but
hopefully my hypothetical use case is clear?

On Tue, 17 Nov 2020 at 17:29, Luis Machado <luis.machado@linaro.org> wrote:
>
> On 11/17/20 12:16 PM, David Spickett wrote:
> >> Right now you can infer the technology and logical/allocation from the
> >> type. There is no need for a two step process. I don't anticipate a need
> >> for that in the future either, as long as we prevent the tag type ENUM
> >> from having overlapping values.
> >
> > Right, so to not overlap, a value of that tag type ENUM must be a
> > combination of technology and tag...kind. (words are hard)
> > E.g. MTE logical tag, <future tech> allocation tag , <other tech> strange tag
>
> Why? It only needs to be a unique value that represents a unique
> combination. See below.
>
> >
> > So if <future AArch64 tag technology> were to also have "logical" and
> > "allocation" tags, they would be new type values, yes?
> > 0 = MTE logical
> > 1 = MTE allocation
> > 2 = <future AArch64 tag technology> logical
> > 3 = <future AArch64 tag technology> allocation
> >
> > Because if they are still 0 and 1, they overlap and you can't tell MTE
> > and <future AArch64 tag technology> apart.
>
> I think there is some confusion here. Let me try to clarify.
>
> Yes, we currently only have tag types 0 and 1 (AArch64's MTE and SPARC
> ADI technologies, logical/allocation kind). If we add more tag
> technologies, we will also add new code/commands that will pass the
> appropriate tag types down to the target/remote layer.
>
> For example, if we end up supporting capability tags as a new type of
> tag (say, type 2, given we already have 0 and 1) , we will have to
> modify the code to handle that. It will be either a new command or new
> code to handle it.
>
> The target/remote layer will only see unique numbers 0, 1 and 2.
>
> For AArch64, these numbers would mean the following:
>
> 0 - MTE logical
> 1 - MTE allocation
> 2 - Capability
>
> For SPARC ADI, the following:
>
> 0 - ADI logical
> 1 - ADI allocation
> 2 - Unknown/Invalid
>
> >
> > I get that at the user interface layer you have some mapping back to a
> > set of generic types, talking just about the
> > packet contents.
> >
> >> So this is wrong, as the remote/native side won't be able to tell both
> >> definitions of type "1" apart.
> >
> > Sorry that was a typo. Should be:
> > 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> > allocation, 3 = future tag form (not logical/allocation) etc...
> > (basically what I restated above)
>
> I think the typo is still there.
>
> You meant 0,1,2 3 and 4, right?
>
> But I see what you mean. Even though the tag type name is "tag_logical"
> right now, the implementation choice is to interpret that as MTE for
> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
>
> The rationale for having these two generic tag types ("tag_logical" and
> "tag_allocation") is that this technology may be common to multiple
> architectures (AArch64 and SPARC right now).
>
> Personally, I don't think having 4 type enums (mte_logical,
> mte_allocation, adi_logical and adi_allocation) would be better. That
> would require extra code for a similar technology. So, just to pass
> down, say, mte_logical instead of adi_logical, when those are in fact
> the same kind of tag/technology.
>
> Does that make sense?
>
> >
> >> If we want to address this and make it a bit more flexible, then we will
> >> need to let architectures define their own tag type values. Then generic
> >> code will have to go through an arch-specific hook to fetch the tag type.
> >
> >> Would that address your concerns?
> >
> > I think so. I thought of this working like the breakpoint types I
> > referenced. Breakpoint type 1 for MIPS isn't in any way the same as
> > type 1 for Arm etc.
> > (ok they might be similar but the docs make it clear that the list of
> > types is per architecture)
> >
>
> I think the situation is similar here. I opted to group similar things
> together in the type names.
>
> mte_allocation is similar to adi_allocation, but they're different in
> that mte_allocation has granule size 16, while adi_allocation has
> granule size 64.
>
> mte_logical is exactly the same as adi_logical. They are both 4 bits in
> size.
>
> >> As long as GDB sends a unique tag type identifier (non-overlapping
> >> values), we will be able to tell them apart from the remote side.
> >
> > Yes but depending on how those IDs are allocated we may only be able
> > to tell logical vs allocation not MTE vs CHERI vs <future whatever>.
> >
> > On Tue, 17 Nov 2020 at 14:44, Luis Machado <luis.machado@linaro.org> wrote:
> >>
> >> On 11/17/20 9:29 AM, David Spickett wrote:
> >>>> Right. The type is really telling you what specific kind of tag you are
> >>>> requesting, not the technology. So it may be perfectly valid to request
> >>>> a MTE logical tag from the remote target, but the remote target doesn't
> >>>> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>>>
> >>>> The tag types don't overlap at the moment, given they are an ENUM in
> >>>> generic code. So the server will tell them apart by their values.
> >>>
> >>> Ok but my concern here is that there are two aspects to type. (which I
> >>> probably confused earlier tbf)
> >>>
> >>> 1. logical vs allocation
> >>> 2. MTE vs <future tagging technology>
> >>>
> >>> So we have three scenarios:
> >>> 1. Server uses type to decide between logical and allocation
> >>
> >> Right now 0 maps to logical and 1 maps to allocation for all
> >> architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE
> >> allocation.
> >>
> >> But, if more tag types are supported in the future, we will need to map
> >> types to logical, allocation or something else.
> >>
> >>> 2. Server uses type to decide between MTE and <future tagging technology>
> >>
> >> Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet
> >> supported). In the future, if there are more tagging technologies, we
> >> will need to provide a mapping from tag types to tag technology.
> >>
> >>> 3. The combination of the two, should a system have both technologies
> >>
> >> In this case, we will use two mappings: type to tag type and type to tag
> >> technology.
> >>
> >>>
> >>> What I want to avoid is a two step process:
> >>> 1. Somehow select tagging technology you want to interact with
> >>> 2. You send memtag packets with the logical vs allocation "type"
> >>>
> >>> Which would be needed if the protocol "type" is just allocation vs
> >>> logical. If the "type" includes the technology
> >>> then we can do it in one step.
> >>
> >> Right now you can infer the technology and logical/allocation from the
> >> type. There is no need for a two step process. I don't anticipate a need
> >> for that in the future either, as long as we prevent the tag type ENUM
> >> from having overlapping values.
> >>
> >>>
> >>> So I prefer:
> >>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> >>> allocation, 3 = future tag form (not logical/allocation) etc...
> >>
> >> So this is wrong, as the remote/native side won't be able to tell both
> >> definitions of type "1" apart.
> >>
> >>> Over:
> >>> 0 = logical, 1 = allocation, 2 = future term for other tag form etc...
> >>
> >> This is correct in my view. Everything is unique.
> >>
> >> The complicating factor here is that generic code/UI needs to use a
> >> generic tag type so all architectures supporting memory tagging can use
> >> the commands out of the box.
> >>
> >> For AArch64, tag_logical/tag_allocation means MTE logical/MTE
> >> allocation. For SPARC ADI, this means whatever their tagging mechanism is.
> >>
> >> If we turn tag_logical into mte_logical, SPARC ADI won't be able to use
> >> that. We will, again, need a mapping.
> >>
> >> If we want to address this and make it a bit more flexible, then we will
> >> need to let architectures define their own tag type values. Then generic
> >> code will have to go through an arch-specific hook to fetch the tag type.
> >>
> >> Would that address your concerns?
> >>
> >>>
> >>> I see the need for the second form in gdb internally, but my concern
> >>> is only with the protocol side.
> >>
> >> As long as GDB sends a unique tag type identifier (non-overlapping
> >> values), we will be able to tell them apart from the remote side.
> >>
> >>>
> >>>> I just want to keep that option open
> >>>> if someone wants to do it, or if some other type of tag shows up that
> >>>> would require such support.
> >>>
> >>> I hadn't thought of that. I agree that type should include that too.
> >>>
> >>> On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>
> >>>> Hi,
> >>>>
> >>>> On 11/17/20 7:05 AM, David Spickett wrote:
> >>>>>> Right now the design makes these types architecture-specific.
> >>>>>
> >>>>> This works too, in fact it matches the breakpoint types example better that way.
> >>>>>
> >>>>>> But there's one catch right now. The user-visible commands know about
> >>>>>> two types of tags (logical and allocation). The native/remote side of
> >>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>>>> ask the native/remote target about logical tags.
> >>>>>>
> >>>>>> This is slightly messy and, in my opinion, should be an implementation
> >>>>>> detail.
> >>>>>
> >>>>> Tell me if I have this right.
> >>>>>
> >>>>> In gdb in overall you have these two types but the server only uses
> >>>>> one of them, the allocation tag type.
> >>>>> So only the allocation tag type will ever go over the protocol. (for
> >>>>> MTE at least)
> >>>>
> >>>> That's correct. Only GDB knows about logical tags. Those don't make
> >>>> their way to the remote via the remote protocol.
> >>>>
> >>>>>
> >>>>> Given that, if we assume that "mte allocation" type is 1. A future
> >>>>> AArch64 kind of memory tagging could allocate 2 and on for its tag
> >>>>> types.
> >>>>> Something like:
> >>>>> AArch64 Memory Tag types -
> >>>>>      0 : MTE logical (which is internal only, reserved but documented as
> >>>>> unused, or left out completely?)
> >>>>>      1 : MTE allocation (the one we use at present)
> >>>>>      2: <future tagging> logical tag (because maybe there is some server
> >>>>> component for this kind of tagging extension?)
> >>>>>      3: <future tagging> allocation tag
> >>>>>
> >>>>> The reason I want to clarify is that I understood the type to
> >>>>> differentiate tagging technologies, not the kind of tag within them.
> >>>>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
> >>>>> The use case being what if you have MTE and <future tag type> active
> >>>>> in the same target and I want to set an MTE allocation tag,
> >>>>> how can the server tell them apart?
> >>>>
> >>>> Right. The type is really telling you what specific kind of tag you are
> >>>> requesting, not the technology. So it may be perfectly valid to request
> >>>> a MTE logical tag from the remote target, but the remote target doesn't
> >>>> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>>>
> >>>> The tag types don't overlap at the moment, given they are an ENUM in
> >>>> generic code. So the server will tell them apart by their values.
> >>>>
> >>>>>
> >>>>> If the type numbers overlap between tagging technologies, we can't
> >>>>> tell them apart.
> >>>>> However if they encode what extension they are for and the
> >>>>> logical/allocation type (as in the example above) then we can.
> >>>>>
> >>>>> A lot of that is probably academic given there's one relevant type but
> >>>>> we can at least document the intent of the field.
> >>>>> E.g. "these types are global to AArch64 so new types should not
> >>>>> overlap existing ones"
> >>>>
> >>>> I suppose. I chose to have generic ENUM's without specific references to
> >>>> MTE for that reason. Architectures can use logical/allocation tags as
> >>>> they see fit, but the ENUM values will not overlap.
> >>>>
> >>>> We need to support the UI as well, so there needs to be some generic
> >>>> definitions so commands can query different tag types.
> >>>>
> >>>>>
> >>>>>> Otherwise we'd need to standardize on particular tag type names across
> >>>>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>>>> "capability tag" etc.
> >>>>>
> >>>>> Well I was thinking of type more as a single value like "mte". Anyway
> >>>>> I'm fine with the integer route.
> >>>>
> >>>> Though we don't have a use for requesting logical tags from the remote
> >>>> targets, it is possible to support that. Passing "mte" or any other
> >>>> technology name would close that option.
> >>>>
> >>>> If, for example, we decide to have a dumb GDB client and a smart
> >>>> GDBserver (unlikely at this point), then it would make sense to pass
> >>>> down logical tag requests I think. I just want to keep that option open
> >>>> if someone wants to do it, or if some other type of tag shows up that
> >>>> would require such support.
> >>>>
> >>>>>
> >>>>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> On 11/16/20 1:04 PM, David Spickett wrote:
> >>>>>>> Also with regard to the "type" field.
> >>>>>>>
> >>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>>>> +integer.
> >>>>>>>
> >>>>>>> (typo aside) Is this field architecture specific and will there be a
> >>>>>>> list of these type numbers documented anywhere? (or already is)
> >>>>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
> >>>>>>> tag type>. Or would that <other tag type> be 2.
> >>>>>>>
> >>>>>>> My assumption has been that it is the latter and that a value means a
> >>>>>>> kind of tagging extension. So for example 1=MTE rather than
> >>>>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
> >>>>>>
> >>>>>> Right now the design makes these types architecture-specific. It would
> >>>>>> be nice to have more documentation about them, for sure.
> >>>>>>
> >>>>>> But there's one catch right now. The user-visible commands know about
> >>>>>> two types of tags (logical and allocation). The native/remote side of
> >>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>>>> ask the native/remote target about logical tags.
> >>>>>>
> >>>>>> This is slightly messy and, in my opinion, should be an implementation
> >>>>>> detail.
> >>>>>>
> >>>>>> So, in summary... We have a couple generic tag types GDB knows about:
> >>>>>> logical and allocation.
> >>>>>>
> >>>>>> Those types get translated to an arch/a target-specific type when they
> >>>>>> cross the native/remote target boundary.
> >>>>>>
> >>>>>> In theory we could have generic tag types 1 and 2 in generic code, but
> >>>>>> tag type 2 gets translated to type 1 in a remote packet.
> >>>>>>
> >>>>>> Maybe we could improve this a little.
> >>>>>>
> >>>>>>>
> >>>>>>> A page like:
> >>>>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> >>>>>>>
> >>>>>>> Or just a short note, given that there's only one type right now.
> >>>>>>
> >>>>>> Yes, that would be nice to expand for the tag types.
> >>>>>>
> >>>>>>>
> >>>>>>> Also, I may have suggested the type be a string at some point. However
> >>>>>>> based on examples like the link above
> >>>>>>> I don't see much advantage to it apart from making packet dumps easier
> >>>>>>> to read. Just wanted to close the loop on that
> >>>>>>> if I didn't before.
> >>>>>>
> >>>>>> I don't have a strong preference here. I'm just forwarding the tag type
> >>>>>> from generic code.
> >>>>>>
> >>>>>> If we want to pass strings, we will need a gdbarch hook that maps a type
> >>>>>> to a string in the remote target layer.
> >>>>>>
> >>>>>> Otherwise we'd need to standardize on particular tag type names across
> >>>>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>>>> "capability tag" etc.
> >>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
> >>>>>>>>
> >>>>>>>> Minor thing, there is a missing space here in "typeis".
> >>>>>>>>
> >>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>>>>> +integer.
> >>>>>>>>
> >>>>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >>>>>>>>>
> >>>>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
> >>>>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> >>>>>>>>>> Cc: david.spickett@linaro.org
> >>>>>>>>>>
> >>>>>>>>>> gdb/doc/ChangeLog:
> >>>>>>>>>>
> >>>>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>>>>>>>>>
> >>>>>>>>>>           * gdb.texinfo (General Query Packets): Document qMemTags and
> >>>>>>>>>>           QMemTags.  Document the "memory-tagging" feature.
> >>>>>>>>>> ---
> >>>>>>>>>>      gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >>>>>>>>>>      1 file changed, 96 insertions(+)
> >>>>>>>>>
> >>>>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-18 10:39                       ` David Spickett
@ 2020-11-18 10:56                         ` Luis Machado
  2020-11-18 11:22                           ` David Spickett
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-18 10:56 UTC (permalink / raw)
  To: David Spickett; +Cc: Eli Zaretskii, gdb-patches

On 11/18/20 7:39 AM, David Spickett wrote:
>> I think the typo is still there.
>>
>> You meant 0,1,2 3 and 4, right?
> 
> Sorry, long day. That is what I meant.
> 
>> But I see what you mean. Even though the tag type name is "tag_logical"
>> right now, the implementation choice is to interpret that as MTE for
>> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
>>
>> The rationale for having these two generic tag types ("tag_logical" and
>> "tag_allocation") is that this technology may be common to multiple
>> architectures (AArch64 and SPARC right now).
>>
>> Personally, I don't think having 4 type enums (mte_logical,
>> mte_allocation, adi_logical and adi_allocation) would be better. That
>> would require extra code for a similar technology. So, just to pass
>> down, say, mte_logical instead of adi_logical, when those are in fact
>> the same kind of tag/technology.
>>
>> Does that make sense?
> 
> Yes it does. I'm not suggesting a combined type enum for all architectures.
> 
>>   The rationale for having these two generic tag types ("tag_logical" and
>> "tag_allocation") is that this technology may be common to multiple
>> architectures (AArch64 and SPARC right now).
> 
> I think it's sketchy to think of logical and allocation as anything more than
> "concepts".
> 
> On a user interface level yes. logical tags come from pointers, that's the nice
> way of summarising them. And you can have common code to show them in
> common ways.
> 
> Server side though the allocation tags for MTE and the allocation
> tags for <future aarch64 tagging> could/will have different interfaces
> to read them.
> (even if it is just a ptrace enum)
> So the protocol needs to know the difference. (within the same architecture)
> 
> See below...
> 
>> For AArch64, these numbers would mean the following:
>>
>> 0 - MTE logical
>> 1 - MTE allocation
>> 2 - Capability
>>
>> For SPARC ADI, the following:
>>
>> 0 - ADI logical
>> 1 - ADI allocation
>> 2 - Unknown/Invalid
> 
> My concern is what happens when <future aarch64 tagging> comes in. Assume that:
> * it also has tags referred to as logical and allocation
> * it can be present alongside MTE in the same process/debug target
> * the interface to read the allocation tags is different (aka it's a
> different code path)
> 
> If you say well, <future aarch64 tagging> allocation tag is an
> allocation tag like any other,
> then the server gets "hey read me an allocation tag". But for what?
> MTE or <future aarch64 tagging>?
> 
> If you add these new <future aarch64 tagging> tags as new enum values like:
> 0 - MTE logical
> 1 - MTE allocation
> 2 - Capability
> 3 - <future aarch64 tagging> logical
> 4 - <future aarch64 tagging> allocation
> 
> Then the server gets "hey read me a <future aarch64 tagging> allocation tag".
> 

This has been my plan so far. The fact we're adding generic 
logical/allocation tag types right now is to accommodate ADI, which uses 
similar technology.

A new <future> technology will have to use a different identifiers in 
the enum definition. I'm not planning on overloading tag types with more 
than one meaning per-architecture.

That is, tag_logical will always be MTE logical for AArch64.

> There's an argument to be made that this isn't a real problem and
> might never happen,
> and if it did you could add some kind of priming packet. "I'm going to
> read MTE", "read me an allocation tag".
> qMemTagsEX, whatever.
> 
> I just think you could avoid that right now by encoding the type in
> the way I suggested.

I think we have the same model in mind, but somehow it has not been made 
clear.

> (again, in the protocol, clients can map it however they want to reuse code)
> 
> I'll try to summarise where I'm at:
> 
> Grouping similar tag kinds (as in 0 = logical for SPARC ADI and 0 =
> logical for MTE also) doesn't bother me.
> We've got plenty of ints to go around and yes it does help the client
> share some code.
> 
> As long as, within the same architecture (aarch64 here), the server
> can tell MTE from <future aarch64 tagging>.

Right. This is what I had in mind.

> If we document the intent of the "type" field in the protocol I think
> that fixes this, since the use case is academic at this point.
> I suggest something like:
> "This type value is per architecture and each value encodes the
> architecture specific tagging technology used (e.g MTE) and the tag
> kind (e.g. logical or allocation)."
> <followed by a table for aarch64>
> 
> If it makes sense to say "Architectures that want to add memory
> tagging support may choose to overlap with existing values from other
> architectures to reuse existing commands..." then great.
> We've made the intent clear.
> 
> This leaves the door open for SPARC ADI to do as you suggested and
> overlap their logical/allocation with aarch64 mte and reuse the
> existing code.
> But it also confirms that <future aarch64 tagging> will get new type
> values regardless of whether it has things called logical/allocation
> tags.
> So that servers can tell them apart.
> 
> This means your code in these patches doesn't need to change at all.
> Right now we have the convenience of lining up the logical/allocation
> kinds and if that
> changes in future then the clients can change. (for example we add a
> mapping from aarch64 tag types back to the smaller generic list of tag
> types)
> 
> Which is a lot of words to ask for a small docs addition, but
> hopefully my hypothetical use case is clear?

I think we've reached the important part here. Do you want 
clarification, through documentation, that we're going to stick with 
unique tag type identifiers per-architecture?

I was slightly confused because unique identifiers per-architecture were 
my goal from the start, but somehow we got lost in discussing some of 
these tag type ambiguity cases.

> 
> On Tue, 17 Nov 2020 at 17:29, Luis Machado <luis.machado@linaro.org> wrote:
>>
>> On 11/17/20 12:16 PM, David Spickett wrote:
>>>> Right now you can infer the technology and logical/allocation from the
>>>> type. There is no need for a two step process. I don't anticipate a need
>>>> for that in the future either, as long as we prevent the tag type ENUM
>>>> from having overlapping values.
>>>
>>> Right, so to not overlap, a value of that tag type ENUM must be a
>>> combination of technology and tag...kind. (words are hard)
>>> E.g. MTE logical tag, <future tech> allocation tag , <other tech> strange tag
>>
>> Why? It only needs to be a unique value that represents a unique
>> combination. See below.
>>
>>>
>>> So if <future AArch64 tag technology> were to also have "logical" and
>>> "allocation" tags, they would be new type values, yes?
>>> 0 = MTE logical
>>> 1 = MTE allocation
>>> 2 = <future AArch64 tag technology> logical
>>> 3 = <future AArch64 tag technology> allocation
>>>
>>> Because if they are still 0 and 1, they overlap and you can't tell MTE
>>> and <future AArch64 tag technology> apart.
>>
>> I think there is some confusion here. Let me try to clarify.
>>
>> Yes, we currently only have tag types 0 and 1 (AArch64's MTE and SPARC
>> ADI technologies, logical/allocation kind). If we add more tag
>> technologies, we will also add new code/commands that will pass the
>> appropriate tag types down to the target/remote layer.
>>
>> For example, if we end up supporting capability tags as a new type of
>> tag (say, type 2, given we already have 0 and 1) , we will have to
>> modify the code to handle that. It will be either a new command or new
>> code to handle it.
>>
>> The target/remote layer will only see unique numbers 0, 1 and 2.
>>
>> For AArch64, these numbers would mean the following:
>>
>> 0 - MTE logical
>> 1 - MTE allocation
>> 2 - Capability
>>
>> For SPARC ADI, the following:
>>
>> 0 - ADI logical
>> 1 - ADI allocation
>> 2 - Unknown/Invalid
>>
>>>
>>> I get that at the user interface layer you have some mapping back to a
>>> set of generic types, talking just about the
>>> packet contents.
>>>
>>>> So this is wrong, as the remote/native side won't be able to tell both
>>>> definitions of type "1" apart.
>>>
>>> Sorry that was a typo. Should be:
>>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
>>> allocation, 3 = future tag form (not logical/allocation) etc...
>>> (basically what I restated above)
>>
>> I think the typo is still there.
>>
>> You meant 0,1,2 3 and 4, right?
>>
>> But I see what you mean. Even though the tag type name is "tag_logical"
>> right now, the implementation choice is to interpret that as MTE for
>> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
>>
>> The rationale for having these two generic tag types ("tag_logical" and
>> "tag_allocation") is that this technology may be common to multiple
>> architectures (AArch64 and SPARC right now).
>>
>> Personally, I don't think having 4 type enums (mte_logical,
>> mte_allocation, adi_logical and adi_allocation) would be better. That
>> would require extra code for a similar technology. So, just to pass
>> down, say, mte_logical instead of adi_logical, when those are in fact
>> the same kind of tag/technology.
>>
>> Does that make sense?
>>
>>>
>>>> If we want to address this and make it a bit more flexible, then we will
>>>> need to let architectures define their own tag type values. Then generic
>>>> code will have to go through an arch-specific hook to fetch the tag type.
>>>
>>>> Would that address your concerns?
>>>
>>> I think so. I thought of this working like the breakpoint types I
>>> referenced. Breakpoint type 1 for MIPS isn't in any way the same as
>>> type 1 for Arm etc.
>>> (ok they might be similar but the docs make it clear that the list of
>>> types is per architecture)
>>>
>>
>> I think the situation is similar here. I opted to group similar things
>> together in the type names.
>>
>> mte_allocation is similar to adi_allocation, but they're different in
>> that mte_allocation has granule size 16, while adi_allocation has
>> granule size 64.
>>
>> mte_logical is exactly the same as adi_logical. They are both 4 bits in
>> size.
>>
>>>> As long as GDB sends a unique tag type identifier (non-overlapping
>>>> values), we will be able to tell them apart from the remote side.
>>>
>>> Yes but depending on how those IDs are allocated we may only be able
>>> to tell logical vs allocation not MTE vs CHERI vs <future whatever>.
>>>
>>> On Tue, 17 Nov 2020 at 14:44, Luis Machado <luis.machado@linaro.org> wrote:
>>>>
>>>> On 11/17/20 9:29 AM, David Spickett wrote:
>>>>>> Right. The type is really telling you what specific kind of tag you are
>>>>>> requesting, not the technology. So it may be perfectly valid to request
>>>>>> a MTE logical tag from the remote target, but the remote target doesn't
>>>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>>>>>
>>>>>> The tag types don't overlap at the moment, given they are an ENUM in
>>>>>> generic code. So the server will tell them apart by their values.
>>>>>
>>>>> Ok but my concern here is that there are two aspects to type. (which I
>>>>> probably confused earlier tbf)
>>>>>
>>>>> 1. logical vs allocation
>>>>> 2. MTE vs <future tagging technology>
>>>>>
>>>>> So we have three scenarios:
>>>>> 1. Server uses type to decide between logical and allocation
>>>>
>>>> Right now 0 maps to logical and 1 maps to allocation for all
>>>> architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE
>>>> allocation.
>>>>
>>>> But, if more tag types are supported in the future, we will need to map
>>>> types to logical, allocation or something else.
>>>>
>>>>> 2. Server uses type to decide between MTE and <future tagging technology>
>>>>
>>>> Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet
>>>> supported). In the future, if there are more tagging technologies, we
>>>> will need to provide a mapping from tag types to tag technology.
>>>>
>>>>> 3. The combination of the two, should a system have both technologies
>>>>
>>>> In this case, we will use two mappings: type to tag type and type to tag
>>>> technology.
>>>>
>>>>>
>>>>> What I want to avoid is a two step process:
>>>>> 1. Somehow select tagging technology you want to interact with
>>>>> 2. You send memtag packets with the logical vs allocation "type"
>>>>>
>>>>> Which would be needed if the protocol "type" is just allocation vs
>>>>> logical. If the "type" includes the technology
>>>>> then we can do it in one step.
>>>>
>>>> Right now you can infer the technology and logical/allocation from the
>>>> type. There is no need for a two step process. I don't anticipate a need
>>>> for that in the future either, as long as we prevent the tag type ENUM
>>>> from having overlapping values.
>>>>
>>>>>
>>>>> So I prefer:
>>>>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
>>>>> allocation, 3 = future tag form (not logical/allocation) etc...
>>>>
>>>> So this is wrong, as the remote/native side won't be able to tell both
>>>> definitions of type "1" apart.
>>>>
>>>>> Over:
>>>>> 0 = logical, 1 = allocation, 2 = future term for other tag form etc...
>>>>
>>>> This is correct in my view. Everything is unique.
>>>>
>>>> The complicating factor here is that generic code/UI needs to use a
>>>> generic tag type so all architectures supporting memory tagging can use
>>>> the commands out of the box.
>>>>
>>>> For AArch64, tag_logical/tag_allocation means MTE logical/MTE
>>>> allocation. For SPARC ADI, this means whatever their tagging mechanism is.
>>>>
>>>> If we turn tag_logical into mte_logical, SPARC ADI won't be able to use
>>>> that. We will, again, need a mapping.
>>>>
>>>> If we want to address this and make it a bit more flexible, then we will
>>>> need to let architectures define their own tag type values. Then generic
>>>> code will have to go through an arch-specific hook to fetch the tag type.
>>>>
>>>> Would that address your concerns?
>>>>
>>>>>
>>>>> I see the need for the second form in gdb internally, but my concern
>>>>> is only with the protocol side.
>>>>
>>>> As long as GDB sends a unique tag type identifier (non-overlapping
>>>> values), we will be able to tell them apart from the remote side.
>>>>
>>>>>
>>>>>> I just want to keep that option open
>>>>>> if someone wants to do it, or if some other type of tag shows up that
>>>>>> would require such support.
>>>>>
>>>>> I hadn't thought of that. I agree that type should include that too.
>>>>>
>>>>> On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> On 11/17/20 7:05 AM, David Spickett wrote:
>>>>>>>> Right now the design makes these types architecture-specific.
>>>>>>>
>>>>>>> This works too, in fact it matches the breakpoint types example better that way.
>>>>>>>
>>>>>>>> But there's one catch right now. The user-visible commands know about
>>>>>>>> two types of tags (logical and allocation). The native/remote side of
>>>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>>>>>> ask the native/remote target about logical tags.
>>>>>>>>
>>>>>>>> This is slightly messy and, in my opinion, should be an implementation
>>>>>>>> detail.
>>>>>>>
>>>>>>> Tell me if I have this right.
>>>>>>>
>>>>>>> In gdb in overall you have these two types but the server only uses
>>>>>>> one of them, the allocation tag type.
>>>>>>> So only the allocation tag type will ever go over the protocol. (for
>>>>>>> MTE at least)
>>>>>>
>>>>>> That's correct. Only GDB knows about logical tags. Those don't make
>>>>>> their way to the remote via the remote protocol.
>>>>>>
>>>>>>>
>>>>>>> Given that, if we assume that "mte allocation" type is 1. A future
>>>>>>> AArch64 kind of memory tagging could allocate 2 and on for its tag
>>>>>>> types.
>>>>>>> Something like:
>>>>>>> AArch64 Memory Tag types -
>>>>>>>       0 : MTE logical (which is internal only, reserved but documented as
>>>>>>> unused, or left out completely?)
>>>>>>>       1 : MTE allocation (the one we use at present)
>>>>>>>       2: <future tagging> logical tag (because maybe there is some server
>>>>>>> component for this kind of tagging extension?)
>>>>>>>       3: <future tagging> allocation tag
>>>>>>>
>>>>>>> The reason I want to clarify is that I understood the type to
>>>>>>> differentiate tagging technologies, not the kind of tag within them.
>>>>>>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
>>>>>>> The use case being what if you have MTE and <future tag type> active
>>>>>>> in the same target and I want to set an MTE allocation tag,
>>>>>>> how can the server tell them apart?
>>>>>>
>>>>>> Right. The type is really telling you what specific kind of tag you are
>>>>>> requesting, not the technology. So it may be perfectly valid to request
>>>>>> a MTE logical tag from the remote target, but the remote target doesn't
>>>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
>>>>>>
>>>>>> The tag types don't overlap at the moment, given they are an ENUM in
>>>>>> generic code. So the server will tell them apart by their values.
>>>>>>
>>>>>>>
>>>>>>> If the type numbers overlap between tagging technologies, we can't
>>>>>>> tell them apart.
>>>>>>> However if they encode what extension they are for and the
>>>>>>> logical/allocation type (as in the example above) then we can.
>>>>>>>
>>>>>>> A lot of that is probably academic given there's one relevant type but
>>>>>>> we can at least document the intent of the field.
>>>>>>> E.g. "these types are global to AArch64 so new types should not
>>>>>>> overlap existing ones"
>>>>>>
>>>>>> I suppose. I chose to have generic ENUM's without specific references to
>>>>>> MTE for that reason. Architectures can use logical/allocation tags as
>>>>>> they see fit, but the ENUM values will not overlap.
>>>>>>
>>>>>> We need to support the UI as well, so there needs to be some generic
>>>>>> definitions so commands can query different tag types.
>>>>>>
>>>>>>>
>>>>>>>> Otherwise we'd need to standardize on particular tag type names across
>>>>>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>>>>>> "capability tag" etc.
>>>>>>>
>>>>>>> Well I was thinking of type more as a single value like "mte". Anyway
>>>>>>> I'm fine with the integer route.
>>>>>>
>>>>>> Though we don't have a use for requesting logical tags from the remote
>>>>>> targets, it is possible to support that. Passing "mte" or any other
>>>>>> technology name would close that option.
>>>>>>
>>>>>> If, for example, we decide to have a dumb GDB client and a smart
>>>>>> GDBserver (unlikely at this point), then it would make sense to pass
>>>>>> down logical tag requests I think. I just want to keep that option open
>>>>>> if someone wants to do it, or if some other type of tag shows up that
>>>>>> would require such support.
>>>>>>
>>>>>>>
>>>>>>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 11/16/20 1:04 PM, David Spickett wrote:
>>>>>>>>> Also with regard to the "type" field.
>>>>>>>>>
>>>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>>>>>> +integer.
>>>>>>>>>
>>>>>>>>> (typo aside) Is this field architecture specific and will there be a
>>>>>>>>> list of these type numbers documented anywhere? (or already is)
>>>>>>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
>>>>>>>>> tag type>. Or would that <other tag type> be 2.
>>>>>>>>>
>>>>>>>>> My assumption has been that it is the latter and that a value means a
>>>>>>>>> kind of tagging extension. So for example 1=MTE rather than
>>>>>>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
>>>>>>>>
>>>>>>>> Right now the design makes these types architecture-specific. It would
>>>>>>>> be nice to have more documentation about them, for sure.
>>>>>>>>
>>>>>>>> But there's one catch right now. The user-visible commands know about
>>>>>>>> two types of tags (logical and allocation). The native/remote side of
>>>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
>>>>>>>> ask the native/remote target about logical tags.
>>>>>>>>
>>>>>>>> This is slightly messy and, in my opinion, should be an implementation
>>>>>>>> detail.
>>>>>>>>
>>>>>>>> So, in summary... We have a couple generic tag types GDB knows about:
>>>>>>>> logical and allocation.
>>>>>>>>
>>>>>>>> Those types get translated to an arch/a target-specific type when they
>>>>>>>> cross the native/remote target boundary.
>>>>>>>>
>>>>>>>> In theory we could have generic tag types 1 and 2 in generic code, but
>>>>>>>> tag type 2 gets translated to type 1 in a remote packet.
>>>>>>>>
>>>>>>>> Maybe we could improve this a little.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> A page like:
>>>>>>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
>>>>>>>>>
>>>>>>>>> Or just a short note, given that there's only one type right now.
>>>>>>>>
>>>>>>>> Yes, that would be nice to expand for the tag types.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Also, I may have suggested the type be a string at some point. However
>>>>>>>>> based on examples like the link above
>>>>>>>>> I don't see much advantage to it apart from making packet dumps easier
>>>>>>>>> to read. Just wanted to close the loop on that
>>>>>>>>> if I didn't before.
>>>>>>>>
>>>>>>>> I don't have a strong preference here. I'm just forwarding the tag type
>>>>>>>> from generic code.
>>>>>>>>
>>>>>>>> If we want to pass strings, we will need a gdbarch hook that maps a type
>>>>>>>> to a string in the remote target layer.
>>>>>>>>
>>>>>>>> Otherwise we'd need to standardize on particular tag type names across
>>>>>>>> different architectures, like "hw memory tag", "sw memory tag",
>>>>>>>> "capability tag" etc.
>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
>>>>>>>>>>
>>>>>>>>>> Minor thing, there is a missing space here in "typeis".
>>>>>>>>>>
>>>>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
>>>>>>>>>>> +integer.
>>>>>>>>>>
>>>>>>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
>>>>>>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>>>>>>>>>>> Cc: david.spickett@linaro.org
>>>>>>>>>>>>
>>>>>>>>>>>> gdb/doc/ChangeLog:
>>>>>>>>>>>>
>>>>>>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>>>>>>>>>>>
>>>>>>>>>>>>            * gdb.texinfo (General Query Packets): Document qMemTags and
>>>>>>>>>>>>            QMemTags.  Document the "memory-tagging" feature.
>>>>>>>>>>>> ---
>>>>>>>>>>>>       gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>>>       1 file changed, 96 insertions(+)
>>>>>>>>>>>
>>>>>>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 07/24] Documentation for memory tagging remote packets
  2020-11-18 10:56                         ` Luis Machado
@ 2020-11-18 11:22                           ` David Spickett
  0 siblings, 0 replies; 96+ messages in thread
From: David Spickett @ 2020-11-18 11:22 UTC (permalink / raw)
  To: Luis Machado; +Cc: Eli Zaretskii, gdb-patches

> That is, tag_logical will always be MTE logical for AArch64.

Awesome, we're on the same page.

> I think we have the same model in mind, but somehow it has not been made
> clear.

In future I will start by suggesting a concrete change before going
into the reasoning. I think not doing so confused things.

> I think we've reached the important part here. Do you want
> clarification, through documentation, that we're going to stick with
> unique tag type identifiers per-architecture?

Yes, exactly.

On Wed, 18 Nov 2020 at 10:56, Luis Machado <luis.machado@linaro.org> wrote:
>
> On 11/18/20 7:39 AM, David Spickett wrote:
> >> I think the typo is still there.
> >>
> >> You meant 0,1,2 3 and 4, right?
> >
> > Sorry, long day. That is what I meant.
> >
> >> But I see what you mean. Even though the tag type name is "tag_logical"
> >> right now, the implementation choice is to interpret that as MTE for
> >> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
> >>
> >> The rationale for having these two generic tag types ("tag_logical" and
> >> "tag_allocation") is that this technology may be common to multiple
> >> architectures (AArch64 and SPARC right now).
> >>
> >> Personally, I don't think having 4 type enums (mte_logical,
> >> mte_allocation, adi_logical and adi_allocation) would be better. That
> >> would require extra code for a similar technology. So, just to pass
> >> down, say, mte_logical instead of adi_logical, when those are in fact
> >> the same kind of tag/technology.
> >>
> >> Does that make sense?
> >
> > Yes it does. I'm not suggesting a combined type enum for all architectures.
> >
> >>   The rationale for having these two generic tag types ("tag_logical" and
> >> "tag_allocation") is that this technology may be common to multiple
> >> architectures (AArch64 and SPARC right now).
> >
> > I think it's sketchy to think of logical and allocation as anything more than
> > "concepts".
> >
> > On a user interface level yes. logical tags come from pointers, that's the nice
> > way of summarising them. And you can have common code to show them in
> > common ways.
> >
> > Server side though the allocation tags for MTE and the allocation
> > tags for <future aarch64 tagging> could/will have different interfaces
> > to read them.
> > (even if it is just a ptrace enum)
> > So the protocol needs to know the difference. (within the same architecture)
> >
> > See below...
> >
> >> For AArch64, these numbers would mean the following:
> >>
> >> 0 - MTE logical
> >> 1 - MTE allocation
> >> 2 - Capability
> >>
> >> For SPARC ADI, the following:
> >>
> >> 0 - ADI logical
> >> 1 - ADI allocation
> >> 2 - Unknown/Invalid
> >
> > My concern is what happens when <future aarch64 tagging> comes in. Assume that:
> > * it also has tags referred to as logical and allocation
> > * it can be present alongside MTE in the same process/debug target
> > * the interface to read the allocation tags is different (aka it's a
> > different code path)
> >
> > If you say well, <future aarch64 tagging> allocation tag is an
> > allocation tag like any other,
> > then the server gets "hey read me an allocation tag". But for what?
> > MTE or <future aarch64 tagging>?
> >
> > If you add these new <future aarch64 tagging> tags as new enum values like:
> > 0 - MTE logical
> > 1 - MTE allocation
> > 2 - Capability
> > 3 - <future aarch64 tagging> logical
> > 4 - <future aarch64 tagging> allocation
> >
> > Then the server gets "hey read me a <future aarch64 tagging> allocation tag".
> >
>
> This has been my plan so far. The fact we're adding generic
> logical/allocation tag types right now is to accommodate ADI, which uses
> similar technology.
>
> A new <future> technology will have to use a different identifiers in
> the enum definition. I'm not planning on overloading tag types with more
> than one meaning per-architecture.
>
> That is, tag_logical will always be MTE logical for AArch64.
>
> > There's an argument to be made that this isn't a real problem and
> > might never happen,
> > and if it did you could add some kind of priming packet. "I'm going to
> > read MTE", "read me an allocation tag".
> > qMemTagsEX, whatever.
> >
> > I just think you could avoid that right now by encoding the type in
> > the way I suggested.
>
> I think we have the same model in mind, but somehow it has not been made
> clear.
>
> > (again, in the protocol, clients can map it however they want to reuse code)
> >
> > I'll try to summarise where I'm at:
> >
> > Grouping similar tag kinds (as in 0 = logical for SPARC ADI and 0 =
> > logical for MTE also) doesn't bother me.
> > We've got plenty of ints to go around and yes it does help the client
> > share some code.
> >
> > As long as, within the same architecture (aarch64 here), the server
> > can tell MTE from <future aarch64 tagging>.
>
> Right. This is what I had in mind.
>
> > If we document the intent of the "type" field in the protocol I think
> > that fixes this, since the use case is academic at this point.
> > I suggest something like:
> > "This type value is per architecture and each value encodes the
> > architecture specific tagging technology used (e.g MTE) and the tag
> > kind (e.g. logical or allocation)."
> > <followed by a table for aarch64>
> >
> > If it makes sense to say "Architectures that want to add memory
> > tagging support may choose to overlap with existing values from other
> > architectures to reuse existing commands..." then great.
> > We've made the intent clear.
> >
> > This leaves the door open for SPARC ADI to do as you suggested and
> > overlap their logical/allocation with aarch64 mte and reuse the
> > existing code.
> > But it also confirms that <future aarch64 tagging> will get new type
> > values regardless of whether it has things called logical/allocation
> > tags.
> > So that servers can tell them apart.
> >
> > This means your code in these patches doesn't need to change at all.
> > Right now we have the convenience of lining up the logical/allocation
> > kinds and if that
> > changes in future then the clients can change. (for example we add a
> > mapping from aarch64 tag types back to the smaller generic list of tag
> > types)
> >
> > Which is a lot of words to ask for a small docs addition, but
> > hopefully my hypothetical use case is clear?
>
> I think we've reached the important part here. Do you want
> clarification, through documentation, that we're going to stick with
> unique tag type identifiers per-architecture?
>
> I was slightly confused because unique identifiers per-architecture were
> my goal from the start, but somehow we got lost in discussing some of
> these tag type ambiguity cases.
>
> >
> > On Tue, 17 Nov 2020 at 17:29, Luis Machado <luis.machado@linaro.org> wrote:
> >>
> >> On 11/17/20 12:16 PM, David Spickett wrote:
> >>>> Right now you can infer the technology and logical/allocation from the
> >>>> type. There is no need for a two step process. I don't anticipate a need
> >>>> for that in the future either, as long as we prevent the tag type ENUM
> >>>> from having overlapping values.
> >>>
> >>> Right, so to not overlap, a value of that tag type ENUM must be a
> >>> combination of technology and tag...kind. (words are hard)
> >>> E.g. MTE logical tag, <future tech> allocation tag , <other tech> strange tag
> >>
> >> Why? It only needs to be a unique value that represents a unique
> >> combination. See below.
> >>
> >>>
> >>> So if <future AArch64 tag technology> were to also have "logical" and
> >>> "allocation" tags, they would be new type values, yes?
> >>> 0 = MTE logical
> >>> 1 = MTE allocation
> >>> 2 = <future AArch64 tag technology> logical
> >>> 3 = <future AArch64 tag technology> allocation
> >>>
> >>> Because if they are still 0 and 1, they overlap and you can't tell MTE
> >>> and <future AArch64 tag technology> apart.
> >>
> >> I think there is some confusion here. Let me try to clarify.
> >>
> >> Yes, we currently only have tag types 0 and 1 (AArch64's MTE and SPARC
> >> ADI technologies, logical/allocation kind). If we add more tag
> >> technologies, we will also add new code/commands that will pass the
> >> appropriate tag types down to the target/remote layer.
> >>
> >> For example, if we end up supporting capability tags as a new type of
> >> tag (say, type 2, given we already have 0 and 1) , we will have to
> >> modify the code to handle that. It will be either a new command or new
> >> code to handle it.
> >>
> >> The target/remote layer will only see unique numbers 0, 1 and 2.
> >>
> >> For AArch64, these numbers would mean the following:
> >>
> >> 0 - MTE logical
> >> 1 - MTE allocation
> >> 2 - Capability
> >>
> >> For SPARC ADI, the following:
> >>
> >> 0 - ADI logical
> >> 1 - ADI allocation
> >> 2 - Unknown/Invalid
> >>
> >>>
> >>> I get that at the user interface layer you have some mapping back to a
> >>> set of generic types, talking just about the
> >>> packet contents.
> >>>
> >>>> So this is wrong, as the remote/native side won't be able to tell both
> >>>> definitions of type "1" apart.
> >>>
> >>> Sorry that was a typo. Should be:
> >>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> >>> allocation, 3 = future tag form (not logical/allocation) etc...
> >>> (basically what I restated above)
> >>
> >> I think the typo is still there.
> >>
> >> You meant 0,1,2 3 and 4, right?
> >>
> >> But I see what you mean. Even though the tag type name is "tag_logical"
> >> right now, the implementation choice is to interpret that as MTE for
> >> AArch64 and ADI for SPARC. Same thing for "tag_allocation".
> >>
> >> The rationale for having these two generic tag types ("tag_logical" and
> >> "tag_allocation") is that this technology may be common to multiple
> >> architectures (AArch64 and SPARC right now).
> >>
> >> Personally, I don't think having 4 type enums (mte_logical,
> >> mte_allocation, adi_logical and adi_allocation) would be better. That
> >> would require extra code for a similar technology. So, just to pass
> >> down, say, mte_logical instead of adi_logical, when those are in fact
> >> the same kind of tag/technology.
> >>
> >> Does that make sense?
> >>
> >>>
> >>>> If we want to address this and make it a bit more flexible, then we will
> >>>> need to let architectures define their own tag type values. Then generic
> >>>> code will have to go through an arch-specific hook to fetch the tag type.
> >>>
> >>>> Would that address your concerns?
> >>>
> >>> I think so. I thought of this working like the breakpoint types I
> >>> referenced. Breakpoint type 1 for MIPS isn't in any way the same as
> >>> type 1 for Arm etc.
> >>> (ok they might be similar but the docs make it clear that the list of
> >>> types is per architecture)
> >>>
> >>
> >> I think the situation is similar here. I opted to group similar things
> >> together in the type names.
> >>
> >> mte_allocation is similar to adi_allocation, but they're different in
> >> that mte_allocation has granule size 16, while adi_allocation has
> >> granule size 64.
> >>
> >> mte_logical is exactly the same as adi_logical. They are both 4 bits in
> >> size.
> >>
> >>>> As long as GDB sends a unique tag type identifier (non-overlapping
> >>>> values), we will be able to tell them apart from the remote side.
> >>>
> >>> Yes but depending on how those IDs are allocated we may only be able
> >>> to tell logical vs allocation not MTE vs CHERI vs <future whatever>.
> >>>
> >>> On Tue, 17 Nov 2020 at 14:44, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>
> >>>> On 11/17/20 9:29 AM, David Spickett wrote:
> >>>>>> Right. The type is really telling you what specific kind of tag you are
> >>>>>> requesting, not the technology. So it may be perfectly valid to request
> >>>>>> a MTE logical tag from the remote target, but the remote target doesn't
> >>>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>>>>>
> >>>>>> The tag types don't overlap at the moment, given they are an ENUM in
> >>>>>> generic code. So the server will tell them apart by their values.
> >>>>>
> >>>>> Ok but my concern here is that there are two aspects to type. (which I
> >>>>> probably confused earlier tbf)
> >>>>>
> >>>>> 1. logical vs allocation
> >>>>> 2. MTE vs <future tagging technology>
> >>>>>
> >>>>> So we have three scenarios:
> >>>>> 1. Server uses type to decide between logical and allocation
> >>>>
> >>>> Right now 0 maps to logical and 1 maps to allocation for all
> >>>> architectures. For AArch64 0 maps to MTE logical and 1 maps to MTE
> >>>> allocation.
> >>>>
> >>>> But, if more tag types are supported in the future, we will need to map
> >>>> types to logical, allocation or something else.
> >>>>
> >>>>> 2. Server uses type to decide between MTE and <future tagging technology>
> >>>>
> >>>> Right now 0 and 1 map to MTE for AArch64 and ADI for SPARC (not yet
> >>>> supported). In the future, if there are more tagging technologies, we
> >>>> will need to provide a mapping from tag types to tag technology.
> >>>>
> >>>>> 3. The combination of the two, should a system have both technologies
> >>>>
> >>>> In this case, we will use two mappings: type to tag type and type to tag
> >>>> technology.
> >>>>
> >>>>>
> >>>>> What I want to avoid is a two step process:
> >>>>> 1. Somehow select tagging technology you want to interact with
> >>>>> 2. You send memtag packets with the logical vs allocation "type"
> >>>>>
> >>>>> Which would be needed if the protocol "type" is just allocation vs
> >>>>> logical. If the "type" includes the technology
> >>>>> then we can do it in one step.
> >>>>
> >>>> Right now you can infer the technology and logical/allocation from the
> >>>> type. There is no need for a two step process. I don't anticipate a need
> >>>> for that in the future either, as long as we prevent the tag type ENUM
> >>>> from having overlapping values.
> >>>>
> >>>>>
> >>>>> So I prefer:
> >>>>> 0 = mte logical, 1 = mte allocation, 1 = future logical, 2 = future
> >>>>> allocation, 3 = future tag form (not logical/allocation) etc...
> >>>>
> >>>> So this is wrong, as the remote/native side won't be able to tell both
> >>>> definitions of type "1" apart.
> >>>>
> >>>>> Over:
> >>>>> 0 = logical, 1 = allocation, 2 = future term for other tag form etc...
> >>>>
> >>>> This is correct in my view. Everything is unique.
> >>>>
> >>>> The complicating factor here is that generic code/UI needs to use a
> >>>> generic tag type so all architectures supporting memory tagging can use
> >>>> the commands out of the box.
> >>>>
> >>>> For AArch64, tag_logical/tag_allocation means MTE logical/MTE
> >>>> allocation. For SPARC ADI, this means whatever their tagging mechanism is.
> >>>>
> >>>> If we turn tag_logical into mte_logical, SPARC ADI won't be able to use
> >>>> that. We will, again, need a mapping.
> >>>>
> >>>> If we want to address this and make it a bit more flexible, then we will
> >>>> need to let architectures define their own tag type values. Then generic
> >>>> code will have to go through an arch-specific hook to fetch the tag type.
> >>>>
> >>>> Would that address your concerns?
> >>>>
> >>>>>
> >>>>> I see the need for the second form in gdb internally, but my concern
> >>>>> is only with the protocol side.
> >>>>
> >>>> As long as GDB sends a unique tag type identifier (non-overlapping
> >>>> values), we will be able to tell them apart from the remote side.
> >>>>
> >>>>>
> >>>>>> I just want to keep that option open
> >>>>>> if someone wants to do it, or if some other type of tag shows up that
> >>>>>> would require such support.
> >>>>>
> >>>>> I hadn't thought of that. I agree that type should include that too.
> >>>>>
> >>>>> On Tue, 17 Nov 2020 at 12:01, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>>>
> >>>>>> Hi,
> >>>>>>
> >>>>>> On 11/17/20 7:05 AM, David Spickett wrote:
> >>>>>>>> Right now the design makes these types architecture-specific.
> >>>>>>>
> >>>>>>> This works too, in fact it matches the breakpoint types example better that way.
> >>>>>>>
> >>>>>>>> But there's one catch right now. The user-visible commands know about
> >>>>>>>> two types of tags (logical and allocation). The native/remote side of
> >>>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>>>>>> ask the native/remote target about logical tags.
> >>>>>>>>
> >>>>>>>> This is slightly messy and, in my opinion, should be an implementation
> >>>>>>>> detail.
> >>>>>>>
> >>>>>>> Tell me if I have this right.
> >>>>>>>
> >>>>>>> In gdb in overall you have these two types but the server only uses
> >>>>>>> one of them, the allocation tag type.
> >>>>>>> So only the allocation tag type will ever go over the protocol. (for
> >>>>>>> MTE at least)
> >>>>>>
> >>>>>> That's correct. Only GDB knows about logical tags. Those don't make
> >>>>>> their way to the remote via the remote protocol.
> >>>>>>
> >>>>>>>
> >>>>>>> Given that, if we assume that "mte allocation" type is 1. A future
> >>>>>>> AArch64 kind of memory tagging could allocate 2 and on for its tag
> >>>>>>> types.
> >>>>>>> Something like:
> >>>>>>> AArch64 Memory Tag types -
> >>>>>>>       0 : MTE logical (which is internal only, reserved but documented as
> >>>>>>> unused, or left out completely?)
> >>>>>>>       1 : MTE allocation (the one we use at present)
> >>>>>>>       2: <future tagging> logical tag (because maybe there is some server
> >>>>>>> component for this kind of tagging extension?)
> >>>>>>>       3: <future tagging> allocation tag
> >>>>>>>
> >>>>>>> The reason I want to clarify is that I understood the type to
> >>>>>>> differentiate tagging technologies, not the kind of tag within them.
> >>>>>>> (the type tells you MTE vs <future tag type> instead of allocation vs logical)
> >>>>>>> The use case being what if you have MTE and <future tag type> active
> >>>>>>> in the same target and I want to set an MTE allocation tag,
> >>>>>>> how can the server tell them apart?
> >>>>>>
> >>>>>> Right. The type is really telling you what specific kind of tag you are
> >>>>>> requesting, not the technology. So it may be perfectly valid to request
> >>>>>> a MTE logical tag from the remote target, but the remote target doesn't
> >>>>>> know how to reply to that at the moment (nor does it make much sense, IMO).
> >>>>>>
> >>>>>> The tag types don't overlap at the moment, given they are an ENUM in
> >>>>>> generic code. So the server will tell them apart by their values.
> >>>>>>
> >>>>>>>
> >>>>>>> If the type numbers overlap between tagging technologies, we can't
> >>>>>>> tell them apart.
> >>>>>>> However if they encode what extension they are for and the
> >>>>>>> logical/allocation type (as in the example above) then we can.
> >>>>>>>
> >>>>>>> A lot of that is probably academic given there's one relevant type but
> >>>>>>> we can at least document the intent of the field.
> >>>>>>> E.g. "these types are global to AArch64 so new types should not
> >>>>>>> overlap existing ones"
> >>>>>>
> >>>>>> I suppose. I chose to have generic ENUM's without specific references to
> >>>>>> MTE for that reason. Architectures can use logical/allocation tags as
> >>>>>> they see fit, but the ENUM values will not overlap.
> >>>>>>
> >>>>>> We need to support the UI as well, so there needs to be some generic
> >>>>>> definitions so commands can query different tag types.
> >>>>>>
> >>>>>>>
> >>>>>>>> Otherwise we'd need to standardize on particular tag type names across
> >>>>>>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>>>>>> "capability tag" etc.
> >>>>>>>
> >>>>>>> Well I was thinking of type more as a single value like "mte". Anyway
> >>>>>>> I'm fine with the integer route.
> >>>>>>
> >>>>>> Though we don't have a use for requesting logical tags from the remote
> >>>>>> targets, it is possible to support that. Passing "mte" or any other
> >>>>>> technology name would close that option.
> >>>>>>
> >>>>>> If, for example, we decide to have a dumb GDB client and a smart
> >>>>>> GDBserver (unlikely at this point), then it would make sense to pass
> >>>>>> down logical tag requests I think. I just want to keep that option open
> >>>>>> if someone wants to do it, or if some other type of tag shows up that
> >>>>>> would require such support.
> >>>>>>
> >>>>>>>
> >>>>>>> On Mon, 16 Nov 2020 at 17:23, Luis Machado <luis.machado@linaro.org> wrote:
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> On 11/16/20 1:04 PM, David Spickett wrote:
> >>>>>>>>> Also with regard to the "type" field.
> >>>>>>>>>
> >>>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>>>>>> +integer.
> >>>>>>>>>
> >>>>>>>>> (typo aside) Is this field architecture specific and will there be a
> >>>>>>>>> list of these type numbers documented anywhere? (or already is)
> >>>>>>>>> For example would 1 on AArch64 be MTE, and on <other arch> be <other
> >>>>>>>>> tag type>. Or would that <other tag type> be 2.
> >>>>>>>>>
> >>>>>>>>> My assumption has been that it is the latter and that a value means a
> >>>>>>>>> kind of tagging extension. So for example 1=MTE rather than
> >>>>>>>>> 1= mte logical and 2 = mte allocation. Correct me if I am wrong there.
> >>>>>>>>
> >>>>>>>> Right now the design makes these types architecture-specific. It would
> >>>>>>>> be nice to have more documentation about them, for sure.
> >>>>>>>>
> >>>>>>>> But there's one catch right now. The user-visible commands know about
> >>>>>>>> two types of tags (logical and allocation). The native/remote side of
> >>>>>>>> GDB only sees one type, the allocation one, as it doesn't make sense to
> >>>>>>>> ask the native/remote target about logical tags.
> >>>>>>>>
> >>>>>>>> This is slightly messy and, in my opinion, should be an implementation
> >>>>>>>> detail.
> >>>>>>>>
> >>>>>>>> So, in summary... We have a couple generic tag types GDB knows about:
> >>>>>>>> logical and allocation.
> >>>>>>>>
> >>>>>>>> Those types get translated to an arch/a target-specific type when they
> >>>>>>>> cross the native/remote target boundary.
> >>>>>>>>
> >>>>>>>> In theory we could have generic tag types 1 and 2 in generic code, but
> >>>>>>>> tag type 2 gets translated to type 1 in a remote packet.
> >>>>>>>>
> >>>>>>>> Maybe we could improve this a little.
> >>>>>>>>
> >>>>>>>>>
> >>>>>>>>> A page like:
> >>>>>>>>> https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Breakpoint-Kinds.html#ARM-Breakpoint-Kinds
> >>>>>>>>>
> >>>>>>>>> Or just a short note, given that there's only one type right now.
> >>>>>>>>
> >>>>>>>> Yes, that would be nice to expand for the tag types.
> >>>>>>>>
> >>>>>>>>>
> >>>>>>>>> Also, I may have suggested the type be a string at some point. However
> >>>>>>>>> based on examples like the link above
> >>>>>>>>> I don't see much advantage to it apart from making packet dumps easier
> >>>>>>>>> to read. Just wanted to close the loop on that
> >>>>>>>>> if I didn't before.
> >>>>>>>>
> >>>>>>>> I don't have a strong preference here. I'm just forwarding the tag type
> >>>>>>>> from generic code.
> >>>>>>>>
> >>>>>>>> If we want to pass strings, we will need a gdbarch hook that maps a type
> >>>>>>>> to a string in the remote target layer.
> >>>>>>>>
> >>>>>>>> Otherwise we'd need to standardize on particular tag type names across
> >>>>>>>> different architectures, like "hw memory tag", "sw memory tag",
> >>>>>>>> "capability tag" etc.
> >>>>>>>>
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> On Mon, 16 Nov 2020 at 15:44, David Spickett <david.spickett@linaro.org> wrote:
> >>>>>>>>>>
> >>>>>>>>>> Minor thing, there is a missing space here in "typeis".
> >>>>>>>>>>
> >>>>>>>>>>> +@var{type} is the type of tag the request wants to fetch.  The typeis a signed
> >>>>>>>>>>> +integer.
> >>>>>>>>>>
> >>>>>>>>>> On Mon, 9 Nov 2020 at 17:08, Eli Zaretskii <eliz@gnu.org> wrote:
> >>>>>>>>>>>
> >>>>>>>>>>>> Date: Mon,  9 Nov 2020 14:04:18 -0300
> >>>>>>>>>>>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> >>>>>>>>>>>> Cc: david.spickett@linaro.org
> >>>>>>>>>>>>
> >>>>>>>>>>>> gdb/doc/ChangeLog:
> >>>>>>>>>>>>
> >>>>>>>>>>>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> >>>>>>>>>>>>
> >>>>>>>>>>>>            * gdb.texinfo (General Query Packets): Document qMemTags and
> >>>>>>>>>>>>            QMemTags.  Document the "memory-tagging" feature.
> >>>>>>>>>>>> ---
> >>>>>>>>>>>>       gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++
> >>>>>>>>>>>>       1 file changed, 96 insertions(+)
> >>>>>>>>>>>
> >>>>>>>>>>> OK for this part, thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-11-16 13:48 ` [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  2020-11-16 14:37   ` Alan Hayward
@ 2020-11-23 16:08   ` Luis Machado
  2020-11-30 13:38     ` Luis Machado
  1 sibling, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-23 16:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Ping v2?

On 11/16/20 10:48 AM, Luis Machado wrote:
> Ping?
> 
> FTR, I'm aiming at having this ready for GDB 11.
> 
> On 11/9/20 2:04 PM, Luis Machado wrote:
>> Here's v3 of this patch series.
>>
>> Memory tagging improves memory safety by tagging various parts of 
>> memory and
>> raising exceptions when the allocation tag (the one associated with a 
>> range of
>> memory addresses) does not match the logical tag contained in a 
>> pointer that is
>> used to access the memory area.
>>
>> We already have an implementation of such a mechanism for sparc64 
>> (ADI), but
>> it is target-specific and not exposed to the rest of GDB. This series 
>> aims to
>> make the infrastructure available to other targets that may wish to 
>> support
>> their specific memory tagging approaches. For AArch64 Linux this is 
>> called
>> MTE (Memory Tagging Extensions).
>>
>> The series is split into a set that deals with generic changes to GDB's
>> infrastructure (target methods, gdbarch hooks and remote packets), a 
>> set that
>> implements support for AArch64 Linux and one last set that implements new
>> commands, updates the documentation and adds tests.
>>
>> The goal is to make it so the architecture independent parts of GDB don't
>> need to interpret tag formats, given the formats are likely different
>> for each architecture.  For this reason, GDB will handle tags as a 
>> sequence of
>> bytes and will not assume a particular format.
>>
>> The architecture-specific code can handle the sequence of bytes 
>> appropriately.
>>
>> Luis Machado (24):
>>    New target methods for memory tagging support
>>    New gdbarch memory tagging hooks
>>    Add GDB-side remote target support for memory tagging
>>    Unit testing for GDB-side remote memory tagging handling
>>    GDBserver remote packet support for memory tagging
>>    Unit tests for gdbserver memory tagging remote packets
>>    Documentation for memory tagging remote packets
>>    AArch64: Add MTE CPU feature check support
>>    AArch64: Add target description/feature for MTE registers
>>    AArch64: Add MTE register set support for GDB and gdbserver
>>    AArch64: Add MTE ptrace requests
>>    AArch64: Implement memory tagging target methods for AArch64
>>    Refactor parsing of /proc/<pid>/smaps
>>    AArch64: Implement the memory tagging gdbarch hooks
>>    AArch64: Add unit testing for logical tag set/get operations
>>    AArch64: Report tag violation error information
>>    AArch64: Add gdbserver MTE support
>>    AArch64: Add MTE register set support for core files
>>    New mtag commands
>>    Documentation for the new mtag commands
>>    Extend "x" and "print" commands to support memory tagging
>>    Document new "x" and "print" memory tagging extensions
>>    Add NEWS entry.
>>    Add memory tagging testcases
>>
>>   gdb/Makefile.in                        |   3 +
>>   gdb/NEWS                               |  32 ++
>>   gdb/aarch64-linux-nat.c                | 129 ++++++-
>>   gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>>   gdb/aarch64-linux-tdep.h               |   3 +
>>   gdb/aarch64-tdep.c                     |  40 ++-
>>   gdb/aarch64-tdep.h                     |  12 +-
>>   gdb/arch-utils.c                       |  50 +++
>>   gdb/arch-utils.h                       |  23 ++
>>   gdb/arch/aarch64-mte-linux.c           |  70 ++++
>>   gdb/arch/aarch64-mte-linux.h           |  66 ++++
>>   gdb/arch/aarch64.c                     |   7 +-
>>   gdb/arch/aarch64.h                     |   7 +-
>>   gdb/configure.nat                      |   3 +-
>>   gdb/configure.tgt                      |   1 +
>>   gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>>   gdb/features/Makefile                  |   1 +
>>   gdb/features/aarch64-mte.c             |  14 +
>>   gdb/features/aarch64-mte.xml           |  11 +
>>   gdb/gdbarch.c                          | 137 ++++++++
>>   gdb/gdbarch.h                          |  53 +++
>>   gdb/gdbarch.sh                         |  36 ++
>>   gdb/linux-tdep.c                       | 358 ++++++++++++-------
>>   gdb/linux-tdep.h                       |   4 +
>>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>>   gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
>>   gdb/remote.c                           | 232 ++++++++++++
>>   gdb/target-delegates.c                 |  84 +++++
>>   gdb/target.h                           |  37 ++
>>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>   gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>>   gdb/testsuite/lib/gdb.exp              |  16 +
>>   gdb/valprint.h                         |   1 +
>>   gdbserver/Makefile.in                  |   1 +
>>   gdbserver/configure.srv                |   2 +
>>   gdbserver/linux-aarch64-ipa.cc         |   8 +-
>>   gdbserver/linux-aarch64-low.cc         |  97 ++++-
>>   gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>>   gdbserver/linux-aarch64-tdesc.h        |   3 +-
>>   gdbserver/remote-utils.cc              |  43 ++-
>>   gdbserver/remote-utils.h               |   7 +-
>>   gdbserver/server.cc                    | 245 +++++++++++++
>>   gdbserver/server.h                     |   3 +
>>   gdbserver/target.cc                    |  20 ++
>>   gdbserver/target.h                     |  17 +
>>   gdbsupport/rsp-low.cc                  |   2 +-
>>   include/elf/common.h                   |   3 +
>>   50 files changed, 3536 insertions(+), 186 deletions(-)
>>   create mode 100644 gdb/arch/aarch64-mte-linux.c
>>   create mode 100644 gdb/arch/aarch64-mte-linux.h
>>   create mode 100644 gdb/features/aarch64-mte.c
>>   create mode 100644 gdb/features/aarch64-mte.xml
>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-11-23 16:08   ` Luis Machado
@ 2020-11-30 13:38     ` Luis Machado
  2020-12-07 13:17       ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-11-30 13:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Ping v3. Is there any other feedback on this series or should I take it 
that the current version looks good (with the suggested fixes)?

Thanks,
Luis

On 11/23/20 1:08 PM, Luis Machado wrote:
> Ping v2?
> 
> On 11/16/20 10:48 AM, Luis Machado wrote:
>> Ping?
>>
>> FTR, I'm aiming at having this ready for GDB 11.
>>
>> On 11/9/20 2:04 PM, Luis Machado wrote:
>>> Here's v3 of this patch series.
>>>
>>> Memory tagging improves memory safety by tagging various parts of 
>>> memory and
>>> raising exceptions when the allocation tag (the one associated with a 
>>> range of
>>> memory addresses) does not match the logical tag contained in a 
>>> pointer that is
>>> used to access the memory area.
>>>
>>> We already have an implementation of such a mechanism for sparc64 
>>> (ADI), but
>>> it is target-specific and not exposed to the rest of GDB. This series 
>>> aims to
>>> make the infrastructure available to other targets that may wish to 
>>> support
>>> their specific memory tagging approaches. For AArch64 Linux this is 
>>> called
>>> MTE (Memory Tagging Extensions).
>>>
>>> The series is split into a set that deals with generic changes to GDB's
>>> infrastructure (target methods, gdbarch hooks and remote packets), a 
>>> set that
>>> implements support for AArch64 Linux and one last set that implements 
>>> new
>>> commands, updates the documentation and adds tests.
>>>
>>> The goal is to make it so the architecture independent parts of GDB 
>>> don't
>>> need to interpret tag formats, given the formats are likely different
>>> for each architecture.  For this reason, GDB will handle tags as a 
>>> sequence of
>>> bytes and will not assume a particular format.
>>>
>>> The architecture-specific code can handle the sequence of bytes 
>>> appropriately.
>>>
>>> Luis Machado (24):
>>>    New target methods for memory tagging support
>>>    New gdbarch memory tagging hooks
>>>    Add GDB-side remote target support for memory tagging
>>>    Unit testing for GDB-side remote memory tagging handling
>>>    GDBserver remote packet support for memory tagging
>>>    Unit tests for gdbserver memory tagging remote packets
>>>    Documentation for memory tagging remote packets
>>>    AArch64: Add MTE CPU feature check support
>>>    AArch64: Add target description/feature for MTE registers
>>>    AArch64: Add MTE register set support for GDB and gdbserver
>>>    AArch64: Add MTE ptrace requests
>>>    AArch64: Implement memory tagging target methods for AArch64
>>>    Refactor parsing of /proc/<pid>/smaps
>>>    AArch64: Implement the memory tagging gdbarch hooks
>>>    AArch64: Add unit testing for logical tag set/get operations
>>>    AArch64: Report tag violation error information
>>>    AArch64: Add gdbserver MTE support
>>>    AArch64: Add MTE register set support for core files
>>>    New mtag commands
>>>    Documentation for the new mtag commands
>>>    Extend "x" and "print" commands to support memory tagging
>>>    Document new "x" and "print" memory tagging extensions
>>>    Add NEWS entry.
>>>    Add memory tagging testcases
>>>
>>>   gdb/Makefile.in                        |   3 +
>>>   gdb/NEWS                               |  32 ++
>>>   gdb/aarch64-linux-nat.c                | 129 ++++++-
>>>   gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>>>   gdb/aarch64-linux-tdep.h               |   3 +
>>>   gdb/aarch64-tdep.c                     |  40 ++-
>>>   gdb/aarch64-tdep.h                     |  12 +-
>>>   gdb/arch-utils.c                       |  50 +++
>>>   gdb/arch-utils.h                       |  23 ++
>>>   gdb/arch/aarch64-mte-linux.c           |  70 ++++
>>>   gdb/arch/aarch64-mte-linux.h           |  66 ++++
>>>   gdb/arch/aarch64.c                     |   7 +-
>>>   gdb/arch/aarch64.h                     |   7 +-
>>>   gdb/configure.nat                      |   3 +-
>>>   gdb/configure.tgt                      |   1 +
>>>   gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>>>   gdb/features/Makefile                  |   1 +
>>>   gdb/features/aarch64-mte.c             |  14 +
>>>   gdb/features/aarch64-mte.xml           |  11 +
>>>   gdb/gdbarch.c                          | 137 ++++++++
>>>   gdb/gdbarch.h                          |  53 +++
>>>   gdb/gdbarch.sh                         |  36 ++
>>>   gdb/linux-tdep.c                       | 358 ++++++++++++-------
>>>   gdb/linux-tdep.h                       |   4 +
>>>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>>>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>>>   gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
>>>   gdb/remote.c                           | 232 ++++++++++++
>>>   gdb/target-delegates.c                 |  84 +++++
>>>   gdb/target.h                           |  37 ++
>>>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>>>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>>>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>>   gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>>>   gdb/testsuite/lib/gdb.exp              |  16 +
>>>   gdb/valprint.h                         |   1 +
>>>   gdbserver/Makefile.in                  |   1 +
>>>   gdbserver/configure.srv                |   2 +
>>>   gdbserver/linux-aarch64-ipa.cc         |   8 +-
>>>   gdbserver/linux-aarch64-low.cc         |  97 ++++-
>>>   gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>>>   gdbserver/linux-aarch64-tdesc.h        |   3 +-
>>>   gdbserver/remote-utils.cc              |  43 ++-
>>>   gdbserver/remote-utils.h               |   7 +-
>>>   gdbserver/server.cc                    | 245 +++++++++++++
>>>   gdbserver/server.h                     |   3 +
>>>   gdbserver/target.cc                    |  20 ++
>>>   gdbserver/target.h                     |  17 +
>>>   gdbsupport/rsp-low.cc                  |   2 +-
>>>   include/elf/common.h                   |   3 +
>>>   50 files changed, 3536 insertions(+), 186 deletions(-)
>>>   create mode 100644 gdb/arch/aarch64-mte-linux.c
>>>   create mode 100644 gdb/arch/aarch64-mte-linux.h
>>>   create mode 100644 gdb/features/aarch64-mte.c
>>>   create mode 100644 gdb/features/aarch64-mte.xml
>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-11-30 13:38     ` Luis Machado
@ 2020-12-07 13:17       ` Luis Machado
  2020-12-07 14:17         ` Alan Hayward
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-12-07 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: alan.hayward, jhb, david.spickett

Ping v4.

On 11/30/20 10:38 AM, Luis Machado wrote:
> Ping v3. Is there any other feedback on this series or should I take it 
> that the current version looks good (with the suggested fixes)?
> 
> Thanks,
> Luis
> 
> On 11/23/20 1:08 PM, Luis Machado wrote:
>> Ping v2?
>>
>> On 11/16/20 10:48 AM, Luis Machado wrote:
>>> Ping?
>>>
>>> FTR, I'm aiming at having this ready for GDB 11.
>>>
>>> On 11/9/20 2:04 PM, Luis Machado wrote:
>>>> Here's v3 of this patch series.
>>>>
>>>> Memory tagging improves memory safety by tagging various parts of 
>>>> memory and
>>>> raising exceptions when the allocation tag (the one associated with 
>>>> a range of
>>>> memory addresses) does not match the logical tag contained in a 
>>>> pointer that is
>>>> used to access the memory area.
>>>>
>>>> We already have an implementation of such a mechanism for sparc64 
>>>> (ADI), but
>>>> it is target-specific and not exposed to the rest of GDB. This 
>>>> series aims to
>>>> make the infrastructure available to other targets that may wish to 
>>>> support
>>>> their specific memory tagging approaches. For AArch64 Linux this is 
>>>> called
>>>> MTE (Memory Tagging Extensions).
>>>>
>>>> The series is split into a set that deals with generic changes to GDB's
>>>> infrastructure (target methods, gdbarch hooks and remote packets), a 
>>>> set that
>>>> implements support for AArch64 Linux and one last set that 
>>>> implements new
>>>> commands, updates the documentation and adds tests.
>>>>
>>>> The goal is to make it so the architecture independent parts of GDB 
>>>> don't
>>>> need to interpret tag formats, given the formats are likely different
>>>> for each architecture.  For this reason, GDB will handle tags as a 
>>>> sequence of
>>>> bytes and will not assume a particular format.
>>>>
>>>> The architecture-specific code can handle the sequence of bytes 
>>>> appropriately.
>>>>
>>>> Luis Machado (24):
>>>>    New target methods for memory tagging support
>>>>    New gdbarch memory tagging hooks
>>>>    Add GDB-side remote target support for memory tagging
>>>>    Unit testing for GDB-side remote memory tagging handling
>>>>    GDBserver remote packet support for memory tagging
>>>>    Unit tests for gdbserver memory tagging remote packets
>>>>    Documentation for memory tagging remote packets
>>>>    AArch64: Add MTE CPU feature check support
>>>>    AArch64: Add target description/feature for MTE registers
>>>>    AArch64: Add MTE register set support for GDB and gdbserver
>>>>    AArch64: Add MTE ptrace requests
>>>>    AArch64: Implement memory tagging target methods for AArch64
>>>>    Refactor parsing of /proc/<pid>/smaps
>>>>    AArch64: Implement the memory tagging gdbarch hooks
>>>>    AArch64: Add unit testing for logical tag set/get operations
>>>>    AArch64: Report tag violation error information
>>>>    AArch64: Add gdbserver MTE support
>>>>    AArch64: Add MTE register set support for core files
>>>>    New mtag commands
>>>>    Documentation for the new mtag commands
>>>>    Extend "x" and "print" commands to support memory tagging
>>>>    Document new "x" and "print" memory tagging extensions
>>>>    Add NEWS entry.
>>>>    Add memory tagging testcases
>>>>
>>>>   gdb/Makefile.in                        |   3 +
>>>>   gdb/NEWS                               |  32 ++
>>>>   gdb/aarch64-linux-nat.c                | 129 ++++++-
>>>>   gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>>>>   gdb/aarch64-linux-tdep.h               |   3 +
>>>>   gdb/aarch64-tdep.c                     |  40 ++-
>>>>   gdb/aarch64-tdep.h                     |  12 +-
>>>>   gdb/arch-utils.c                       |  50 +++
>>>>   gdb/arch-utils.h                       |  23 ++
>>>>   gdb/arch/aarch64-mte-linux.c           |  70 ++++
>>>>   gdb/arch/aarch64-mte-linux.h           |  66 ++++
>>>>   gdb/arch/aarch64.c                     |   7 +-
>>>>   gdb/arch/aarch64.h                     |   7 +-
>>>>   gdb/configure.nat                      |   3 +-
>>>>   gdb/configure.tgt                      |   1 +
>>>>   gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>>>>   gdb/features/Makefile                  |   1 +
>>>>   gdb/features/aarch64-mte.c             |  14 +
>>>>   gdb/features/aarch64-mte.xml           |  11 +
>>>>   gdb/gdbarch.c                          | 137 ++++++++
>>>>   gdb/gdbarch.h                          |  53 +++
>>>>   gdb/gdbarch.sh                         |  36 ++
>>>>   gdb/linux-tdep.c                       | 358 ++++++++++++-------
>>>>   gdb/linux-tdep.h                       |   4 +
>>>>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>>>>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>>>>   gdb/printcmd.c                         | 468 
>>>> ++++++++++++++++++++++++-
>>>>   gdb/remote.c                           | 232 ++++++++++++
>>>>   gdb/target-delegates.c                 |  84 +++++
>>>>   gdb/target.h                           |  37 ++
>>>>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>>>>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>>>>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>>>   gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>>>>   gdb/testsuite/lib/gdb.exp              |  16 +
>>>>   gdb/valprint.h                         |   1 +
>>>>   gdbserver/Makefile.in                  |   1 +
>>>>   gdbserver/configure.srv                |   2 +
>>>>   gdbserver/linux-aarch64-ipa.cc         |   8 +-
>>>>   gdbserver/linux-aarch64-low.cc         |  97 ++++-
>>>>   gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>>>>   gdbserver/linux-aarch64-tdesc.h        |   3 +-
>>>>   gdbserver/remote-utils.cc              |  43 ++-
>>>>   gdbserver/remote-utils.h               |   7 +-
>>>>   gdbserver/server.cc                    | 245 +++++++++++++
>>>>   gdbserver/server.h                     |   3 +
>>>>   gdbserver/target.cc                    |  20 ++
>>>>   gdbserver/target.h                     |  17 +
>>>>   gdbsupport/rsp-low.cc                  |   2 +-
>>>>   include/elf/common.h                   |   3 +
>>>>   50 files changed, 3536 insertions(+), 186 deletions(-)
>>>>   create mode 100644 gdb/arch/aarch64-mte-linux.c
>>>>   create mode 100644 gdb/arch/aarch64-mte-linux.h
>>>>   create mode 100644 gdb/features/aarch64-mte.c
>>>>   create mode 100644 gdb/features/aarch64-mte.xml
>>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>>>>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation
  2020-12-07 13:17       ` Luis Machado
@ 2020-12-07 14:17         ` Alan Hayward
  0 siblings, 0 replies; 96+ messages in thread
From: Alan Hayward @ 2020-12-07 14:17 UTC (permalink / raw)
  To: Luis Machado
  Cc: gdb-patches\@sourceware.org, jhb@freebsd.org, david.spickett, nd

As mentioned previously, I’m happy with this series.
Approved for the AArch64 parts and the other parts look good to me.

It would be nice to get approval for this as it’ll be really crucial to have
available for when the hardware starts rolling out. I suspect memory tagging
is going cause to lots of bugs in the early days of it being used.


Alan.


> On 7 Dec 2020, at 13:17, Luis Machado <luis.machado@linaro.org> wrote:
> 
> Ping v4.
> 
> On 11/30/20 10:38 AM, Luis Machado wrote:
>> Ping v3. Is there any other feedback on this series or should I take it that the current version looks good (with the suggested fixes)?
>> Thanks,
>> Luis
>> On 11/23/20 1:08 PM, Luis Machado wrote:
>>> Ping v2?
>>> 
>>> On 11/16/20 10:48 AM, Luis Machado wrote:
>>>> Ping?
>>>> 
>>>> FTR, I'm aiming at having this ready for GDB 11.
>>>> 
>>>> On 11/9/20 2:04 PM, Luis Machado wrote:
>>>>> Here's v3 of this patch series.
>>>>> 
>>>>> Memory tagging improves memory safety by tagging various parts of memory and
>>>>> raising exceptions when the allocation tag (the one associated with a range of
>>>>> memory addresses) does not match the logical tag contained in a pointer that is
>>>>> used to access the memory area.
>>>>> 
>>>>> We already have an implementation of such a mechanism for sparc64 (ADI), but
>>>>> it is target-specific and not exposed to the rest of GDB. This series aims to
>>>>> make the infrastructure available to other targets that may wish to support
>>>>> their specific memory tagging approaches. For AArch64 Linux this is called
>>>>> MTE (Memory Tagging Extensions).
>>>>> 
>>>>> The series is split into a set that deals with generic changes to GDB's
>>>>> infrastructure (target methods, gdbarch hooks and remote packets), a set that
>>>>> implements support for AArch64 Linux and one last set that implements new
>>>>> commands, updates the documentation and adds tests.
>>>>> 
>>>>> The goal is to make it so the architecture independent parts of GDB don't
>>>>> need to interpret tag formats, given the formats are likely different
>>>>> for each architecture.  For this reason, GDB will handle tags as a sequence of
>>>>> bytes and will not assume a particular format.
>>>>> 
>>>>> The architecture-specific code can handle the sequence of bytes appropriately.
>>>>> 
>>>>> Luis Machado (24):
>>>>>    New target methods for memory tagging support
>>>>>    New gdbarch memory tagging hooks
>>>>>    Add GDB-side remote target support for memory tagging
>>>>>    Unit testing for GDB-side remote memory tagging handling
>>>>>    GDBserver remote packet support for memory tagging
>>>>>    Unit tests for gdbserver memory tagging remote packets
>>>>>    Documentation for memory tagging remote packets
>>>>>    AArch64: Add MTE CPU feature check support
>>>>>    AArch64: Add target description/feature for MTE registers
>>>>>    AArch64: Add MTE register set support for GDB and gdbserver
>>>>>    AArch64: Add MTE ptrace requests
>>>>>    AArch64: Implement memory tagging target methods for AArch64
>>>>>    Refactor parsing of /proc/<pid>/smaps
>>>>>    AArch64: Implement the memory tagging gdbarch hooks
>>>>>    AArch64: Add unit testing for logical tag set/get operations
>>>>>    AArch64: Report tag violation error information
>>>>>    AArch64: Add gdbserver MTE support
>>>>>    AArch64: Add MTE register set support for core files
>>>>>    New mtag commands
>>>>>    Documentation for the new mtag commands
>>>>>    Extend "x" and "print" commands to support memory tagging
>>>>>    Document new "x" and "print" memory tagging extensions
>>>>>    Add NEWS entry.
>>>>>    Add memory tagging testcases
>>>>> 
>>>>>   gdb/Makefile.in                        |   3 +
>>>>>   gdb/NEWS                               |  32 ++
>>>>>   gdb/aarch64-linux-nat.c                | 129 ++++++-
>>>>>   gdb/aarch64-linux-tdep.c               | 334 +++++++++++++++++-
>>>>>   gdb/aarch64-linux-tdep.h               |   3 +
>>>>>   gdb/aarch64-tdep.c                     |  40 ++-
>>>>>   gdb/aarch64-tdep.h                     |  12 +-
>>>>>   gdb/arch-utils.c                       |  50 +++
>>>>>   gdb/arch-utils.h                       |  23 ++
>>>>>   gdb/arch/aarch64-mte-linux.c           |  70 ++++
>>>>>   gdb/arch/aarch64-mte-linux.h           |  66 ++++
>>>>>   gdb/arch/aarch64.c                     |   7 +-
>>>>>   gdb/arch/aarch64.h                     |   7 +-
>>>>>   gdb/configure.nat                      |   3 +-
>>>>>   gdb/configure.tgt                      |   1 +
>>>>>   gdb/doc/gdb.texinfo                    | 215 +++++++++++-
>>>>>   gdb/features/Makefile                  |   1 +
>>>>>   gdb/features/aarch64-mte.c             |  14 +
>>>>>   gdb/features/aarch64-mte.xml           |  11 +
>>>>>   gdb/gdbarch.c                          | 137 ++++++++
>>>>>   gdb/gdbarch.h                          |  53 +++
>>>>>   gdb/gdbarch.sh                         |  36 ++
>>>>>   gdb/linux-tdep.c                       | 358 ++++++++++++-------
>>>>>   gdb/linux-tdep.h                       |   4 +
>>>>>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>>>>>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>>>>>   gdb/printcmd.c                         | 468 ++++++++++++++++++++++++-
>>>>>   gdb/remote.c                           | 232 ++++++++++++
>>>>>   gdb/target-delegates.c                 |  84 +++++
>>>>>   gdb/target.h                           |  37 ++
>>>>>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>>>>>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 ++++++++++++++++++++
>>>>>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>>>>>   gdb/testsuite/gdb.base/memtag.exp      |  64 ++++
>>>>>   gdb/testsuite/lib/gdb.exp              |  16 +
>>>>>   gdb/valprint.h                         |   1 +
>>>>>   gdbserver/Makefile.in                  |   1 +
>>>>>   gdbserver/configure.srv                |   2 +
>>>>>   gdbserver/linux-aarch64-ipa.cc         |   8 +-
>>>>>   gdbserver/linux-aarch64-low.cc         |  97 ++++-
>>>>>   gdbserver/linux-aarch64-tdesc.cc       |  10 +-
>>>>>   gdbserver/linux-aarch64-tdesc.h        |   3 +-
>>>>>   gdbserver/remote-utils.cc              |  43 ++-
>>>>>   gdbserver/remote-utils.h               |   7 +-
>>>>>   gdbserver/server.cc                    | 245 +++++++++++++
>>>>>   gdbserver/server.h                     |   3 +
>>>>>   gdbserver/target.cc                    |  20 ++
>>>>>   gdbserver/target.h                     |  17 +
>>>>>   gdbsupport/rsp-low.cc                  |   2 +-
>>>>>   include/elf/common.h                   |   3 +
>>>>>   50 files changed, 3536 insertions(+), 186 deletions(-)
>>>>>   create mode 100644 gdb/arch/aarch64-mte-linux.c
>>>>>   create mode 100644 gdb/arch/aarch64-mte-linux.h
>>>>>   create mode 100644 gdb/features/aarch64-mte.c
>>>>>   create mode 100644 gdb/features/aarch64-mte.xml
>>>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.c
>>>>>   create mode 100644 gdb/nat/aarch64-mte-linux-ptrace.h
>>>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
>>>>>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
>>>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.c
>>>>>   create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>>>>> 


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 01/24] New target methods for memory tagging support
  2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
@ 2020-12-25  4:26   ` Simon Marchi
  2020-12-28 15:05     ` Luis Machado
  2020-12-25  5:08   ` Simon Marchi
  1 sibling, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  4:26 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v3:
> 
> - Updated the code documentation for the fetch_memtags and store_memtags
>   methods.
> 
> Updates on v2:
> 
> - Added type parameter to fetch_memtags/store_memtags hooks.
> 
> --
> 
> This patch starts adding some of the generic pieces to accomodate memory
> tagging.
> 
> We have three new target methods:
> 
> - supports_memory_tagging: Checks if the target supports memory tagging. This
>   defaults to false for targets that don't support memory tagging.
> 
> - fetch_memtags: Fetches the allocation tags associated with a particular
>   memory range [address, address + length).
> 
>   The default is to return 0 without returning any tags. This should only
>   be called if memory tagging is supported.
> 
> - store_memtags: Stores a set of allocation tags for a particular memory
>   range [address, address + length).
> 
>   The default is to return 0. This should only
>   be called if memory tagging is supported.

If fetch/store should only be called on targets for which supports_memory_tagging
returns true, why is the default to return 0?

It seems to me like it should be either:

- it's ok to call fetch/store on any target, if the target doesn't implement memtags,
  the default of returning 0 is used
- it's only ok to call fetch/store on targets that implement memtags, in which case
  I would expect the default to maybe be tcomplain or even an assert

Or is there something I don't see?

> 
> It also adds a control option for enabling/disabling memory tagging
> manually: set memory-tagging on/off.
>
> The default is "on", with GDB making its use conditional to the
> architecture supporting memory tagging.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* printcmd.c (memtag): New static global.
> 	(show_memtag): New function.
> 	(_initialize_printcmd): Add set/show memory-tagging command.
> 	* remote.c (remote_target) <supports_memory_tagging>: New method
> 	override.
> 	<fetch_memtags>: New method override.
> 	<store_memtags>: New method override.
> 	(remote_target::supports_memory_tagging): New method.
> 	(remote_target::fetch_memtags): New method.
> 	(remote_target::store_memtags): New method.
> 	* target-delegates.c
> 	(dummy_target) <supports_memory_tagging>: New method override.
> 	<fetch_memtags>: New method override.
> 	<store_memtags>: New method override.
> 	(debug_target) <supports_memory_tagging>: New method override.
> 	<fetch_memtags>: New method override.
> 	<store_memtags>: New method override.
> 	(target_ops::supports_memory_tagging): New method.
> 	(target_ops::fetch_memtags): New method.
> 	(target_ops::store_memtags): New method.
> 	(dummy_target::supports_memory_tagging): New method.
> 	(dummy_target::fetch_memtags): New method.
> 	(dummy_target::store_memtags): New method.
> 	(debug_target::supports_memory_tagging): New method.
> 	(debug_target::fetch_memtags): New method.
> 	(debug_target::store_memtags): New method.

Oh, you wrote this by hand :(.  target-delegates.c is generated (see the
command at the top of the file).  

Otherwise, that LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 02/24] New gdbarch memory tagging hooks
  2020-11-09 17:04 ` [PATCH v3 02/24] New gdbarch memory tagging hooks Luis Machado
@ 2020-12-25  4:40   ` Simon Marchi
  2020-12-28 15:44     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  4:40 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> We need some new gdbarch hooks to help us manipulate memory tags without having
> to have GDB calls the target methods directly.

calls -> call?

> 
> This patch adds the following hooks:
> 
> gdbarch_memtag_to_string
> --
> Returns a printable string corresponding to the tag.
> 
> gdbarch_tagged_address_p
> --
> Checks if a particular address is protected with memory tagging.
> 
> gdbarch_memtag_mismatch_p
> --
> Checks if there is a mismatch between the logical tag of a pointer and the
> allocation tag.

It would seem more natural to me to have gdbarch_memtag_matches_p
instead,which would just be the opposite gdbarch_memtag_mismatch_p.
If I want to know if a tag matches, I have to do:

  if (!gdbarch_memtag_mismatch_p (...))

and that's like a double negative, "if the memtag does not not match".

> gdbarch_set_memtags:
> --
> Sets either the allocation tag or the logical tag for a particular value.
> 
> gdbarch_get_memtag:
> --
> Gets either the allocation tag or the logical tag for a particular value.
> 
> gdbarch_granule_size
> --
> Sets the memory tag granule size, which represents the number of bytes a
> particular allocation tag covers. For example, this is 16 bytes for
> AArch64's MTE.

I'd suggest having "memtag" in the name of this function, to make it clear
it's memtag-related.  Like "gdbarch_memtag_granule_size".

> 
> I've used struct value as opposed to straight CORE_ADDR so other architectures
> can use the infrastructure without having to rely on fixed types.

What do you mean by "having to rely on fixed types"?

Otherwise, this LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 01/24] New target methods for memory tagging support
  2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
  2020-12-25  4:26   ` Simon Marchi
@ 2020-12-25  5:08   ` Simon Marchi
  1 sibling, 0 replies; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  5:08 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett


> +    /* Return the allocated memory tags of type TYPE associated with
> +       [ADDRESS, ADDRESS + LEN) in TAGS.
> +
> +       LEN is the number of bytes in the memory range.  TAGS is a vector of
> +       bytes containing the tags found in the above memory range.
> +
> +       It is up to the architecture/target to interpret the bytes in the TAGS
> +       vector and read the tags appropriately.  */
> +    virtual int fetch_memtags (CORE_ADDR address, size_t len,
> +			       gdb::byte_vector &tags, int type)
> +      TARGET_DEFAULT_IGNORE ();
> +
> +    /* Write the allocation tags of type TYPE contained in TAGS to the memory
> +       range [ADDRESS, ADDRESS + LEN).
> +
> +       LEN is the number of bytes in the memory range.  TAGS is a vector of
> +       bytes containing the tags to be stored to the memory range.
> +
> +       It is up to the architecture/target to interpret the bytes in the TAGS
> +       vector and store them appropriately.  */
> +    virtual int store_memtags (CORE_ADDR address, size_t len,
> +			       const gdb::byte_vector &tags, int type)

Some more feedback: make the return values bool, if they are bool, and document
the meaning in the comment.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 03/24] Add GDB-side remote target support for memory tagging
  2020-11-09 17:04 ` [PATCH v3 03/24] Add GDB-side remote target support for memory tagging Luis Machado
@ 2020-12-25  5:08   ` Simon Marchi
  2020-12-28 16:28     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  5:08 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updates for v2:
> 
> - Add type field to target hooks.
> - Add type data to qMemTags and QMemTags. The packets now look like this:
> 
> qMemTags:<address>,<length>:<type>
> QMemTags:<address>,<length>:<type>:<uninterpreted tag bytes>
> 
> --
> 
> This patch adds memory tagging support to GDB's remote side, with
> packet string checks, new packet support and an implementation of
> the two new tags methods fetch_atags and store_atags.

fetch_memtags / store_memtags ?

> 
> GDBserver needs to know how to read/write allocation tags, since that is
> done via ptrace.  It doesn't need to know about logical tags.
> 
> The new packets are:
> 
> qMemTags:<address>,<length>
> --
> 
> Reads tags from the address range [<address>, <address + length>)
> 
> QMemTags:<address>,<length>:<uninterpreted tag bytes>
> --
> Writes the tags represented by the uninterpreted bytes to the address range
> [<address>, <address + length>).

Should the packet description above be updated to include the "type" field?

> @@ -14404,7 +14422,65 @@ set_range_stepping (const char *ignore_args, int from_tty,
>  bool
>  remote_target::supports_memory_tagging ()
>  {
> -  return false;
> +  return remote_memory_tagging_p ();
> +}
> +
> +/* Create the qMemTags packet given ADDRESS, LEN and TYPE.
> +
> +   Return 0 if successful, non-zero otherwise.  */
> +
> +static void
> +create_fmemtags_request (gdb::char_vector &packet, CORE_ADDR address,
> +			 size_t len, int type)

The comment is wrong, the function does not return anything.

Why "fmemtags"?  Oh, it's for "fetch".  I'd prefer if you spelled
it completely (create_fetch_memtags_request), it's not very clear
otherwise (same for smemtags).

> +{
> +  int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
> +
> +  std::string request = string_printf ("qMemTags:%s,%s:%s",
> +				       phex_nz (address, addr_size),
> +				       phex_nz (len, sizeof (len)),
> +				       phex_nz (type, sizeof (type)));
> +
> +  strcpy (packet.data (), request.c_str ());
> +}
> +
> +/* Parse the qMemTags packet reply into TAGS.
> +
> +   Return 0 if successful, non-zero otherwise.  */
> +
> +static int
> +parse_fmemtags_reply (gdb::char_vector &reply, gdb::byte_vector &tags)

reply should be const, the return value should be bool.

Otherwise, LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling
  2020-11-09 17:04 ` [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling Luis Machado
@ 2020-12-25  5:34   ` Simon Marchi
  2020-12-28 17:17     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  5:34 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updated in v2:
> 
> - Adjusted unit tests to cope with new type field in the remote packets.
> 
> --
> 
> Include some unit testing for the functions handling the new qMemTags and
> QMemTags packets.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* remote: Include gdbsupport/selftest.h.
> 	(test_memory_tagging_functions): New function.
> 	(_initialize_remote): Register test_memory_tagging_functions.
> ---
>  gdb/remote.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 89 insertions(+)
> 
> diff --git a/gdb/remote.c b/gdb/remote.c
> index e45eef4bee..6db7a74542 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -79,6 +79,7 @@
>  #include <algorithm>
>  #include <unordered_map>
>  #include "async-event.h"
> +#include "gdbsupport/selftest.h"
>  
>  /* The remote target.  */
>  
> @@ -14529,6 +14530,89 @@ remote_target::store_memtags (CORE_ADDR address, size_t len,
>    return 0;
>  }
>  
> +#if GDB_SELF_TEST
> +
> +namespace selftests {
> +
> +static void
> +test_memory_tagging_functions (void)

Remove "void".

> +{
> +  remote_target remote;
> +
> +  struct packet_config *config
> +    = &remote_protocol_packets[PACKET_memory_tagging_feature];
> +
> +  /* Test memory tagging packet support.  */
> +  config->support = PACKET_SUPPORT_UNKNOWN;
> +  SELF_CHECK (remote.supports_memory_tagging () == false);
> +  config->support = PACKET_DISABLE;
> +  SELF_CHECK (remote.supports_memory_tagging () == false);
> +  config->support = PACKET_ENABLE;
> +  SELF_CHECK (remote.supports_memory_tagging () == true);

This seems to set the global flag of whether the remote side supports
memory tagging.  Even though it's not likely to be a real problem, IWBN
to restore the global state that you touch.

Otherwise, LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 05/24] GDBserver remote packet support for memory tagging
  2020-11-09 17:04 ` [PATCH v3 05/24] GDBserver remote packet support for memory tagging Luis Machado
@ 2020-12-25  5:50   ` Simon Marchi
  2020-12-28 17:46     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25  5:50 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index 95db9807a9..7eddd0e01f 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -547,12 +547,71 @@ handle_btrace_conf_general_set (char *own_buf)
>    return 1;
>  }
>  
> +/* Create the qMemTags packet reply given TAGS.  */
> +
> +static int
> +create_fmemtags_reply (char *reply, const gdb::byte_vector &tags)
> +{
> +  /* It is an error to pass a zero-sized tag vector.  */
> +  if (tags.size () == 0)
> +    return 1;

If this catches a logic error in GDBserver, this should be an assert.

> +
> +  std::string packet ("m");
> +
> +  /* Write the tag data.  */
> +  packet += bin2hex (tags.data (), tags.size ());
> +
> +  /* Check if the reply is too big for the packet to handle.  */
> +  if (PBUFSIZ < packet.size ())
> +    return 1;
> +
> +  strcpy (reply, packet.c_str ());
> +  return 0;
> +}
> +
> +/* Parse the QMemTags request into ADDR, LEN and TAGS.
> +
> +   Return 0 if successful, non-zero otherwise.  */
> +
> +static int
> +parse_smemtags_request (char *request, CORE_ADDR *addr, size_t *len,
> +			gdb::byte_vector &tags, int *type)
> +{
> +  if (!startswith (request, "QMemTags:"))
> +    return 1;

That check seems unnecessary, or maybe I'd convert it to an assert.

> diff --git a/gdbserver/server.h b/gdbserver/server.h
> index 22228050a8..3d4a086e18 100644
> --- a/gdbserver/server.h
> +++ b/gdbserver/server.h
> @@ -190,6 +190,9 @@ struct client_state
>  
>    int current_traceframe = -1;
>  
> +  /* If true, memory tagging features are supported.  */
> +  bool memory_tagging_feature = false;

Just a note that as of this patch, this field is unnecessary.  If it gets
used later, that's fine.

> @@ -499,6 +500,19 @@ class process_stratum_target
>  
>    /* Return tdesc index for IPA.  */
>    virtual int get_ipa_tdesc_idx ();
> +
> +  /* Returns true if the target supports memory tagging facilities.  */
> +  virtual bool supports_memory_tagging ();
> +
> +  /* Return the allocated memory tags of type TYPE associated with
> +     [ADDRESS, ADDRESS + LEN) in TAGS.  */
> +  virtual int fetch_memtags (CORE_ADDR address, size_t len,
> +			     gdb::byte_vector &tags, int type);
> +
> +  /* Write the allocation tags of type TYPE contained in TAGS to the
> +     memory range [ADDRESS, ADDRESS + LEN).  */
> +  virtual int store_memtags (CORE_ADDR address, size_t len,
> +			     const gdb::byte_vector &tags, int type);

I suppose that these should return bool.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets
  2020-11-09 17:04 ` [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets Luis Machado
@ 2020-12-25 20:13   ` Simon Marchi
  2020-12-28 18:12     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-25 20:13 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v2:
> 
> - Update unit tests to cope with additional tag type field in the remote
> packets.
> 
> --
> 
> Add some unit testing to exercise the functions handling the qMemTags and
> QMemTags packets as well as feature support.
> 
> gdbserver/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* server.cc (test_memory_tagging_functions): New function.
> 	(captured_main): Register test_memory_tagging_functions.
> ---
>  gdbserver/server.cc | 100 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 100 insertions(+)
> 
> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
> index 7eddd0e01f..6812b624f8 100644
> --- a/gdbserver/server.cc
> +++ b/gdbserver/server.cc
> @@ -3647,6 +3647,103 @@ detach_or_kill_for_exit_cleanup ()
>      }
>  }
>  
> +#if GDB_SELF_TEST
> +
> +namespace selftests {
> +
> +static void
> +test_memory_tagging_functions (void)
> +{
> +  /* Setup testing.  */
> +  gdb::char_vector packet;
> +  gdb::byte_vector tags, bv;
> +  std::string expected;
> +  packet.resize (32000);
> +  CORE_ADDR addr;
> +  size_t len;
> +  int type;
> +
> +  /* Test parsing a qMemTags request.  */
> +
> +  /* Invalid request, addr len and type unchanged.  */
> +  addr = 0xff;
> +  len = 255;
> +  type = 255;
> +  strcpy (packet.data (), "qMemTags_wrong:0,0:0");
> +  SELF_CHECK (parse_fmemtags_request (packet.data (), &addr, &len, &type) != 0);
> +  SELF_CHECK (addr == 0xff && len == 255 && type == 255);

As I said earlier, I would have made parse_fmemtags_request assert that the
packet begins with "qMemTags:" (instead of returning an error value), but it's
really a nit and I can live with both.

Otherwise this patch LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 08/24] AArch64: Add MTE CPU feature check support
  2020-11-09 17:04 ` [PATCH v3 08/24] AArch64: Add MTE CPU feature check support Luis Machado
@ 2020-12-26  0:04   ` Simon Marchi
  0 siblings, 0 replies; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  0:04 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> This patch is a preparation for the next patches implementing MTE. It just adds
> a HWCAP2 constant for MTE, creates a new generic arch/aarch64-mte-linux.h file
> and includes that file in the source files that will use it.

I'm up to here, and that LGTM.

I skipped over the previous patch / discussion, as I don't have a strong opinion
on the RSP format.  Not because it's not important, but because I don't know
enough about the subject matter to have one.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers
  2020-11-09 17:04 ` [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers Luis Machado
@ 2020-12-26  0:10   ` Simon Marchi
  2020-12-28 18:28     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  0:10 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> This patch adds a target description and feature "mte" for aarch64.
> 
> It includes one new register, tag_ctl, that can be used to configure the
> tag generation rules and sync/async modes. 

Can you explain this sentence?  I especially don't understand "sync/async modes"..

The code itself LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver
  2020-11-09 17:04 ` [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
@ 2020-12-26  0:17   ` Simon Marchi
  2020-12-28 18:41     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  0:17 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> AArch64 MTE support in the Linux kernel exposes a new register
> through ptrace.  This patch adds the required code to support it.
> 
> include/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* elf/common.h (NT_ARM_TAGGED_ADDR_CTRL): Define.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* aarch64-linux-nat.c (fetch_mteregs_from_thread): New function.
> 	(store_mteregs_to_thread): New function.
> 	(aarch64_linux_nat_target::fetch_registers): Update to call
> 	fetch_mteregs_from_thread.
> 	(aarch64_linux_nat_target::store_registers): Update to call
> 	store_mteregs_to_thread.
> 	* aarch64-tdep.c (aarch64_mte_register_names): New struct.
> 	(aarch64_cannot_store_register): Handle MTE registers.
> 	(aarch64_gdbarch_init): Initialize and setup MTE registers.
> 	* aarch64-tdep.h (gdbarch_tdep) <mte_reg_base>: New field.
> 	<has_mte>: New method.
> 	* arch/aarch64-linux.h (AARCH64_LINUX_SIZEOF_MTE): Define.
> 
> gdbserver/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* linux-aarch64-low.cc (aarch64_fill_mteregset): New function.
> 	(aarch64_store_mteregset): New function.
> 	(aarch64_regsets): Add MTE register set entry.
> 	(aarch64_sve_regsets): Add MTE register set entry.
> ---
>  gdb/aarch64-linux-nat.c        | 70 ++++++++++++++++++++++++++++++++++
>  gdb/aarch64-tdep.c             | 24 ++++++++++++
>  gdb/aarch64-tdep.h             |  9 +++++
>  gdb/arch/aarch64-mte-linux.h   |  3 ++
>  gdbserver/linux-aarch64-low.cc | 29 ++++++++++++++
>  include/elf/common.h           |  3 ++
>  6 files changed, 138 insertions(+)
> 
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index 1392ec440c..dea34da669 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -461,6 +461,60 @@ fetch_pauth_masks_from_thread (struct regcache *regcache)
>  			&pauth_regset[1]);
>  }
>  
> +/* Fill GDB's register array with the MTE register values from
> +   the current thread.  */
> +
> +static void
> +fetch_mteregs_from_thread (struct regcache *regcache)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
> +  int regno = tdep->mte_reg_base;
> +
> +  gdb_assert (regno != -1);
> +
> +  uint64_t tag_ctl = 0;
> +  struct iovec iovec;
> +
> +  iovec.iov_base = &tag_ctl;
> +  iovec.iov_len = sizeof (tag_ctl);
> +
> +  int tid = regcache->ptid ().lwp ();

Should this use get_ptrace_pid?  Same in the store version.

> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL,
> +		&iovec) != 0)

The indentation is wrong on this last line (and it would all fit on one line).

> diff --git a/include/elf/common.h b/include/elf/common.h
> index fc672de9f2..334e9e301f 100644
> --- a/include/elf/common.h
> +++ b/include/elf/common.h
> @@ -660,6 +660,9 @@
>  					/*   note name must be "LINUX".  */
>  #define NT_ARM_PAC_MASK	0x406		/* AArch pointer authentication code masks */
>  					/*   note name must be "LINUX".  */
> +#define NT_ARM_TAGGED_ADDR_CTRL	0x409	/* AArch64 tagged address control
> +					   (prctl()) */
> +					/*   note name must be "LINUX".  */
>  #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
>  					/*   note name must be "LINUX".  */
>  #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */

What this changed approved by binutils?


Otherwise, this LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 11/24] AArch64: Add MTE ptrace requests
  2020-11-09 17:04 ` [PATCH v3 11/24] AArch64: Add MTE ptrace requests Luis Machado
@ 2020-12-26  0:19   ` Simon Marchi
  2020-12-28 19:12     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  0:19 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> This patch adds the required ptrace request definitions into a new include
> file that will be used by the next patches.
> 
> They are PTRACE_PEEKMTETAGS and PTRACE_POKEMTETAGS.

IIUC, this is to allow building GDB on an older kernel that doesn't provide
these definitions?

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64
  2020-11-09 17:04 ` [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
@ 2020-12-26  0:33   ` Simon Marchi
  2020-12-28 19:50     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  0:33 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> 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.
> 	(MTE_GRANULE_SIZE): Define.
> 	(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       |  34 +++++
>  gdb/arch/aarch64-mte-linux.h       |  10 ++
>  gdb/configure.nat                  |   3 +-
>  gdb/configure.tgt                  |   1 +
>  gdb/nat/aarch64-mte-linux-ptrace.c | 200 +++++++++++++++++++++++++++++
>  gdb/nat/aarch64-mte-linux-ptrace.h |  17 +++
>  8 files changed, 315 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 4f08beea44..452e21b2b2 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -693,6 +693,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 dea34da669..4edf5a0454 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.  */
> +  int fetch_memtags (CORE_ADDR address, size_t len,
> +		     gdb::byte_vector &tags, int type) override;
> +
> +  /* Write allocation tags to memory via PTRACE.  */
> +  int 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;
> @@ -1050,6 +1062,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.  */
> +
> +int
> +aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
> +					 gdb::byte_vector &tags, int type)
> +{
> +  int tid = inferior_ptid.lwp ();

I believe this should use get_ptrace_pid (same in the store version).

> +
> +  /* Allocation tags?  */
> +  if (type == 1)
> +    return aarch64_mte_fetch_memtags (tid, address, len, tags);
> +
> +  return 1;

What's the logic of this "return 1"?  Does this mean "success", and
is this what we want to do when it's an unhandled type?  Oh, now that I
read the doc for aarch64_mte_fetch_memtags, I see that 1 means failure.
See comment below.

> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
> index 4124e80543..e555f0af19 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,12 @@
>  /* 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 MTE_GRANULE_SIZE 16

I'd suggest prefixing this, AARCH64_MTE_GRANULE_SIZE.

> +
> +/* Return the number of tag granules in the memory range
> +   [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
> +extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
> +				size_t granule_size);

And aarch64_mte_get_tag_granules.

> +/* Helper function to display various possible errors when reading
> +   MTE tags.  */
> +
> +static void
> +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
> +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;
> +    }
> +}

These functions should probably be marked with ATTRIBUTE_NORETURN.

> +
> +/* 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)
> +    {
> +      t.clear ();

That clear seems unnecessary.

> diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
> index 099b6440ca..7ba6f014f6 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 TAGS_MAX_SIZE 4096

I think this define should have a more scoped named, like
AARCH64_MTE_TAGS_MAX_SIZE.

> +
> +/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN)
> +   into TAGS.
> +
> +   Return 0 if successful and non-zero otherwise.  */
> +extern int aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
> +				      gdb::byte_vector &tags);
> +
> +/* Write the TAGS allocation tags to the memory range
> +   [ADDRESS, ADDRESS + LEN).
> +
> +   Return 0 if successful and non-zero otherwise.  */
> +extern int aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
> +				      const gdb::byte_vector &tags);

IWBN to use bool for the return value, true for success and false for failure.
And as mentioned in the first patch, the target methods should also use bool
for the return value and be documented (although with bool, it's pretty obvious
that "true" means success, unlike with ints where both ways are common).

Otherwise, LGTM.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps
  2020-11-09 17:04 ` [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps Luis Machado
@ 2020-12-26  6:36   ` Simon Marchi
  2020-12-29 10:57     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  6:36 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> The Linux kernel exposes the information about MTE-protected pages via the
> proc filesystem, more specifically through the smaps file.
> 
> What we're looking for is a mapping with the 'mt' flag, which tells us that
> mapping was created with a PROT_MTE flag and, thus, is capable of using memory
> tagging.
> 
> We already parse that file for other purposes (core file
> generation/filtering), so this patch refactors the code to make the parsing
> of the smaps file reusable for memory tagging.
> 
> The function linux_address_in_memtag_page uses the refactored code to allow
> querying for memory tag support in a particular address, and it gets used in the
> next patch.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* linux-tdep.c (struct smaps_vmflags) <memory_tagging>: New flag
> 	bit.
> 	(struct smaps_data): New struct.
> 	(decode_vmflags): Handle the 'mt' flag.
> 	(parse_smaps_data): New function, refactored from
> 	linux_find_memory_regions_full.
> 	(linux_address_in_memtag_page): New function.
> 	(linux_find_memory_regions_full): Refactor into parse_smaps_data.
> 	* linux-tdep.h (linux_address_in_memtag_page): New prototype.
> ---
>  gdb/linux-tdep.c | 358 +++++++++++++++++++++++++++++++----------------
>  gdb/linux-tdep.h |   4 +
>  2 files changed, 241 insertions(+), 121 deletions(-)
> 
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index bacb61398f..91bdcc133b 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -86,8 +86,33 @@ struct smaps_vmflags
>      /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
>  
>      unsigned int shared_mapping : 1;
> +
> +    /* Memory map has memory tagging enabled.  */
> +
> +    unsigned int memory_tagging : 1;
>    };
>  
> +/* Data structure that holds the information contained in the
> +   /proc/<pid>/smaps file.  */
> +
> +struct smaps_data
> +{
> +  ULONGEST start_address;
> +  ULONGEST end_address;
> +  std::string filename;
> +  struct smaps_vmflags vmflags;
> +  bool read;
> +  bool write;
> +  bool exec;
> +  bool priv;
> +  bool has_anonymous;
> +  bool mapping_anon_p;
> +  bool mapping_file_p;
> +
> +  ULONGEST inode;
> +  ULONGEST offset;
> +};
> +
>  /* Whether to take the /proc/PID/coredump_filter into account when
>     generating a corefile.  */
>  
> @@ -472,6 +497,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
>  	v->exclude_coredump = 1;
>        else if (strcmp (s, "sh") == 0)
>  	v->shared_mapping = 1;
> +      else if (strcmp (s, "mt") == 0)
> +	v->memory_tagging = 1;
>      }
>  }
>  
> @@ -1267,6 +1294,184 @@ typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
>  					const char *filename,
>  					ULONGEST addr,
>  					ULONGEST offset);
> +/* Helper function to parse the contents of /proc/<pid>/smaps into a data
> +   structure, for easy access.
> +
> +   DATA is the contents of the smaps file.  The parsed contents are stored
> +   into the SMAPS vector.  */

Add a blank line above this comment.

> +
> +static int
> +parse_smaps_data (const char *data,
> +		  std::vector<struct smaps_data> &smaps,
> +		  const char *mapsfilename)

The return value of that function is unused, it always return 0.  I'd suggest
making it return the std::vector directly.

> +{
> +  char *line, *t;
> +
> +  gdb_assert (data != nullptr);
> +
> +  smaps.clear ();
> +
> +  line = strtok_r ((char *) data, "\n", &t);
> +
> +  while (line != NULL)
> +    {
> +      ULONGEST addr, endaddr, offset, inode;
> +      const char *permissions, *device, *filename;
> +      struct smaps_vmflags v;
> +      size_t permissions_len, device_len;
> +      int read, write, exec, priv;
> +      int has_anonymous = 0;
> +      int mapping_anon_p;
> +      int mapping_file_p;
> +
> +      memset (&v, 0, sizeof (v));
> +      read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
> +		    &offset, &device, &device_len, &inode, &filename);
> +      mapping_anon_p = mapping_is_anonymous_p (filename);
> +      /* If the mapping is not anonymous, then we can consider it
> +	 to be file-backed.  These two states (anonymous or
> +	 file-backed) seem to be exclusive, but they can actually
> +	 coexist.  For example, if a file-backed mapping has
> +	 "Anonymous:" pages (see more below), then the Linux
> +	 kernel will dump this mapping when the user specified
> +	 that she only wants anonymous mappings in the corefile
> +	 (*even* when she explicitly disabled the dumping of
> +	 file-backed mappings).  */
> +      mapping_file_p = !mapping_anon_p;
> +
> +      /* Decode permissions.  */
> +      read = (memchr (permissions, 'r', permissions_len) != 0);
> +      write = (memchr (permissions, 'w', permissions_len) != 0);
> +      exec = (memchr (permissions, 'x', permissions_len) != 0);
> +      /* 'private' here actually means VM_MAYSHARE, and not
> +	 VM_SHARED.  In order to know if a mapping is really
> +	 private or not, we must check the flag "sh" in the
> +	 VmFlags field.  This is done by decode_vmflags.  However,
> +	 if we are using a Linux kernel released before the commit
> +	 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
> +	 not have the VmFlags there.  In this case, there is
> +	 really no way to know if we are dealing with VM_SHARED,
> +	 so we just assume that VM_MAYSHARE is enough.  */
> +      priv = memchr (permissions, 'p', permissions_len) != 0;
> +
> +      /* Try to detect if region should be dumped by parsing smaps
> +	 counters.  */
> +      for (line = strtok_r (NULL, "\n", &t);
> +	   line != NULL && line[0] >= 'A' && line[0] <= 'Z';
> +	   line = strtok_r (NULL, "\n", &t))
> +	{
> +	  char keyword[64 + 1];
> +
> +	  if (sscanf (line, "%64s", keyword) != 1)
> +	    {
> +	      warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
> +	      break;
> +	    }
> +
> +	  if (strcmp (keyword, "Anonymous:") == 0)
> +	    {
> +	      /* Older Linux kernels did not support the
> +		 "Anonymous:" counter.  Check it here.  */
> +	      has_anonymous = 1;
> +	    }
> +	  else if (strcmp (keyword, "VmFlags:") == 0)
> +	    decode_vmflags (line, &v);
> +
> +	  if (strcmp (keyword, "AnonHugePages:") == 0
> +	      || strcmp (keyword, "Anonymous:") == 0)
> +	    {
> +	      unsigned long number;
> +
> +	      if (sscanf (line, "%*s%lu", &number) != 1)
> +		{
> +		  warning (_("Error parsing {s,}maps file '%s' number"),
> +			   mapsfilename);
> +		  break;
> +		}
> +	      if (number > 0)
> +		{
> +		  /* Even if we are dealing with a file-backed
> +		     mapping, if it contains anonymous pages we
> +		     consider it to be *also* an anonymous
> +		     mapping, because this is what the Linux
> +		     kernel does:
> +
> +		     // Dump segments that have been written to.
> +		     if (vma->anon_vma && FILTER(ANON_PRIVATE))
> +		       goto whole;
> +
> +		    Note that if the mapping is already marked as
> +		    file-backed (i.e., mapping_file_p is
> +		    non-zero), then this is a special case, and
> +		    this mapping will be dumped either when the
> +		    user wants to dump file-backed *or* anonymous
> +		    mappings.  */
> +		  mapping_anon_p = 1;
> +		}
> +	    }
> +	}
> +      /* Save the smaps entry to the vector.  */
> +	struct smaps_data map;
> +	std::string fname (filename);

You don't need to create the string here, just do 

  map.filename = filename;

below.

> +
> +	smaps.emplace_back (map);
> +    }
> +
> +  return 0;
> +}
> +
> +/* See linux-tdep.h.  */
> +
> +bool
> +linux_address_in_memtag_page (CORE_ADDR address)
> +{
> +  if (current_inferior ()->fake_pid_p)
> +    return false;> +
> +  pid_t pid = current_inferior ()->pid;
> +
> +  std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
> +
> +  gdb::unique_xmalloc_ptr<char> data
> +    = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
> +
> +  if (data == nullptr)
> +    return false;
> +
> +  std::vector<struct smaps_data> smaps;
> +
> +  /* Parse the contents of smaps into a vector.  */
> +  parse_smaps_data (data.get (), smaps, smaps_file.c_str ());
> +
> +  if (!smaps.empty ())
> +    {

No need for this `if`.

> +      for (struct smaps_data map : smaps)

Iterate by const reference:

  for (const smaps_data &map : smaps)

> +	{
> +	  /* 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;
> +	}
> +    }
> +
> +  return false;
> +}
>  
>  /* List memory regions in the inferior for a corefile.  */
>  
> @@ -1276,8 +1481,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>  				linux_find_memory_region_ftype *func,
>  				void *obfd)
>  {
> -  char mapsfilename[100];
> -  char coredumpfilter_name[100];
> +  std::string coredumpfilter_name;

Declare this on first use (we could push some preparatory patches to change
these to std::string, to make this patch simpler).

>    pid_t pid;
>    /* Default dump behavior of coredump_filter (0x33), according to
>       Documentation/filesystems/proc.txt from the Linux kernel
> @@ -1295,10 +1499,9 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>  
>    if (use_coredump_filter)
>      {
> -      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
> -		 "/proc/%d/coredump_filter", pid);
> +      coredumpfilter_name = string_printf ("/proc/%d/coredump_filter", pid);
>        gdb::unique_xmalloc_ptr<char> coredumpfilterdata
> -	= target_fileio_read_stralloc (NULL, coredumpfilter_name);
> +	= target_fileio_read_stralloc (NULL, coredumpfilter_name.c_str ());
>        if (coredumpfilterdata != NULL)
>  	{
>  	  unsigned int flags;
> @@ -1308,125 +1511,39 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>  	}
>      }
>  
> -  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
> +  std::string mapsfilename = string_printf ("/proc/%d/smaps", pid);
>    gdb::unique_xmalloc_ptr<char> data
> -    = target_fileio_read_stralloc (NULL, mapsfilename);
> +    = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
>    if (data == NULL)
>      {
>        /* Older Linux kernels did not support /proc/PID/smaps.  */
> -      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
> -      data = target_fileio_read_stralloc (NULL, mapsfilename);
> +      mapsfilename = string_printf ("/proc/%d/maps", pid);
> +      data = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
>      }
>  
> -  if (data != NULL)
> -    {
> -      char *line, *t;
> -
> -      line = strtok_r (data.get (), "\n", &t);
> -      while (line != NULL)
> -	{
> -	  ULONGEST addr, endaddr, offset, inode;
> -	  const char *permissions, *device, *filename;
> -	  struct smaps_vmflags v;
> -	  size_t permissions_len, device_len;
> -	  int read, write, exec, priv;
> -	  int has_anonymous = 0;
> -	  int should_dump_p = 0;
> -	  int mapping_anon_p;
> -	  int mapping_file_p;
> -
> -	  memset (&v, 0, sizeof (v));
> -	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
> -			&offset, &device, &device_len, &inode, &filename);
> -	  mapping_anon_p = mapping_is_anonymous_p (filename);
> -	  /* If the mapping is not anonymous, then we can consider it
> -	     to be file-backed.  These two states (anonymous or
> -	     file-backed) seem to be exclusive, but they can actually
> -	     coexist.  For example, if a file-backed mapping has
> -	     "Anonymous:" pages (see more below), then the Linux
> -	     kernel will dump this mapping when the user specified
> -	     that she only wants anonymous mappings in the corefile
> -	     (*even* when she explicitly disabled the dumping of
> -	     file-backed mappings).  */
> -	  mapping_file_p = !mapping_anon_p;
> -
> -	  /* Decode permissions.  */
> -	  read = (memchr (permissions, 'r', permissions_len) != 0);
> -	  write = (memchr (permissions, 'w', permissions_len) != 0);
> -	  exec = (memchr (permissions, 'x', permissions_len) != 0);
> -	  /* 'private' here actually means VM_MAYSHARE, and not
> -	     VM_SHARED.  In order to know if a mapping is really
> -	     private or not, we must check the flag "sh" in the
> -	     VmFlags field.  This is done by decode_vmflags.  However,
> -	     if we are using a Linux kernel released before the commit
> -	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
> -	     not have the VmFlags there.  In this case, there is
> -	     really no way to know if we are dealing with VM_SHARED,
> -	     so we just assume that VM_MAYSHARE is enough.  */
> -	  priv = memchr (permissions, 'p', permissions_len) != 0;
> -
> -	  /* Try to detect if region should be dumped by parsing smaps
> -	     counters.  */
> -	  for (line = strtok_r (NULL, "\n", &t);
> -	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
> -	       line = strtok_r (NULL, "\n", &t))
> -	    {
> -	      char keyword[64 + 1];
> +  if (data == nullptr)
> +    return 1;
>  
> -	      if (sscanf (line, "%64s", keyword) != 1)
> -		{
> -		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
> -		  break;
> -		}
> +  std::vector<struct smaps_data> smaps;
>  
> -	      if (strcmp (keyword, "Anonymous:") == 0)
> -		{
> -		  /* Older Linux kernels did not support the
> -		     "Anonymous:" counter.  Check it here.  */
> -		  has_anonymous = 1;
> -		}
> -	      else if (strcmp (keyword, "VmFlags:") == 0)
> -		decode_vmflags (line, &v);
> +  /* Parse the contents of smaps into a vector.  */
> +  parse_smaps_data (data.get (), smaps, mapsfilename.c_str ());
>  
> -	      if (strcmp (keyword, "AnonHugePages:") == 0
> -		  || strcmp (keyword, "Anonymous:") == 0)
> -		{
> -		  unsigned long number;
> -
> -		  if (sscanf (line, "%*s%lu", &number) != 1)
> -		    {
> -		      warning (_("Error parsing {s,}maps file '%s' number"),
> -			       mapsfilename);
> -		      break;
> -		    }
> -		  if (number > 0)
> -		    {
> -		      /* Even if we are dealing with a file-backed
> -			 mapping, if it contains anonymous pages we
> -			 consider it to be *also* an anonymous
> -			 mapping, because this is what the Linux
> -			 kernel does:
> -
> -			 // Dump segments that have been written to.
> -			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
> -			 	goto whole;
> -
> -			 Note that if the mapping is already marked as
> -			 file-backed (i.e., mapping_file_p is
> -			 non-zero), then this is a special case, and
> -			 this mapping will be dumped either when the
> -			 user wants to dump file-backed *or* anonymous
> -			 mappings.  */
> -		      mapping_anon_p = 1;
> -		    }
> -		}
> -	    }
> +  if (!smaps.empty ())
> +    {
> +      for (struct smaps_data map : smaps)

Same comments as above.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks
  2020-11-09 17:04 ` [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
@ 2020-12-26  6:52   ` Simon Marchi
  2020-12-29 12:16     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26  6:52 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v2:
> 
> - Update target methods to contain a tag type parameter.
> 
> --
> 
> This patch implements the memory tagging gdbarch hooks for AArch64, for
> the MTE feature.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* aarch64-linux-tdep.c: Include target.h, arch-utils.h, value.h.
> 	(aarch64_linux_get_atag, aarch64_linux_tagged_address_p)
> 	(aarch64_linux_memtag_mismatch_p, aarch64_linux_set_memtags)
> 	(aarch64_linux_get_memtag, aarch64_linux_memtag_to_string): New
> 	functions.
> 	(aarch64_linux_init_abi): Initialize MTE-related gdbarch hooks.
> 	* arch/aarch64-mte-linux.c (make_ltag_bits, make_ltag)
> 	(aarch64_linux_set_ltag, aarch64_linux_get_ltag): New functions.
> 	* arch/aarch64-mte-linux.h (MTE_LOGICAL_TAG_START_BIT)
> 	(MTE_LOGICAL_MAX_VALUE): Define.
> 	(make_ltag_bits, make_ltag, aarch64_linux_set_ltag)
> 	(aarch64_linux_get_ltag): New prototype.
> ---
>  gdb/aarch64-linux-tdep.c     | 212 +++++++++++++++++++++++++++++++++++
>  gdb/arch/aarch64-mte-linux.c |  36 ++++++
>  gdb/arch/aarch64-mte-linux.h |  19 ++++
>  3 files changed, 267 insertions(+)
> 
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 5f6fb42792..00c4f45035 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -30,6 +30,7 @@
>  #include "symtab.h"
>  #include "tramp-frame.h"
>  #include "trad-frame.h"
> +#include "target.h"
>  #include "target/target.h"
>  
>  #include "regcache.h"
> @@ -46,6 +47,9 @@
>  
>  #include "arch/aarch64-mte-linux.h"
>  
> +#include "arch-utils.h"
> +#include "value.h"
> +
>  /* Signal frame handling.
>  
>        +------------+  ^
> @@ -1437,6 +1441,189 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
>    return {};
>  }
>  
> +/* Helper to get the allocation tag from a 64-bit ADDRESS.
> +
> +   Return 0 for success and non-zero otherwise.  */
> +
> +static int
> +aarch64_linux_get_atag (CORE_ADDR address, CORE_ADDR *tag)
> +{

I'd suggest making the return value a bool.  Or, even better IMO
would be to make the return value gdb::optional<CORE_ADDR>, an
empty optional meaning failure.

> +  gdb::byte_vector tags;
> +
> +  /* Attempt to fetch the allocation tag.  */
> +  if (target_fetch_memtags (address, 0, tags, tag_allocation) != 0)
> +    return 1;
> +
> +  /* Only one tag should've been returned.  Make sure we got exactly that.  */
> +  gdb_assert (tags.size () == 1);
> +
> +  /* Although our tags are 4 bits in size, they are stored in a
> +     byte.  */
> +  *tag = tags[0];
> +
> +  return 0;
> +}
> +
> +/* Implement the tagged_address_p gdbarch method.  */
> +
> +static bool
> +aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, struct value *address)
> +{
> +  gdb_assert (address != nullptr);
> +
> +  CORE_ADDR addr = value_as_address (address);
> +
> +  /* Remove the top byte for the memory range check.  */
> +  addr = address_significant (gdbarch, addr);
> +
> +  /* Check if the page that contains ADDRESS is mapped with PROT_MTE.  */
> +  if (!linux_address_in_memtag_page (addr))
> +    return false;
> +
> +  /* We have a valid tag in the top byte of the 64-bit address.  */
> +  return true;
> +}
> +
> +/* Implement the memtag_mismatch_p gdbarch method.  */
> +
> +static bool
> +aarch64_linux_memtag_mismatch_p (struct gdbarch *gdbarch,
> +				 struct value *address)
> +{
> +  gdb_assert (address != nullptr);
> +
> +  /* Make sure we are dealing with a tagged address to begin with.  */
> +  if (!aarch64_linux_tagged_address_p (gdbarch, address))
> +    return false;
> +
> +  CORE_ADDR addr = value_as_address (address);
> +
> +  /* Fetch the allocation tag for ADDRESS.  */
> +  CORE_ADDR atag = 0;
> +
> +  if (aarch64_linux_get_atag (addr, &atag) != 0)
> +    return false;
> +
> +  /* Fetch the logical tag for ADDRESS.  */
> +  gdb_byte ltag = aarch64_linux_get_ltag (addr);
> +
> +  /* Are the tags the same?  */
> +  if (ltag == atag)
> +    return false;
> +
> +  return true;

That could very well be

  return ltag != atag;

I'm wondering about the potential performance impacts of all this.  When 
memory tagging is in use, how often are the memtag functions expected to be
called?  By the looks of it, it seems like checking for a mismatch does
2 open and parse of /proc/pid/smaps.  Is that right, and is this function
something that is going to be called often, say, when printing values?

> +}
> +
> +/* Implement the set_memtags gdbarch method.  */
> +
> +static int
> +aarch64_linux_set_memtags (struct gdbarch *gdbarch, struct value *address,
> +			   size_t length, const gdb::byte_vector &tags,
> +			   enum memtag_type tag_type)
> +{
> +  if (tags.empty ())
> +    return 0;
> +
> +  gdb_assert (address != nullptr);
> +
> +  CORE_ADDR addr = value_as_address (address);
> +
> +  /* Set the logical tag or the allocation tag.  */
> +  if (tag_type == tag_logical)
> +    {
> +      /* When setting logical tags, we don't care about the length, since
> +	 we are only setting a single logical tag.  */
> +      addr = aarch64_linux_set_ltag (addr, tags[0]);
> +
> +      /* Update the value's content with the tag.  */
> +      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +      gdb_byte *srcbuf = value_contents_raw (address);
> +      store_unsigned_integer (srcbuf, sizeof (addr), byte_order, addr);
> +    }
> +  else
> +    {
> +      /* Make sure we are dealing with a tagged address to begin with.  */
> +      if (!aarch64_linux_tagged_address_p (gdbarch, address))
> +	return 1;
> +
> +      /* With G being the number of tag granules and N the number of tags
> +	 passed in, we can have the following cases:
> +
> +	 1 - G == N: Store all the N tags to memory.
> +
> +	 2 - G < N : Warn about having more tags than granules, but write G
> +		     tags.
> +
> +	 3 - G > N : This is a "fill tags" operation.  We should use the tags
> +		     as a pattern to fill the granules repeatedly until we have
> +		     written G tags to memory.
> +      */
> +
> +      size_t g = get_tag_granules (addr, length, MTE_GRANULE_SIZE);
> +      size_t n = tags.size ();
> +
> +      if (g < n)
> +	{
> +	  warning (_("Got more tags than memory granules.  Tags will be "
> +		     "truncated."));
> +	}

Remove curly braces.

> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
> index e555f0af19..5c5783f28b 100644
> --- a/gdb/arch/aarch64-mte-linux.h
> +++ b/gdb/arch/aarch64-mte-linux.h
> @@ -32,10 +32,29 @@
>  
>  /* We have one tag per 16 bytes of memory.  */
>  #define MTE_GRANULE_SIZE 16
> +#define MTE_LOGICAL_TAG_START_BIT   56
> +#define MTE_LOGICAL_MAX_VALUE	    0xf
>  
>  /* Return the number of tag granules in the memory range
>     [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
>  extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
>  				size_t granule_size);
>  
> +/* Return the 4-bit tag made from VALUE.  */
> +extern CORE_ADDR make_ltag_bits (CORE_ADDR value);

As mentioned previously, I'd suggest giving a name that's better scoped,
since these symbols are in a header file / exported.  Or if they are just
used in aarch64-mte-linux.c, move them there (the defines as well, if
possible).

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-11-09 17:04 ` [PATCH v3 16/24] AArch64: Report tag violation error information Luis Machado
  2020-11-16 15:43   ` David Spickett
@ 2020-12-26 22:23   ` Simon Marchi
  2020-12-30  0:50     ` Luis Machado
  1 sibling, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26 22:23 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
> information can be obtained through the siginfo data structure.
> 
> For AArch64 the Linux kernel may expose the fault address and tag
> information, if we have a synchronous event. Otherwise there is
> no fault address available.

Can you give an example of the end result message?

> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* aarch64-linux-tdep.c
> 	(aarch64_linux_report_signal_info): New function.
> 	(aarch64_linux_init_abi): Register
> 	aarch64_linux_report_signal_info as the report_signal_info hook.
> 	* arch/aarch64-linux.h (SEGV_MTEAERR): Define.
> 	(SEGV_MTESERR): Define.
> ---
>  gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
>  gdb/arch/aarch64-mte-linux.h |  6 ++++
>  2 files changed, 70 insertions(+)
> 
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 39b1790263..70e180e1cb 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
>    return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
>  }
>  
> +/* AArch64 Linux implementation of the report_signal_info gdbarch
> +   hook.  Displays information about possible memory tag violations.  */
> +
> +static void
> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
> +				  struct ui_out *uiout,
> +				  enum gdb_signal siggnal)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
> +    return;
> +
> +  CORE_ADDR fault_addr = 0;
> +  long si_code = 0;
> +
> +  try
> +    {
> +      /* Sigcode tells us if the segfault is actually a memory tag
> +	 violation.  */
> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");

Is the \n necessary?

> +
> +      fault_addr
> +	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> +    }
> +  catch (const gdb_exception &exception)
> +    {
> +      return;
> +    }

I think it's better to catch gdb_exception_error, to avoid catching ^C
(gdb_exception_quit).

And if there's an error doing the evaluation... do we want to print
a warning of some sort?

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 17/24] AArch64: Add gdbserver MTE support
  2020-11-09 17:04 ` [PATCH v3 17/24] AArch64: Add gdbserver MTE support Luis Machado
@ 2020-12-26 22:30   ` Simon Marchi
  2020-12-29 14:32     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-26 22:30 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v2:
> 
> - Updated target methods to contain a tag type parameter.
> 
> --
> 
> Adds the AArch64-specific memory tagging support (MTE) by implementing the
> required hooks and checks for GDBserver.
> 
> gdbserver/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* Makefile.in (SFILES): Add /../gdb/nat/aarch64-mte-linux-ptrace.c.
> 	* configure.srv (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o and
> 	nat/aarch64-mte-linux-ptrace.o.
> 	* linux-aarch64-low.cc: Include nat/aarch64-mte-linux-ptrace.h.
> 	(class aarch64_target) <supports_memory_tagging>
> 	<fetch_memtags, store_memtags>: New method overrides.
> 	(aarch64_target::supports_memory_tagging)
> 	(aarch64_target::fetch_memtags)
> 	(aarch64_target::store_memtags): New methods.
> ---
>  gdbserver/Makefile.in          |  1 +
>  gdbserver/configure.srv        |  2 ++
>  gdbserver/linux-aarch64-low.cc | 61 ++++++++++++++++++++++++++++++++++
>  3 files changed, 64 insertions(+)
> 
> diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
> index 1969ed0ec3..45b605c3b5 100644
> --- a/gdbserver/Makefile.in
> +++ b/gdbserver/Makefile.in
> @@ -221,6 +221,7 @@ SFILES = \
>  	$(srcdir)/../gdb/arch/ppc-linux-common.c \
>  	$(srcdir)/../gdb/arch/riscv.c \
>  	$(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \
> +	$(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \
>  	$(srcdir)/../gdb/nat/linux-btrace.c \
>  	$(srcdir)/../gdb/nat/linux-namespaces.c \
>  	$(srcdir)/../gdb/nat/linux-osdata.c \
> diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
> index 833ad27c4c..0bbd990758 100644
> --- a/gdbserver/configure.srv
> +++ b/gdbserver/configure.srv
> @@ -52,8 +52,10 @@ case "${gdbserver_host}" in
>  			srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o"
>  			srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o"
>  			srv_tgtobj="$srv_tgtobj arch/aarch64.o"
> +			srv_tgtobj="$srv_tgtobj arch/aarch64-mte-linux.o"
>  			srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o"
>  			srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o"
> +			srv_tgtobj="$srv_tgtobj nat/aarch64-mte-linux-ptrace.o"

Please keep the list sorted.

> +int
> +aarch64_target::fetch_memtags (CORE_ADDR address, size_t len,
> +			       gdb::byte_vector &tags, int type)
> +{
> +  /* Allocation tags are per-process, so any tid is fine.  */
> +  int tid = lwpid_of (current_thread);
> +
> +  /* Allocation tag?  */
> +  if (type == 1)
> +    return aarch64_mte_fetch_memtags (tid, address, len, tags);

Is there a define you could use instead of the magic "1"?

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 19/24] New mtag commands
  2020-11-09 17:04 ` [PATCH v3 19/24] New mtag commands Luis Machado
@ 2020-12-27  3:32   ` Simon Marchi
  2020-12-29 17:21     ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-27  3:32 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> Add new commands under the "mtag" prefix to allow users to inspect, modify and
> check memory tags in different ways.
> 
> The available subcommands are the following:
> 
> - mtag showltag <expression>: Shows the logical tag for a particular address.
> 
> - mtag withltag <expression> <tag>: Prints the address tagged with the logical
>   tag <tag>.
> 
> - mtag showatag <expression>: Shows the allocation tag for a particular address.
> 
> - mtag setatag <expression> <length> <tags>: Sets one or more allocation tags to
>   the specified tags.
> 
> - mtag check <expression>: Check if the logical tag in <address> matches its
>   allocation tag.

The only thing that bugs me here is the command names.  I'm sure we could bikeshed
for ever about this, but here are my comments:

 - I don't really like the "everything glued together" style, that makes it harder
   to read the name.  For instance, I don't like the existing "set remoteaddresssize"
   command, that's just ugly.  We usually separate words with dashes.
 - I don't really like the use of abbreviations (especially one-letter abbreviations)
   in commands, as it's not good for discoverability.  I would prefer if we used full
   names, for clarity, and if you really want a short version, add an alias.  My
   opinion is that with tab-completion, long (but clear) command names are not really
   an issue.

So:

 - mtag show-logical-tag
 - mtag with-logical-tag
 - mtag show-allocation-tag
 - mtag set-allocation-tag

And the "mtag" prefix... maybe "memory-tag", or "mem-tag" at least?  It's not obvious
that the "m" stands for "memory", 

> 
> These commands make use of the memory tagging gdbarch methods, and are still
> available, but disabled, when memory tagging is not supported by the
> architecture.
> 
> I've pondered about a way to make these commands invisible when memory tagging
> is not available, but given the check is at runtime (and support may come and go
> based on a process' configuration), that is a bit too late in the process to
> either not include the commands or get rid of them.

I think it's fine if the commands are always there, because it just says "this
architecture does not support memory tagging" if you try to use them with an
architecture that does not support memory tagging.

FYI, I get this when trying to build this patch:

  CXX    printcmd.o
cc1plus: warning: command-line option ‘-Wmissing-prototypes’ is valid for C/ObjC but not for C++
/home/simark/src/binutils-gdb/gdb/printcmd.c: In function ‘void parse_withltag_input(const char*, value**, gdb::byte_vector&, value_print_options*)’:
/home/simark/src/binutils-gdb/gdb/printcmd.c:2918:10: error: ‘hex2bin’ was not declared in this scope
 2918 |   tags = hex2bin (s_tag.c_str ());
      |          ^~~~~~~
/home/simark/src/binutils-gdb/gdb/printcmd.c: In function ‘void parse_setatag_input(const char*, value**, size_t*, gdb::byte_vector&)’:
/home/simark/src/binutils-gdb/gdb/printcmd.c:2997:10: error: ‘hex2bin’ was not declared in this scope
 2997 |   tags = hex2bin (s_tags.c_str ());
      |          ^~~~~~~


> 
> Ideas are welcome.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* printcmd.c: Include gdbsupport/rsp-low.h.
> 	(mtaglist): New static global.
> 	(process_print_command_args): Factored out of
> 	print_command_1.
> 	(print_command_1): Use process_print_command_args.
> 	(show_addr_not_tagged, show_memtag_unsupported, mtag_command)
> 	(mtag_showtag_command, mtag_showltag_command, mtag_showatag_command)
> 	(parse_withltag_input, mtag_withltag_command, parse_setatag_input)
> 	(mtag_setatag_command, mtag_check_command): New functions.
> 	(_initialize_printcmd): Add "mtag" prefix and subcommands.
> 
> gdbsupport/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* rsp-low.cc (fromhex): Change error message text to not be
> 	RSP-specific.

Then, this function should probably be moved out of rsp-low.cc, perhaps
to common-utils.cc.

> ---
>  gdb/printcmd.c        | 359 ++++++++++++++++++++++++++++++++++++++++--
>  gdbsupport/rsp-low.cc |   2 +-
>  2 files changed, 348 insertions(+), 13 deletions(-)
> 
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index 28451612ab..6949678235 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -53,6 +53,11 @@
>  #include "source.h"
>  #include "gdbsupport/byte-vector.h"
>  #include "gdbsupport/gdb_optional.h"
> +#include "gdbsupport/rsp-low.h"
> +
> +/* Chain containing all defined mtag subcommands.  */
> +
> +struct cmd_list_element *mtaglist;

static?

>  
>  /* Last specified output format.  */
>  
> @@ -1219,31 +1224,38 @@ print_value (value *val, const value_print_options &opts)
>    annotate_value_history_end ();
>  }
>  
> -/* Implementation of the "print" and "call" commands.  */
> +/* Helper for parsing arguments for print_command_1.  */
>  
> -static void
> -print_command_1 (const char *args, int voidprint)
> +static struct value *
> +process_print_command_args (const char *args, value_print_options *print_opts)
>  {
> -  struct value *val;
> -  value_print_options print_opts;
> -
> -  get_user_print_options (&print_opts);
> +  get_user_print_options (print_opts);
>    /* Override global settings with explicit options, if any.  */
> -  auto group = make_value_print_options_def_group (&print_opts);
> +  auto group = make_value_print_options_def_group (print_opts);
>    gdb::option::process_options
>      (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group);
>  
> -  print_command_parse_format (&args, "print", &print_opts);
> +  print_command_parse_format (&args, "print", print_opts);
>  
>    const char *exp = args;
>  
>    if (exp != nullptr && *exp)
>      {
>        expression_up expr = parse_expression (exp);
> -      val = evaluate_expression (expr.get ());
> +      return evaluate_expression (expr.get ());
>      }
> -  else
> -    val = access_value_history (0);
> +
> +  return access_value_history (0);
> +}
> +
> +/* Implementation of the "print" and "call" commands.  */
> +
> +static void
> +print_command_1 (const char *args, int voidprint)
> +{
> +  value_print_options print_opts;
> +
> +  struct value *val = process_print_command_args (args, &print_opts);
>  
>    if (voidprint || (val && value_type (val) &&
>  		    value_type (val)->code () != TYPE_CODE_VOID))
> @@ -2711,6 +2723,273 @@ eval_command (const char *arg, int from_tty)
>    execute_command (expanded.c_str (), from_tty);
>  }
>  
> +/* Convenience function for error checking in mtag commands.  */
> +
> +static void
> +show_addr_not_tagged (CORE_ADDR address)
> +{
> +  error (_("Address %s not in a region mapped with a memory tagging flag."),
> +	 paddress (target_gdbarch (), address));
> +}
> +
> +/* Convenience function for error checking in mtag commands.  */
> +
> +static void
> +show_memtag_unsupported (void)
> +{
> +  error (_("Memory tagging not supported or disabled by the current"
> +	   " architecture."));
> +}
> +
> +/* Implement the "mtag" prefix command.  */
> +
> +static void
> +mtag_command (const char *arg, int from_tty)
> +{
> +  help_list (mtaglist, "mtag ", all_commands, gdb_stdout);
> +}
> +
> +/* Helper for showltag and showatag.  */
> +
> +static void
> +mtag_showtag_command (const char *args, enum memtag_type tag_type)
> +{
> +  if (args == nullptr)
> +    error_no_arg (_("address or pointer"));
> +
> +  /* Parse args into a value.  If the value is a pointer or an address,
> +     then fetch the logical or allocation tag.  */
> +  value_print_options print_opts;
> +
> +  struct value *val = process_print_command_args (args, &print_opts);
> +
> +  /* If the address is not in a region memory mapped with a memory tagging
> +     flag, it is no use trying to access/manipulate its allocation tag.
> +
> +     It is OK to manipulate the logical tag though.  */
> +  if (tag_type == tag_allocation
> +      && !gdbarch_tagged_address_p (target_gdbarch (), val))
> +    show_addr_not_tagged (value_as_address (val));
> +
> +  std::string tag = gdbarch_memtag_to_string (target_gdbarch (),
> +					      val, tag_type);
> +  if (tag.empty ())
> +    printf_filtered (_("%s tag unavailable.\n"),
> +		     tag_type == tag_logical? "Logical" : "Allocation");
> +
> +  struct value *v_tag = process_print_command_args (tag.c_str (),
> +						    &print_opts);
> +  print_opts.output_format = 'x';
> +  print_value (v_tag, print_opts);

When I read the patch description, I almost mentioned that it might make
sense to name the commands "print-xyz" instead of "show-xyz".  "print" is
used to print values, while "show" is used to show parameter values.  The
new commands are more print-like IMO.  And the fact that they share print's
syntax, I think it would make even more sense.

To be clear, I'm proposing that we name the sub-commands "print-logical-tag"
and "print-allocation-tag".

> +}
> +
> +/* Implement the "mtag showltag" command.  */
> +
> +static void
> +mtag_showltag_command (const char *args, int from_tty)
> +{
> +  if (!memtag || !target_supports_memory_tagging ())
> +    show_memtag_unsupported ();
> +
> +  mtag_showtag_command (args, tag_logical);
> +}
> +
> +/* Implement the "mtag showatag" command.  */
> +
> +static void
> +mtag_showatag_command (const char *args, int from_tty)
> +{
> +  if (!memtag || !target_supports_memory_tagging ())
> +    show_memtag_unsupported ();
> +
> +  mtag_showtag_command (args, tag_allocation);
> +}
> +
> +/* Parse ARGS and extract ADDR and TAG.
> +   ARGS should have format <expression> <tag bytes>.  */
> +
> +static void
> +parse_withltag_input (const char *args, struct value **val,
> +		      gdb::byte_vector &tags, value_print_options *print_opts)
> +{
> +  /* Given <expression> can be reasonably complex, we parse things backwards
> +     so we can isolate the <tag bytes> portion.  */

This comment doesn't seem to agree with the implementation, or I'm missing
something.  I don't see any things being parsed backwards.

> +
> +  /* Fetch the address.  */
> +  std::string s_address = extract_string_maybe_quoted (&args);
> +
> +  /* Parse the address into a value.  */
> +  *val = process_print_command_args (s_address.c_str (), print_opts);
> +
> +  /* Fetch the tag bytes.  */
> +  std::string s_tag = extract_string_maybe_quoted (&args);
> +
> +  /* Validate the input.  */
> +  if (s_address.empty () || s_tag.empty ())
> +    error (_("Missing arguments."));
> +
> +  if (s_tag.length () % 2)
> +    error (_("Error parsing tags argument. The tag should be 2 digits."));

I think the error message is a bit confusing.  At least, it doesn't match the
check.  Should it be "the tag(s) should be an even number of digits"?

> +
> +  tags = hex2bin (s_tag.c_str ());
> +}
> +
> +/* Implement the "mtag withltag" command.  */
> +
> +static void
> +mtag_withltag_command (const char *args, int from_tty)
> +{
> +  if (!memtag || !target_supports_memory_tagging ())
> +    show_memtag_unsupported ();
> +
> +  if (args == nullptr)
> +    error_no_arg (_("<address> <tag>"));
> +
> +  gdb::byte_vector tags;
> +  struct value *val;
> +  value_print_options print_opts;
> +
> +  /* Parse the input.  */
> +  parse_withltag_input (args, &val, tags, &print_opts);
> +
> +  /* Setting the logical tag is just a local operation that does not touch
> +     any memory from the target.  Given an input value, we modify the value
> +     to include the appropriate tag.
> +
> +     For this reason we need to cast the argument value to a
> +     (void *) pointer.  This is so we have the right the for the gdbarch

This sentence looks broken.

> +     hook to manipulate the value and insert the tag.
> +
> +     Otherwise, this would fail if, for example, GDB parsed the argument value
> +     into an int-sized value and the pointer value has a type of greater
> +     length.  */
> +
> +  /* Cast to (void *).  */
> +  val = value_cast (builtin_type (target_gdbarch ())->builtin_data_ptr,
> +		    val);
> +
> +  if (gdbarch_set_memtags (target_gdbarch (), val, 0, tags,
> +			   tag_logical) != 0)
> +    printf_filtered (_("Could not update the logical tag data.\n"));
> +  else
> +    {
> +      /* Always print it in hex format.  */
> +      print_opts.output_format = 'x';
> +      print_value (val, print_opts);
> +    }
> +}
> +
> +/* Parse ARGS and extract ADDR, LENGTH and TAGS.  */
> +
> +static void
> +parse_setatag_input (const char *args, struct value **val, size_t *length,
> +		     gdb::byte_vector &tags)
> +{
> +  /* Fetch the address.  */
> +  std::string s_address = extract_string_maybe_quoted (&args);
> +
> +  /* Parse the address into a value.  */
> +  value_print_options print_opts;
> +  *val = process_print_command_args (s_address.c_str (), &print_opts);
> +
> +  /* Fetch the length.  */
> +  std::string s_length = extract_string_maybe_quoted (&args);
> +
> +  /* Fetch the tag bytes.  */
> +  std::string s_tags = extract_string_maybe_quoted (&args);
> +
> +  /* Validate the input.  */
> +  if (s_address.empty () || s_length.empty () || s_tags.empty ())
> +    error (_("Missing arguments."));
> +
> +  errno = 0;
> +  *length = strtoulst (s_length.c_str (), NULL, 10);
> +  if (errno != 0)
> +    error (_("Error parsing length argument."));
> +
> +  if (s_tags.length () % 2)
> +    error (_("Error parsing tags argument. Tags should be 2 digits per byte."));
> +
> +  tags = hex2bin (s_tags.c_str ());
> +
> +  /* If the address is not in a region memory mapped with a memory tagging
> +     flag, it is no use trying to access/manipulate its allocation tag.  */
> +  if (!gdbarch_tagged_address_p (target_gdbarch (), *val))
> +    show_addr_not_tagged (value_as_address (*val));
> +}
> +
> +/* Implement the "mtag setatag" command.
> +   ARGS should be in the format <address> <length> <tags>.  */
> +
> +static void
> +mtag_setatag_command (const char *args, int from_tty)
> +{
> +  if (!memtag || !target_supports_memory_tagging ())
> +    show_memtag_unsupported ();
> +
> +  if (args == nullptr)
> +    error_no_arg (_("<starting address> <length> <tag bytes>"));
> +
> +  gdb::byte_vector tags;
> +  size_t length = 0;
> +  struct value *val;
> +
> +  /* Parse the input.  */
> +  parse_setatag_input (args, &val, &length, tags);
> +
> +  if (gdbarch_set_memtags (target_gdbarch (), val, length, tags,
> +			   tag_allocation) != 0)
> +    printf_filtered (_("Could not update the allocation tag(s).\n"));
> +  else
> +    printf_filtered (_("Allocation tag(s) updated successfully.\n"));
> +}
> +
> +/* Implement the "mtag check" command.  */
> +
> +static void
> +mtag_check_command (const char *args, int from_tty)
> +{
> +  if (!memtag || !target_supports_memory_tagging ())
> +    show_memtag_unsupported ();
> +
> +  if (args == nullptr)
> +    error (_("Argument required (address or pointer)"));
> +
> +  /* Parse the expression into a value.  If the value is an address or
> +     pointer, then check its logical tag against the allocation tag.  */
> +  value_print_options print_opts;
> +
> +  struct value *val = process_print_command_args (args, &print_opts);
> +
> +  /* If the address is not in a region memory mapped with a memory tagging
> +     flag, it is no use trying to access/manipulate its allocation tag.  */
> +  if (!gdbarch_tagged_address_p (target_gdbarch (), val))
> +    show_addr_not_tagged (value_as_address (val));
> +
> +  CORE_ADDR addr = value_as_address (val);
> +
> +  /* If memory tagging validation is on, check if the tag is valid.  */

This comment doesn't seem in-line with the implementation, there is no
check here whether the mem tag validation is on or off.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-11-09 17:04 ` [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging Luis Machado
  2020-11-09 17:14   ` Eli Zaretskii
@ 2020-12-27  4:18   ` Simon Marchi
  2020-12-29 18:50     ` Luis Machado
  1 sibling, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-27  4:18 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> The "print" command will point out any possible tag mismatches it finds
> when dealing with pointers, in case such a pointer is tagged.  No additional
> modifiers are needed.
> 
> Suppose we have a pointer "p" with value 0x1234 (logical tag 0x0) and that we
> have an allocation tag of 0x1 for that particular area of memory. This is the
> expected output:
> 
> (gdb) p/x p
> Logical tag (0x0) does not match the allocation tag (0x1).
> $1 = 0x1234

Should there be an option to print to enable/disable this behavior?
Something like "print -memory-tags-violations <on|off>", and a
corresponding "set print memory-tags-violations <on|off>"?

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 24/24] Add memory tagging testcases
  2020-11-09 17:04 ` [PATCH v3 24/24] Add memory tagging testcases Luis Machado
  2020-11-16 15:47   ` David Spickett
@ 2020-12-27  4:36   ` Simon Marchi
  2020-12-29 19:32     ` Luis Machado
  1 sibling, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2020-12-27  4:36 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
> +# Targets that don't support memory tagging should not execute the
> +# runtime memory tagging tests.
> +if {![supports_memtag]} {
> +    untested "memory tagging unsupported"

Use unsupported?

https://www.gnu.org/software/dejagnu/manual/unsupported-procedure.html

> +    return -1
> +}
> +
> +gdb_breakpoint "access_memory"
> +
> +if [gdb_continue "access_memory"] {
> +    fail "could not run to tagged memory test function"

gdb_continue will already produce a FAIL, so no need to use another one here.

> +    return -1
> +}
> +
> +# Fetch a known pointer to an area mapped with PROT_MTE.
> +set tagged_ptr_symbol "tagged_ptr"
> +set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
> +
> +if {$tagged_ptr_addr == -1} {
> +    untested "unexpected pointer or tag value"

If that happens, that would be an expected error in the test that should be
fixed, right?  If so, I'd suggest using "unresolved".  We should be able to
get that value, if we can't something is wrong (it's not just a matter of
something being unsupported).

> +    return -1
> +}
> +
> +# Fetch a known pointer to an area not mapped with PROT_MTE.
> +set untagged_ptr_symbol "untagged_ptr"
> +set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
> +
> +if {$untagged_ptr_addr == -1} {
> +    untested "unexpected pointer or tag value"

Same here.

> +with_test_prefix "symbolic" {
> +    # Test inspecting an allocation tag from a pointer to a memory area that
> +    # is not mapped with PROT_MTE.
> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
> +    gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
> +	     "mtag showatag with an untagged address"
> +
> +    gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
> +	     "mtag setatag with an untagged address"
> +
> +    # Test setting and showing the logical tags for a literal address.
> +    for {set i 0} {$i < 32} {incr i} {
> +	set addr_tagged 0
> +
> +	with_test_prefix "tag ${i}" {
> +	    set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +	    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +			       "update value of symbol ${tagged_ptr_symbol}"
> +	}
> +
> +	set tag_hexnz [get_hex_tag [expr $i % 16]]
> +	gdb_test "mtag showltag ${tagged_ptr_symbol}" \
> +		 " = 0x${tag_hexnz}" \
> +		 "showltag with tag ${i}"
> +
> +	set tag_hexnn [get_tag_nn $i]
> +	gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
> +		 " = \\(void \\*\\) ${addr_tagged}" \
> +		 "withltag with tag ${i}"
> +    }
> +
> +    # Reset the tagged ptr to its original value
> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> +		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> +
> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
> +    # Test setting and showing the allocation tags.
> +    for {set i 0} {$i < 32} {incr i} {
> +
> +	set tag_hexnn [get_tag_nn $i]
> +	gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> +		 $setatag_msg \
> +		 "setatag with tag ${i}"
> +
> +	set tag_hexnz [get_hex_tag [expr $i % 16]]
> +	gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
> +		 "showatag with tag ${i}"
> +    }
> +
> +    # Test tag mismatches.
> +    with_test_prefix "tag mismatches" {
> +	for {set i 0} {$i < 32} {incr i} {
> +
> +	    # Set the allocation tag to a known value (0).
> +	    set tag_hexnn [get_tag_nn $i]
> +	    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> +		     $setatag_msg \
> +		     "setatag with tag ${i}"
> +
> +	    set atag_hexnz [get_hex_tag [expr $i % 16]]
> +
> +	    # Validate that the logical tag matches the allocation tag.
> +	    with_test_prefix "tag ${i}" {
> +		set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> +	    }
> +
> +	    with_test_prefix "tag ${i}" {
> +		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +				   "set ${tagged_ptr_symbol} to a matching logical tag"
> +	    }
> +
> +	    gdb_test "mtag check ${tagged_ptr_symbol}" \
> +		     "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
> +		     "check match with tag ${i}"
> +
> +	    # Get a pointer with the logical tag that does not match the
> +	    # allocation tag.
> +	    set ltag [expr $i + 1]
> +	    with_test_prefix "fetch mismatch tag ${i}" {
> +		set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
> +	    }
> +
> +	    with_test_prefix "tag ${i}" {
> +		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> +				   "set ${tagged_ptr_symbol} to a mismatching logical tag"
> +	    }
> +
> +	    # Validate that the logical tag does not match the allocation
> +	    # tag.
> +	    set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
> +	    gdb_test "mtag check ${tagged_ptr_symbol}" \
> +		     "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
> +		     "check mismatch with tag ${i}"
> +	}
> +    # Reset the tagged ptr to its original value
> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> +		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"

The indentation is off here.

> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 55154db6a5..347704ce0a 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
>      }
>  }
>  
> +# Return 1 if memory tagging is supported at runtime, otherwise return 0.
> +
> +proc supports_memtag {} {

Should this use gdb_caching_proc?

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 01/24] New target methods for memory tagging support
  2020-12-25  4:26   ` Simon Marchi
@ 2020-12-28 15:05     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 15:05 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 1:26 AM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v3:
>>
>> - Updated the code documentation for the fetch_memtags and store_memtags
>>    methods.
>>
>> Updates on v2:
>>
>> - Added type parameter to fetch_memtags/store_memtags hooks.
>>
>> --
>>
>> This patch starts adding some of the generic pieces to accomodate memory
>> tagging.
>>
>> We have three new target methods:
>>
>> - supports_memory_tagging: Checks if the target supports memory tagging. This
>>    defaults to false for targets that don't support memory tagging.
>>
>> - fetch_memtags: Fetches the allocation tags associated with a particular
>>    memory range [address, address + length).
>>
>>    The default is to return 0 without returning any tags. This should only
>>    be called if memory tagging is supported.
>>
>> - store_memtags: Stores a set of allocation tags for a particular memory
>>    range [address, address + length).
>>
>>    The default is to return 0. This should only
>>    be called if memory tagging is supported.
> 
> If fetch/store should only be called on targets for which supports_memory_tagging
> returns true, why is the default to return 0?

The text tries to make it more obvious that the architecture needs to 
support memory tagging before invoking these functions. It isn't the 
case for native targets, but we will always have target implementations 
for the remote targets.

There is a corner case for extended-remote where we connect to the 
target, but don't have any inferiors running. That means we don't get 
qSupported features and can't really be sure if the target supports 
memory tagging or not.

I think it is unlikely someone will invoke these functions incorrectly 
though.

> 
> It seems to me like it should be either:
> 
> - it's ok to call fetch/store on any target, if the target doesn't implement memtags,
>    the default of returning 0 is used
> - it's only ok to call fetch/store on targets that implement memtags, in which case
>    I would expect the default to maybe be tcomplain or even an assert
> 
> Or is there something I don't see?
> 

No. That makes sense. I've changed this to a tcomplain for both 
implementations.

>>
>> It also adds a control option for enabling/disabling memory tagging
>> manually: set memory-tagging on/off.
>>
>> The default is "on", with GDB making its use conditional to the
>> architecture supporting memory tagging.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* printcmd.c (memtag): New static global.
>> 	(show_memtag): New function.
>> 	(_initialize_printcmd): Add set/show memory-tagging command.
>> 	* remote.c (remote_target) <supports_memory_tagging>: New method
>> 	override.
>> 	<fetch_memtags>: New method override.
>> 	<store_memtags>: New method override.
>> 	(remote_target::supports_memory_tagging): New method.
>> 	(remote_target::fetch_memtags): New method.
>> 	(remote_target::store_memtags): New method.
>> 	* target-delegates.c
>> 	(dummy_target) <supports_memory_tagging>: New method override.
>> 	<fetch_memtags>: New method override.
>> 	<store_memtags>: New method override.
>> 	(debug_target) <supports_memory_tagging>: New method override.
>> 	<fetch_memtags>: New method override.
>> 	<store_memtags>: New method override.
>> 	(target_ops::supports_memory_tagging): New method.
>> 	(target_ops::fetch_memtags): New method.
>> 	(target_ops::store_memtags): New method.
>> 	(dummy_target::supports_memory_tagging): New method.
>> 	(dummy_target::fetch_memtags): New method.
>> 	(dummy_target::store_memtags): New method.
>> 	(debug_target::supports_memory_tagging): New method.
>> 	(debug_target::fetch_memtags): New method.
>> 	(debug_target::store_memtags): New method.
> 
> Oh, you wrote this by hand :(.  target-delegates.c is generated (see the
> command at the top of the file).

Yikes. I see that now. Glad to not have to write one more piece of 
ChangeLog! :-)

> 
> Otherwise, that LGTM.
> 
> Simon
>
About returning bool... I recall we touched this subject before. The 
integer return was supposed to cover cases where we wanted to return 
error codes.

But, given we don't have any clearly defined error codes at the moment, 
I'll stick with bool for success/failure.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 02/24] New gdbarch memory tagging hooks
  2020-12-25  4:40   ` Simon Marchi
@ 2020-12-28 15:44     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 15:44 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 1:40 AM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> We need some new gdbarch hooks to help us manipulate memory tags without having
>> to have GDB calls the target methods directly.
> 
> calls -> call?
> 

Fixed.

>>
>> This patch adds the following hooks:
>>
>> gdbarch_memtag_to_string
>> --
>> Returns a printable string corresponding to the tag.
>>
>> gdbarch_tagged_address_p
>> --
>> Checks if a particular address is protected with memory tagging.
>>
>> gdbarch_memtag_mismatch_p
>> --
>> Checks if there is a mismatch between the logical tag of a pointer and the
>> allocation tag.
> 
> It would seem more natural to me to have gdbarch_memtag_matches_p
> instead,which would just be the opposite gdbarch_memtag_mismatch_p.
> If I want to know if a tag matches, I have to do:
> 
>    if (!gdbarch_memtag_mismatch_p (...))
> 
> and that's like a double negative, "if the memtag does not not match".
> 

Mismatches are what we're looking for, so I named it based on that. But 
I see your point. I've renamed it to gdbarch_memtag_matches_p

>> gdbarch_set_memtags:
>> --
>> Sets either the allocation tag or the logical tag for a particular value.
>>
>> gdbarch_get_memtag:
>> --
>> Gets either the allocation tag or the logical tag for a particular value.
>>
>> gdbarch_granule_size
>> --
>> Sets the memory tag granule size, which represents the number of bytes a
>> particular allocation tag covers. For example, this is 16 bytes for
>> AArch64's MTE.
> 
> I'd suggest having "memtag" in the name of this function, to make it clear
> it's memtag-related.  Like "gdbarch_memtag_granule_size".

I think I only messed up the text, because the code is already as suggested.

> 
>>
>> I've used struct value as opposed to straight CORE_ADDR so other architectures
>> can use the infrastructure without having to rely on fixed types.
> 
> What do you mean by "having to rely on fixed types"?
> 

Instead of assuming the tagged address will fit in a CORE_ADDR, for 
example, we use a "struct value *" to cope with architectures that have 
addresses that are larger than a CORE_ADDR or that have completely 
different types.

CHERI/Morello is one such example. The pointers will be capability types 
of 16 bytes, with a tag stored as metadata. So this patch makes it 
possible to support those architectures in the future.

Using "struct value *" also prevents generic code from having to know 
what specific types/sizes we're dealing with.

Does that make it clear?


> Otherwise, this LGTM.
> 
> Simon
> 

Thanks for the review.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 03/24] Add GDB-side remote target support for memory tagging
  2020-12-25  5:08   ` Simon Marchi
@ 2020-12-28 16:28     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 16:28 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 2:08 AM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updates for v2:
>>
>> - Add type field to target hooks.
>> - Add type data to qMemTags and QMemTags. The packets now look like this:
>>
>> qMemTags:<address>,<length>:<type>
>> QMemTags:<address>,<length>:<type>:<uninterpreted tag bytes>
>>
>> --
>>
>> This patch adds memory tagging support to GDB's remote side, with
>> packet string checks, new packet support and an implementation of
>> the two new tags methods fetch_atags and store_atags.
> 
> fetch_memtags / store_memtags ?
> 

Yeah. This (and others below) are an artifact of some back-and-forth on 
reasonable names. Fixed now.

>>
>> GDBserver needs to know how to read/write allocation tags, since that is
>> done via ptrace.  It doesn't need to know about logical tags.
>>
>> The new packets are:
>>
>> qMemTags:<address>,<length>
>> --
>>
>> Reads tags from the address range [<address>, <address + length>)
>>
>> QMemTags:<address>,<length>:<uninterpreted tag bytes>
>> --
>> Writes the tags represented by the uninterpreted bytes to the address range
>> [<address>, <address + length>).
> 
> Should the packet description above be updated to include the "type" field?
> 

Yes. Fixed now.

>> @@ -14404,7 +14422,65 @@ set_range_stepping (const char *ignore_args, int from_tty,
>>   bool
>>   remote_target::supports_memory_tagging ()
>>   {
>> -  return false;
>> +  return remote_memory_tagging_p ();
>> +}
>> +
>> +/* Create the qMemTags packet given ADDRESS, LEN and TYPE.
>> +
>> +   Return 0 if successful, non-zero otherwise.  */
>> +
>> +static void
>> +create_fmemtags_request (gdb::char_vector &packet, CORE_ADDR address,
>> +			 size_t len, int type)
> 
> The comment is wrong, the function does not return anything.
> 
> Why "fmemtags"?  Oh, it's for "fetch".  I'd prefer if you spelled
> it completely (create_fetch_memtags_request), it's not very clear
> otherwise (same for smemtags).
> 

Exactly. Updated now to spell it completely.

>> +{
>> +  int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
>> +
>> +  std::string request = string_printf ("qMemTags:%s,%s:%s",
>> +				       phex_nz (address, addr_size),
>> +				       phex_nz (len, sizeof (len)),
>> +				       phex_nz (type, sizeof (type)));
>> +
>> +  strcpy (packet.data (), request.c_str ());
>> +}
>> +
>> +/* Parse the qMemTags packet reply into TAGS.
>> +
>> +   Return 0 if successful, non-zero otherwise.  */
>> +
>> +static int
>> +parse_fmemtags_reply (gdb::char_vector &reply, gdb::byte_vector &tags)
> 
> reply should be const, the return value should be bool.
> 

Fixed now.

> Otherwise, LGTM.
> 
> Simon
> 

Thanks!

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling
  2020-12-25  5:34   ` Simon Marchi
@ 2020-12-28 17:17     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 17:17 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 2:34 AM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updated in v2:
>>
>> - Adjusted unit tests to cope with new type field in the remote packets.
>>
>> --
>>
>> Include some unit testing for the functions handling the new qMemTags and
>> QMemTags packets.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* remote: Include gdbsupport/selftest.h.
>> 	(test_memory_tagging_functions): New function.
>> 	(_initialize_remote): Register test_memory_tagging_functions.
>> ---
>>   gdb/remote.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 89 insertions(+)
>>
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index e45eef4bee..6db7a74542 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -79,6 +79,7 @@
>>   #include <algorithm>
>>   #include <unordered_map>
>>   #include "async-event.h"
>> +#include "gdbsupport/selftest.h"
>>   
>>   /* The remote target.  */
>>   
>> @@ -14529,6 +14530,89 @@ remote_target::store_memtags (CORE_ADDR address, size_t len,
>>     return 0;
>>   }
>>   
>> +#if GDB_SELF_TEST
>> +
>> +namespace selftests {
>> +
>> +static void
>> +test_memory_tagging_functions (void)
> 
> Remove "void".
> 

Fixed.

>> +{
>> +  remote_target remote;
>> +
>> +  struct packet_config *config
>> +    = &remote_protocol_packets[PACKET_memory_tagging_feature];
>> +
>> +  /* Test memory tagging packet support.  */
>> +  config->support = PACKET_SUPPORT_UNKNOWN;
>> +  SELF_CHECK (remote.supports_memory_tagging () == false);
>> +  config->support = PACKET_DISABLE;
>> +  SELF_CHECK (remote.supports_memory_tagging () == false);
>> +  config->support = PACKET_ENABLE;
>> +  SELF_CHECK (remote.supports_memory_tagging () == true);
> 
> This seems to set the global flag of whether the remote side supports
> memory tagging.  Even though it's not likely to be a real problem, IWBN
> to restore the global state that you touch.
> 

Good catch. I've fixed this with a scoped_restore.

> Otherwise, LGTM.
> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 05/24] GDBserver remote packet support for memory tagging
  2020-12-25  5:50   ` Simon Marchi
@ 2020-12-28 17:46     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 17:46 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 2:50 AM, Simon Marchi wrote:
>> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
>> index 95db9807a9..7eddd0e01f 100644
>> --- a/gdbserver/server.cc
>> +++ b/gdbserver/server.cc
>> @@ -547,12 +547,71 @@ handle_btrace_conf_general_set (char *own_buf)
>>     return 1;
>>   }
>>   
>> +/* Create the qMemTags packet reply given TAGS.  */
>> +
>> +static int
>> +create_fmemtags_reply (char *reply, const gdb::byte_vector &tags)
>> +{
>> +  /* It is an error to pass a zero-sized tag vector.  */
>> +  if (tags.size () == 0)
>> +    return 1;
> 
> If this catches a logic error in GDBserver, this should be an assert.
> 

That makes sense. Fixed with an assertion.

>> +
>> +  std::string packet ("m");
>> +
>> +  /* Write the tag data.  */
>> +  packet += bin2hex (tags.data (), tags.size ());
>> +
>> +  /* Check if the reply is too big for the packet to handle.  */
>> +  if (PBUFSIZ < packet.size ())
>> +    return 1;
>> +
>> +  strcpy (reply, packet.c_str ());
>> +  return 0;
>> +}
>> +
>> +/* Parse the QMemTags request into ADDR, LEN and TAGS.
>> +
>> +   Return 0 if successful, non-zero otherwise.  */
>> +
>> +static int
>> +parse_smemtags_request (char *request, CORE_ADDR *addr, size_t *len,
>> +			gdb::byte_vector &tags, int *type)
>> +{
>> +  if (!startswith (request, "QMemTags:"))
>> +    return 1;
> 
> That check seems unnecessary, or maybe I'd convert it to an assert.
>

I've converted both occurrences of this to an assertion, just to be safe.

  >> diff --git a/gdbserver/server.h b/gdbserver/server.h
>> index 22228050a8..3d4a086e18 100644
>> --- a/gdbserver/server.h
>> +++ b/gdbserver/server.h
>> @@ -190,6 +190,9 @@ struct client_state
>>   
>>     int current_traceframe = -1;
>>   
>> +  /* If true, memory tagging features are supported.  */
>> +  bool memory_tagging_feature = false;
> 
> Just a note that as of this patch, this field is unnecessary.  If it gets
> used later, that's fine.
> 

Right. The way the series was put together, each part builds on top of 
the previous one. So this will be used in later patches.

>> @@ -499,6 +500,19 @@ class process_stratum_target
>>   
>>     /* Return tdesc index for IPA.  */
>>     virtual int get_ipa_tdesc_idx ();
>> +
>> +  /* Returns true if the target supports memory tagging facilities.  */
>> +  virtual bool supports_memory_tagging ();
>> +
>> +  /* Return the allocated memory tags of type TYPE associated with
>> +     [ADDRESS, ADDRESS + LEN) in TAGS.  */
>> +  virtual int fetch_memtags (CORE_ADDR address, size_t len,
>> +			     gdb::byte_vector &tags, int type);
>> +
>> +  /* Write the allocation tags of type TYPE contained in TAGS to the
>> +     memory range [ADDRESS, ADDRESS + LEN).  */
>> +  virtual int store_memtags (CORE_ADDR address, size_t len,
>> +			     const gdb::byte_vector &tags, int type);
> 
> I suppose that these should return bool.
> 
> Simon
> 

Yes. Updated to match what was done for the GDB changes. I also updated 
the documentation for functions and the naming to spell it completely.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets
  2020-12-25 20:13   ` Simon Marchi
@ 2020-12-28 18:12     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 18:12 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 5:13 PM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v2:
>>
>> - Update unit tests to cope with additional tag type field in the remote
>> packets.
>>
>> --
>>
>> Add some unit testing to exercise the functions handling the qMemTags and
>> QMemTags packets as well as feature support.
>>
>> gdbserver/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* server.cc (test_memory_tagging_functions): New function.
>> 	(captured_main): Register test_memory_tagging_functions.
>> ---
>>   gdbserver/server.cc | 100 ++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 100 insertions(+)
>>
>> diff --git a/gdbserver/server.cc b/gdbserver/server.cc
>> index 7eddd0e01f..6812b624f8 100644
>> --- a/gdbserver/server.cc
>> +++ b/gdbserver/server.cc
>> @@ -3647,6 +3647,103 @@ detach_or_kill_for_exit_cleanup ()
>>       }
>>   }
>>   
>> +#if GDB_SELF_TEST
>> +
>> +namespace selftests {
>> +
>> +static void
>> +test_memory_tagging_functions (void)
>> +{
>> +  /* Setup testing.  */
>> +  gdb::char_vector packet;
>> +  gdb::byte_vector tags, bv;
>> +  std::string expected;
>> +  packet.resize (32000);
>> +  CORE_ADDR addr;
>> +  size_t len;
>> +  int type;
>> +
>> +  /* Test parsing a qMemTags request.  */
>> +
>> +  /* Invalid request, addr len and type unchanged.  */
>> +  addr = 0xff;
>> +  len = 255;
>> +  type = 255;
>> +  strcpy (packet.data (), "qMemTags_wrong:0,0:0");
>> +  SELF_CHECK (parse_fmemtags_request (packet.data (), &addr, &len, &type) != 0);
>> +  SELF_CHECK (addr == 0xff && len == 255 && type == 255);
> 
> As I said earlier, I would have made parse_fmemtags_request assert that the
> packet begins with "qMemTags:" (instead of returning an error value), but it's
> really a nit and I can live with both.

Fixed now and removed the tests that cause an assertion.

> 
> Otherwise this patch LGTM.
> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers
  2020-12-26  0:10   ` Simon Marchi
@ 2020-12-28 18:28     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 18:28 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 9:10 PM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> This patch adds a target description and feature "mte" for aarch64.
>>
>> It includes one new register, tag_ctl, that can be used to configure the
>> tag generation rules and sync/async modes.
> 
> Can you explain this sentence?  I especially don't understand "sync/async modes"..
> 

Sure. This register is exposed by the kernel as a set of bits that you 
can use to control some characteristics of the memory tagging mecanism.

There are 3 modes of operation: ignore, sync and async. From the kernel 
documentation:

- *Ignore* - This is the default mode. The CPU (and kernel) ignores the
tag check fault.

- *Synchronous* - The kernel raises a ``SIGSEGV`` synchronously, with
``.si_code = SEGV_MTESERR`` and ``.si_addr = <fault-address>``. The
memory access is not performed. If ``SIGSEGV`` is ignored or blocked
by the offending thread, the containing process is terminated with a
``coredump``.

- *Asynchronous* - The kernel raises a ``SIGSEGV``, in the offending
thread, asynchronously following one or multiple tag check faults,
with ``.si_code = SEGV_MTEAERR`` and ``.si_addr = 0`` (the faulting
address is unknown).

So, basically, we have options to ignore the tag fault, report a tag 
fault without extra information (async) and report a tag fault with 
precise information (sync).

> The code itself LGTM.
> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver
  2020-12-26  0:17   ` Simon Marchi
@ 2020-12-28 18:41     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 18:41 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 9:17 PM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> AArch64 MTE support in the Linux kernel exposes a new register
>> through ptrace.  This patch adds the required code to support it.
>>
>> include/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* elf/common.h (NT_ARM_TAGGED_ADDR_CTRL): Define.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* aarch64-linux-nat.c (fetch_mteregs_from_thread): New function.
>> 	(store_mteregs_to_thread): New function.
>> 	(aarch64_linux_nat_target::fetch_registers): Update to call
>> 	fetch_mteregs_from_thread.
>> 	(aarch64_linux_nat_target::store_registers): Update to call
>> 	store_mteregs_to_thread.
>> 	* aarch64-tdep.c (aarch64_mte_register_names): New struct.
>> 	(aarch64_cannot_store_register): Handle MTE registers.
>> 	(aarch64_gdbarch_init): Initialize and setup MTE registers.
>> 	* aarch64-tdep.h (gdbarch_tdep) <mte_reg_base>: New field.
>> 	<has_mte>: New method.
>> 	* arch/aarch64-linux.h (AARCH64_LINUX_SIZEOF_MTE): Define.
>>
>> gdbserver/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* linux-aarch64-low.cc (aarch64_fill_mteregset): New function.
>> 	(aarch64_store_mteregset): New function.
>> 	(aarch64_regsets): Add MTE register set entry.
>> 	(aarch64_sve_regsets): Add MTE register set entry.
>> ---
>>   gdb/aarch64-linux-nat.c        | 70 ++++++++++++++++++++++++++++++++++
>>   gdb/aarch64-tdep.c             | 24 ++++++++++++
>>   gdb/aarch64-tdep.h             |  9 +++++
>>   gdb/arch/aarch64-mte-linux.h   |  3 ++
>>   gdbserver/linux-aarch64-low.cc | 29 ++++++++++++++
>>   include/elf/common.h           |  3 ++
>>   6 files changed, 138 insertions(+)
>>
>> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
>> index 1392ec440c..dea34da669 100644
>> --- a/gdb/aarch64-linux-nat.c
>> +++ b/gdb/aarch64-linux-nat.c
>> @@ -461,6 +461,60 @@ fetch_pauth_masks_from_thread (struct regcache *regcache)
>>   			&pauth_regset[1]);
>>   }
>>   
>> +/* Fill GDB's register array with the MTE register values from
>> +   the current thread.  */
>> +
>> +static void
>> +fetch_mteregs_from_thread (struct regcache *regcache)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
>> +  int regno = tdep->mte_reg_base;
>> +
>> +  gdb_assert (regno != -1);
>> +
>> +  uint64_t tag_ctl = 0;
>> +  struct iovec iovec;
>> +
>> +  iovec.iov_base = &tag_ctl;
>> +  iovec.iov_len = sizeof (tag_ctl);
>> +
>> +  int tid = regcache->ptid ().lwp ();
> 
> Should this use get_ptrace_pid?  Same in the store version.
> 

I wasn't aware of that function. Thanks for the info.

>> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL,
>> +		&iovec) != 0)
> 
> The indentation is wrong on this last line (and it would all fit on one line).
> 

Fixed in both the fetch and store functions to be on the same line.

>> diff --git a/include/elf/common.h b/include/elf/common.h
>> index fc672de9f2..334e9e301f 100644
>> --- a/include/elf/common.h
>> +++ b/include/elf/common.h
>> @@ -660,6 +660,9 @@
>>   					/*   note name must be "LINUX".  */
>>   #define NT_ARM_PAC_MASK	0x406		/* AArch pointer authentication code masks */
>>   					/*   note name must be "LINUX".  */
>> +#define NT_ARM_TAGGED_ADDR_CTRL	0x409	/* AArch64 tagged address control
>> +					   (prctl()) */
>> +					/*   note name must be "LINUX".  */
>>   #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
>>   					/*   note name must be "LINUX".  */
>>   #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
> 
> What this changed approved by binutils?

Not yet. There was some back-and-forth on the name of this register set 
with the kernel folks. I'll post it to the binutils list after fixing up 
the current version.

> 
> 
> Otherwise, this LGTM.
> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 11/24] AArch64: Add MTE ptrace requests
  2020-12-26  0:19   ` Simon Marchi
@ 2020-12-28 19:12     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 19:12 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 9:19 PM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> This patch adds the required ptrace request definitions into a new include
>> file that will be used by the next patches.
>>
>> They are PTRACE_PEEKMTETAGS and PTRACE_POKEMTETAGS.
> 
> IIUC, this is to allow building GDB on an older kernel that doesn't provide
> these definitions?

That's right. It makes it possible to build GDB on hardware/kernel not 
supporting MTE, but still allowing GDB to support MTE.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64
  2020-12-26  0:33   ` Simon Marchi
@ 2020-12-28 19:50     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-28 19:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/25/20 9:33 PM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> 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.
>> 	(MTE_GRANULE_SIZE): Define.
>> 	(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       |  34 +++++
>>   gdb/arch/aarch64-mte-linux.h       |  10 ++
>>   gdb/configure.nat                  |   3 +-
>>   gdb/configure.tgt                  |   1 +
>>   gdb/nat/aarch64-mte-linux-ptrace.c | 200 +++++++++++++++++++++++++++++
>>   gdb/nat/aarch64-mte-linux-ptrace.h |  17 +++
>>   8 files changed, 315 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 4f08beea44..452e21b2b2 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -693,6 +693,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 dea34da669..4edf5a0454 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.  */
>> +  int fetch_memtags (CORE_ADDR address, size_t len,
>> +		     gdb::byte_vector &tags, int type) override;
>> +
>> +  /* Write allocation tags to memory via PTRACE.  */
>> +  int 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;
>> @@ -1050,6 +1062,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.  */
>> +
>> +int
>> +aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
>> +					 gdb::byte_vector &tags, int type)
>> +{
>> +  int tid = inferior_ptid.lwp ();
> 
> I believe this should use get_ptrace_pid (same in the store version).
> 

Indeed. Fixed now.

>> +
>> +  /* Allocation tags?  */
>> +  if (type == 1)
>> +    return aarch64_mte_fetch_memtags (tid, address, len, tags);
>> +
>> +  return 1;
> 
> What's the logic of this "return 1"?  Does this mean "success", and
> is this what we want to do when it's an unhandled type?  Oh, now that I
> read the doc for aarch64_mte_fetch_memtags, I see that 1 means failure.
> See comment below.
> 

All of these were supposed to return error codes. But right now we don't 
have a list of possible codes, therefore it is basically 0/1 for 
success/failure. I've switched to using bool.

>> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
>> index 4124e80543..e555f0af19 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,12 @@
>>   /* 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 MTE_GRANULE_SIZE 16
> 
> I'd suggest prefixing this, AARCH64_MTE_GRANULE_SIZE.
> 

Done now.

>> +
>> +/* Return the number of tag granules in the memory range
>> +   [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
>> +extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
>> +				size_t granule_size);
> 
> And aarch64_mte_get_tag_granules.
> 

Done.

>> +/* Helper function to display various possible errors when reading
>> +   MTE tags.  */
>> +
>> +static void
>> +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
>> +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;
>> +    }
>> +}
> 
> These functions should probably be marked with ATTRIBUTE_NORETURN.
> 

Attribute added.

>> +
>> +/* 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)
>> +    {
>> +      t.clear ();
> 
> That clear seems unnecessary.
> 

You're right. Removed now.

>> diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
>> index 099b6440ca..7ba6f014f6 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 TAGS_MAX_SIZE 4096
> 
> I think this define should have a more scoped named, like
> AARCH64_MTE_TAGS_MAX_SIZE.
> 

That makes sense too.

>> +
>> +/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN)
>> +   into TAGS.
>> +
>> +   Return 0 if successful and non-zero otherwise.  */
>> +extern int aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
>> +				      gdb::byte_vector &tags);
>> +
>> +/* Write the TAGS allocation tags to the memory range
>> +   [ADDRESS, ADDRESS + LEN).
>> +
>> +   Return 0 if successful and non-zero otherwise.  */
>> +extern int aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
>> +				      const gdb::byte_vector &tags);
> 
> IWBN to use bool for the return value, true for success and false for failure.
> And as mentioned in the first patch, the target methods should also use bool
> for the return value and be documented (although with bool, it's pretty obvious
> that "true" means success, unlike with ints where both ways are common).
> 
> Otherwise, LGTM.
> 
> Simon
> 

Thanks for the review and suggestions so far. They were very useful.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps
  2020-12-26  6:36   ` Simon Marchi
@ 2020-12-29 10:57     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-29 10:57 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/26/20 3:36 AM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> The Linux kernel exposes the information about MTE-protected pages via the
>> proc filesystem, more specifically through the smaps file.
>>
>> What we're looking for is a mapping with the 'mt' flag, which tells us that
>> mapping was created with a PROT_MTE flag and, thus, is capable of using memory
>> tagging.
>>
>> We already parse that file for other purposes (core file
>> generation/filtering), so this patch refactors the code to make the parsing
>> of the smaps file reusable for memory tagging.
>>
>> The function linux_address_in_memtag_page uses the refactored code to allow
>> querying for memory tag support in a particular address, and it gets used in the
>> next patch.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* linux-tdep.c (struct smaps_vmflags) <memory_tagging>: New flag
>> 	bit.
>> 	(struct smaps_data): New struct.
>> 	(decode_vmflags): Handle the 'mt' flag.
>> 	(parse_smaps_data): New function, refactored from
>> 	linux_find_memory_regions_full.
>> 	(linux_address_in_memtag_page): New function.
>> 	(linux_find_memory_regions_full): Refactor into parse_smaps_data.
>> 	* linux-tdep.h (linux_address_in_memtag_page): New prototype.
>> ---
>>   gdb/linux-tdep.c | 358 +++++++++++++++++++++++++++++++----------------
>>   gdb/linux-tdep.h |   4 +
>>   2 files changed, 241 insertions(+), 121 deletions(-)
>>
>> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
>> index bacb61398f..91bdcc133b 100644
>> --- a/gdb/linux-tdep.c
>> +++ b/gdb/linux-tdep.c
>> @@ -86,8 +86,33 @@ struct smaps_vmflags
>>       /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
>>   
>>       unsigned int shared_mapping : 1;
>> +
>> +    /* Memory map has memory tagging enabled.  */
>> +
>> +    unsigned int memory_tagging : 1;
>>     };
>>   
>> +/* Data structure that holds the information contained in the
>> +   /proc/<pid>/smaps file.  */
>> +
>> +struct smaps_data
>> +{
>> +  ULONGEST start_address;
>> +  ULONGEST end_address;
>> +  std::string filename;
>> +  struct smaps_vmflags vmflags;
>> +  bool read;
>> +  bool write;
>> +  bool exec;
>> +  bool priv;
>> +  bool has_anonymous;
>> +  bool mapping_anon_p;
>> +  bool mapping_file_p;
>> +
>> +  ULONGEST inode;
>> +  ULONGEST offset;
>> +};
>> +
>>   /* Whether to take the /proc/PID/coredump_filter into account when
>>      generating a corefile.  */
>>   
>> @@ -472,6 +497,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
>>   	v->exclude_coredump = 1;
>>         else if (strcmp (s, "sh") == 0)
>>   	v->shared_mapping = 1;
>> +      else if (strcmp (s, "mt") == 0)
>> +	v->memory_tagging = 1;
>>       }
>>   }
>>   
>> @@ -1267,6 +1294,184 @@ typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
>>   					const char *filename,
>>   					ULONGEST addr,
>>   					ULONGEST offset);
>> +/* Helper function to parse the contents of /proc/<pid>/smaps into a data
>> +   structure, for easy access.
>> +
>> +   DATA is the contents of the smaps file.  The parsed contents are stored
>> +   into the SMAPS vector.  */
> 
> Add a blank line above this comment.
> 

Fixed.

>> +
>> +static int
>> +parse_smaps_data (const char *data,
>> +		  std::vector<struct smaps_data> &smaps,
>> +		  const char *mapsfilename)
> 
> The return value of that function is unused, it always return 0.  I'd suggest
> making it return the std::vector directly.
> 

There has been some changes to this function. I recall it returning 1 as 
well. I've changed it as suggested. It makes it simpler.

>> +{
>> +  char *line, *t;
>> +
>> +  gdb_assert (data != nullptr);
>> +
>> +  smaps.clear ();
>> +
>> +  line = strtok_r ((char *) data, "\n", &t);
>> +
>> +  while (line != NULL)
>> +    {
>> +      ULONGEST addr, endaddr, offset, inode;
>> +      const char *permissions, *device, *filename;
>> +      struct smaps_vmflags v;
>> +      size_t permissions_len, device_len;
>> +      int read, write, exec, priv;
>> +      int has_anonymous = 0;
>> +      int mapping_anon_p;
>> +      int mapping_file_p;
>> +
>> +      memset (&v, 0, sizeof (v));
>> +      read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
>> +		    &offset, &device, &device_len, &inode, &filename);
>> +      mapping_anon_p = mapping_is_anonymous_p (filename);
>> +      /* If the mapping is not anonymous, then we can consider it
>> +	 to be file-backed.  These two states (anonymous or
>> +	 file-backed) seem to be exclusive, but they can actually
>> +	 coexist.  For example, if a file-backed mapping has
>> +	 "Anonymous:" pages (see more below), then the Linux
>> +	 kernel will dump this mapping when the user specified
>> +	 that she only wants anonymous mappings in the corefile
>> +	 (*even* when she explicitly disabled the dumping of
>> +	 file-backed mappings).  */
>> +      mapping_file_p = !mapping_anon_p;
>> +
>> +      /* Decode permissions.  */
>> +      read = (memchr (permissions, 'r', permissions_len) != 0);
>> +      write = (memchr (permissions, 'w', permissions_len) != 0);
>> +      exec = (memchr (permissions, 'x', permissions_len) != 0);
>> +      /* 'private' here actually means VM_MAYSHARE, and not
>> +	 VM_SHARED.  In order to know if a mapping is really
>> +	 private or not, we must check the flag "sh" in the
>> +	 VmFlags field.  This is done by decode_vmflags.  However,
>> +	 if we are using a Linux kernel released before the commit
>> +	 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
>> +	 not have the VmFlags there.  In this case, there is
>> +	 really no way to know if we are dealing with VM_SHARED,
>> +	 so we just assume that VM_MAYSHARE is enough.  */
>> +      priv = memchr (permissions, 'p', permissions_len) != 0;
>> +
>> +      /* Try to detect if region should be dumped by parsing smaps
>> +	 counters.  */
>> +      for (line = strtok_r (NULL, "\n", &t);
>> +	   line != NULL && line[0] >= 'A' && line[0] <= 'Z';
>> +	   line = strtok_r (NULL, "\n", &t))
>> +	{
>> +	  char keyword[64 + 1];
>> +
>> +	  if (sscanf (line, "%64s", keyword) != 1)
>> +	    {
>> +	      warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
>> +	      break;
>> +	    }
>> +
>> +	  if (strcmp (keyword, "Anonymous:") == 0)
>> +	    {
>> +	      /* Older Linux kernels did not support the
>> +		 "Anonymous:" counter.  Check it here.  */
>> +	      has_anonymous = 1;
>> +	    }
>> +	  else if (strcmp (keyword, "VmFlags:") == 0)
>> +	    decode_vmflags (line, &v);
>> +
>> +	  if (strcmp (keyword, "AnonHugePages:") == 0
>> +	      || strcmp (keyword, "Anonymous:") == 0)
>> +	    {
>> +	      unsigned long number;
>> +
>> +	      if (sscanf (line, "%*s%lu", &number) != 1)
>> +		{
>> +		  warning (_("Error parsing {s,}maps file '%s' number"),
>> +			   mapsfilename);
>> +		  break;
>> +		}
>> +	      if (number > 0)
>> +		{
>> +		  /* Even if we are dealing with a file-backed
>> +		     mapping, if it contains anonymous pages we
>> +		     consider it to be *also* an anonymous
>> +		     mapping, because this is what the Linux
>> +		     kernel does:
>> +
>> +		     // Dump segments that have been written to.
>> +		     if (vma->anon_vma && FILTER(ANON_PRIVATE))
>> +		       goto whole;
>> +
>> +		    Note that if the mapping is already marked as
>> +		    file-backed (i.e., mapping_file_p is
>> +		    non-zero), then this is a special case, and
>> +		    this mapping will be dumped either when the
>> +		    user wants to dump file-backed *or* anonymous
>> +		    mappings.  */
>> +		  mapping_anon_p = 1;
>> +		}
>> +	    }
>> +	}
>> +      /* Save the smaps entry to the vector.  */
>> +	struct smaps_data map;
>> +	std::string fname (filename);
> 
> You don't need to create the string here, just do
> 
>    map.filename = filename;
> 
> below.
> 

Fixed.

>> +
>> +	smaps.emplace_back (map);
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +/* See linux-tdep.h.  */
>> +
>> +bool
>> +linux_address_in_memtag_page (CORE_ADDR address)
>> +{
>> +  if (current_inferior ()->fake_pid_p)
>> +    return false;> +
>> +  pid_t pid = current_inferior ()->pid;
>> +
>> +  std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
>> +
>> +  gdb::unique_xmalloc_ptr<char> data
>> +    = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
>> +
>> +  if (data == nullptr)
>> +    return false;
>> +
>> +  std::vector<struct smaps_data> smaps;
>> +
>> +  /* Parse the contents of smaps into a vector.  */
>> +  parse_smaps_data (data.get (), smaps, smaps_file.c_str ());
>> +
>> +  if (!smaps.empty ())
>> +    {
> 
> No need for this `if`.
> 
>> +      for (struct smaps_data map : smaps)
> 
> Iterate by const reference:
> 
>    for (const smaps_data &map : smaps)
> 

Fixed now.

>> +	{
>> +	  /* 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;
>> +	}
>> +    }
>> +
>> +  return false;
>> +}
>>   
>>   /* List memory regions in the inferior for a corefile.  */
>>   
>> @@ -1276,8 +1481,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>>   				linux_find_memory_region_ftype *func,
>>   				void *obfd)
>>   {
>> -  char mapsfilename[100];
>> -  char coredumpfilter_name[100];
>> +  std::string coredumpfilter_name;
> 
> Declare this on first use (we could push some preparatory patches to change
> these to std::string, to make this patch simpler).
> 

Yeah. That looks like it will benefit from a cleanup. I'll do as a 
separate patch.

>>     pid_t pid;
>>     /* Default dump behavior of coredump_filter (0x33), according to
>>        Documentation/filesystems/proc.txt from the Linux kernel
>> @@ -1295,10 +1499,9 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>>   
>>     if (use_coredump_filter)
>>       {
>> -      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
>> -		 "/proc/%d/coredump_filter", pid);
>> +      coredumpfilter_name = string_printf ("/proc/%d/coredump_filter", pid);
>>         gdb::unique_xmalloc_ptr<char> coredumpfilterdata
>> -	= target_fileio_read_stralloc (NULL, coredumpfilter_name);
>> +	= target_fileio_read_stralloc (NULL, coredumpfilter_name.c_str ());
>>         if (coredumpfilterdata != NULL)
>>   	{
>>   	  unsigned int flags;
>> @@ -1308,125 +1511,39 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>>   	}
>>       }
>>   
>> -  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
>> +  std::string mapsfilename = string_printf ("/proc/%d/smaps", pid);
>>     gdb::unique_xmalloc_ptr<char> data
>> -    = target_fileio_read_stralloc (NULL, mapsfilename);
>> +    = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
>>     if (data == NULL)
>>       {
>>         /* Older Linux kernels did not support /proc/PID/smaps.  */
>> -      xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
>> -      data = target_fileio_read_stralloc (NULL, mapsfilename);
>> +      mapsfilename = string_printf ("/proc/%d/maps", pid);
>> +      data = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
>>       }
>>   
>> -  if (data != NULL)
>> -    {
>> -      char *line, *t;
>> -
>> -      line = strtok_r (data.get (), "\n", &t);
>> -      while (line != NULL)
>> -	{
>> -	  ULONGEST addr, endaddr, offset, inode;
>> -	  const char *permissions, *device, *filename;
>> -	  struct smaps_vmflags v;
>> -	  size_t permissions_len, device_len;
>> -	  int read, write, exec, priv;
>> -	  int has_anonymous = 0;
>> -	  int should_dump_p = 0;
>> -	  int mapping_anon_p;
>> -	  int mapping_file_p;
>> -
>> -	  memset (&v, 0, sizeof (v));
>> -	  read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
>> -			&offset, &device, &device_len, &inode, &filename);
>> -	  mapping_anon_p = mapping_is_anonymous_p (filename);
>> -	  /* If the mapping is not anonymous, then we can consider it
>> -	     to be file-backed.  These two states (anonymous or
>> -	     file-backed) seem to be exclusive, but they can actually
>> -	     coexist.  For example, if a file-backed mapping has
>> -	     "Anonymous:" pages (see more below), then the Linux
>> -	     kernel will dump this mapping when the user specified
>> -	     that she only wants anonymous mappings in the corefile
>> -	     (*even* when she explicitly disabled the dumping of
>> -	     file-backed mappings).  */
>> -	  mapping_file_p = !mapping_anon_p;
>> -
>> -	  /* Decode permissions.  */
>> -	  read = (memchr (permissions, 'r', permissions_len) != 0);
>> -	  write = (memchr (permissions, 'w', permissions_len) != 0);
>> -	  exec = (memchr (permissions, 'x', permissions_len) != 0);
>> -	  /* 'private' here actually means VM_MAYSHARE, and not
>> -	     VM_SHARED.  In order to know if a mapping is really
>> -	     private or not, we must check the flag "sh" in the
>> -	     VmFlags field.  This is done by decode_vmflags.  However,
>> -	     if we are using a Linux kernel released before the commit
>> -	     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
>> -	     not have the VmFlags there.  In this case, there is
>> -	     really no way to know if we are dealing with VM_SHARED,
>> -	     so we just assume that VM_MAYSHARE is enough.  */
>> -	  priv = memchr (permissions, 'p', permissions_len) != 0;
>> -
>> -	  /* Try to detect if region should be dumped by parsing smaps
>> -	     counters.  */
>> -	  for (line = strtok_r (NULL, "\n", &t);
>> -	       line != NULL && line[0] >= 'A' && line[0] <= 'Z';
>> -	       line = strtok_r (NULL, "\n", &t))
>> -	    {
>> -	      char keyword[64 + 1];
>> +  if (data == nullptr)
>> +    return 1;
>>   
>> -	      if (sscanf (line, "%64s", keyword) != 1)
>> -		{
>> -		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
>> -		  break;
>> -		}
>> +  std::vector<struct smaps_data> smaps;
>>   
>> -	      if (strcmp (keyword, "Anonymous:") == 0)
>> -		{
>> -		  /* Older Linux kernels did not support the
>> -		     "Anonymous:" counter.  Check it here.  */
>> -		  has_anonymous = 1;
>> -		}
>> -	      else if (strcmp (keyword, "VmFlags:") == 0)
>> -		decode_vmflags (line, &v);
>> +  /* Parse the contents of smaps into a vector.  */
>> +  parse_smaps_data (data.get (), smaps, mapsfilename.c_str ());
>>   
>> -	      if (strcmp (keyword, "AnonHugePages:") == 0
>> -		  || strcmp (keyword, "Anonymous:") == 0)
>> -		{
>> -		  unsigned long number;
>> -
>> -		  if (sscanf (line, "%*s%lu", &number) != 1)
>> -		    {
>> -		      warning (_("Error parsing {s,}maps file '%s' number"),
>> -			       mapsfilename);
>> -		      break;
>> -		    }
>> -		  if (number > 0)
>> -		    {
>> -		      /* Even if we are dealing with a file-backed
>> -			 mapping, if it contains anonymous pages we
>> -			 consider it to be *also* an anonymous
>> -			 mapping, because this is what the Linux
>> -			 kernel does:
>> -
>> -			 // Dump segments that have been written to.
>> -			 if (vma->anon_vma && FILTER(ANON_PRIVATE))
>> -			 	goto whole;
>> -
>> -			 Note that if the mapping is already marked as
>> -			 file-backed (i.e., mapping_file_p is
>> -			 non-zero), then this is a special case, and
>> -			 this mapping will be dumped either when the
>> -			 user wants to dump file-backed *or* anonymous
>> -			 mappings.  */
>> -		      mapping_anon_p = 1;
>> -		    }
>> -		}
>> -	    }
>> +  if (!smaps.empty ())
>> +    {
>> +      for (struct smaps_data map : smaps)
> 
> Same comments as above.
> 
> Simon
> 

Fixed. Thanks.

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks
  2020-12-26  6:52   ` Simon Marchi
@ 2020-12-29 12:16     ` Luis Machado
  2021-01-18 16:29       ` Simon Marchi
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-12-29 12:16 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/26/20 3:52 AM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v2:
>>
>> - Update target methods to contain a tag type parameter.
>>
>> --
>>
>> This patch implements the memory tagging gdbarch hooks for AArch64, for
>> the MTE feature.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* aarch64-linux-tdep.c: Include target.h, arch-utils.h, value.h.
>> 	(aarch64_linux_get_atag, aarch64_linux_tagged_address_p)
>> 	(aarch64_linux_memtag_mismatch_p, aarch64_linux_set_memtags)
>> 	(aarch64_linux_get_memtag, aarch64_linux_memtag_to_string): New
>> 	functions.
>> 	(aarch64_linux_init_abi): Initialize MTE-related gdbarch hooks.
>> 	* arch/aarch64-mte-linux.c (make_ltag_bits, make_ltag)
>> 	(aarch64_linux_set_ltag, aarch64_linux_get_ltag): New functions.
>> 	* arch/aarch64-mte-linux.h (MTE_LOGICAL_TAG_START_BIT)
>> 	(MTE_LOGICAL_MAX_VALUE): Define.
>> 	(make_ltag_bits, make_ltag, aarch64_linux_set_ltag)
>> 	(aarch64_linux_get_ltag): New prototype.
>> ---
>>   gdb/aarch64-linux-tdep.c     | 212 +++++++++++++++++++++++++++++++++++
>>   gdb/arch/aarch64-mte-linux.c |  36 ++++++
>>   gdb/arch/aarch64-mte-linux.h |  19 ++++
>>   3 files changed, 267 insertions(+)
>>
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index 5f6fb42792..00c4f45035 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -30,6 +30,7 @@
>>   #include "symtab.h"
>>   #include "tramp-frame.h"
>>   #include "trad-frame.h"
>> +#include "target.h"
>>   #include "target/target.h"
>>   
>>   #include "regcache.h"
>> @@ -46,6 +47,9 @@
>>   
>>   #include "arch/aarch64-mte-linux.h"
>>   
>> +#include "arch-utils.h"
>> +#include "value.h"
>> +
>>   /* Signal frame handling.
>>   
>>         +------------+  ^
>> @@ -1437,6 +1441,189 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
>>     return {};
>>   }
>>   
>> +/* Helper to get the allocation tag from a 64-bit ADDRESS.
>> +
>> +   Return 0 for success and non-zero otherwise.  */
>> +
>> +static int
>> +aarch64_linux_get_atag (CORE_ADDR address, CORE_ADDR *tag)
>> +{
> 
> I'd suggest making the return value a bool.  Or, even better IMO
> would be to make the return value gdb::optional<CORE_ADDR>, an
> empty optional meaning failure.
> 

Done now.

>> +  gdb::byte_vector tags;
>> +
>> +  /* Attempt to fetch the allocation tag.  */
>> +  if (target_fetch_memtags (address, 0, tags, tag_allocation) != 0)
>> +    return 1;
>> +
>> +  /* Only one tag should've been returned.  Make sure we got exactly that.  */
>> +  gdb_assert (tags.size () == 1);
>> +
>> +  /* Although our tags are 4 bits in size, they are stored in a
>> +     byte.  */
>> +  *tag = tags[0];
>> +
>> +  return 0;
>> +}
>> +
>> +/* Implement the tagged_address_p gdbarch method.  */
>> +
>> +static bool
>> +aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, struct value *address)
>> +{
>> +  gdb_assert (address != nullptr);
>> +
>> +  CORE_ADDR addr = value_as_address (address);
>> +
>> +  /* Remove the top byte for the memory range check.  */
>> +  addr = address_significant (gdbarch, addr);
>> +
>> +  /* Check if the page that contains ADDRESS is mapped with PROT_MTE.  */
>> +  if (!linux_address_in_memtag_page (addr))
>> +    return false;
>> +
>> +  /* We have a valid tag in the top byte of the 64-bit address.  */
>> +  return true;
>> +}
>> +
>> +/* Implement the memtag_mismatch_p gdbarch method.  */
>> +
>> +static bool
>> +aarch64_linux_memtag_mismatch_p (struct gdbarch *gdbarch,
>> +				 struct value *address)
>> +{
>> +  gdb_assert (address != nullptr);
>> +
>> +  /* Make sure we are dealing with a tagged address to begin with.  */
>> +  if (!aarch64_linux_tagged_address_p (gdbarch, address))
>> +    return false;
>> +
>> +  CORE_ADDR addr = value_as_address (address);
>> +
>> +  /* Fetch the allocation tag for ADDRESS.  */
>> +  CORE_ADDR atag = 0;
>> +
>> +  if (aarch64_linux_get_atag (addr, &atag) != 0)
>> +    return false;
>> +
>> +  /* Fetch the logical tag for ADDRESS.  */
>> +  gdb_byte ltag = aarch64_linux_get_ltag (addr);
>> +
>> +  /* Are the tags the same?  */
>> +  if (ltag == atag)
>> +    return false;
>> +
>> +  return true;
> 
> That could very well be
> 
>    return ltag != atag;
> 
> I'm wondering about the potential performance impacts of all this.  When
> memory tagging is in use, how often are the memtag functions expected to be
> called?  By the looks of it, it seems like checking for a mismatch does
> 2 open and parse of /proc/pid/smaps.  Is that right, and is this function
> something that is going to be called often, say, when printing values?
> 

If MTE is enabled, the checks will happen every time one prints a 
pointer or dumps some tagged memory region with the "x" command.

I considered and discussed the impact of this mechanism during the 
implementation of MTE support in GDB. Unfortunately the interface the 
kernel uses to communicate the required data to GDB isn't great.

The maps file is small and quick to parse, but the smaps file is not 
presented in a way that makes it easy for consumers to parse the data. 
Even worse, we can't cache the data, as threads may potentially 
map/unmap PROT_MTE pages during execution. It needs to be a read freshly.

To mitigate this, we could default to not check tags when printing, 
while still handling tag faults.

>> +}
>> +
>> +/* Implement the set_memtags gdbarch method.  */
>> +
>> +static int
>> +aarch64_linux_set_memtags (struct gdbarch *gdbarch, struct value *address,
>> +			   size_t length, const gdb::byte_vector &tags,
>> +			   enum memtag_type tag_type)
>> +{
>> +  if (tags.empty ())
>> +    return 0;
>> +
>> +  gdb_assert (address != nullptr);
>> +
>> +  CORE_ADDR addr = value_as_address (address);
>> +
>> +  /* Set the logical tag or the allocation tag.  */
>> +  if (tag_type == tag_logical)
>> +    {
>> +      /* When setting logical tags, we don't care about the length, since
>> +	 we are only setting a single logical tag.  */
>> +      addr = aarch64_linux_set_ltag (addr, tags[0]);
>> +
>> +      /* Update the value's content with the tag.  */
>> +      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>> +      gdb_byte *srcbuf = value_contents_raw (address);
>> +      store_unsigned_integer (srcbuf, sizeof (addr), byte_order, addr);
>> +    }
>> +  else
>> +    {
>> +      /* Make sure we are dealing with a tagged address to begin with.  */
>> +      if (!aarch64_linux_tagged_address_p (gdbarch, address))
>> +	return 1;
>> +
>> +      /* With G being the number of tag granules and N the number of tags
>> +	 passed in, we can have the following cases:
>> +
>> +	 1 - G == N: Store all the N tags to memory.
>> +
>> +	 2 - G < N : Warn about having more tags than granules, but write G
>> +		     tags.
>> +
>> +	 3 - G > N : This is a "fill tags" operation.  We should use the tags
>> +		     as a pattern to fill the granules repeatedly until we have
>> +		     written G tags to memory.
>> +      */
>> +
>> +      size_t g = get_tag_granules (addr, length, MTE_GRANULE_SIZE);
>> +      size_t n = tags.size ();
>> +
>> +      if (g < n)
>> +	{
>> +	  warning (_("Got more tags than memory granules.  Tags will be "
>> +		     "truncated."));
>> +	}
> 
> Remove curly braces.
> 

Isn't the rule to have curly braces for one-statement conditionals if 
such statement spans more than a single line? That has been my 
understanding so far.

>> diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
>> index e555f0af19..5c5783f28b 100644
>> --- a/gdb/arch/aarch64-mte-linux.h
>> +++ b/gdb/arch/aarch64-mte-linux.h
>> @@ -32,10 +32,29 @@
>>   
>>   /* We have one tag per 16 bytes of memory.  */
>>   #define MTE_GRANULE_SIZE 16
>> +#define MTE_LOGICAL_TAG_START_BIT   56
>> +#define MTE_LOGICAL_MAX_VALUE	    0xf
>>   
>>   /* Return the number of tag granules in the memory range
>>      [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
>>   extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
>>   				size_t granule_size);
>>   
>> +/* Return the 4-bit tag made from VALUE.  */
>> +extern CORE_ADDR make_ltag_bits (CORE_ADDR value);
> 
> As mentioned previously, I'd suggest giving a name that's better scoped,
> since these symbols are in a header file / exported.  Or if they are just
> used in aarch64-mte-linux.c, move them there (the defines as well, if
> possible).

I'm adjusting the MTE-related functions to have more scoped names.

> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 17/24] AArch64: Add gdbserver MTE support
  2020-12-26 22:30   ` Simon Marchi
@ 2020-12-29 14:32     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-29 14:32 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/26/20 7:30 PM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v2:
>>
>> - Updated target methods to contain a tag type parameter.
>>
>> --
>>
>> Adds the AArch64-specific memory tagging support (MTE) by implementing the
>> required hooks and checks for GDBserver.
>>
>> gdbserver/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* Makefile.in (SFILES): Add /../gdb/nat/aarch64-mte-linux-ptrace.c.
>> 	* configure.srv (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o and
>> 	nat/aarch64-mte-linux-ptrace.o.
>> 	* linux-aarch64-low.cc: Include nat/aarch64-mte-linux-ptrace.h.
>> 	(class aarch64_target) <supports_memory_tagging>
>> 	<fetch_memtags, store_memtags>: New method overrides.
>> 	(aarch64_target::supports_memory_tagging)
>> 	(aarch64_target::fetch_memtags)
>> 	(aarch64_target::store_memtags): New methods.
>> ---
>>   gdbserver/Makefile.in          |  1 +
>>   gdbserver/configure.srv        |  2 ++
>>   gdbserver/linux-aarch64-low.cc | 61 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 64 insertions(+)
>>
>> diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in
>> index 1969ed0ec3..45b605c3b5 100644
>> --- a/gdbserver/Makefile.in
>> +++ b/gdbserver/Makefile.in
>> @@ -221,6 +221,7 @@ SFILES = \
>>   	$(srcdir)/../gdb/arch/ppc-linux-common.c \
>>   	$(srcdir)/../gdb/arch/riscv.c \
>>   	$(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \
>> +	$(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \
>>   	$(srcdir)/../gdb/nat/linux-btrace.c \
>>   	$(srcdir)/../gdb/nat/linux-namespaces.c \
>>   	$(srcdir)/../gdb/nat/linux-osdata.c \
>> diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
>> index 833ad27c4c..0bbd990758 100644
>> --- a/gdbserver/configure.srv
>> +++ b/gdbserver/configure.srv
>> @@ -52,8 +52,10 @@ case "${gdbserver_host}" in
>>   			srv_tgtobj="$srv_tgtobj nat/aarch64-linux.o"
>>   			srv_tgtobj="$srv_tgtobj arch/aarch64-insn.o"
>>   			srv_tgtobj="$srv_tgtobj arch/aarch64.o"
>> +			srv_tgtobj="$srv_tgtobj arch/aarch64-mte-linux.o"
>>   			srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o"
>>   			srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o"
>> +			srv_tgtobj="$srv_tgtobj nat/aarch64-mte-linux-ptrace.o"
> 
> Please keep the list sorted.
> 

Fixed.

>> +int
>> +aarch64_target::fetch_memtags (CORE_ADDR address, size_t len,
>> +			       gdb::byte_vector &tags, int type)
>> +{
>> +  /* Allocation tags are per-process, so any tid is fine.  */
>> +  int tid = lwpid_of (current_thread);
>> +
>> +  /* Allocation tag?  */
>> +  if (type == 1)
>> +    return aarch64_mte_fetch_memtags (tid, address, len, tags);
> 
> Is there a define you could use instead of the magic "1"?

Yes. I suppose I could share the definition with the GDB code. I'll fix 
the code.

> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 19/24] New mtag commands
  2020-12-27  3:32   ` Simon Marchi
@ 2020-12-29 17:21     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-29 17:21 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/27/20 12:32 AM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Add new commands under the "mtag" prefix to allow users to inspect, modify and
>> check memory tags in different ways.
>>
>> The available subcommands are the following:
>>
>> - mtag showltag <expression>: Shows the logical tag for a particular address.
>>
>> - mtag withltag <expression> <tag>: Prints the address tagged with the logical
>>    tag <tag>.
>>
>> - mtag showatag <expression>: Shows the allocation tag for a particular address.
>>
>> - mtag setatag <expression> <length> <tags>: Sets one or more allocation tags to
>>    the specified tags.
>>
>> - mtag check <expression>: Check if the logical tag in <address> matches its
>>    allocation tag.
> 
> The only thing that bugs me here is the command names.  I'm sure we could bikeshed
> for ever about this, but here are my comments:

I suppose we could... :-)

> 
>   - I don't really like the "everything glued together" style, that makes it harder
>     to read the name.  For instance, I don't like the existing "set remoteaddresssize"
>     command, that's just ugly.  We usually separate words with dashes.
>   - I don't really like the use of abbreviations (especially one-letter abbreviations)
>     in commands, as it's not good for discoverability.  I would prefer if we used full
>     names, for clarity, and if you really want a short version, add an alias.  My
>     opinion is that with tab-completion, long (but clear) command names are not really
>     an issue.
> 
> So:
> 
>   - mtag show-logical-tag
>   - mtag with-logical-tag
>   - mtag show-allocation-tag
>   - mtag set-allocation-tag

I don't mind the long names to be honest. What I find a bit annoying is 
having to work with longer names while the column limit is still 80. 
I've been hitting this issue a bit more with C++ and longer function 
names. Sometimes it is hard to break things up across multiple lines.

> 
> And the "mtag" prefix... maybe "memory-tag", or "mem-tag" at least?  It's not obvious
> that the "m" stands for "memory",
> 

In any case, I've changed the commands to spell it all completely and 
also switched from using "show" to using "print".

>>
>> These commands make use of the memory tagging gdbarch methods, and are still
>> available, but disabled, when memory tagging is not supported by the
>> architecture.
>>
>> I've pondered about a way to make these commands invisible when memory tagging
>> is not available, but given the check is at runtime (and support may come and go
>> based on a process' configuration), that is a bit too late in the process to
>> either not include the commands or get rid of them.
> 
> I think it's fine if the commands are always there, because it just says "this
> architecture does not support memory tagging" if you try to use them with an
> architecture that does not support memory tagging.
> 
> FYI, I get this when trying to build this patch:
> 
>    CXX    printcmd.o
> cc1plus: warning: command-line option ‘-Wmissing-prototypes’ is valid for C/ObjC but not for C++
> /home/simark/src/binutils-gdb/gdb/printcmd.c: In function ‘void parse_withltag_input(const char*, value**, gdb::byte_vector&, value_print_options*)’:
> /home/simark/src/binutils-gdb/gdb/printcmd.c:2918:10: error: ‘hex2bin’ was not declared in this scope
>   2918 |   tags = hex2bin (s_tag.c_str ());
>        |          ^~~~~~~
> /home/simark/src/binutils-gdb/gdb/printcmd.c: In function ‘void parse_setatag_input(const char*, value**, size_t*, gdb::byte_vector&)’:
> /home/simark/src/binutils-gdb/gdb/printcmd.c:2997:10: error: ‘hex2bin’ was not declared in this scope
>   2997 |   tags = hex2bin (s_tags.c_str ());
>        |          ^~~~~~~
> 
> 
>>
>> Ideas are welcome.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* printcmd.c: Include gdbsupport/rsp-low.h.
>> 	(mtaglist): New static global.
>> 	(process_print_command_args): Factored out of
>> 	print_command_1.
>> 	(print_command_1): Use process_print_command_args.
>> 	(show_addr_not_tagged, show_memtag_unsupported, mtag_command)
>> 	(mtag_showtag_command, mtag_showltag_command, mtag_showatag_command)
>> 	(parse_withltag_input, mtag_withltag_command, parse_setatag_input)
>> 	(mtag_setatag_command, mtag_check_command): New functions.
>> 	(_initialize_printcmd): Add "mtag" prefix and subcommands.
>>
>> gdbsupport/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* rsp-low.cc (fromhex): Change error message text to not be
>> 	RSP-specific.
> 
> Then, this function should probably be moved out of rsp-low.cc, perhaps
> to common-utils.cc.
> 

Done now.

>> ---
>>   gdb/printcmd.c        | 359 ++++++++++++++++++++++++++++++++++++++++--
>>   gdbsupport/rsp-low.cc |   2 +-
>>   2 files changed, 348 insertions(+), 13 deletions(-)
>>
>> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
>> index 28451612ab..6949678235 100644
>> --- a/gdb/printcmd.c
>> +++ b/gdb/printcmd.c
>> @@ -53,6 +53,11 @@
>>   #include "source.h"
>>   #include "gdbsupport/byte-vector.h"
>>   #include "gdbsupport/gdb_optional.h"
>> +#include "gdbsupport/rsp-low.h"
>> +
>> +/* Chain containing all defined mtag subcommands.  */
>> +
>> +struct cmd_list_element *mtaglist;
> 
> static?
> 

Fixed.

>>   
>>   /* Last specified output format.  */
>>   
>> @@ -1219,31 +1224,38 @@ print_value (value *val, const value_print_options &opts)
>>     annotate_value_history_end ();
>>   }
>>   
>> -/* Implementation of the "print" and "call" commands.  */
>> +/* Helper for parsing arguments for print_command_1.  */
>>   
>> -static void
>> -print_command_1 (const char *args, int voidprint)
>> +static struct value *
>> +process_print_command_args (const char *args, value_print_options *print_opts)
>>   {
>> -  struct value *val;
>> -  value_print_options print_opts;
>> -
>> -  get_user_print_options (&print_opts);
>> +  get_user_print_options (print_opts);
>>     /* Override global settings with explicit options, if any.  */
>> -  auto group = make_value_print_options_def_group (&print_opts);
>> +  auto group = make_value_print_options_def_group (print_opts);
>>     gdb::option::process_options
>>       (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group);
>>   
>> -  print_command_parse_format (&args, "print", &print_opts);
>> +  print_command_parse_format (&args, "print", print_opts);
>>   
>>     const char *exp = args;
>>   
>>     if (exp != nullptr && *exp)
>>       {
>>         expression_up expr = parse_expression (exp);
>> -      val = evaluate_expression (expr.get ());
>> +      return evaluate_expression (expr.get ());
>>       }
>> -  else
>> -    val = access_value_history (0);
>> +
>> +  return access_value_history (0);
>> +}
>> +
>> +/* Implementation of the "print" and "call" commands.  */
>> +
>> +static void
>> +print_command_1 (const char *args, int voidprint)
>> +{
>> +  value_print_options print_opts;
>> +
>> +  struct value *val = process_print_command_args (args, &print_opts);
>>   
>>     if (voidprint || (val && value_type (val) &&
>>   		    value_type (val)->code () != TYPE_CODE_VOID))
>> @@ -2711,6 +2723,273 @@ eval_command (const char *arg, int from_tty)
>>     execute_command (expanded.c_str (), from_tty);
>>   }
>>   
>> +/* Convenience function for error checking in mtag commands.  */
>> +
>> +static void
>> +show_addr_not_tagged (CORE_ADDR address)
>> +{
>> +  error (_("Address %s not in a region mapped with a memory tagging flag."),
>> +	 paddress (target_gdbarch (), address));
>> +}
>> +
>> +/* Convenience function for error checking in mtag commands.  */
>> +
>> +static void
>> +show_memtag_unsupported (void)
>> +{
>> +  error (_("Memory tagging not supported or disabled by the current"
>> +	   " architecture."));
>> +}
>> +
>> +/* Implement the "mtag" prefix command.  */
>> +
>> +static void
>> +mtag_command (const char *arg, int from_tty)
>> +{
>> +  help_list (mtaglist, "mtag ", all_commands, gdb_stdout);
>> +}
>> +
>> +/* Helper for showltag and showatag.  */
>> +
>> +static void
>> +mtag_showtag_command (const char *args, enum memtag_type tag_type)
>> +{
>> +  if (args == nullptr)
>> +    error_no_arg (_("address or pointer"));
>> +
>> +  /* Parse args into a value.  If the value is a pointer or an address,
>> +     then fetch the logical or allocation tag.  */
>> +  value_print_options print_opts;
>> +
>> +  struct value *val = process_print_command_args (args, &print_opts);
>> +
>> +  /* If the address is not in a region memory mapped with a memory tagging
>> +     flag, it is no use trying to access/manipulate its allocation tag.
>> +
>> +     It is OK to manipulate the logical tag though.  */
>> +  if (tag_type == tag_allocation
>> +      && !gdbarch_tagged_address_p (target_gdbarch (), val))
>> +    show_addr_not_tagged (value_as_address (val));
>> +
>> +  std::string tag = gdbarch_memtag_to_string (target_gdbarch (),
>> +					      val, tag_type);
>> +  if (tag.empty ())
>> +    printf_filtered (_("%s tag unavailable.\n"),
>> +		     tag_type == tag_logical? "Logical" : "Allocation");
>> +
>> +  struct value *v_tag = process_print_command_args (tag.c_str (),
>> +						    &print_opts);
>> +  print_opts.output_format = 'x';
>> +  print_value (v_tag, print_opts);
> 
> When I read the patch description, I almost mentioned that it might make
> sense to name the commands "print-xyz" instead of "show-xyz".  "print" is
> used to print values, while "show" is used to show parameter values.  The
> new commands are more print-like IMO.  And the fact that they share print's
> syntax, I think it would make even more sense.
> 
> To be clear, I'm proposing that we name the sub-commands "print-logical-tag"
> and "print-allocation-tag".
> 

I've changed it for all commands.

>> +}
>> +
>> +/* Implement the "mtag showltag" command.  */
>> +
>> +static void
>> +mtag_showltag_command (const char *args, int from_tty)
>> +{
>> +  if (!memtag || !target_supports_memory_tagging ())
>> +    show_memtag_unsupported ();
>> +
>> +  mtag_showtag_command (args, tag_logical);
>> +}
>> +
>> +/* Implement the "mtag showatag" command.  */
>> +
>> +static void
>> +mtag_showatag_command (const char *args, int from_tty)
>> +{
>> +  if (!memtag || !target_supports_memory_tagging ())
>> +    show_memtag_unsupported ();
>> +
>> +  mtag_showtag_command (args, tag_allocation);
>> +}
>> +
>> +/* Parse ARGS and extract ADDR and TAG.
>> +   ARGS should have format <expression> <tag bytes>.  */
>> +
>> +static void
>> +parse_withltag_input (const char *args, struct value **val,
>> +		      gdb::byte_vector &tags, value_print_options *print_opts)
>> +{
>> +  /* Given <expression> can be reasonably complex, we parse things backwards
>> +     so we can isolate the <tag bytes> portion.  */
> 
> This comment doesn't seem to agree with the implementation, or I'm missing
> something.  I don't see any things being parsed backwards.
> 

Leftovers from a previous strategy. I removed it now.

>> +
>> +  /* Fetch the address.  */
>> +  std::string s_address = extract_string_maybe_quoted (&args);
>> +
>> +  /* Parse the address into a value.  */
>> +  *val = process_print_command_args (s_address.c_str (), print_opts);
>> +
>> +  /* Fetch the tag bytes.  */
>> +  std::string s_tag = extract_string_maybe_quoted (&args);
>> +
>> +  /* Validate the input.  */
>> +  if (s_address.empty () || s_tag.empty ())
>> +    error (_("Missing arguments."));
>> +
>> +  if (s_tag.length () % 2)
>> +    error (_("Error parsing tags argument. The tag should be 2 digits."));
> 
> I think the error message is a bit confusing.  At least, it doesn't match the
> check.  Should it be "the tag(s) should be an even number of digits"?
> 

Yeah. I reused the code from the other function that accepts more than a 
couple digits. Fixed now.

>> +
>> +  tags = hex2bin (s_tag.c_str ());
>> +}
>> +
>> +/* Implement the "mtag withltag" command.  */
>> +
>> +static void
>> +mtag_withltag_command (const char *args, int from_tty)
>> +{
>> +  if (!memtag || !target_supports_memory_tagging ())
>> +    show_memtag_unsupported ();
>> +
>> +  if (args == nullptr)
>> +    error_no_arg (_("<address> <tag>"));
>> +
>> +  gdb::byte_vector tags;
>> +  struct value *val;
>> +  value_print_options print_opts;
>> +
>> +  /* Parse the input.  */
>> +  parse_withltag_input (args, &val, tags, &print_opts);
>> +
>> +  /* Setting the logical tag is just a local operation that does not touch
>> +     any memory from the target.  Given an input value, we modify the value
>> +     to include the appropriate tag.
>> +
>> +     For this reason we need to cast the argument value to a
>> +     (void *) pointer.  This is so we have the right the for the gdbarch
> 
> This sentence looks broken.
> 

It should read "... we have the right type for the ...". Fixed now.

>> +     hook to manipulate the value and insert the tag.
>> +
>> +     Otherwise, this would fail if, for example, GDB parsed the argument value
>> +     into an int-sized value and the pointer value has a type of greater
>> +     length.  */
>> +
>> +  /* Cast to (void *).  */
>> +  val = value_cast (builtin_type (target_gdbarch ())->builtin_data_ptr,
>> +		    val);
>> +
>> +  if (gdbarch_set_memtags (target_gdbarch (), val, 0, tags,
>> +			   tag_logical) != 0)
>> +    printf_filtered (_("Could not update the logical tag data.\n"));
>> +  else
>> +    {
>> +      /* Always print it in hex format.  */
>> +      print_opts.output_format = 'x';
>> +      print_value (val, print_opts);
>> +    }
>> +}
>> +
>> +/* Parse ARGS and extract ADDR, LENGTH and TAGS.  */
>> +
>> +static void
>> +parse_setatag_input (const char *args, struct value **val, size_t *length,
>> +		     gdb::byte_vector &tags)
>> +{
>> +  /* Fetch the address.  */
>> +  std::string s_address = extract_string_maybe_quoted (&args);
>> +
>> +  /* Parse the address into a value.  */
>> +  value_print_options print_opts;
>> +  *val = process_print_command_args (s_address.c_str (), &print_opts);
>> +
>> +  /* Fetch the length.  */
>> +  std::string s_length = extract_string_maybe_quoted (&args);
>> +
>> +  /* Fetch the tag bytes.  */
>> +  std::string s_tags = extract_string_maybe_quoted (&args);
>> +
>> +  /* Validate the input.  */
>> +  if (s_address.empty () || s_length.empty () || s_tags.empty ())
>> +    error (_("Missing arguments."));
>> +
>> +  errno = 0;
>> +  *length = strtoulst (s_length.c_str (), NULL, 10);
>> +  if (errno != 0)
>> +    error (_("Error parsing length argument."));
>> +
>> +  if (s_tags.length () % 2)
>> +    error (_("Error parsing tags argument. Tags should be 2 digits per byte."));
>> +
>> +  tags = hex2bin (s_tags.c_str ());
>> +
>> +  /* If the address is not in a region memory mapped with a memory tagging
>> +     flag, it is no use trying to access/manipulate its allocation tag.  */
>> +  if (!gdbarch_tagged_address_p (target_gdbarch (), *val))
>> +    show_addr_not_tagged (value_as_address (*val));
>> +}
>> +
>> +/* Implement the "mtag setatag" command.
>> +   ARGS should be in the format <address> <length> <tags>.  */
>> +
>> +static void
>> +mtag_setatag_command (const char *args, int from_tty)
>> +{
>> +  if (!memtag || !target_supports_memory_tagging ())
>> +    show_memtag_unsupported ();
>> +
>> +  if (args == nullptr)
>> +    error_no_arg (_("<starting address> <length> <tag bytes>"));
>> +
>> +  gdb::byte_vector tags;
>> +  size_t length = 0;
>> +  struct value *val;
>> +
>> +  /* Parse the input.  */
>> +  parse_setatag_input (args, &val, &length, tags);
>> +
>> +  if (gdbarch_set_memtags (target_gdbarch (), val, length, tags,
>> +			   tag_allocation) != 0)
>> +    printf_filtered (_("Could not update the allocation tag(s).\n"));
>> +  else
>> +    printf_filtered (_("Allocation tag(s) updated successfully.\n"));
>> +}
>> +
>> +/* Implement the "mtag check" command.  */
>> +
>> +static void
>> +mtag_check_command (const char *args, int from_tty)
>> +{
>> +  if (!memtag || !target_supports_memory_tagging ())
>> +    show_memtag_unsupported ();
>> +
>> +  if (args == nullptr)
>> +    error (_("Argument required (address or pointer)"));
>> +
>> +  /* Parse the expression into a value.  If the value is an address or
>> +     pointer, then check its logical tag against the allocation tag.  */
>> +  value_print_options print_opts;
>> +
>> +  struct value *val = process_print_command_args (args, &print_opts);
>> +
>> +  /* If the address is not in a region memory mapped with a memory tagging
>> +     flag, it is no use trying to access/manipulate its allocation tag.  */
>> +  if (!gdbarch_tagged_address_p (target_gdbarch (), val))
>> +    show_addr_not_tagged (value_as_address (val));
>> +
>> +  CORE_ADDR addr = value_as_address (val);
>> +
>> +  /* If memory tagging validation is on, check if the tag is valid.  */
> 
> This comment doesn't seem in-line with the implementation, there is no
> check here whether the mem tag validation is on or off.

No. Another leftover from earlier versions of the code. I've moved the 
check for whether we have tag checks on/off to the beginning of the 
function, so this doesn't make sense anymore. Fixed now.

Given the amount of changes in this particular patch, I'm inclined to 
send a v4 just to make sure.

> 
> Simon
>

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-12-27  4:18   ` Simon Marchi
@ 2020-12-29 18:50     ` Luis Machado
  2021-01-18 17:56       ` Simon Marchi
  0 siblings, 1 reply; 96+ messages in thread
From: Luis Machado @ 2020-12-29 18:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/27/20 1:18 AM, Simon Marchi wrote:
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> The "print" command will point out any possible tag mismatches it finds
>> when dealing with pointers, in case such a pointer is tagged.  No additional
>> modifiers are needed.
>>
>> Suppose we have a pointer "p" with value 0x1234 (logical tag 0x0) and that we
>> have an allocation tag of 0x1 for that particular area of memory. This is the
>> expected output:
>>
>> (gdb) p/x p
>> Logical tag (0x0) does not match the allocation tag (0x1).
>> $1 = 0x1234
> 
> Should there be an option to print to enable/disable this behavior?
> Something like "print -memory-tags-violations <on|off>", and a
> corresponding "set print memory-tags-violations <on|off>"?

The switch that controls this is the one that enables/disables memory 
tagging. It controls both the print command behavior and the "x" command 
behavior.

Do you think we should have a command for each individual command?

> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 24/24] Add memory tagging testcases
  2020-12-27  4:36   ` Simon Marchi
@ 2020-12-29 19:32     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-29 19:32 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/27/20 1:36 AM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> +# Targets that don't support memory tagging should not execute the
>> +# runtime memory tagging tests.
>> +if {![supports_memtag]} {
>> +    untested "memory tagging unsupported"
> 
> Use unsupported?
>  > https://www.gnu.org/software/dejagnu/manual/unsupported-procedure.html
> 

Fixed.

>> +    return -1
>> +}
>> +
>> +gdb_breakpoint "access_memory"
>> +
>> +if [gdb_continue "access_memory"] {
>> +    fail "could not run to tagged memory test function"
> 
> gdb_continue will already produce a FAIL, so no need to use another one here.
> 

Thanks for spotting this. Fixed now.

>> +    return -1
>> +}
>> +
>> +# Fetch a known pointer to an area mapped with PROT_MTE.
>> +set tagged_ptr_symbol "tagged_ptr"
>> +set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
>> +
>> +if {$tagged_ptr_addr == -1} {
>> +    untested "unexpected pointer or tag value"
> 
> If that happens, that would be an expected error in the test that should be
> fixed, right?  If so, I'd suggest using "unresolved".  We should be able to
> get that value, if we can't something is wrong (it's not just a matter of
> something being unsupported).
> 

That's true. If that happens, all the bets are off, and we don't want to 
continue the test.

>> +    return -1
>> +}
>> +
>> +# Fetch a known pointer to an area not mapped with PROT_MTE.
>> +set untagged_ptr_symbol "untagged_ptr"
>> +set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
>> +
>> +if {$untagged_ptr_addr == -1} {
>> +    untested "unexpected pointer or tag value"
> 
> Same here.
> 

Fixed.

>> +with_test_prefix "symbolic" {
>> +    # Test inspecting an allocation tag from a pointer to a memory area that
>> +    # is not mapped with PROT_MTE.
>> +    set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
>> +    gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
>> +	     "mtag showatag with an untagged address"
>> +
>> +    gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
>> +	     "mtag setatag with an untagged address"
>> +
>> +    # Test setting and showing the logical tags for a literal address.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +	set addr_tagged 0
>> +
>> +	with_test_prefix "tag ${i}" {
>> +	    set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +	    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +			       "update value of symbol ${tagged_ptr_symbol}"
>> +	}
>> +
>> +	set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +	gdb_test "mtag showltag ${tagged_ptr_symbol}" \
>> +		 " = 0x${tag_hexnz}" \
>> +		 "showltag with tag ${i}"
>> +
>> +	set tag_hexnn [get_tag_nn $i]
>> +	gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
>> +		 " = \\(void \\*\\) ${addr_tagged}" \
>> +		 "withltag with tag ${i}"
>> +    }
>> +
>> +    # Reset the tagged ptr to its original value
>> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
>> +		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
>> +
>> +    set setatag_msg "Allocation tag\\(s\\) updated successfully\."
>> +    # Test setting and showing the allocation tags.
>> +    for {set i 0} {$i < 32} {incr i} {
>> +
>> +	set tag_hexnn [get_tag_nn $i]
>> +	gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
>> +		 $setatag_msg \
>> +		 "setatag with tag ${i}"
>> +
>> +	set tag_hexnz [get_hex_tag [expr $i % 16]]
>> +	gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
>> +		 "showatag with tag ${i}"
>> +    }
>> +
>> +    # Test tag mismatches.
>> +    with_test_prefix "tag mismatches" {
>> +	for {set i 0} {$i < 32} {incr i} {
>> +
>> +	    # Set the allocation tag to a known value (0).
>> +	    set tag_hexnn [get_tag_nn $i]
>> +	    gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
>> +		     $setatag_msg \
>> +		     "setatag with tag ${i}"
>> +
>> +	    set atag_hexnz [get_hex_tag [expr $i % 16]]
>> +
>> +	    # Validate that the logical tag matches the allocation tag.
>> +	    with_test_prefix "tag ${i}" {
>> +		set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
>> +	    }
>> +
>> +	    with_test_prefix "tag ${i}" {
>> +		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +				   "set ${tagged_ptr_symbol} to a matching logical tag"
>> +	    }
>> +
>> +	    gdb_test "mtag check ${tagged_ptr_symbol}" \
>> +		     "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
>> +		     "check match with tag ${i}"
>> +
>> +	    # Get a pointer with the logical tag that does not match the
>> +	    # allocation tag.
>> +	    set ltag [expr $i + 1]
>> +	    with_test_prefix "fetch mismatch tag ${i}" {
>> +		set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
>> +	    }
>> +
>> +	    with_test_prefix "tag ${i}" {
>> +		gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
>> +				   "set ${tagged_ptr_symbol} to a mismatching logical tag"
>> +	    }
>> +
>> +	    # Validate that the logical tag does not match the allocation
>> +	    # tag.
>> +	    set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
>> +	    gdb_test "mtag check ${tagged_ptr_symbol}" \
>> +		     "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
>> +		     "check mismatch with tag ${i}"
>> +	}
>> +    # Reset the tagged ptr to its original value
>> +    gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
>> +		       "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> 
> The indentation is off here.
> 

Oops. Fixed now.

>> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
>> index 55154db6a5..347704ce0a 100644
>> --- a/gdb/testsuite/lib/gdb.exp
>> +++ b/gdb/testsuite/lib/gdb.exp
>> @@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
>>       }
>>   }
>>   
>> +# Return 1 if memory tagging is supported at runtime, otherwise return 0.
>> +
>> +proc supports_memtag {} {
> 
> Should this use gdb_caching_proc?
> 

It should, since we don't expect the setting to change across the run.

> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 16/24] AArch64: Report tag violation error information
  2020-12-26 22:23   ` Simon Marchi
@ 2020-12-30  0:50     ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2020-12-30  0:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 12/26/20 7:23 PM, Simon Marchi wrote:
> 
> 
> On 2020-11-09 12:04 p.m., Luis Machado via Gdb-patches wrote:
>> Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
>> information can be obtained through the siginfo data structure.
>>
>> For AArch64 the Linux kernel may expose the fault address and tag
>> information, if we have a synchronous event. Otherwise there is
>> no fault address available.
> 
> Can you give an example of the end result message?
> 

I've attached it to the commit message.

The synchronous event looks like this:

--
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault
Memory tag violation while accessing address 0x0000fffff7ff8000
Allocation tag 0x1.
--

The asynchronous event looks like this:

--
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault
Memory tag violation
Fault address unavailable.
--

>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* aarch64-linux-tdep.c
>> 	(aarch64_linux_report_signal_info): New function.
>> 	(aarch64_linux_init_abi): Register
>> 	aarch64_linux_report_signal_info as the report_signal_info hook.
>> 	* arch/aarch64-linux.h (SEGV_MTEAERR): Define.
>> 	(SEGV_MTESERR): Define.
>> ---
>>   gdb/aarch64-linux-tdep.c     | 64 ++++++++++++++++++++++++++++++++++++
>>   gdb/arch/aarch64-mte-linux.h |  6 ++++
>>   2 files changed, 70 insertions(+)
>>
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index 39b1790263..70e180e1cb 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
>>     return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
>>   }
>>   
>> +/* AArch64 Linux implementation of the report_signal_info gdbarch
>> +   hook.  Displays information about possible memory tag violations.  */
>> +
>> +static void
>> +aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>> +				  struct ui_out *uiout,
>> +				  enum gdb_signal siggnal)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
>> +    return;
>> +
>> +  CORE_ADDR fault_addr = 0;
>> +  long si_code = 0;
>> +
>> +  try
>> +    {
>> +      /* Sigcode tells us if the segfault is actually a memory tag
>> +	 violation.  */
>> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
> 
> Is the \n necessary?
> 

No. Fixed now.

>> +
>> +      fault_addr
>> +	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
>> +    }
>> +  catch (const gdb_exception &exception)
>> +    {
>> +      return;
>> +    }
> 
> I think it's better to catch gdb_exception_error, to avoid catching ^C
> (gdb_exception_quit).
> 
> And if there's an error doing the evaluation... do we want to print
> a warning of some sort?
> 

I went with printing the exception with...

exception_print (gdb_stderr, exception);


> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks
  2020-12-29 12:16     ` Luis Machado
@ 2021-01-18 16:29       ` Simon Marchi
  2021-01-20 20:01         ` Tom Tromey
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2021-01-18 16:29 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett

>>> +      if (g < n)
>>> +    {
>>> +      warning (_("Got more tags than memory granules.  Tags will be "
>>> +             "truncated."));
>>> +    }
>>
>> Remove curly braces.
>>
> 
> Isn't the rule to have curly braces for one-statement conditionals if such statement spans more than a single line? That has been my understanding so far.

I don't really know for sure, the GNU coding style is kinda vague.  But
if you find it let me know.

My understanding (and I don't really know where I took this) was to apply
this rule when you have a comment:

if (something)
  /* Something.  */
  something ();

vs

if (something)
  {
    /* Something.  */
    something ();
  }

The situation where it's really important, that the GNU coding standard
talks about, is a if-else inside an if:

if (foo)
  if (bar)
    win ();
  else
    lose ();

vs

if (foo)
  {
    if (bar)
      win ();
    else
      lose ();
  }

It would be easy to get confused with the first one.  But all the other
ones are not a big deal.

Simon

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2020-12-29 18:50     ` Luis Machado
@ 2021-01-18 17:56       ` Simon Marchi
  2021-01-18 20:20         ` Luis Machado
  0 siblings, 1 reply; 96+ messages in thread
From: Simon Marchi @ 2021-01-18 17:56 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: david.spickett



On 2020-12-29 1:50 p.m., Luis Machado wrote:
> The switch that controls this is the one that enables/disables memory tagging. It controls both the print command behavior and the "x" command behavior.
> 
> Do you think we should have a command for each individual command?

Hmm well I'm comparing it to the other "set print" options.  If you
add an option (say, "memory-tag-violations" to the
value_print_option_defs array, you get both

  set print memory-tag-violations on/off

and

  print -memory-tag-violations on/off

options for free.

And now that I think about it a bit more, I am not sure why the
"set memory-tagging" exists (at least as of today).  It controls
whether you can use the "memory-tag" commands, but I don't really
see why that's useful.  If you don't want to use these commands,
you can just not use them not need for them to be disabled.

Otherwise, the memory_tagging global is only used to control
whether "print" and "x" should talk about memory tags.  With
my suggestion above, print already has its -memory-tag-violations
flag and "set print memory-tag-violations" option.  And the
"x" command already has its /m option that you implemented.
So I don't see a need for the "set memory-tagging" option.

If tracking memory tags required maintaining a state as the
program runs, then it would make sense to have a
"set memory-tagging on/off" option to enable/disable that
feature.

And I think that printing memory tags and printing memory tag
violations are two separate things, so we should be precise in
the option names.  We might later want to implement a "print"
option to print the logical tags every time a pointer value is
printed (a bit like symbols are printed when the pointer points
to a symbol).  That could then be controlled by

  set print memory-logical-tags
  print -memory-logical-tags

By naming the new print option "memory-tag-violations" (rather
than say "memory-tags"), we leave the door open to things like
that.

Random usage questions:

If I do

  (gdb) print myptr

and myptr has the wrong logical tag for the pointed memory area,
it will print that there is a memory tag violation.  But will it
also print it if myptr is dereferenced in an expression, like
this?

  (gdb) print *myptr + 2

I guess not, as this is only checked when the final value is
printed.  Is this something we might want in the future?

What happens for arrays?  If the granule size is 16 bytes, but you
have an array of 32 bytes, does the array have two different
allocation tags?  But then the pointer (that points to the beginning
of the array) can only contain a single logical tag.  What happens
when you use the pointer to access the various areas of the array?

Simon


^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging
  2021-01-18 17:56       ` Simon Marchi
@ 2021-01-18 20:20         ` Luis Machado
  0 siblings, 0 replies; 96+ messages in thread
From: Luis Machado @ 2021-01-18 20:20 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: david.spickett

On 1/18/21 2:56 PM, Simon Marchi wrote:
> 
> 
> On 2020-12-29 1:50 p.m., Luis Machado wrote:
>> The switch that controls this is the one that enables/disables memory tagging. It controls both the print command behavior and the "x" command behavior.
>>
>> Do you think we should have a command for each individual command?
> 
> Hmm well I'm comparing it to the other "set print" options.  If you
> add an option (say, "memory-tag-violations" to the
> value_print_option_defs array, you get both
> 
>    set print memory-tag-violations on/off
> 
> and
> 
>    print -memory-tag-violations on/off
> 
> options for free.
> 
> And now that I think about it a bit more, I am not sure why the
> "set memory-tagging" exists (at least as of today).  It controls
> whether you can use the "memory-tag" commands, but I don't really
> see why that's useful.  If you don't want to use these commands,
> you can just not use them not need for them to be disabled.
> 
> Otherwise, the memory_tagging global is only used to control
> whether "print" and "x" should talk about memory tags.  With
> my suggestion above, print already has its -memory-tag-violations
> flag and "set print memory-tag-violations" option.  And the
> "x" command already has its /m option that you implemented.
> So I don't see a need for the "set memory-tagging" option.
> 
> If tracking memory tags required maintaining a state as the
> program runs, then it would make sense to have a
> "set memory-tagging on/off" option to enable/disable that
> feature.
> 
> And I think that printing memory tags and printing memory tag
> violations are two separate things, so we should be precise in
> the option names.  We might later want to implement a "print"
> option to print the logical tags every time a pointer value is
> printed (a bit like symbols are printed when the pointer points
> to a symbol).  That could then be controlled by
> 
>    set print memory-logical-tags
>    print -memory-logical-tags
> 
> By naming the new print option "memory-tag-violations" (rather
> than say "memory-tags"), we leave the door open to things like
> that.

Thinking about this, it makes sense. If a target does not implement the 
memory tagging commands, then GDB will display an error stating so.

I can update v4 to follow this suggestion.

> 
> Random usage questions:
> 
> If I do
> 
>    (gdb) print myptr
> 
> and myptr has the wrong logical tag for the pointed memory area,
> it will print that there is a memory tag violation.  But will it
> also print it if myptr is dereferenced in an expression, like
> this?
> 
>    (gdb) print *myptr + 2
> 
> I guess not, as this is only checked when the final value is
> printed.  Is this something we might want in the future?

Right. GDB first evaluates the expression into a result (struct value 
*), then checks if the result is a pointer. If that is the case, then it 
proceeds to do the check.

We don't check each individual element in an expression. We could do so 
in the future, of course. But, given the most common use case we're 
trying to cover, I don't think the extra complexity and verbosity would 
be worth it.

The most common use case would be a faulty program that is running into 
a SIGSEGV due to a tag violation. Then the developer can use GDB to 
pinpoint where that violation is coming from, why it is happening and 
what the right tag should be for that particular case.

Checking every individual element of an expression (tag-wise) would be a 
bit too much. And the default for this feature most likely would need to 
be "off" so we don't incur in unnecessary overhead.

The answer to the question "is this particular pointer tagged?" is 
already a bit expensive to answer, given we need to go through the 
/proc/<pid>/smaps file and parse each memory map entry.



> 
> What happens for arrays?  If the granule size is 16 bytes, but you
> have an array of 32 bytes, does the array have two different
> allocation tags?  But then the pointer (that points to the beginning
> of the array) can only contain a single logical tag.  What happens
> when you use the pointer to access the various areas of the array?

Compiler-wise, I'm pretty sure a contiguous array of 32 bytes would have 
the same tag across its 2 granules. Of course you could create an area 
with 2 granules containing different tags, and then try to access those 
as an array of 32 bytes through some pointer.

In GDB, "p array[0]" wouldn't cause warnings about tag mismatches 
because you're evaluating the expression and getting, say, an integer 
back. And integers don't hold logical tags.

If you issue "p array" instead, then GDB will attempt to validate the 
tag for you.

(gdb) ptype a
type = unsigned char *
(gdb) memory-tag print-allocation-tag &a[0]
$3 = 0x0
(gdb) memory-tag print-allocation-tag &a[16]
$4 = 0x0
(gdb) p a
Logical tag (0x8) does not match the allocation tag (0x0).
$1 = (unsigned char *) 0x800fffff7ffa000 "\001\002"
(gdb) p a[0]
$5 = 1 '\001'
(gdb) p a[16]
$6 = 0 '\000'
(gdb) p &a[16]
Logical tag (0x8) does not match the allocation tag (0x0).
$7 = (unsigned char *) 0x800fffff7ffa010 ""

> 
> Simon
> 

^ permalink raw reply	[flat|nested] 96+ messages in thread

* Re: [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks
  2021-01-18 16:29       ` Simon Marchi
@ 2021-01-20 20:01         ` Tom Tromey
  0 siblings, 0 replies; 96+ messages in thread
From: Tom Tromey @ 2021-01-20 20:01 UTC (permalink / raw)
  To: Simon Marchi via Gdb-patches; +Cc: Luis Machado, Simon Marchi, david.spickett

>>>>> "Simon" == Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:

Simon> I don't really know for sure, the GNU coding style is kinda vague.  But
Simon> if you find it let me know.

They don't really specify everything to that level of detail.

Simon> My understanding (and I don't really know where I took this) was to apply
Simon> this rule when you have a comment:

Simon> if (something)
Simon>   /* Something.  */
Simon>   something ();

Simon> vs

Simon> if (something)
Simon>   {
Simon>     /* Something.  */
Simon>     something ();
Simon>   }

Yes, that's the way I have interpreted them as well.

Tom

^ permalink raw reply	[flat|nested] 96+ messages in thread

end of thread, other threads:[~2021-01-20 20:01 UTC | newest]

Thread overview: 96+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-09 17:04 [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
2020-11-09 17:04 ` [PATCH v3 01/24] New target methods for memory tagging support Luis Machado
2020-12-25  4:26   ` Simon Marchi
2020-12-28 15:05     ` Luis Machado
2020-12-25  5:08   ` Simon Marchi
2020-11-09 17:04 ` [PATCH v3 02/24] New gdbarch memory tagging hooks Luis Machado
2020-12-25  4:40   ` Simon Marchi
2020-12-28 15:44     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 03/24] Add GDB-side remote target support for memory tagging Luis Machado
2020-12-25  5:08   ` Simon Marchi
2020-12-28 16:28     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 04/24] Unit testing for GDB-side remote memory tagging handling Luis Machado
2020-12-25  5:34   ` Simon Marchi
2020-12-28 17:17     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 05/24] GDBserver remote packet support for memory tagging Luis Machado
2020-12-25  5:50   ` Simon Marchi
2020-12-28 17:46     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 06/24] Unit tests for gdbserver memory tagging remote packets Luis Machado
2020-12-25 20:13   ` Simon Marchi
2020-12-28 18:12     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 07/24] Documentation for " Luis Machado
2020-11-09 17:08   ` Eli Zaretskii
2020-11-16 15:44     ` David Spickett
2020-11-16 16:04       ` David Spickett
2020-11-16 17:22         ` Luis Machado
2020-11-17 10:05           ` David Spickett
2020-11-17 12:01             ` Luis Machado
2020-11-17 12:29               ` David Spickett
2020-11-17 14:44                 ` Luis Machado
2020-11-17 15:16                   ` David Spickett
2020-11-17 17:29                     ` Luis Machado
2020-11-18 10:39                       ` David Spickett
2020-11-18 10:56                         ` Luis Machado
2020-11-18 11:22                           ` David Spickett
2020-11-16 16:49       ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 08/24] AArch64: Add MTE CPU feature check support Luis Machado
2020-12-26  0:04   ` Simon Marchi
2020-11-09 17:04 ` [PATCH v3 09/24] AArch64: Add target description/feature for MTE registers Luis Machado
2020-12-26  0:10   ` Simon Marchi
2020-12-28 18:28     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 10/24] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
2020-12-26  0:17   ` Simon Marchi
2020-12-28 18:41     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 11/24] AArch64: Add MTE ptrace requests Luis Machado
2020-12-26  0:19   ` Simon Marchi
2020-12-28 19:12     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 12/24] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
2020-12-26  0:33   ` Simon Marchi
2020-12-28 19:50     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 13/24] Refactor parsing of /proc/<pid>/smaps Luis Machado
2020-12-26  6:36   ` Simon Marchi
2020-12-29 10:57     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 14/24] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
2020-12-26  6:52   ` Simon Marchi
2020-12-29 12:16     ` Luis Machado
2021-01-18 16:29       ` Simon Marchi
2021-01-20 20:01         ` Tom Tromey
2020-11-09 17:04 ` [PATCH v3 15/24] AArch64: Add unit testing for logical tag set/get operations Luis Machado
2020-11-09 17:04 ` [PATCH v3 16/24] AArch64: Report tag violation error information Luis Machado
2020-11-16 15:43   ` David Spickett
2020-11-16 16:45     ` Luis Machado
2020-11-17  9:36       ` David Spickett
2020-12-26 22:23   ` Simon Marchi
2020-12-30  0:50     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 17/24] AArch64: Add gdbserver MTE support Luis Machado
2020-12-26 22:30   ` Simon Marchi
2020-12-29 14:32     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 18/24] AArch64: Add MTE register set support for core files Luis Machado
2020-11-09 17:04 ` [PATCH v3 19/24] New mtag commands Luis Machado
2020-12-27  3:32   ` Simon Marchi
2020-12-29 17:21     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 20/24] Documentation for the new " Luis Machado
2020-11-09 17:11   ` Eli Zaretskii
2020-11-09 17:04 ` [PATCH v3 21/24] Extend "x" and "print" commands to support memory tagging Luis Machado
2020-11-09 17:14   ` Eli Zaretskii
2020-11-09 17:20     ` Luis Machado
2020-12-27  4:18   ` Simon Marchi
2020-12-29 18:50     ` Luis Machado
2021-01-18 17:56       ` Simon Marchi
2021-01-18 20:20         ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 22/24] Document new "x" and "print" memory tagging extensions Luis Machado
2020-11-09 17:16   ` Eli Zaretskii
2020-11-09 17:04 ` [PATCH v3 23/24] Add NEWS entry Luis Machado
2020-11-09 17:19   ` Eli Zaretskii
2020-11-09 17:22     ` Luis Machado
2020-11-09 17:04 ` [PATCH v3 24/24] Add memory tagging testcases Luis Machado
2020-11-16 15:47   ` David Spickett
2020-11-16 16:51     ` Luis Machado
2020-12-27  4:36   ` Simon Marchi
2020-12-29 19:32     ` Luis Machado
2020-11-16 13:48 ` [PATCH v3 00/24] Memory Tagging Support + AArch64 Linux implementation Luis Machado
2020-11-16 14:37   ` Alan Hayward
2020-11-23 16:08   ` Luis Machado
2020-11-30 13:38     ` Luis Machado
2020-12-07 13:17       ` Luis Machado
2020-12-07 14:17         ` Alan Hayward

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).