public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation
@ 2021-01-27 20:20 Luis Machado
  2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
                   ` (25 more replies)
  0 siblings, 26 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

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 (25):
  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
  Convert char array to std::string in linux_find_memory_regions_full
  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 memory-tag 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                               |  36 +-
 gdb/aarch64-linux-nat.c                | 127 ++++++-
 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           |  73 ++++
 gdb/arch/aarch64-mte-linux.h           |  75 +++++
 gdb/arch/aarch64.c                     |   7 +-
 gdb/arch/aarch64.h                     |   7 +-
 gdb/configure.nat                      |   3 +-
 gdb/configure.tgt                      |   1 +
 gdb/doc/gdb.texinfo                    | 233 ++++++++++++-
 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                       | 378 +++++++++++++--------
 gdb/linux-tdep.h                       |   4 +
 gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
 gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
 gdb/printcmd.c                         | 444 ++++++++++++++++++++++++-
 gdb/remote.c                           | 227 +++++++++++++
 gdb/target-debug.h                     |  24 ++
 gdb/target-delegates.c                 |  95 ++++++
 gdb/target.h                           |  41 +++
 gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
 gdb/testsuite/gdb.arch/aarch64-mte.exp | 369 ++++++++++++++++++++
 gdb/testsuite/gdb.base/memtag.c        |  22 ++
 gdb/testsuite/gdb.base/memtag.exp      |  66 ++++
 gdb/testsuite/gdb.base/options.exp     |   1 +
 gdb/testsuite/gdb.base/with.exp        |   2 +-
 gdb/testsuite/lib/gdb.exp              |  16 +
 gdb/valprint.c                         |  22 ++
 gdb/valprint.h                         |   4 +
 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                    | 219 ++++++++++++
 gdbserver/server.h                     |   3 +
 gdbserver/target.cc                    |  20 ++
 gdbserver/target.h                     |  21 ++
 gdbsupport/common-utils.cc             |  49 +++
 gdbsupport/common-utils.h              |  15 +
 gdbsupport/rsp-low.cc                  |  49 ---
 gdbsupport/rsp-low.h                   |  19 --
 include/elf/common.h                   |   3 +
 57 files changed, 3655 insertions(+), 265 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.25.1


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

* [PATCH v5 01/25] New target methods for memory tagging support
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-01-27 23:26   ` Lancelot SIX
  2021-02-05  2:31   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 02/25] New gdbarch memory tagging hooks Luis Machado
                   ` (24 subsequent siblings)
  25 siblings, 2 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v5:

- Remove the memory_tagging global (in favor of setting a specific print
  option) and related functions.

Updates on v4:

- Updated the return types of fetch/store member functions from int to bool.
- Implemented target-debug type print helpers.
- Renamed global memtag to memory_tagging.

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.

gdb/ChangeLog:

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

	* 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: Regenerate.
	* 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.
	* target-debug.h (target_debug_print_size_t)
	(target_debug_print_const_gdb_byte_vector_r)
	(target_debug_print_gdb_byte_vector_r): New functions.
---
 gdb/remote.c           | 34 +++++++++++++++
 gdb/target-debug.h     | 24 +++++++++++
 gdb/target-delegates.c | 95 ++++++++++++++++++++++++++++++++++++++++++
 gdb/target.h           | 41 ++++++++++++++++++
 4 files changed, 194 insertions(+)

diff --git a/gdb/remote.c b/gdb/remote.c
index bc995edc53..b130f1ddae 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -690,6 +690,14 @@ 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;
+
+  bool fetch_memtags (CORE_ADDR address, size_t len,
+		     gdb::byte_vector &tags, int type) override;
+
+  bool 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,
@@ -14472,6 +14480,32 @@ show_remote_timeout (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* Implement the "supports_memory_tagging" target_ops method.  */
+
+bool
+remote_target::supports_memory_tagging ()
+{
+  return false;
+}
+
+/* Implement the "fetch_memtags" target_ops method.  */
+
+bool
+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.  */
+
+bool
+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-debug.h b/gdb/target-debug.h
index 6910338865..5bc384a39a 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -212,4 +212,28 @@ target_debug_print_signals (gdb::array_view<const unsigned char> sigs)
   fputs_unfiltered (" }", gdb_stdlog);
 }
 
+static void
+target_debug_print_size_t (size_t size)
+{
+  fprintf_unfiltered (gdb_stdlog, "%s", pulongest (size));
+}
+
+static void
+target_debug_print_const_gdb_byte_vector_r (const gdb::byte_vector &vector)
+{
+  fputs_unfiltered ("{", gdb_stdlog);
+
+  for (size_t i = 0; i < vector.size (); i++)
+    {
+      fprintf_unfiltered (gdb_stdlog, " %s",
+			  phex_nz (vector[i], 1));
+    }
+  fputs_unfiltered (" }", gdb_stdlog);
+}
+
+static void
+target_debug_print_gdb_byte_vector_r (gdb::byte_vector &vector)
+{
+  target_debug_print_gdb_byte_vector_r (vector);
+}
 #endif /* TARGET_DEBUG_H */
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 437b19b858..e4563e4dac 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -173,6 +173,9 @@ 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;
+  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
+  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
 };
 
 struct debug_target : public target_ops
@@ -344,6 +347,9 @@ 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;
+  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
+  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
 };
 
 void
@@ -4413,3 +4419,92 @@ debug_target::done_generating_core ()
   fputs_unfiltered (")\n", gdb_stdlog);
 }
 
+bool
+target_ops::supports_memory_tagging ()
+{
+  return this->beneath ()->supports_memory_tagging ();
+}
+
+bool
+dummy_target::supports_memory_tagging ()
+{
+  return false;
+}
+
+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;
+}
+
+bool
+target_ops::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
+{
+  return this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
+}
+
+bool
+dummy_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
+{
+  tcomplain ();
+}
+
+bool
+debug_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->fetch_memtags (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->fetch_memtags (", this->beneath ()->shortname ());
+  target_debug_print_CORE_ADDR (arg0);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_size_t (arg1);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_gdb_byte_vector_r (arg2);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_int (arg3);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
+bool
+target_ops::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
+{
+  return this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
+}
+
+bool
+dummy_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
+{
+  tcomplain ();
+}
+
+bool
+debug_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->store_memtags (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->store_memtags (", this->beneath ()->shortname ());
+  target_debug_print_CORE_ADDR (arg0);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_size_t (arg1);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_const_gdb_byte_vector_r (arg2);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_int (arg3);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
diff --git a/gdb/target.h b/gdb/target.h
index 917476d16a..19395f1258 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1260,6 +1260,38 @@ 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, false otherwise.  */
+    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.
+
+       Returns true if fetching the tags succeeded and false otherwise.  */
+    virtual bool fetch_memtags (CORE_ADDR address, size_t len,
+			       gdb::byte_vector &tags, int type)
+      TARGET_DEFAULT_NORETURN (tcomplain ());
+
+    /* 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.
+
+       Returns true if storing the tags succeeded and false otherwise.  */
+    virtual bool store_memtags (CORE_ADDR address, size_t len,
+			       const gdb::byte_vector &tags, int type)
+      TARGET_DEFAULT_NORETURN (tcomplain ());
   };
 
 /* Deleter for std::unique_ptr.  See comments in
@@ -2312,6 +2344,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.25.1


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

* [PATCH v5 02/25] New gdbarch memory tagging hooks
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  2:38   ` Simon Marchi
  2021-02-05  3:58   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 03/25] Add GDB-side remote target support for memory tagging Luis Machado
                   ` (23 subsequent siblings)
  25 siblings, 2 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Updated return type of gdbarch_set_memtags to bool.
- Renamed gdbarch_memtag_mismatch_p to gdbarch_memtag_matches_p.
- Renamed gdbarch_granule_size to gdbarch_memtag_granule_size.

--

We need some new gdbarch hooks to help us manipulate memory tags without having
to have GDB call 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_matches_p
--
Checks if the logical tag of a pointer and the allocation tag from the address
the pointer points to matches.

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_memtag_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 a particular type for
addresses/pointers.  Some architecture may use pointers of 16 bytes that don't
fit in a CORE_ADDR, for example.

gdb/ChangeLog:

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

	* arch-utils.c (default_memtag_to_string, default_tagged_address_p)
	(default_memtag_matches_p, default_set_memtags)
	(default_get_memtag): New functions.
	* arch-utils.h (default_memtag_to_string, default_tagged_address_p)
	(default_memtag_matches_p, default_set_memtags)
	(default_get_memtag): New prototypes.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
	* gdbarch.sh (memtag_to_string, tagged_address_p, memtag_matches_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 b5547424e4..751b857067 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_matches_p (struct gdbarch *gdbarch, struct value *address)
+{
+  /* By default, assume the tags match.  */
+  return true;
+}
+
+/* See arch-utils.h */
+
+bool
+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 true (successful);  */
+  return true;
+}
+
+/* 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 a7e53ea5ae..e1ffa03eff 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_matches_p.  */
+extern bool default_memtag_matches_p (struct gdbarch *gdbarch,
+				       struct value *address);
+
+/* Default implementation of gdbarch_set_memtags.  */
+bool 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 43d1c154a7..1a65d2647f 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_matches_p_ftype *memtag_matches_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;
@@ -433,6 +439,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_matches_p = default_memtag_matches_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;
@@ -626,6 +637,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_matches_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 */
@@ -1088,6 +1105,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));
@@ -1217,6 +1237,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_matches_p = <%s>\n",
+                      host_address_to_string (gdbarch->memtag_matches_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));
@@ -1370,6 +1399,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));
@@ -1478,6 +1510,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));
@@ -3283,6 +3318,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_matches_p (struct gdbarch *gdbarch, struct value *address)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->memtag_matches_p != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_memtag_matches_p called\n");
+  return gdbarch->memtag_matches_p (gdbarch, address);
+}
+
+void
+set_gdbarch_memtag_matches_p (struct gdbarch *gdbarch,
+                              gdbarch_memtag_matches_p_ftype memtag_matches_p)
+{
+  gdbarch->memtag_matches_p = memtag_matches_p;
+}
+
+bool
+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 2fef567c06..c12e2dc07b 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -117,6 +117,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.  */
@@ -712,6 +724,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 matches the memory tag for that
+   particular address.  Return false otherwise. */
+
+typedef bool (gdbarch_memtag_matches_p_ftype) (struct gdbarch *gdbarch, struct value *address);
+extern bool gdbarch_memtag_matches_p (struct gdbarch *gdbarch, struct value *address);
+extern void set_gdbarch_memtag_matches_p (struct gdbarch *gdbarch, gdbarch_memtag_matches_p_ftype *memtag_matches_p);
+
+/* Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS
+   Return true if successful and false otherwise. */
+
+typedef bool (gdbarch_set_memtags_ftype) (struct gdbarch *gdbarch, struct value *address, size_t length, const gdb::byte_vector &tags, enum memtag_type tag_type);
+extern bool 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 e7c9615924..357fb64505 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 matches the memory tag for that
+# particular address.  Return false otherwise.
+m;bool;memtag_matches_p;struct value *address;address;;default_memtag_matches_p;;0
+
+# Set the tags for the address range [ADDRESS, ADDRESS + LENGTH) to TAGS
+# Return true if successful and false otherwise.
+m;bool;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.
@@ -1362,6 +1386,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.25.1


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

* [PATCH v5 03/25] Add GDB-side remote target support for memory tagging
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
  2021-01-27 20:20 ` [PATCH v5 02/25] New gdbarch memory tagging hooks Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  2:48   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling Luis Machado
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates for v4:

- Rename RSP helper functions.
- Fixup parameter and return types.

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>:<type>
--

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

QMemTags:<address>,<length>:<type>:<uninterpreted tag bytes>
--
Writes the tags of specified type 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_fetch_memtags_request, parse_fetch_memtags_reply)
	(create_store_memtags_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 | 106 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 103 insertions(+), 3 deletions(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index b130f1ddae..bb3473b04c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -2175,6 +2175,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
 };
 
@@ -2316,6 +2320,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.  */
 
@@ -5310,6 +5322,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;
@@ -5404,6 +5418,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
@@ -14485,7 +14503,63 @@ show_remote_timeout (struct ui_file *file, 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.  */
+
+static void
+create_fetch_memtags_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 true if successful, false otherwise.  */
+
+static bool
+parse_fetch_memtags_reply (const gdb::char_vector &reply,
+			   gdb::byte_vector &tags)
+{
+  if (reply.empty () || reply[0] == 'E' || reply[0] != 'm')
+    return false;
+
+  /* Copy the tag data.  */
+  tags = hex2bin (reply.data () + 1);
+
+  return true;
+}
+
+/* Create the QMemTags packet given ADDRESS, LEN, TYPE and TAGS.  */
+
+static void
+create_store_memtags_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.  */
@@ -14494,7 +14568,18 @@ bool
 remote_target::fetch_memtags (CORE_ADDR address, size_t len,
 			      gdb::byte_vector &tags, int type)
 {
-  return 0;
+  /* 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_fetch_memtags_request (rs->buf, address, len, type);
+
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  return parse_fetch_memtags_reply (rs->buf, tags);
 }
 
 /* Implement the "store_memtags" target_ops method.  */
@@ -14503,7 +14588,19 @@ bool
 remote_target::store_memtags (CORE_ADDR address, size_t len,
 			      const gdb::byte_vector &tags, int type)
 {
-  return 0;
+  /* 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_store_memtags_request (rs->buf, address, len, type, tags);
+
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  /* Verify if the request was successful.  */
+  return packet_check_result (rs->buf.data ()) == PACKET_OK;
 }
 
 void _initialize_remote ();
@@ -14905,6 +15002,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.25.1


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

* [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (2 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 03/25] Add GDB-side remote target support for memory tagging Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  2:50   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 05/25] GDBserver remote packet support for memory tagging Luis Machado
                   ` (21 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updated in v4:

- Renamed functions based on reviews.
- Adjusted code to cope with bool return value.
- Restoring of global setting after unit testing.

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 | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/gdb/remote.c b/gdb/remote.c
index bb3473b04c..22cae2a94f 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.  */
 
@@ -14603,6 +14604,93 @@ remote_target::store_memtags (CORE_ADDR address, size_t len,
   return packet_check_result (rs->buf.data ()) == PACKET_OK;
 }
 
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+static void
+test_memory_tagging_functions ()
+{
+  remote_target remote;
+
+  struct packet_config *config
+    = &remote_protocol_packets[PACKET_memory_tagging_feature];
+
+  scoped_restore restore_memtag_support_
+    = make_scoped_restore (&config->support,
+			   config->support);
+
+  /* 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_fetch_memtags_request (packet, 0x0, 0x0, 0);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  expected = "qMemTags:deadbeef,10:1";
+  create_fetch_memtags_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_fetch_memtags_reply (packet, tags) == false);
+  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_fetch_memtags_reply (packet, tags) == true);
+  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_store_memtags_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_store_memtags_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 ()
@@ -15136,4 +15224,9 @@ from the target."),
 
   /* 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.25.1


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

* [PATCH v5 05/25] GDBserver remote packet support for memory tagging
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (3 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  2:56   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 06/25] Unit tests for gdbserver memory tagging remote packets Luis Machado
                   ` (20 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Updated naming of helper functions.
- Updated return types from int to bool.
- Removed return type for functions not returning a value.
- Updated code documentation.

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_fetch_memtags_reply)
	(parse_store_memtags_request): New
	functions.
	(handle_general_set): Handle the QMemTags packet.
	(parse_fetch_memtags_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       | 141 ++++++++++++++++++++++++++++++++++++++
 gdbserver/server.h        |   3 +
 gdbserver/target.cc       |  20 ++++++
 gdbserver/target.h        |  21 ++++++
 6 files changed, 210 insertions(+), 25 deletions(-)

diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
index cfdf1c1883..4e76f08ac5 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 5a8e764cbc..59d77b750c 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 77e89fe6ed..69635742a8 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.
+
+   Returns true if parsing succeeded and false otherwise.  */
+
+static bool
+create_fetch_memtags_reply (char *reply, const gdb::byte_vector &tags)
+{
+  /* It is an error to pass a zero-sized tag vector.  */
+  gdb_assert (tags.size () != 0);
+
+  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 false;
+
+  strcpy (reply, packet.c_str ());
+  return true;
+}
+
+/* Parse the QMemTags request into ADDR, LEN and TAGS.
+
+   Returns true if parsing succeeded and false otherwise.  */
+
+static bool
+parse_store_memtags_request (char *request, CORE_ADDR *addr, size_t *len,
+			     gdb::byte_vector &tags, int *type)
+{
+  gdb_assert (startswith (request, "QMemTags:"));
+
+  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 false;
+
+  /* Skip the colon.  */
+  p++;
+
+  /* Read the tag data.  */
+  tags = hex2bin (p);
+
+  return true;
+}
+
 /* 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,32 @@ 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_store_memtags_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 +2151,27 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
   return (unsigned long long) crc;
 }
 
+/* Parse the qMemTags packet request into ADDR and LEN.  */
+
+static void
+parse_fetch_memtags_request (char *request, CORE_ADDR *addr, size_t *len,
+			     int *type)
+{
+  gdb_assert (startswith (request, "qMemTags:"));
+
+  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;
+}
+
 /* Add supported btrace packets to BUF.  */
 
 static void
@@ -2284,6 +2390,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 +2513,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 +2708,31 @@ 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);
+
+      parse_fetch_memtags_request (own_buf, &addr, &len, &type);
+
+      int ret = the_target->fetch_memtags (addr, len, tags, type);
+
+      if (ret)
+	ret = create_fetch_memtags_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;
@@ -3811,6 +3951,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 416544c1f3..3e280732a8 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 4c6f77501b..1f2159714b 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;
+}
+
+bool
+process_stratum_target::fetch_memtags (CORE_ADDR address, size_t len,
+				       gdb::byte_vector &tags, int type)
+{
+  gdb_assert_not_reached ("target op fetch_memtags not supported");
+}
+
+bool
+process_stratum_target::store_memtags (CORE_ADDR address, size_t len,
+				       const gdb::byte_vector &tags, int type)
+{
+  gdb_assert_not_reached ("target op store_memtags not supported");
+}
+
 int
 process_stratum_target::read_offsets (CORE_ADDR *text, CORE_ADDR *data)
 {
diff --git a/gdbserver/target.h b/gdbserver/target.h
index 336ee5ad9d..2831a6ce7c 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,23 @@ 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.
+
+     Returns true if successful and false otherwise.  */
+  virtual bool 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).
+
+     Returns true if successful and false otherwise.  */
+  virtual bool store_memtags (CORE_ADDR address, size_t len,
+			      const gdb::byte_vector &tags, int type);
 };
 
 extern process_stratum_target *the_target;
@@ -525,6 +543,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.25.1


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

* [PATCH v5 06/25] Unit tests for gdbserver memory tagging remote packets
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (4 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 05/25] GDBserver remote packet support for memory tagging Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-01-27 20:20 ` [PATCH v5 07/25] Documentation for " Luis Machado
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Assert on invalid packet request instead of just returning an error code.

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 | 78 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 69635742a8..700db0f7d8 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -3644,6 +3644,81 @@ 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.  */
+
+  /* Valid request, addr, len and type updated.  */
+  addr = 0xff;
+  len = 255;
+  type = 255;
+  strcpy (packet.data (), "qMemTags:0,0:0");
+  parse_fetch_memtags_request (packet.data (), &addr, &len, &type);
+  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");
+  parse_fetch_memtags_request (packet.data (), &addr, &len, &type);
+  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_fetch_memtags_reply (packet.data (), bv) == true);
+  SELF_CHECK (strcmp (packet.data (), expected.c_str ()) == 0);
+
+  /* Test parsing a QMemTags request.  */
+
+  /* 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_store_memtags_request (packet.data (),
+					   &addr, &len, tags, &type) == true);
+  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_store_memtags_request (packet.data (), &addr, &len, tags,
+					   &type) == true);
+  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.  */
 
@@ -3661,6 +3736,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.25.1


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

* [PATCH v5 07/25] Documentation for memory tagging remote packets
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (5 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 06/25] Unit tests for gdbserver memory tagging remote packets Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-01-28  3:30   ` Eli Zaretskii
  2021-01-27 20:20 ` [PATCH v5 08/25] AArch64: Add MTE CPU feature check support Luis Machado
                   ` (18 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Add documentation for ARM-specific memory tag types.

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.
	(ARM-Specific Protocol Details): Document memory tag types.
---
 gdb/doc/gdb.texinfo | 114 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 84243a72ea..a10a74d0c3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40965,6 +40965,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
@@ -41632,6 +41713,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:
@@ -41846,6 +41932,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::
@@ -42327,6 +42423,7 @@ details of XML target descriptions for each architecture.
 
 @menu
 * ARM Breakpoint Kinds::
+* ARM Memory Tag Types::
 @end menu
 
 @node ARM Breakpoint Kinds
@@ -42348,6 +42445,23 @@ These breakpoint kinds are defined for the @samp{Z0} and @samp{Z1} packets.
 
 @end table
 
+@node ARM Memory Tag Types
+@subsubsection @acronym{ARM} Memory Tag Types
+@cindex memory tag types, @acronym{ARM}
+
+These memory tag types are defined for the @samp{qMemTag} and @samp{QMemTag}
+packets.
+
+@table @r
+
+@item 0
+MTE logical tag
+
+@item 1
+MTE allocation tag
+
+@end table
+
 @node MIPS-Specific Protocol Details
 @subsection @acronym{MIPS}-specific Protocol Details
 
-- 
2.25.1


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

* [PATCH v5 08/25] AArch64: Add MTE CPU feature check support
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (6 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 07/25] Documentation for " Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  3:05   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 09/25] AArch64: Add target description/feature for MTE registers Luis Machado
                   ` (17 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

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 c8979fe276..4e1e6da88d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1469,6 +1469,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 0cae91b569..424e616b04 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 b1bbd55e5c..260d1c59c1 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 86c5f069fa..7d7da87fdc 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.25.1


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

* [PATCH v5 09/25] AArch64: Add target description/feature for MTE registers
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (7 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 08/25] AArch64: Add MTE CPU feature check support Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-01-27 20:20 ` [PATCH v5 10/25] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

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 424e616b04..c56880e33d 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 260d1c59c1..f113d1ea30 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -730,9 +730,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 3ac0564dd9..685c50b84d 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -58,7 +58,7 @@
 #define HA_MAX_NUM_FLDS		4
 
 /* All possible aarch64 target descriptors.  */
-static target_desc *tdesc_aarch64_list[AARCH64_MAX_SVE_VQ + 1][2/*pauth*/];
+static 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
@@ -3260,21 +3260,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;
@@ -3374,7 +3376,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 3783f5cd5e..f6d24292f8 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 d243116be4..c38f8312c9 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 6c98d5fa37..0eb702c5b5 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 5049b88d3e..522ad58aab 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -202,6 +202,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 24211df558..ebf017ed11 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 7d7da87fdc..14493c1fbe 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -664,9 +664,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 a7f728ecda..ee005b8ea1 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 95f115c2de..8319ca7d68 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.25.1


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

* [PATCH v5 10/25] AArch64: Add MTE register set support for GDB and gdbserver
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (8 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 09/25] AArch64: Add target description/feature for MTE registers Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-01-27 20:20 ` [PATCH v5 11/25] AArch64: Add MTE ptrace requests Luis Machado
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Use get_ptrace_pid in a couple spots.

--

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        | 68 ++++++++++++++++++++++++++++++++++
 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, 136 insertions(+)

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index c56880e33d..fe3ba44c55 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -461,6 +461,58 @@ 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 = get_ptrace_pid (regcache->ptid ());
+  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 = get_ptrace_pid (regcache->ptid ());
+  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 +531,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 +548,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 +570,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 +580,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 685c50b84d..44833eb94d 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -172,6 +172,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
 {
@@ -3346,6 +3352,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
@@ -3383,6 +3390,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;
@@ -3453,6 +3462,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;
 
@@ -3470,6 +3493,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 f6d24292f8..7bf612b012 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 14493c1fbe..a066d963a5 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 ()
 {
@@ -706,6 +729,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
 };
 
@@ -735,6 +761,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 e7d55ae078..da911b8e18 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -672,6 +672,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.25.1


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

* [PATCH v5 11/25] AArch64: Add MTE ptrace requests
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (9 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 10/25] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  3:13   ` Simon Marchi
  2021-01-27 20:20 ` [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

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 4e1e6da88d..b763351912 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1506,6 +1506,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.25.1


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

* [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (10 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 11/25] AArch64: Add MTE ptrace requests Luis Machado
@ 2021-01-27 20:20 ` Luis Machado
  2021-02-05  3:30   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full Luis Machado
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:20 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

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

Updates on v2:

- Added type parameter to the target method implementations.

--

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

gdb/ChangeLog:

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

	* Makefile.in (ALL_64_TARGET_OBS): Add arch/aarch64-mte-linux.o.
	(HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h and
	nat/aarch64-mte-linux-ptrace.h.
	* aarch64-linux-nat.c: Include nat/aarch64-mte-linux-ptrace.h.
	(aarch64_linux_nat_target) <supports_memory_tagging>: New method
	override.
	<fetch_memtags>: New method override.
	<store_memtags>: New method override.
	(aarch64_linux_nat_target::supports_memory_tagging): New method.
	(aarch64_linux_nat_target::fetch_memtags): New method.
	(aarch64_linux_nat_target::store_memtags): New method.
	* arch/aarch64-mte-linux.c: New file.
	* arch/aarch64-mte-linux.h: Include gdbsupport/common-defs.h.
	(AARCH64_MTE_GRANULE_SIZE): Define.
	(aarch64_memtag_type): New enum.
	(aarch64_mte_get_tag_granules): New prototype.
	* configure.nat (NATDEPFILES): Add nat/aarch64-mte-linux-ptrace.o.
	* configure.tgt (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o.
	* nat/aarch64-mte-linux-ptrace.c: New file.
	* nat/aarch64-mte-linux-ptrace.h: New file.
---
 gdb/Makefile.in                    |   1 +
 gdb/aarch64-linux-nat.c            |  50 ++++++++
 gdb/arch/aarch64-mte-linux.c       |  34 +++++
 gdb/arch/aarch64-mte-linux.h       |  19 +++
 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, 324 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 b763351912..26f1aff4d5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -698,6 +698,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 fe3ba44c55..c8f09d5b22 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -52,6 +52,8 @@
 
 #include "arch/aarch64-mte-linux.h"
 
+#include "nat/aarch64-mte-linux-ptrace.h"
+
 #ifndef TRAP_HWBKPT
 #define TRAP_HWBKPT 0x0004
 #endif
@@ -102,6 +104,16 @@ class aarch64_linux_nat_target final : public linux_nat_target
     override;
 
   struct gdbarch *thread_architecture (ptid_t) override;
+
+  bool supports_memory_tagging () override;
+
+  /* Read memory allocation tags from memory via PTRACE.  */
+  bool fetch_memtags (CORE_ADDR address, size_t len,
+		      gdb::byte_vector &tags, int type) override;
+
+  /* Write allocation tags to memory via PTRACE.  */
+  bool store_memtags (CORE_ADDR address, size_t len,
+		      const gdb::byte_vector &tags, int type) override;
 };
 
 static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -1054,6 +1066,44 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
   return gdbarch_find_by_info (info);
 }
 
+/* Implement the "supports_memory_tagging" target_ops method.  */
+
+bool
+aarch64_linux_nat_target::supports_memory_tagging ()
+{
+  return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0;
+}
+
+/* Implement the "fetch_memtags" target_ops method.  */
+
+bool
+aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
+					 gdb::byte_vector &tags, int type)
+{
+  int tid = get_ptrace_pid (inferior_ptid);
+
+  /* Allocation tags?  */
+  if (type == static_cast <int> (aarch64_memtag_type::mte_allocation))
+    return aarch64_mte_fetch_memtags (tid, address, len, tags);
+
+  return false;
+}
+
+/* Implement the "store_memtags" target_ops method.  */
+
+bool
+aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
+					 const gdb::byte_vector &tags, int type)
+{
+  int tid = get_ptrace_pid (inferior_ptid);
+
+  /* Allocation tags?  */
+  if (type == static_cast <int> (aarch64_memtag_type::mte_allocation))
+    return aarch64_mte_store_memtags (tid, address, len, tags);
+
+  return false;
+}
+
 /* Define AArch64 maintenance commands.  */
 
 static void
diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
new file mode 100644
index 0000000000..ede5f5f2b9
--- /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
+aarch64_mte_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..108031e08a 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -20,6 +20,8 @@
 #ifndef ARCH_AARCH64_LINUX_H
 #define ARCH_AARCH64_LINUX_H
 
+#include "gdbsupport/common-defs.h"
+
 /* Feature check for Memory Tagging Extension.  */
 #ifndef HWCAP2_MTE
 #define HWCAP2_MTE  (1 << 18)
@@ -28,4 +30,21 @@
 /* The MTE regset consists of a single 64-bit register.  */
 #define AARCH64_LINUX_SIZEOF_MTE 8
 
+/* We have one tag per 16 bytes of memory.  */
+#define AARCH64_MTE_GRANULE_SIZE 16
+
+/* Memory tag types for AArch64.  */
+enum class aarch64_memtag_type
+{
+  /* MTE logical tag contained in pointers.  */
+  mte_logical = 0,
+  /* MTE allocation tag stored in memory tag granules.  */
+  mte_allocation
+};
+
+/* Return the number of tag granules in the memory range
+   [ADDR, ADDR + LEN) given GRANULE_SIZE.  */
+extern size_t aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
+					    size_t granule_size);
+
 #endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 286975966d..e34cccffd9 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -236,7 +236,8 @@ case ${gdb_host} in
 		NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \
 		aarch32-linux-nat.o nat/aarch64-linux-hw-point.o \
 		nat/aarch64-linux.o \
-		nat/aarch64-sve-linux-ptrace.o"
+		nat/aarch64-sve-linux-ptrace.o \
+		nat/aarch64-mte-linux-ptrace.o"
 		;;
 	    arc)
 		# Host: ARC based machine running GNU/Linux
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 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..be4f2b93d8
--- /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 ATTRIBUTE_NORETURN
+aarch64_mte_linux_peek_error (int error)
+{
+  switch (error)
+    {
+    case EIO:
+      perror_with_name (_("PEEKMTETAGS not supported"));
+      break;
+    case EFAULT:
+      perror_with_name (_("Couldn't fetch allocation tags"));
+      break;
+    case EOPNOTSUPP:
+      perror_with_name (_("PROT_ME not enabled for requested address"));
+    default:
+      perror_with_name (_("Unknown MTE error"));
+      break;
+    }
+}
+
+/* Helper function to display various possible errors when writing
+   MTE tags.  */
+
+static void ATTRIBUTE_NORETURN
+aarch64_mte_linux_poke_error (int error)
+{
+  switch (error)
+    {
+    case EIO:
+      perror_with_name (_("POKEMTETAGS not supported"));
+      break;
+    case EFAULT:
+      perror_with_name (_("Couldn't store allocation tags"));
+      break;
+    case EOPNOTSUPP:
+      perror_with_name (_("PROT_ME not enabled for requested address"));
+    default:
+      perror_with_name (_("Unknown MTE error"));
+      break;
+    }
+}
+
+/* Helper to prepare a vector of tags to be passed on to the kernel.  The
+   main purpose of this function is to optimize the number of calls to
+   ptrace if we're writing too many tags at once, like a pattern fill
+   request.
+
+   Return a vector of tags of up to MAX_SIZE size, containing the tags that
+   must be passed on to the kernel, extracted from TAGS, starting at POS.
+   GRANULES is the number of tag granules to be modified.  */
+
+static gdb::byte_vector
+prepare_tag_vector (size_t granules, const gdb::byte_vector &tags, size_t pos,
+		    size_t max_size)
+{
+  gdb::byte_vector t;
+
+  if (granules == 0)
+    return t;
+
+  gdb_assert (tags.size () > 0 && max_size > 0);
+
+  if (granules > AARCH64_MTE_TAGS_MAX_SIZE)
+    t.resize (AARCH64_MTE_TAGS_MAX_SIZE);
+  else
+    t.resize (granules);
+
+  size_t tag_count = tags.size ();
+
+  for (size_t i = 0; i < t.size (); i++)
+    t[i] = tags[(pos + i) % tag_count];
+
+  return t;
+}
+
+/* See nat/aarch64-mte-linux-ptrace.h */
+
+bool
+aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+			   gdb::byte_vector &tags)
+{
+  size_t ntags = aarch64_mte_get_tag_granules (address, len,
+					       AARCH64_MTE_GRANULE_SIZE);
+  gdb_byte tagbuf[ntags];
+
+  struct iovec iovec;
+  iovec.iov_base = tagbuf;
+  iovec.iov_len = ntags;
+
+  tags.clear ();
+  bool done_reading = false;
+
+  /* The kernel may return less tags than we requested.  Loop until we've read
+     all the requested tags or until we get an error.  */
+  while (!done_reading)
+    {
+      /* Attempt to read ntags allocation tags from the kernel.  */
+      if (ptrace (PTRACE_PEEKMTETAGS, tid, address, &iovec) < 0)
+	aarch64_mte_linux_peek_error (errno);
+
+      /* Make sure the kernel returned at least one tag.  */
+      if (iovec.iov_len <= 0)
+	{
+	  tags.clear ();
+	  return false;
+	}
+
+      /* Copy the tags the kernel returned.  */
+      for (size_t i = 0; i < iovec.iov_len; i++)
+	tags.push_back (tagbuf[i]);
+
+      /* Are we done reading tags?  */
+      if (tags.size () == ntags)
+	done_reading = true;
+      else
+	{
+	  address += iovec.iov_len * AARCH64_MTE_GRANULE_SIZE;
+	  iovec.iov_len = ntags - iovec.iov_len;
+	}
+    }
+  return true;
+}
+
+/* See nat/aarch64-mte-linux-ptrace.h */
+
+bool
+aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
+			   const gdb::byte_vector &tags)
+{
+  if (tags.size () == 0)
+    return true;
+
+  /* Get the number of tags we need to write.  */
+  size_t ntags = aarch64_mte_get_tag_granules (address, len,
+					       AARCH64_MTE_GRANULE_SIZE);
+  bool done_writing = false;
+  size_t tags_written = 0;
+
+  /* Write all the tags, AARCH64_MTE_TAGS_MAX_SIZE blocks at a time.  */
+  while (!done_writing)
+    {
+      gdb::byte_vector t = prepare_tag_vector (ntags - tags_written, tags,
+					       tags_written,
+					       AARCH64_MTE_TAGS_MAX_SIZE);
+
+      struct iovec iovec;
+      iovec.iov_base = t.data ();
+      iovec.iov_len = t.size ();
+
+      /* Request the kernel to update the allocation tags.  */
+      if (ptrace (PTRACE_POKEMTETAGS, tid, address, &iovec) < 0)
+	aarch64_mte_linux_poke_error (errno);
+
+      /* Make sure the kernel wrote at least one tag.  */
+      if (iovec.iov_len <= 0)
+	return false;
+
+      tags_written += iovec.iov_len;
+
+      /* Are we done writing tags?  */
+      if (tags_written == ntags)
+	done_writing = true;
+      else
+	address += iovec.iov_len * AARCH64_MTE_GRANULE_SIZE;
+    }
+
+  return true;
+}
diff --git a/gdb/nat/aarch64-mte-linux-ptrace.h b/gdb/nat/aarch64-mte-linux-ptrace.h
index 099b6440ca..eb2b471893 100644
--- a/gdb/nat/aarch64-mte-linux-ptrace.h
+++ b/gdb/nat/aarch64-mte-linux-ptrace.h
@@ -30,4 +30,21 @@
 #define PTRACE_POKEMTETAGS	  34
 #endif
 
+/* Maximum number of tags to pass at once to the kernel.  */
+#define AARCH64_MTE_TAGS_MAX_SIZE 4096
+
+/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN)
+   into TAGS.
+
+   Returns true if successful and false otherwise.  */
+extern bool aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len,
+				       gdb::byte_vector &tags);
+
+/* Write the TAGS allocation tags to the memory range
+   [ADDRESS, ADDRESS + LEN).
+
+   Returns true if successful and false otherwise.  */
+extern bool aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len,
+				       const gdb::byte_vector &tags);
+
 #endif /* NAT_AARCH64_MTE_LINUX_PTRACE_H */
-- 
2.25.1


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

* [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (11 preceding siblings ...)
  2021-01-27 20:20 ` [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  3:32   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps Luis Machado
                   ` (12 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

This is a quick cleanup that removes the use of fixed-length char arrays and
uses std::string instead.

gdb/ChangeLog:

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

	* linux-tdep.c (linux_find_memory_regions_full): Use std::string
	instead of char arrays.
---
 gdb/linux-tdep.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index e9f8e1b613..35e05e12a6 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1277,8 +1277,6 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 				linux_find_memory_region_ftype *func,
 				void *obfd)
 {
-  char mapsfilename[100];
-  char coredumpfilter_name[100];
   pid_t pid;
   /* Default dump behavior of coredump_filter (0x33), according to
      Documentation/filesystems/proc.txt from the Linux kernel
@@ -1296,10 +1294,12 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 
   if (use_coredump_filter)
     {
-      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
-		 "/proc/%d/coredump_filter", pid);
+      std::string core_dump_filter_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, core_dump_filter_name.c_str());
+
       if (coredumpfilterdata != NULL)
 	{
 	  unsigned int flags;
@@ -1309,14 +1309,16 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 	}
     }
 
-  xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
+  std::string maps_filename = string_printf ("/proc/%d/smaps", pid);
+
   gdb::unique_xmalloc_ptr<char> data
-    = target_fileio_read_stralloc (NULL, mapsfilename);
+    = target_fileio_read_stralloc (NULL, maps_filename.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);
+      maps_filename = string_printf ("/proc/%d/maps", pid);
+      data = target_fileio_read_stralloc (NULL, maps_filename.c_str ());
     }
 
   if (data != NULL)
@@ -1376,7 +1378,8 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 
 	      if (sscanf (line, "%64s", keyword) != 1)
 		{
-		  warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
+		  warning (_("Error parsing {s,}maps file '%s'"),
+			   maps_filename.c_str ());
 		  break;
 		}
 
@@ -1397,7 +1400,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
 		  if (sscanf (line, "%*s%lu", &number) != 1)
 		    {
 		      warning (_("Error parsing {s,}maps file '%s' number"),
-			       mapsfilename);
+			       maps_filename.c_str ());
 		      break;
 		    }
 		  if (number > 0)
-- 
2.25.1


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

* [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (12 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  3:38   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
                   ` (11 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Update return type of parse_smaps_data.
- Misc formatting fixes

--

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 | 359 +++++++++++++++++++++++++++++++----------------
 gdb/linux-tdep.h |   4 +
 2 files changed, 241 insertions(+), 122 deletions(-)

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 35e05e12a6..abbd43e22c 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.  */
 
@@ -474,6 +499,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;
     }
 }
 
@@ -1269,6 +1296,181 @@ typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
 					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 std::vector<struct smaps_data>
+parse_smaps_data (const char *data,
+		  const std::string maps_filename)
+{
+  char *line, *t;
+
+  gdb_assert (data != nullptr);
+
+  line = strtok_r ((char *) data, "\n", &t);
+
+  std::vector<struct smaps_data> smaps;
+
+  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'"),
+		       maps_filename.c_str ());
+	      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"),
+			   maps_filename.c_str ());
+		  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;
+
+	map.start_address = addr;
+	map.end_address = endaddr;
+	map.filename = filename;
+	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 smaps;
+}
+
+/* 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.  */
+  smaps = parse_smaps_data (data.get (), smaps_file);
+
+  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.  */
 
 static int
@@ -1319,137 +1521,50 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
       /* Older Linux kernels did not support /proc/PID/smaps.  */
       maps_filename = string_printf ("/proc/%d/maps", pid);
       data = target_fileio_read_stralloc (NULL, maps_filename.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 (sscanf (line, "%64s", keyword) != 1)
-		{
-		  warning (_("Error parsing {s,}maps file '%s'"),
-			   maps_filename.c_str ());
-		  break;
-		}
+      if (data == nullptr)
+	return 1;
+    }
 
-	      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);
+  std::vector<struct smaps_data> smaps;
 
-	      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"),
-			       maps_filename.c_str ());
-		      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;
-		    }
-		}
-	    }
+  /* Parse the contents of smaps into a vector.  */
+  smaps = parse_smaps_data (data.get (), maps_filename.c_str ());
 
-	  if (has_anonymous)
-	    should_dump_p = should_dump_mapping_p (filterflags, &v, priv,
-						   mapping_anon_p,
-						   mapping_file_p,
-						   filename, addr, offset);
-	  else
-	    {
-	      /* Older Linux kernels did not support the "Anonymous:" counter.
-		 If it is missing, we can't be sure - dump all the pages.  */
-	      should_dump_p = 1;
-	    }
+  for (const struct smaps_data map : smaps)
+    {
+      int should_dump_p = 0;
 
-	  /* 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);
+      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.
+	     If it is missing, we can't be sure - dump all the pages.  */
+	  should_dump_p = 1;
 	}
 
-      return 0;
+      /* Invoke the callback function to create the corefile segment.  */
+      if (should_dump_p)
+	{
+	  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 1;
+  return 0;
 }
 
 /* A structure for passing information through
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 7db6eceeab..d72635215d 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -43,6 +43,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.25.1


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

* [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (13 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  4:09   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 16/25] AArch64: Add unit testing for logical tag set/get operations Luis Machado
                   ` (10 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Update function names to be more scoped.
- Use of gdb::optional values.
- Fixed up gdbarch hooks.

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_mte_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 (aarch64_mte_make_ltag_bits)
	(aarch64_mte_make_ltag, aarch64_linux_set_ltag)
	(aarch64_linux_get_ltag): New functions.
	* arch/aarch64-mte-linux.h (AARCH64_MTE_LOGICAL_TAG_START_BIT)
	(AARCH64_MTE_LOGICAL_MAX_VALUE): Define.
	(aarch64_mte_make_ltag_bits, aarch64_mte_make_ltag)
	(aarch64_mte_set_ltag, aarch64_mte_get_ltag): New prototypes.
---
 gdb/aarch64-linux-tdep.c     | 210 +++++++++++++++++++++++++++++++++++
 gdb/arch/aarch64-mte-linux.c |  41 ++++++-
 gdb/arch/aarch64-mte-linux.h |  19 ++++
 3 files changed, 269 insertions(+), 1 deletion(-)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index f113d1ea30..2fe88cf016 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.
 
       +------------+  ^
@@ -1513,6 +1517,187 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
   return {};
 }
 
+/* Helper to get the allocation tag from a 64-bit ADDRESS.
+
+   Return the allocation tag if successful and nullopt otherwise.  */
+
+static gdb::optional<CORE_ADDR>
+aarch64_mte_get_atag (CORE_ADDR address)
+{
+  gdb::byte_vector tags;
+
+  /* Attempt to fetch the allocation tag.  */
+  if (!target_fetch_memtags (address, 0, tags, tag_allocation))
+    return {};
+
+  /* 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.  */
+  return tags[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_matches_p gdbarch method.  */
+
+static bool
+aarch64_linux_memtag_matches_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 true;
+
+  CORE_ADDR addr = value_as_address (address);
+
+  /* Fetch the allocation tag for ADDRESS.  */
+  gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (addr);
+
+  if (!atag.has_value ())
+    return true;
+
+  /* Fetch the logical tag for ADDRESS.  */
+  gdb_byte ltag = aarch64_mte_get_ltag (addr);
+
+  /* Are the tags the same?  */
+  return ltag == *atag;
+}
+
+/* Implement the set_memtags gdbarch method.  */
+
+static bool
+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 true;
+
+  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_mte_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 false;
+
+      /* 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 = aarch64_mte_get_tag_granules (addr, length,
+					       AARCH64_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))
+	return false;
+    }
+  return true;
+}
+
+/* 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_mte_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;
+
+      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (addr);
+
+      if (!atag.has_value ())
+	return nullptr;
+
+      tag = *atag;
+    }
+
+  /* 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)
 {
@@ -1570,6 +1755,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 match.  */
+      set_gdbarch_memtag_matches_p (gdbarch,
+				    aarch64_linux_memtag_matches_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, AARCH64_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 ede5f5f2b9..4461864a32 100644
--- a/gdb/arch/aarch64-mte-linux.c
+++ b/gdb/arch/aarch64-mte-linux.c
@@ -22,7 +22,8 @@
 /* See arch/aarch64-mte-linux.h */
 
 size_t
-aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
+aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
+				    size_t granule_size)
 {
   /* Start address */
   CORE_ADDR s_addr = align_down (addr, granule_size);
@@ -32,3 +33,41 @@ aarch64_mte_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
+aarch64_mte_make_ltag_bits (CORE_ADDR value)
+{
+  return value & AARCH64_MTE_LOGICAL_MAX_VALUE;
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+aarch64_mte_make_ltag (CORE_ADDR value)
+{
+  return aarch64_mte_make_ltag_bits (value)
+	 << AARCH64_MTE_LOGICAL_TAG_START_BIT;
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag)
+{
+  /* Remove the existing tag.  */
+  address &= ~aarch64_mte_make_ltag (AARCH64_MTE_LOGICAL_MAX_VALUE);
+
+  /* Return the new tagged address.  */
+  return address | aarch64_mte_make_ltag (tag);
+}
+
+/* See arch/aarch64-mte-linux.h */
+
+CORE_ADDR
+aarch64_mte_get_ltag (CORE_ADDR address)
+{
+  CORE_ADDR ltag_addr = address >> AARCH64_MTE_LOGICAL_TAG_START_BIT;
+  return aarch64_mte_make_ltag_bits (ltag_addr);
+}
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index 108031e08a..d44cae92a6 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -32,6 +32,8 @@
 
 /* We have one tag per 16 bytes of memory.  */
 #define AARCH64_MTE_GRANULE_SIZE 16
+#define AARCH64_MTE_LOGICAL_TAG_START_BIT 56
+#define AARCH64_MTE_LOGICAL_MAX_VALUE 0xf
 
 /* Memory tag types for AArch64.  */
 enum class aarch64_memtag_type
@@ -47,4 +49,21 @@ enum class aarch64_memtag_type
 extern size_t aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
 					    size_t granule_size);
 
+/* Return the 4-bit tag made from VALUE.  */
+extern CORE_ADDR aarch64_mte_make_ltag_bits (CORE_ADDR value);
+
+/* Return the 4-bit tag that can be OR-ed to an address.  */
+extern CORE_ADDR aarch64_mte_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_mte_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_mte_get_ltag (CORE_ADDR address);
+
 #endif /* ARCH_AARCH64_LINUX_H */
-- 
2.25.1


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

* [PATCH v5 16/25] AArch64: Add unit testing for logical tag set/get operations
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (14 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-27 20:21 ` [PATCH v5 17/25] AArch64: Report tag violation error information Luis Machado
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Update on v4:

- Adjust function names.

--

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 2fe88cf016..1063dd7a82 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.
 
       +------------+  ^
@@ -1955,10 +1957,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_mte_get_ltag (addr) == (i & 0xf));
+
+      addr = aarch64_mte_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.25.1


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

* [PATCH v5 17/25] AArch64: Report tag violation error information
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (15 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 16/25] AArch64: Add unit testing for logical tag set/get operations Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  4:22   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 18/25] AArch64: Add gdbserver MTE support Luis Machado
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Print exception error.
- Update function names.

--

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.

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     | 66 ++++++++++++++++++++++++++++++++++++
 gdb/arch/aarch64-mte-linux.h |  6 ++++
 2 files changed, 72 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 1063dd7a82..4ccee9c34e 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1700,6 +1700,69 @@ 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");
+
+      fault_addr
+	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
+    }
+  catch (const gdb_exception_error &exception)
+    {
+      exception_print (gdb_stderr, 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");
+
+      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (fault_addr);
+
+      if (!atag.has_value ())
+	uiout->text (_("Allocation tag unavailable"));
+      else
+	{
+	  uiout->text (_("Allocation tag "));
+	  uiout->field_string ("allocation-tag", hex_string (*atag));
+	}
+    }
+  else
+    {
+      uiout->text ("\n");
+      uiout->text (_("Fault address unavailable"));
+    }
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1780,6 +1843,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 d44cae92a6..0f181a8595 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -35,6 +35,12 @@
 #define AARCH64_MTE_LOGICAL_TAG_START_BIT 56
 #define AARCH64_MTE_LOGICAL_MAX_VALUE 0xf
 
+/* Memory tagging definitions.  */
+#ifndef SEGV_MTEAERR
+# define SEGV_MTEAERR 8
+# define SEGV_MTESERR 9
+#endif
+
 /* Memory tag types for AArch64.  */
 enum class aarch64_memtag_type
 {
-- 
2.25.1


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

* [PATCH v5 18/25] AArch64: Add gdbserver MTE support
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (16 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 17/25] AArch64: Report tag violation error information Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-27 20:21 ` [PATCH v5 19/25] AArch64: Add MTE register set support for core files Luis Machado
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Updated return types.
- Fixed alphabetical order of files.
- Use enum instead of magic integers.

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 a14d3a7bc1..00370d55a3 100644
--- a/gdbserver/Makefile.in
+++ b/gdbserver/Makefile.in
@@ -229,6 +229,7 @@ SFILES = \
 	$(srcdir)/../gdb/arch/arm-linux.c \
 	$(srcdir)/../gdb/arch/ppc-linux-common.c \
 	$(srcdir)/../gdb/arch/riscv.c \
+	$(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \
 	$(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \
 	$(srcdir)/../gdb/nat/linux-btrace.c \
 	$(srcdir)/../gdb/nat/linux-namespaces.c \
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
index 833ad27c4c..2dd8f75a4e 100644
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -52,7 +52,9 @@ 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-mte-linux-ptrace.o"
 			srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o"
 			srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
 			srv_linux_regsets=yes
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index a066d963a5..daccfef746 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -43,6 +43,7 @@
 #include "arch/aarch64-mte-linux.h"
 #include "linux-aarch32-tdesc.h"
 #include "linux-aarch64-tdesc.h"
+#include "nat/aarch64-mte-linux-ptrace.h"
 #include "nat/aarch64-sve-linux-ptrace.h"
 #include "tdesc.h"
 
@@ -50,6 +51,10 @@
 #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;
+
+  bool fetch_memtags (CORE_ADDR address, size_t len,
+		      gdb::byte_vector &tags, int type) override;
+
+  bool store_memtags (CORE_ADDR address, size_t len,
+		      const gdb::byte_vector &tags, int type) override;
+
 protected:
 
   void low_arch_setup () override;
@@ -3223,6 +3236,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;
+}
+
+bool
+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 == static_cast <int> (aarch64_memtag_type::mte_allocation))
+    return aarch64_mte_fetch_memtags (tid, address, len, tags);
+
+  return false;
+}
+
+bool
+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 == static_cast <int> (aarch64_memtag_type::mte_allocation))
+    return aarch64_mte_store_memtags (tid, address, len, tags);
+
+  return false;
+}
+
 /* The linux target ops object.  */
 
 linux_process_target *the_linux_target = &the_aarch64_target;
-- 
2.25.1


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

* [PATCH v5 19/25] AArch64: Add MTE register set support for core files
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (17 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 18/25] AArch64: Add gdbserver MTE support Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-27 20:21 ` [PATCH v5 20/25] New memory-tag commands Luis Machado
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

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 4ccee9c34e..2aa36300f3 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -727,6 +727,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 84c25172a9..62a6da8349 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.25.1


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

* [PATCH v5 20/25] New memory-tag commands
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (18 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 19/25] AArch64: Add MTE register set support for core files Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  4:49   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 21/25] Documentation for the new mtag commands Luis Machado
                   ` (5 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v5:

- Remove check for memory_tagging global.

Updates on v4:

- Update command names and function names.
- Moved common functions to gdbsupport/common-utils.cc.

--

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

The available subcommands are the following:

- memory-tag print-logical-tag <expression>: Prints the logical tag for a
  particular address.

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

- memory-tag print-allocation-tag <expression>: Prints the allocation tag for
  a particular address.

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

- memory-tag check <expression>: Checks 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.
	(memory_tag_list): 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_memory_tagging_unsupported)
	(memory_tag_command, memory_tag_print_tag_command)
	(memory_tag_print_logical_tag_command)
	(memory_tag_print_allocation_tag_command, parse_with_logical_tag_input)
	(memory_tag_with_logical_tag_command, parse_set_allocation_tag_input)
	(memory_tag_set_allocation_tag_command, memory_tag_check_command): New
	functions.
	(_initialize_printcmd): Add "memory-tag" prefix and subcommands.

gdbsupport/ChangeLog:

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

	* rsp-low.cc (fromhex, hex2bin): Move to ...
	* common-utils.cc: ... here.
	(fromhex) Change error message text to not be RSP-specific.
	* rsp-low.h (fromhex, hex2bin): Move to ...
	* common-utils.h: ... here.
---
 gdb/printcmd.c             | 364 +++++++++++++++++++++++++++++++++++--
 gdbsupport/common-utils.cc |  49 +++++
 gdbsupport/common-utils.h  |  15 ++
 gdbsupport/rsp-low.cc      |  49 -----
 gdbsupport/rsp-low.h       |  19 --
 5 files changed, 416 insertions(+), 80 deletions(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 2e56d28e9f..78acda4e37 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -54,6 +54,11 @@
 #include "gdbsupport/byte-vector.h"
 #include "gdbsupport/gdb_optional.h"
 #include "safe-ctype.h"
+#include "gdbsupport/rsp-low.h"
+
+/* Chain containing all defined memory-tag subcommands.  */
+
+static struct cmd_list_element *memory_tag_list;
 
 /* Last specified output format.  */
 
@@ -1203,21 +1208,19 @@ 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, bool voidprint)
+static struct value *
+process_print_command_args (const char *args, value_print_options *print_opts,
+			    bool voidprint)
 {
-  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;
 
@@ -1226,10 +1229,20 @@ print_command_1 (const char *args, bool voidprint)
       /* VOIDPRINT is true to indicate that we do want to print a void
 	 value, so invert it for parse_expression.  */
       expression_up expr = parse_expression (exp, nullptr, !voidprint);
-      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, voidprint);
 
   if (voidprint || (val && value_type (val) &&
 		    value_type (val)->code () != TYPE_CODE_VOID))
@@ -2780,6 +2793,274 @@ eval_command (const char *arg, int from_tty)
   execute_command (expanded.c_str (), from_tty);
 }
 
+/* Convenience function for error checking in memory-tag 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 memory-tag commands.  */
+
+static void
+show_memory_tagging_unsupported (void)
+{
+  error (_("Memory tagging not supported or disabled by the current"
+	   " architecture."));
+}
+
+/* Implement the "memory-tag" prefix command.  */
+
+static void
+memory_tag_command (const char *arg, int from_tty)
+{
+  help_list (memory_tag_list, "memory-tag ", all_commands, gdb_stdout);
+}
+
+/* Helper for print-logical-tag and print-allocation-tag.  */
+
+static void
+memory_tag_print_tag_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, true);
+
+  /* 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,
+						    true);
+  print_opts.output_format = 'x';
+  print_value (v_tag, print_opts);
+}
+
+/* Implement the "memory-tag print-logical-tag" command.  */
+
+static void
+memory_tag_print_logical_tag_command (const char *args, int from_tty)
+{
+  if (!target_supports_memory_tagging ())
+    show_memory_tagging_unsupported ();
+
+  memory_tag_print_tag_command (args, tag_logical);
+}
+
+/* Implement the "memory-tag print-allocation-tag" command.  */
+
+static void
+memory_tag_print_allocation_tag_command (const char *args, int from_tty)
+{
+  if (!target_supports_memory_tagging ())
+    show_memory_tagging_unsupported ();
+
+  memory_tag_print_tag_command (args, tag_allocation);
+}
+
+/* Parse ARGS and extract ADDR and TAG.
+   ARGS should have format <expression> <tag bytes>.  */
+
+static void
+parse_with_logical_tag_input (const char *args, struct value **val,
+			      gdb::byte_vector &tags,
+			      value_print_options *print_opts)
+{
+  /* Fetch the address.  */
+  std::string address_string = extract_string_maybe_quoted (&args);
+
+  /* Parse the address into a value.  */
+  *val = process_print_command_args (address_string.c_str (), print_opts,
+				     true);
+
+  /* Fetch the tag bytes.  */
+  std::string tag_string = extract_string_maybe_quoted (&args);
+
+  /* Validate the input.  */
+  if (address_string.empty () || tag_string.empty ())
+    error (_("Missing arguments."));
+
+  if (tag_string.length () != 2)
+    error (_("Error parsing tags argument. The tag should be 2 digits."));
+
+  tags = hex2bin (tag_string.c_str ());
+}
+
+/* Implement the "memory-tag with-logical-tag" command.  */
+
+static void
+memory_tag_with_logical_tag_command (const char *args, int from_tty)
+{
+  if (!target_supports_memory_tagging ())
+    show_memory_tagging_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_with_logical_tag_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 type 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))
+    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_set_allocation_tag_input (const char *args, struct value **val,
+				size_t *length, gdb::byte_vector &tags)
+{
+  /* Fetch the address.  */
+  std::string address_string = extract_string_maybe_quoted (&args);
+
+  /* Parse the address into a value.  */
+  value_print_options print_opts;
+  *val = process_print_command_args (address_string.c_str (), &print_opts,
+				     true);
+
+  /* Fetch the length.  */
+  std::string length_string = extract_string_maybe_quoted (&args);
+
+  /* Fetch the tag bytes.  */
+  std::string tags_string = extract_string_maybe_quoted (&args);
+
+  /* Validate the input.  */
+  if (address_string.empty () || length_string.empty () || tags_string.empty ())
+    error (_("Missing arguments."));
+
+  errno = 0;
+  *length = strtoulst (length_string.c_str (), NULL, 10);
+  if (errno != 0)
+    error (_("Error parsing length argument."));
+
+  if (tags_string.length () % 2)
+    error (_("Error parsing tags argument. Tags should be 2 digits per byte."));
+
+  tags = hex2bin (tags_string.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 "memory-tag set-allocation-tag" command.
+   ARGS should be in the format <address> <length> <tags>.  */
+
+static void
+memory_tag_set_allocation_tag_command (const char *args, int from_tty)
+{
+  if (!target_supports_memory_tagging ())
+    show_memory_tagging_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_set_allocation_tag_input (args, &val, &length, tags);
+
+  if (!gdbarch_set_memtags (target_gdbarch (), val, length, tags,
+			   tag_allocation))
+    printf_filtered (_("Could not update the allocation tag(s).\n"));
+  else
+    printf_filtered (_("Allocation tag(s) updated successfully.\n"));
+}
+
+/* Implement the "memory-tag check" command.  */
+
+static void
+memory_tag_check_command (const char *args, int from_tty)
+{
+  if (!target_supports_memory_tagging ())
+    show_memory_tagging_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, true);
+
+  /* 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);
+
+  /* Check if the tag is valid.  */
+  if (!gdbarch_memtag_matches_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 ()
@@ -2982,4 +3263,63 @@ 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."));
+
+  /* Memory tagging commands.  */
+  add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
+Generic command for printing and manipulating memory tag properties."),
+		  &memory_tag_list, "memory-tag ", 0, &cmdlist);
+  add_cmd ("print-logical-tag", class_vars,
+	   memory_tag_print_logical_tag_command,
+	   ("Print the logical tag for an address.\n\
+Usage: memory-tag print-logical-tag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will print the logical tag associated with <address>.  The tag\n\
+interpretation is architecture-specific."),
+	   &memory_tag_list);
+  add_cmd ("print-allocation-tag", class_vars,
+	   memory_tag_print_allocation_tag_command,
+	   _("Print the allocation tag for an address.\n\
+Usage: memory-tag print-allocation-tag <address>.\n\
+<address> is an expression that evaluates to a pointer or memory address.\n\
+GDB will print the allocation tag associated with <address>.  The tag\n\
+interpretation is architecture-specific."),
+	   &memory_tag_list);
+  add_cmd ("with-logical-tag", class_vars, memory_tag_with_logical_tag_command,
+	   _("Set the logical tag for an address.\n\
+Usage: memory-tag with-logical-tag <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 print the\n\
+resulting address with the updated tag."),
+	   &memory_tag_list);
+  add_cmd ("set-allocation-tag", class_vars,
+	   memory_tag_set_allocation_tag_command,
+	   _("Set the allocation tag for an address.\n\
+Usage: memory-tag set-allocation-tag <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."),
+	   &memory_tag_list);
+  add_cmd ("check", class_vars, memory_tag_check_command,
+	   _("Validate the logical tag against the allocation tag.\n\
+Usage: memory-tag 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."),
+	   &memory_tag_list);
 }
diff --git a/gdbsupport/common-utils.cc b/gdbsupport/common-utils.cc
index ed3348057c..8ce839a54a 100644
--- a/gdbsupport/common-utils.cc
+++ b/gdbsupport/common-utils.cc
@@ -392,3 +392,52 @@ align_down (ULONGEST v, int n)
   gdb_assert (n && (n & (n-1)) == 0);
   return (v & -n);
 }
+
+/* See gdbsupport/common-utils.h.  */
+
+int
+fromhex (int a)
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else if (a >= 'A' && a <= 'F')
+    return a - 'A' + 10;
+  else
+    error (_("Invalid hex digit %d"), a);
+}
+
+/* See gdbsupport/common-utils.h.  */
+
+int
+hex2bin (const char *hex, gdb_byte *bin, int count)
+{
+  int i;
+
+  for (i = 0; i < count; i++)
+    {
+      if (hex[0] == 0 || hex[1] == 0)
+	{
+	  /* Hex string is short, or of uneven length.
+	     Return the count that has been converted so far.  */
+	  return i;
+	}
+      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+      hex += 2;
+    }
+  return i;
+}
+
+/* See gdbsupport/common-utils.h.  */
+
+gdb::byte_vector
+hex2bin (const char *hex)
+{
+  size_t bin_len = strlen (hex) / 2;
+  gdb::byte_vector bin (bin_len);
+
+  hex2bin (hex, bin.data (), bin_len);
+
+  return bin;
+}
diff --git a/gdbsupport/common-utils.h b/gdbsupport/common-utils.h
index 4429f086fc..cad20d8899 100644
--- a/gdbsupport/common-utils.h
+++ b/gdbsupport/common-utils.h
@@ -22,6 +22,7 @@
 
 #include <string>
 #include <vector>
+#include "gdbsupport/byte-vector.h"
 
 #include "poison.h"
 
@@ -195,4 +196,18 @@ in_inclusive_range (T value, T low, T high)
 extern ULONGEST align_up (ULONGEST v, int n);
 extern ULONGEST align_down (ULONGEST v, int n);
 
+/* Convert hex digit A to a number, or throw an exception.  */
+extern int fromhex (int a);
+
+/* HEX is a string of characters representing hexadecimal digits.
+   Convert pairs of hex digits to bytes and store sequentially into
+   BIN.  COUNT is the maximum number of characters to convert.  This
+   will convert fewer characters if the number of hex characters
+   actually seen is odd, or if HEX terminates before COUNT characters.
+   Returns the number of characters actually converted.  */
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
+
+/* Like the above, but return a gdb::byte_vector.  */
+gdb::byte_vector hex2bin (const char *hex);
+
 #endif /* COMMON_COMMON_UTILS_H */
diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc
index eb8f70a305..8900ed4fc0 100644
--- a/gdbsupport/rsp-low.cc
+++ b/gdbsupport/rsp-low.cc
@@ -22,21 +22,6 @@
 
 /* See rsp-low.h.  */
 
-int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else if (a >= 'A' && a <= 'F')
-    return a - 'A' + 10;
-  else
-    error (_("Reply contains invalid hex digit %d"), a);
-}
-
-/* See rsp-low.h.  */
-
 int
 tohex (int nib)
 {
@@ -111,40 +96,6 @@ unpack_varlen_hex (const char *buff,	/* packet to parse */
 
 /* See rsp-low.h.  */
 
-int
-hex2bin (const char *hex, gdb_byte *bin, int count)
-{
-  int i;
-
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-	{
-	  /* Hex string is short, or of uneven length.
-	     Return the count that has been converted so far.  */
-	  return i;
-	}
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
-}
-
-/* See rsp-low.h.  */
-
-gdb::byte_vector
-hex2bin (const char *hex)
-{
-  size_t bin_len = strlen (hex) / 2;
-  gdb::byte_vector bin (bin_len);
-
-  hex2bin (hex, bin.data (), bin_len);
-
-  return bin;
-}
-
-/* See rsp-low.h.  */
-
 std::string
 hex2str (const char *hex)
 {
diff --git a/gdbsupport/rsp-low.h b/gdbsupport/rsp-low.h
index fd0b16f158..6ef4b36a1d 100644
--- a/gdbsupport/rsp-low.h
+++ b/gdbsupport/rsp-low.h
@@ -20,12 +20,6 @@
 #ifndef COMMON_RSP_LOW_H
 #define COMMON_RSP_LOW_H
 
-#include "gdbsupport/byte-vector.h"
-
-/* Convert hex digit A to a number, or throw an exception.  */
-
-extern int fromhex (int a);
-
 /* Convert number NIB to a hex digit.  */
 
 extern int tohex (int nib);
@@ -45,19 +39,6 @@ extern char *pack_hex_byte (char *pkt, int byte);
 
 extern const char *unpack_varlen_hex (const char *buff, ULONGEST *result);
 
-/* HEX is a string of characters representing hexadecimal digits.
-   Convert pairs of hex digits to bytes and store sequentially into
-   BIN.  COUNT is the maximum number of characters to convert.  This
-   will convert fewer characters if the number of hex characters
-   actually seen is odd, or if HEX terminates before COUNT characters.
-   Returns the number of characters actually converted.  */
-
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-/* Like the above, but return a gdb::byte_vector.  */
-
-gdb::byte_vector hex2bin (const char *hex);
-
 /* Like hex2bin, but return a std::string.  */
 
 extern std::string hex2str (const char *hex);
-- 
2.25.1


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

* [PATCH v5 21/25] Documentation for the new mtag commands
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (19 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 20/25] New memory-tag commands Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-28  3:31   ` Eli Zaretskii
  2021-02-05  4:50   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging Luis Machado
                   ` (4 subsequent siblings)
  25 siblings, 2 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Update the command names.

--

Document the new "memory-tag" 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 | 97 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a10a74d0c3..f751bdf4d3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10848,6 +10848,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{memory-tag} gives access to the various memory tagging
+commands.
+
+The @code{memory-tag} commands are the following:
+
+@table @code
+@kindex memory-tag print-logical-tag
+@item memory-tag print-logical-tag @var{address_expression}
+Print the logical tag stored at the address given by @var{address_expression}.
+@kindex memory-tag with-logical-tag
+@item memory-tag with-logical-tag @var{address_expression} @var{tag_bytes}
+Print the address given by @var{address_expression}, augmented with a logical
+tag of @var{tag_bytes}.
+@kindex memory-tag print-allocation-tag
+@item memory-tag print-allocation-tag @var{address_expression}
+Print the allocation tag associated with the memory address given by
+@var{address_expression}.
+@kindex memory-tag setatag
+@item memory-tag 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 memory-tag check
+@item memory-tag 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
@@ -24966,6 +25026,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
 
@@ -41023,7 +41118,7 @@ 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
+@var{type} is the type of tag the request wants to fetch.  The type is a signed
 integer.
 
 @var{tag bytes} is a sequence of hex encoded uninterpreted bytes which will be
-- 
2.25.1


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

* [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (20 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 21/25] Documentation for the new mtag commands Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-05  5:02   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
                   ` (3 subsequent siblings)
  25 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v5:

- Add -memory-tag-violations print option to control whether GDB should print
a warning when a logical tag from a pointer doesn't match the allocation tag
contained in memory.
- Remove checks for a removed memory_tagging global variable.
- Update tests listing print options.

Updates on v4:

- Updated function names.
- Removed useless include of infrun.h

--

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.c (show_memory_tag_violations): New function.
	(value_print_option_defs): Add new option "memory-tag-violations".
	(user_print_options) <memory_tag_violations>: Initialize to 1.
	* valprint.h (struct format_data) <print_tags>: New field.
	(value_print_options) <memory_tag_violations>: New field.

gdb/testsuite/ChangeLog:

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

	* gdb.base/options.exp: Adjust for new print options.
	* gdb.base/with.exp: Likewise.
---
 gdb/printcmd.c                     | 82 +++++++++++++++++++++++++++++-
 gdb/testsuite/gdb.base/options.exp |  1 +
 gdb/testsuite/gdb.base/with.exp    |  2 +-
 gdb/valprint.c                     | 22 ++++++++
 gdb/valprint.h                     |  4 ++
 5 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 78acda4e37..322ad16eed 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -193,6 +193,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 == '-')
     {
@@ -215,6 +216,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
@@ -1100,12 +1106,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
+	  && 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);
@@ -1136,6 +1177,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");
     }
@@ -1208,6 +1254,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 (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 *
@@ -1246,7 +1312,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 (print_opts.memory_tag_violations && should_validate_memtags (val)
+	  && !gdbarch_memtag_matches_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);
+    }
 }
 
 /* Called from command completion function to skip over /FMT
diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp
index 44c773c3fa..78ec54502c 100644
--- a/gdb/testsuite/gdb.base/options.exp
+++ b/gdb/testsuite/gdb.base/options.exp
@@ -165,6 +165,7 @@ proc_with_prefix test-print {{prefix ""}} {
 	"-array-indexes"
 	"-elements"
 	"-max-depth"
+	"-memory-tag-violations"
 	"-null-stop"
 	"-object"
 	"-pretty"
diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp
index 0e83ad4898..0d53dbebba 100644
--- a/gdb/testsuite/gdb.base/with.exp
+++ b/gdb/testsuite/gdb.base/with.exp
@@ -238,7 +238,7 @@ with_test_prefix "errors" {
     gdb_test "with w" \
 	"Ambiguous set command \"w\": watchdog, width, write\\."
     gdb_test "with print m" \
-	"Ambiguous set print command \"m\": max-depth, max-symbolic-offset\\."
+	"Ambiguous set print command \"m\": max-depth, max-symbolic-offset, memory-tag-violations\\."
 
     gdb_test "with variable xxx=1" \
 	"Cannot use this setting with the \"with\" command"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 2c3541e668..95f2930adf 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -110,6 +110,7 @@ struct value_print_options user_print_options =
   10,				/* repeat_count_threshold */
   0,				/* output_format */
   0,				/* format */
+  1,				/* memory_tag_violations */
   0,				/* stop_print_at_null */
   0,				/* print_array_indexes */
   0,				/* deref_ref */
@@ -203,6 +204,17 @@ show_repeat_count_threshold (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* If nonzero, prints memory tag violations for pointers.  */
+
+static void
+show_memory_tag_violations (struct ui_file *file, int from_tty,
+			    struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file,
+		    _("Printing of memory tag violations is %s.\n"),
+		    value);
+}
+
 /* If nonzero, stops printing of char arrays at first null.  */
 
 static void
@@ -3023,6 +3035,16 @@ will be replaced with either '{...}' or '(...)' depending on the language.\n\
 Use \"unlimited\" to print the complete structure.")
   },
 
+  boolean_option_def {
+    "memory-tag-violations",
+    [] (value_print_options *opt) { return &opt->memory_tag_violations; },
+    show_memory_tag_violations, /* show_cmd_cb */
+    N_("Set printing of memory tag violations for pointers."),
+    N_("Show printing of memory tag violations for pointers."),
+    N_("When logical tags in pointers do not match the allocation tags in\n\
+memory, issue a warning."),
+  },
+
   boolean_option_def {
     "null-stop",
     [] (value_print_options *opt) { return &opt->stop_print_at_null; },
diff --git a/gdb/valprint.h b/gdb/valprint.h
index ca8ad6aa71..e1dae2cc8f 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -65,6 +65,9 @@ struct value_print_options
      e.g. when the user passes a format to "print".  */
   int format;
 
+  /* Print memory tag violations for pointers.  */
+  bool memory_tag_violations;
+
   /* Stop printing at null character?  */
   bool stop_print_at_null;
 
@@ -252,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.25.1


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

* [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (21 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-28  3:31   ` Eli Zaretskii
  2021-02-05  5:04   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 24/25] Add NEWS entry Luis Machado
                   ` (2 subsequent siblings)
  25 siblings, 2 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

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 f751bdf4d3..5b21991b10 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -9935,6 +9935,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}.
@@ -10702,7 +10706,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}.
 
@@ -10797,6 +10802,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
@@ -10874,8 +10895,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{memory-tag} 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{memory-tag} gives access to the various memory tagging commands.
 
 The @code{memory-tag} commands are the following:
 
-- 
2.25.1


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

* [PATCH v5 24/25] Add NEWS entry.
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (22 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-01-28  3:32   ` Eli Zaretskii
  2021-02-05  5:06   ` Simon Marchi
  2021-01-27 20:21 ` [PATCH v5 25/25] Add memory tagging testcases Luis Machado
  2021-02-04 14:18 ` [PING] [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  25 siblings, 2 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Update command names.

--

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 | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index d2ed28857b..a4e08491ee 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,21 @@
 
 *** Changes since 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.
+
+  - A new modifier 'm' for the "x" command, which displays allocation tags for a
+    particular memory range.
+
+  - Display of memory tag mismatches by "print", for addresses and
+    pointers, if memory tagging is supported by the architecture.
+
 * Building GDB now requires GMP (The GNU Multiple Precision Arithmetic
   Library).
 
@@ -47,6 +62,17 @@ maintenance flush register-cache
 maintenance flush dcache
   A new command to flush the dcache.
 
+memory-tag show-logical-tag ADDRESS
+  Print the logical tag for ADDRESS.
+memory-tag with-logical-tag ADDRESS TAG
+  Print ADDRESS with logical tag TAG.
+memory-tag show-allocation-tag ADDRESS
+  Print the allocation tag for ADDRESS.
+memory-tag set-allocation-tag ADDRESS LENGTH TAGS
+  Set the allocation tag for [ADDRESS, ADDRESS + LENGTH) to TAGS.
+memory-tag check ADDRESS
+  Validate that ADDRESS' logical tag matches the allocation tag.
+
 * Changed commands
 
 break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]
@@ -80,6 +106,14 @@ set style version background COLOR
 set style version intensity VALUE
   Control the styling of GDB's version number text.
 
+* 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.
+
 *** Changes in GDB 10
 
 * There are new feature names for ARC targets: "org.gnu.gdb.arc.core"
@@ -164,8 +198,6 @@ set style version intensity VALUE
 * On Windows targets, it is now possible to debug 32-bit programs with a
   64-bit GDB.
 
-* New commands
-
 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.25.1


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

* [PATCH v5 25/25] Add memory tagging testcases
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (23 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 24/25] Add NEWS entry Luis Machado
@ 2021-01-27 20:21 ` Luis Machado
  2021-02-04 14:18 ` [PING] [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-27 20:21 UTC (permalink / raw)
  To: gdb-patches

Updates on v4:

- Updated command names in the tests.
- Fixed misc formatting issues.
- Turned supports_memtag proc into a gdb_caching_proc

--

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 | 369 +++++++++++++++++++++++++
 gdb/testsuite/gdb.base/memtag.c        |  22 ++
 gdb/testsuite/gdb.base/memtag.exp      |  66 +++++
 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..f7b0081e3f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-mte.exp
@@ -0,0 +1,369 @@
+# 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 that uses MTE and exercise various MTE-related scenarios.
+
+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]} {
+    unsupported "memory tagging unsupported"
+    return -1
+}
+
+gdb_breakpoint "access_memory"
+
+if [gdb_continue "access_memory"] {
+    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} {
+    unresolved "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} {
+    unresolved "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 "memory-tag print-allocation-tag ${untagged_ptr_addr}" $msg \
+	     "memory-tag print-allocation-tag with an untagged address"
+
+    gdb_test "memory-tag set-allocation-tag ${untagged_ptr_addr} 0 00" $msg \
+	     "memory-tag set-allocation-tag 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 "memory-tag print-logical-tag ${addr_tagged}" \
+		 " = 0x${tag_hexnz}" \
+		 "print-logical-tag with tag ${i}"
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "memory-tag with-logical-tag ${addr_tagged} ${tag_hexnn}" \
+		 " = \\(void \\*\\) ${addr_tagged}" \
+		 "with-logical-tag with tag ${i}"
+    }
+
+    set atag_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 "memory-tag set-allocation-tag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
+		 $atag_msg \
+		 "set-allocation-tag with tag ${i}"
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "memory-tag print-allocation-tag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \
+		 "print-allocation-tag 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 "memory-tag set-allocation-tag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
+		     $atag_msg \
+		     "set-allocation-tag 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 "memory-tag 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 "memory-tag 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 "memory-tag print-allocation-tag ${untagged_ptr_symbol}" $msg \
+	     "memory-tag print-allocation-tag with an untagged address"
+
+    gdb_test "memory-tag set-allocation-tag ${untagged_ptr_symbol} 0 00" $msg \
+	     "memory-tag set-allocation-tag 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 "memory-tag print-logical-tag ${tagged_ptr_symbol}" \
+		 " = 0x${tag_hexnz}" \
+		 "print-logical-tag with tag ${i}"
+
+	set tag_hexnn [get_tag_nn $i]
+	gdb_test "memory-tag with-logical-tag ${tagged_ptr_symbol} ${tag_hexnn}" \
+		 " = \\(void \\*\\) ${addr_tagged}" \
+		 "with-logical-tag 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 atag_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 "memory-tag set-allocation-tag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
+		 $atag_msg \
+		 "set-allocation-tag with tag ${i}"
+
+	set tag_hexnz [get_hex_tag [expr $i % 16]]
+	gdb_test "memory-tag print-allocation-tag ${tagged_ptr_symbol}" \
+		 " = 0x${tag_hexnz}" \
+		 "print-allocation-tag 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 "memory-tag set-allocation-tag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
+		     $atag_msg \
+		     "set-allocation-tag 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 "memory-tag 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 "memory-tag 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} {
+	unresolved "unexpected tag value"
+	return -1
+    }
+
+    set atag [expr [expr $ltag + 1] % 16]
+    set atag_hexnn [get_tag_nn $atag]
+
+    gdb_test "memory-tag set-allocation-tag ${tagged_ptr_symbol} 0 ${atag_hexnn}" \
+	     $atag_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 "memory-tag set-allocation-tag tagged_ptr 0 05" \
+	     $atag_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..4045270ada
--- /dev/null
+++ b/gdb/testsuite/gdb.base/memtag.exp
@@ -0,0 +1,66 @@
+# 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 {"with-logical-tag" "print-logical-tag" \
+		    "set-allocation-tag" "print-allocation-tag" "check"} {
+	gdb_test "memory-tag $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]} {
+    unsupported "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 memory-tag commands again.
+    gdb_test "memory-tag print-logical-tag" $msg
+    gdb_test "memory-tag print-allocation-tag" $msg
+    gdb_test "memory-tag with-logical-tag" \
+	     "Argument required \\(<address> <tag>\\)\."
+    gdb_test "memory-tag set-allocation-tag" \
+	     "Argument required \\(<starting address> <length> <tag bytes>\\)\."
+    gdb_test "memory-tag check" $msg
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 2a952c6146..3f730d284c 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2755,6 +2755,22 @@ proc supports_get_siginfo_type {} {
     }
 }
 
+# Return 1 if memory tagging is supported at runtime, otherwise return 0.
+
+gdb_caching_proc supports_memtag {
+    global gdb_prompt
+
+    gdb_test_multiple "memory-tag 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.25.1


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

* Re: [PATCH v5 01/25] New target methods for memory tagging support
  2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
@ 2021-01-27 23:26   ` Lancelot SIX
  2021-01-28 10:02     ` Luis Machado
  2021-02-05  2:31   ` Simon Marchi
  1 sibling, 1 reply; 61+ messages in thread
From: Lancelot SIX @ 2021-01-27 23:26 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

On Wed, Jan 27, 2021 at 05:20:48PM -0300, Luis Machado via Gdb-patches wrote:
> Updates on v5:
> 
> - Remove the memory_tagging global (in favor of setting a specific print
>   option) and related functions.
> 
> Updates on v4:
> 
> - Updated the return types of fetch/store member functions from int to bool.
> - Implemented target-debug type print helpers.
> - Renamed global memtag to memory_tagging.
> 
> 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.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* 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: Regenerate.
> 	* 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.
> 	* target-debug.h (target_debug_print_size_t)
> 	(target_debug_print_const_gdb_byte_vector_r)
> 	(target_debug_print_gdb_byte_vector_r): New functions.
> ---
>  gdb/remote.c           | 34 +++++++++++++++
>  gdb/target-debug.h     | 24 +++++++++++
>  gdb/target-delegates.c | 95 ++++++++++++++++++++++++++++++++++++++++++
>  gdb/target.h           | 41 ++++++++++++++++++
>  4 files changed, 194 insertions(+)
> 
> diff --git a/gdb/remote.c b/gdb/remote.c
> index bc995edc53..b130f1ddae 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -690,6 +690,14 @@ 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;
> +
> +  bool fetch_memtags (CORE_ADDR address, size_t len,
> +		     gdb::byte_vector &tags, int type) override;
> +
> +  bool 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,
> @@ -14472,6 +14480,32 @@ show_remote_timeout (struct ui_file *file, int from_tty,
>  		    value);
>  }
>  
> +/* Implement the "supports_memory_tagging" target_ops method.  */
> +
> +bool
> +remote_target::supports_memory_tagging ()
> +{
> +  return false;
> +}
> +
> +/* Implement the "fetch_memtags" target_ops method.  */
> +
> +bool
> +remote_target::fetch_memtags (CORE_ADDR address, size_t len,
> +			      gdb::byte_vector &tags, int type)
> +{
> +  return 0;

If you return a bool, you should probably return false.

> +}
> +
> +/* Implement the "store_memtags" target_ops method.  */
> +
> +bool
> +remote_target::store_memtags (CORE_ADDR address, size_t len,
> +			      const gdb::byte_vector &tags, int type)
> +{
> +  return 0;

Similarly, return false.

> +}
> +
>  void _initialize_remote ();
>  void
>  _initialize_remote ()
> diff --git a/gdb/target-debug.h b/gdb/target-debug.h
> index 6910338865..5bc384a39a 100644
> --- a/gdb/target-debug.h
> +++ b/gdb/target-debug.h
> @@ -212,4 +212,28 @@ target_debug_print_signals (gdb::array_view<const unsigned char> sigs)
>    fputs_unfiltered (" }", gdb_stdlog);
>  }
>  
> +static void
> +target_debug_print_size_t (size_t size)
> +{
> +  fprintf_unfiltered (gdb_stdlog, "%s", pulongest (size));
> +}
> +
> +static void
> +target_debug_print_const_gdb_byte_vector_r (const gdb::byte_vector &vector)
> +{
> +  fputs_unfiltered ("{", gdb_stdlog);
> +
> +  for (size_t i = 0; i < vector.size (); i++)
> +    {
> +      fprintf_unfiltered (gdb_stdlog, " %s",
> +			  phex_nz (vector[i], 1));
> +    }
> +  fputs_unfiltered (" }", gdb_stdlog);
> +}
> +
> +static void
> +target_debug_print_gdb_byte_vector_r (gdb::byte_vector &vector)
> +{
> +  target_debug_print_gdb_byte_vector_r (vector);

I think you meant target_debug_print_const_gdb_byte_vector_r here.

Lancelot.

> +}
>  #endif /* TARGET_DEBUG_H */
> diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
> index 437b19b858..e4563e4dac 100644
> --- a/gdb/target-delegates.c
> +++ b/gdb/target-delegates.c
> @@ -173,6 +173,9 @@ 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;
> +  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
> +  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
>  };
>  
>  struct debug_target : public target_ops
> @@ -344,6 +347,9 @@ 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;
> +  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
> +  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
>  };
>  
>  void
> @@ -4413,3 +4419,92 @@ debug_target::done_generating_core ()
>    fputs_unfiltered (")\n", gdb_stdlog);
>  }
>  
> +bool
> +target_ops::supports_memory_tagging ()
> +{
> +  return this->beneath ()->supports_memory_tagging ();
> +}
> +
> +bool
> +dummy_target::supports_memory_tagging ()
> +{
> +  return false;
> +}
> +
> +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;
> +}
> +
> +bool
> +target_ops::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
> +{
> +  return this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
> +}
> +
> +bool
> +dummy_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
> +{
> +  tcomplain ();
> +}
> +
> +bool
> +debug_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
> +{
> +  bool result;
> +  fprintf_unfiltered (gdb_stdlog, "-> %s->fetch_memtags (...)\n", this->beneath ()->shortname ());
> +  result = this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
> +  fprintf_unfiltered (gdb_stdlog, "<- %s->fetch_memtags (", this->beneath ()->shortname ());
> +  target_debug_print_CORE_ADDR (arg0);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_size_t (arg1);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_gdb_byte_vector_r (arg2);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_int (arg3);
> +  fputs_unfiltered (") = ", gdb_stdlog);
> +  target_debug_print_bool (result);
> +  fputs_unfiltered ("\n", gdb_stdlog);
> +  return result;
> +}
> +
> +bool
> +target_ops::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
> +{
> +  return this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
> +}
> +
> +bool
> +dummy_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
> +{
> +  tcomplain ();
> +}
> +
> +bool
> +debug_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
> +{
> +  bool result;
> +  fprintf_unfiltered (gdb_stdlog, "-> %s->store_memtags (...)\n", this->beneath ()->shortname ());
> +  result = this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
> +  fprintf_unfiltered (gdb_stdlog, "<- %s->store_memtags (", this->beneath ()->shortname ());
> +  target_debug_print_CORE_ADDR (arg0);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_size_t (arg1);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_const_gdb_byte_vector_r (arg2);
> +  fputs_unfiltered (", ", gdb_stdlog);
> +  target_debug_print_int (arg3);
> +  fputs_unfiltered (") = ", gdb_stdlog);
> +  target_debug_print_bool (result);
> +  fputs_unfiltered ("\n", gdb_stdlog);
> +  return result;
> +}
> +
> diff --git a/gdb/target.h b/gdb/target.h
> index 917476d16a..19395f1258 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -1260,6 +1260,38 @@ 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, false otherwise.  */
> +    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.
> +
> +       Returns true if fetching the tags succeeded and false otherwise.  */
> +    virtual bool fetch_memtags (CORE_ADDR address, size_t len,
> +			       gdb::byte_vector &tags, int type)
> +      TARGET_DEFAULT_NORETURN (tcomplain ());
> +
> +    /* 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.
> +
> +       Returns true if storing the tags succeeded and false otherwise.  */
> +    virtual bool store_memtags (CORE_ADDR address, size_t len,
> +			       const gdb::byte_vector &tags, int type)
> +      TARGET_DEFAULT_NORETURN (tcomplain ());
>    };
>  
>  /* Deleter for std::unique_ptr.  See comments in
> @@ -2312,6 +2344,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.25.1
> 

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

* Re: [PATCH v5 07/25] Documentation for memory tagging remote packets
  2021-01-27 20:20 ` [PATCH v5 07/25] Documentation for " Luis Machado
@ 2021-01-28  3:30   ` Eli Zaretskii
  2021-01-28  9:58     ` Luis Machado
  0 siblings, 1 reply; 61+ messages in thread
From: Eli Zaretskii @ 2021-01-28  3:30 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

> Date: Wed, 27 Jan 2021 17:20:54 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> 
> Updates on v4:
> 
> - Add documentation for ARM-specific memory tag types.
> 
> 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.
> 	(ARM-Specific Protocol Details): Document memory tag types.

This was already approved in previous versions, right?

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

* Re: [PATCH v5 21/25] Documentation for the new mtag commands
  2021-01-27 20:21 ` [PATCH v5 21/25] Documentation for the new mtag commands Luis Machado
@ 2021-01-28  3:31   ` Eli Zaretskii
  2021-02-05  4:50   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Eli Zaretskii @ 2021-01-28  3:31 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

> Date: Wed, 27 Jan 2021 17:21:08 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> 
> Updates on v4:
> 
> - Update the command names.
> 
> --
> 
> Document the new "memory-tag" 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.

Already approved, right?

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

* Re: [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions
  2021-01-27 20:21 ` [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
@ 2021-01-28  3:31   ` Eli Zaretskii
  2021-02-05  5:04   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Eli Zaretskii @ 2021-01-28  3:31 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

> Date: Wed, 27 Jan 2021 17:21:10 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.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.

This was already approved, right?

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

* Re: [PATCH v5 24/25] Add NEWS entry.
  2021-01-27 20:21 ` [PATCH v5 24/25] Add NEWS entry Luis Machado
@ 2021-01-28  3:32   ` Eli Zaretskii
  2021-02-05  5:06   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Eli Zaretskii @ 2021-01-28  3:32 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

> Date: Wed, 27 Jan 2021 17:21:11 -0300
> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
> 
> Updates on v4:
> 
> - Update command names.
> 
> --
> 
> Mention the new packets and memory tagging features.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* NEWS: Mention memory tagging changes.

This was already approved, I think.

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

* Re: [PATCH v5 07/25] Documentation for memory tagging remote packets
  2021-01-28  3:30   ` Eli Zaretskii
@ 2021-01-28  9:58     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-28  9:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

Hi Eli,

On 1/28/21 12:30 AM, Eli Zaretskii wrote:
>> Date: Wed, 27 Jan 2021 17:20:54 -0300
>> From: Luis Machado via Gdb-patches <gdb-patches@sourceware.org>
>>
>> Updates on v4:
>>
>> - Add documentation for ARM-specific memory tag types.
>>
>> 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.
>> 	(ARM-Specific Protocol Details): Document memory tag types.
> 
> This was already approved in previous versions, right?
> 

That's correct. The doc changes haven't received any updates that aren't 
trivial command renames.

Thanks,
Luis

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

* Re: [PATCH v5 01/25] New target methods for memory tagging support
  2021-01-27 23:26   ` Lancelot SIX
@ 2021-01-28 10:02     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-01-28 10:02 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

On 1/27/21 8:26 PM, Lancelot SIX wrote:
> On Wed, Jan 27, 2021 at 05:20:48PM -0300, Luis Machado via Gdb-patches wrote:
>> Updates on v5:
>>
>> - Remove the memory_tagging global (in favor of setting a specific print
>>    option) and related functions.
>>
>> Updates on v4:
>>
>> - Updated the return types of fetch/store member functions from int to bool.
>> - Implemented target-debug type print helpers.
>> - Renamed global memtag to memory_tagging.
>>
>> 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.
>>
>> gdb/ChangeLog:
>>
>> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
>>
>> 	* 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: Regenerate.
>> 	* 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.
>> 	* target-debug.h (target_debug_print_size_t)
>> 	(target_debug_print_const_gdb_byte_vector_r)
>> 	(target_debug_print_gdb_byte_vector_r): New functions.
>> ---
>>   gdb/remote.c           | 34 +++++++++++++++
>>   gdb/target-debug.h     | 24 +++++++++++
>>   gdb/target-delegates.c | 95 ++++++++++++++++++++++++++++++++++++++++++
>>   gdb/target.h           | 41 ++++++++++++++++++
>>   4 files changed, 194 insertions(+)
>>
>> diff --git a/gdb/remote.c b/gdb/remote.c
>> index bc995edc53..b130f1ddae 100644
>> --- a/gdb/remote.c
>> +++ b/gdb/remote.c
>> @@ -690,6 +690,14 @@ 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;
>> +
>> +  bool fetch_memtags (CORE_ADDR address, size_t len,
>> +		     gdb::byte_vector &tags, int type) override;
>> +
>> +  bool 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,
>> @@ -14472,6 +14480,32 @@ show_remote_timeout (struct ui_file *file, int from_tty,
>>   		    value);
>>   }
>>   
>> +/* Implement the "supports_memory_tagging" target_ops method.  */
>> +
>> +bool
>> +remote_target::supports_memory_tagging ()
>> +{
>> +  return false;
>> +}
>> +
>> +/* Implement the "fetch_memtags" target_ops method.  */
>> +
>> +bool
>> +remote_target::fetch_memtags (CORE_ADDR address, size_t len,
>> +			      gdb::byte_vector &tags, int type)
>> +{
>> +  return 0;
> 
> If you return a bool, you should probably return false.
> 
>> +}
>> +
>> +/* Implement the "store_memtags" target_ops method.  */
>> +
>> +bool
>> +remote_target::store_memtags (CORE_ADDR address, size_t len,
>> +			      const gdb::byte_vector &tags, int type)
>> +{
>> +  return 0;
> 
> Similarly, return false.
> 

Missed it, since this gets replaced by the full implementation later. 
I'll address it locally. Thanks for spotting that.

>> +}
>> +
>>   void _initialize_remote ();
>>   void
>>   _initialize_remote ()
>> diff --git a/gdb/target-debug.h b/gdb/target-debug.h
>> index 6910338865..5bc384a39a 100644
>> --- a/gdb/target-debug.h
>> +++ b/gdb/target-debug.h
>> @@ -212,4 +212,28 @@ target_debug_print_signals (gdb::array_view<const unsigned char> sigs)
>>     fputs_unfiltered (" }", gdb_stdlog);
>>   }
>>   
>> +static void
>> +target_debug_print_size_t (size_t size)
>> +{
>> +  fprintf_unfiltered (gdb_stdlog, "%s", pulongest (size));
>> +}
>> +
>> +static void
>> +target_debug_print_const_gdb_byte_vector_r (const gdb::byte_vector &vector)
>> +{
>> +  fputs_unfiltered ("{", gdb_stdlog);
>> +
>> +  for (size_t i = 0; i < vector.size (); i++)
>> +    {
>> +      fprintf_unfiltered (gdb_stdlog, " %s",
>> +			  phex_nz (vector[i], 1));
>> +    }
>> +  fputs_unfiltered (" }", gdb_stdlog);
>> +}
>> +
>> +static void
>> +target_debug_print_gdb_byte_vector_r (gdb::byte_vector &vector)
>> +{
>> +  target_debug_print_gdb_byte_vector_r (vector);
> 
> I think you meant target_debug_print_const_gdb_byte_vector_r here.
> 

That's correct. I'll fix this locally.

Thanks!

> Lancelot.
> 
>> +}
>>   #endif /* TARGET_DEBUG_H */
>> diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
>> index 437b19b858..e4563e4dac 100644
>> --- a/gdb/target-delegates.c
>> +++ b/gdb/target-delegates.c
>> @@ -173,6 +173,9 @@ 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;
>> +  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
>> +  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
>>   };
>>   
>>   struct debug_target : public target_ops
>> @@ -344,6 +347,9 @@ 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;
>> +  bool fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3) override;
>> +  bool store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3) override;
>>   };
>>   
>>   void
>> @@ -4413,3 +4419,92 @@ debug_target::done_generating_core ()
>>     fputs_unfiltered (")\n", gdb_stdlog);
>>   }
>>   
>> +bool
>> +target_ops::supports_memory_tagging ()
>> +{
>> +  return this->beneath ()->supports_memory_tagging ();
>> +}
>> +
>> +bool
>> +dummy_target::supports_memory_tagging ()
>> +{
>> +  return false;
>> +}
>> +
>> +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;
>> +}
>> +
>> +bool
>> +target_ops::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
>> +{
>> +  return this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
>> +}
>> +
>> +bool
>> +dummy_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
>> +{
>> +  tcomplain ();
>> +}
>> +
>> +bool
>> +debug_target::fetch_memtags (CORE_ADDR arg0, size_t arg1, gdb::byte_vector &arg2, int arg3)
>> +{
>> +  bool result;
>> +  fprintf_unfiltered (gdb_stdlog, "-> %s->fetch_memtags (...)\n", this->beneath ()->shortname ());
>> +  result = this->beneath ()->fetch_memtags (arg0, arg1, arg2, arg3);
>> +  fprintf_unfiltered (gdb_stdlog, "<- %s->fetch_memtags (", this->beneath ()->shortname ());
>> +  target_debug_print_CORE_ADDR (arg0);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_size_t (arg1);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_gdb_byte_vector_r (arg2);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_int (arg3);
>> +  fputs_unfiltered (") = ", gdb_stdlog);
>> +  target_debug_print_bool (result);
>> +  fputs_unfiltered ("\n", gdb_stdlog);
>> +  return result;
>> +}
>> +
>> +bool
>> +target_ops::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
>> +{
>> +  return this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
>> +}
>> +
>> +bool
>> +dummy_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
>> +{
>> +  tcomplain ();
>> +}
>> +
>> +bool
>> +debug_target::store_memtags (CORE_ADDR arg0, size_t arg1, const gdb::byte_vector &arg2, int arg3)
>> +{
>> +  bool result;
>> +  fprintf_unfiltered (gdb_stdlog, "-> %s->store_memtags (...)\n", this->beneath ()->shortname ());
>> +  result = this->beneath ()->store_memtags (arg0, arg1, arg2, arg3);
>> +  fprintf_unfiltered (gdb_stdlog, "<- %s->store_memtags (", this->beneath ()->shortname ());
>> +  target_debug_print_CORE_ADDR (arg0);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_size_t (arg1);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_const_gdb_byte_vector_r (arg2);
>> +  fputs_unfiltered (", ", gdb_stdlog);
>> +  target_debug_print_int (arg3);
>> +  fputs_unfiltered (") = ", gdb_stdlog);
>> +  target_debug_print_bool (result);
>> +  fputs_unfiltered ("\n", gdb_stdlog);
>> +  return result;
>> +}
>> +
>> diff --git a/gdb/target.h b/gdb/target.h
>> index 917476d16a..19395f1258 100644
>> --- a/gdb/target.h
>> +++ b/gdb/target.h
>> @@ -1260,6 +1260,38 @@ 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, false otherwise.  */
>> +    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.
>> +
>> +       Returns true if fetching the tags succeeded and false otherwise.  */
>> +    virtual bool fetch_memtags (CORE_ADDR address, size_t len,
>> +			       gdb::byte_vector &tags, int type)
>> +      TARGET_DEFAULT_NORETURN (tcomplain ());
>> +
>> +    /* 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.
>> +
>> +       Returns true if storing the tags succeeded and false otherwise.  */
>> +    virtual bool store_memtags (CORE_ADDR address, size_t len,
>> +			       const gdb::byte_vector &tags, int type)
>> +      TARGET_DEFAULT_NORETURN (tcomplain ());
>>     };
>>   
>>   /* Deleter for std::unique_ptr.  See comments in
>> @@ -2312,6 +2344,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.25.1
>>

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

* [PING] [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation
  2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
                   ` (24 preceding siblings ...)
  2021-01-27 20:21 ` [PATCH v5 25/25] Add memory tagging testcases Luis Machado
@ 2021-02-04 14:18 ` Luis Machado
  25 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-02-04 14:18 UTC (permalink / raw)
  To: gdb-patches


On 1/27/21 5:20 PM, Luis Machado wrote:
> 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 (25):
>    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
>    Convert char array to std::string in linux_find_memory_regions_full
>    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 memory-tag 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                               |  36 +-
>   gdb/aarch64-linux-nat.c                | 127 ++++++-
>   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           |  73 ++++
>   gdb/arch/aarch64-mte-linux.h           |  75 +++++
>   gdb/arch/aarch64.c                     |   7 +-
>   gdb/arch/aarch64.h                     |   7 +-
>   gdb/configure.nat                      |   3 +-
>   gdb/configure.tgt                      |   1 +
>   gdb/doc/gdb.texinfo                    | 233 ++++++++++++-
>   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                       | 378 +++++++++++++--------
>   gdb/linux-tdep.h                       |   4 +
>   gdb/nat/aarch64-mte-linux-ptrace.c     | 200 +++++++++++
>   gdb/nat/aarch64-mte-linux-ptrace.h     |  50 +++
>   gdb/printcmd.c                         | 444 ++++++++++++++++++++++++-
>   gdb/remote.c                           | 227 +++++++++++++
>   gdb/target-debug.h                     |  24 ++
>   gdb/target-delegates.c                 |  95 ++++++
>   gdb/target.h                           |  41 +++
>   gdb/testsuite/gdb.arch/aarch64-mte.c   | 107 ++++++
>   gdb/testsuite/gdb.arch/aarch64-mte.exp | 369 ++++++++++++++++++++
>   gdb/testsuite/gdb.base/memtag.c        |  22 ++
>   gdb/testsuite/gdb.base/memtag.exp      |  66 ++++
>   gdb/testsuite/gdb.base/options.exp     |   1 +
>   gdb/testsuite/gdb.base/with.exp        |   2 +-
>   gdb/testsuite/lib/gdb.exp              |  16 +
>   gdb/valprint.c                         |  22 ++
>   gdb/valprint.h                         |   4 +
>   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                    | 219 ++++++++++++
>   gdbserver/server.h                     |   3 +
>   gdbserver/target.cc                    |  20 ++
>   gdbserver/target.h                     |  21 ++
>   gdbsupport/common-utils.cc             |  49 +++
>   gdbsupport/common-utils.h              |  15 +
>   gdbsupport/rsp-low.cc                  |  49 ---
>   gdbsupport/rsp-low.h                   |  19 --
>   include/elf/common.h                   |   3 +
>   57 files changed, 3655 insertions(+), 265 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] 61+ messages in thread

* Re: [PATCH v5 01/25] New target methods for memory tagging support
  2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
  2021-01-27 23:26   ` Lancelot SIX
@ 2021-02-05  2:31   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  2:31 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:20 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v5:
> 
> - Remove the memory_tagging global (in favor of setting a specific print
>   option) and related functions.
> 
> Updates on v4:
> 
> - Updated the return types of fetch/store member functions from int to bool.
> - Implemented target-debug type print helpers.
> - Renamed global memtag to memory_tagging.
> 
> 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.
> 
> gdb/ChangeLog:
> 
> YYYY-MM-DD  Luis Machado  <luis.machado@linaro.org>
> 
> 	* 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: Regenerate.
> 	* 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.
> 	* target-debug.h (target_debug_print_size_t)
> 	(target_debug_print_const_gdb_byte_vector_r)
> 	(target_debug_print_gdb_byte_vector_r): New functions.
> ---
>  gdb/remote.c           | 34 +++++++++++++++
>  gdb/target-debug.h     | 24 +++++++++++
>  gdb/target-delegates.c | 95 ++++++++++++++++++++++++++++++++++++++++++
>  gdb/target.h           | 41 ++++++++++++++++++
>  4 files changed, 194 insertions(+)
> 
> diff --git a/gdb/remote.c b/gdb/remote.c
> index bc995edc53..b130f1ddae 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -690,6 +690,14 @@ 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;
> +
> +  bool fetch_memtags (CORE_ADDR address, size_t len,
> +		     gdb::byte_vector &tags, int type) override;
> +
> +  bool store_memtags (CORE_ADDR address, size_t len,
> +		     const gdb::byte_vector &tags, int type) override;

The indentation is a bit off here.  Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 02/25] New gdbarch memory tagging hooks
  2021-01-27 20:20 ` [PATCH v5 02/25] New gdbarch memory tagging hooks Luis Machado
@ 2021-02-05  2:38   ` Simon Marchi
  2021-02-05  3:58   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  2:38 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

On 2021-01-27 3:20 p.m., Luis Machado via Gdb-patches wrote:
> +/* 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;

Nit: nullptr.

> +}
> +
>  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 a7e53ea5ae..e1ffa03eff 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);

The comment should read "gdbarch_memtag_to_string".

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 03/25] Add GDB-side remote target support for memory tagging
  2021-01-27 20:20 ` [PATCH v5 03/25] Add GDB-side remote target support for memory tagging Luis Machado
@ 2021-02-05  2:48   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  2:48 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:20 p.m., Luis Machado via Gdb-patches wrote:
> Updates for v4:
> 
> - Rename RSP helper functions.
> - Fixup parameter and return types.
> 
> 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 and 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>:<type>
> --
> 
> Reads tags of the specified type from the address range
> [<address>, <address + length>)
> 
> QMemTags:<address>,<length>:<type>:<uninterpreted tag bytes>
> --
> Writes the tags of specified type 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_fetch_memtags_request, parse_fetch_memtags_reply)
> 	(create_store_memtags_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 | 106 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 103 insertions(+), 3 deletions(-)
> 
> diff --git a/gdb/remote.c b/gdb/remote.c
> index b130f1ddae..bb3473b04c 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -2175,6 +2175,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
>  };
>  
> @@ -2316,6 +2320,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)

Remove `void`.

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling
  2021-01-27 20:20 ` [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling Luis Machado
@ 2021-02-05  2:50   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  2:50 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:20 p.m., Luis Machado via Gdb-patches wrote:
> Updated in v4:
> 
> - Renamed functions based on reviews.
> - Adjusted code to cope with bool return value.
> - Restoring of global setting after unit testing.
> 
> 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 | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 93 insertions(+)
> 
> diff --git a/gdb/remote.c b/gdb/remote.c
> index bb3473b04c..22cae2a94f 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.  */
>  
> @@ -14603,6 +14604,93 @@ remote_target::store_memtags (CORE_ADDR address, size_t len,
>    return packet_check_result (rs->buf.data ()) == PACKET_OK;
>  }
>  
> +#if GDB_SELF_TEST
> +
> +namespace selftests {
> +
> +static void
> +test_memory_tagging_functions ()
> +{
> +  remote_target remote;
> +
> +  struct packet_config *config
> +    = &remote_protocol_packets[PACKET_memory_tagging_feature];
> +
> +  scoped_restore restore_memtag_support_
> +    = make_scoped_restore (&config->support,
> +			   config->support);

I think you could use the single-argument form here, if you want to
create the scoped_restore object but not modify the value right away.

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 05/25] GDBserver remote packet support for memory tagging
  2021-01-27 20:20 ` [PATCH v5 05/25] GDBserver remote packet support for memory tagging Luis Machado
@ 2021-02-05  2:56   ` Simon Marchi
  2021-02-05 12:38     ` Luis Machado
  0 siblings, 1 reply; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  2:56 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
> index cfdf1c1883..4e76f08ac5 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)

For new code, IWBN to follow the convention of putting the doc in the
header, and putting /* See remote-utils.h.  */ here.

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 08/25] AArch64: Add MTE CPU feature check support
  2021-01-27 20:20 ` [PATCH v5 08/25] AArch64: Add MTE CPU feature check support Luis Machado
@ 2021-02-05  3:05   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:05 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> 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.

2021

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 11/25] AArch64: Add MTE ptrace requests
  2021-01-27 20:20 ` [PATCH v5 11/25] AArch64: Add MTE ptrace requests Luis Machado
@ 2021-02-05  3:13   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:13 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:20 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.
> 
> 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 4e1e6da88d..b763351912 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1506,6 +1506,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 \

Let's keep this list in order :)

>  	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.

2021

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64
  2021-01-27 20:20 ` [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
@ 2021-02-05  3:30   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:30 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> +/* Implement the "supports_memory_tagging" target_ops method.  */
> +
> +bool
> +aarch64_linux_nat_target::supports_memory_tagging ()
> +{
> +  return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0;
> +}
> +
> +/* Implement the "fetch_memtags" target_ops method.  */
> +
> +bool
> +aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len,
> +					 gdb::byte_vector &tags, int type)
> +{
> +  int tid = get_ptrace_pid (inferior_ptid);
> +
> +  /* Allocation tags?  */
> +  if (type == static_cast <int> (aarch64_memtag_type::mte_allocation))
> +    return aarch64_mte_fetch_memtags (tid, address, len, tags);

We don't use a space before template parameters, so `static_cast<int>`.

> +
> +  return false;
> +}
> +
> +/* Implement the "store_memtags" target_ops method.  */
> +
> +bool
> +aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len,
> +					 const gdb::byte_vector &tags, int type)
> +{
> +  int tid = get_ptrace_pid (inferior_ptid);
> +
> +  /* Allocation tags?  */
> +  if (type == static_cast <int> (aarch64_memtag_type::mte_allocation))
> +    return aarch64_mte_store_memtags (tid, address, len, tags);

Likewise.

> +
> +  return false;
> +}
> +
>  /* Define AArch64 maintenance commands.  */
>  
>  static void
> diff --git a/gdb/arch/aarch64-mte-linux.c b/gdb/arch/aarch64-mte-linux.c
> new file mode 100644
> index 0000000000..ede5f5f2b9
> --- /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.

2021, I'll stop mentioning these, please apply to all new files

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full
  2021-01-27 20:21 ` [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full Luis Machado
@ 2021-02-05  3:32   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:32 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> @@ -1296,10 +1294,12 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>  
>    if (use_coredump_filter)
>      {
> -      xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
> -		 "/proc/%d/coredump_filter", pid);
> +      std::string core_dump_filter_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, core_dump_filter_name.c_str());

Space before parenthesis.

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps
  2021-01-27 20:21 ` [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps Luis Machado
@ 2021-02-05  3:38   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:38 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> +/* 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.  */
> +  smaps = parse_smaps_data (data.get (), smaps_file);

Declare and assign the vector directly:

  std::vector<smaps_data> smaps = ...;

> +
> +  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.  */
>  
>  static int
> @@ -1319,137 +1521,50 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
>        /* Older Linux kernels did not support /proc/PID/smaps.  */
>        maps_filename = string_printf ("/proc/%d/maps", pid);
>        data = target_fileio_read_stralloc (NULL, maps_filename.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 (sscanf (line, "%64s", keyword) != 1)
> -		{
> -		  warning (_("Error parsing {s,}maps file '%s'"),
> -			   maps_filename.c_str ());
> -		  break;
> -		}
> +      if (data == nullptr)
> +	return 1;
> +    }
>  
> -	      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);
> +  std::vector<struct smaps_data> smaps;
>  
> -	      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"),
> -			       maps_filename.c_str ());
> -		      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;
> -		    }
> -		}
> -	    }
> +  /* Parse the contents of smaps into a vector.  */
> +  smaps = parse_smaps_data (data.get (), maps_filename.c_str ());

Likewise here.

>  
> -	  if (has_anonymous)
> -	    should_dump_p = should_dump_mapping_p (filterflags, &v, priv,
> -						   mapping_anon_p,
> -						   mapping_file_p,
> -						   filename, addr, offset);
> -	  else
> -	    {
> -	      /* Older Linux kernels did not support the "Anonymous:" counter.
> -		 If it is missing, we can't be sure - dump all the pages.  */
> -	      should_dump_p = 1;
> -	    }
> +  for (const struct smaps_data map : smaps)

You are missing the & to make it a reference (otherwise it makes a copy
of each item as it iterates, I don't think you want that.

Otherwise, LGTM.

Simon

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

* Re: [PATCH v5 02/25] New gdbarch memory tagging hooks
  2021-01-27 20:20 ` [PATCH v5 02/25] New gdbarch memory tagging hooks Luis Machado
  2021-02-05  2:38   ` Simon Marchi
@ 2021-02-05  3:58   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  3:58 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> +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,
> +};

Maybe one more suggestion: use enum class.  I find that it ends up more
self-descriptive when you use it.

enum class memtag_type
{
  /* ... */
  logical,

  /* ... */
  allocation,
};

Without enum class (in C), I always try to prefix the enumerators with
the enum type name, to get the same self-decriptiveness (and to avoid
name clashes):

enum memtag_type
{
  memtag_type_logical,
  memtag_type_allocation,
};

... but enum class is just cleaner, and safer.

Simon

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

* Re: [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks
  2021-01-27 20:21 ` [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
@ 2021-02-05  4:09   ` Simon Marchi
  2021-02-05 14:05     ` Luis Machado
  0 siblings, 1 reply; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  4:09 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v4:
> 
> - Update function names to be more scoped.
> - Use of gdb::optional values.
> - Fixed up gdbarch hooks.
> 
> 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_mte_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 (aarch64_mte_make_ltag_bits)
> 	(aarch64_mte_make_ltag, aarch64_linux_set_ltag)
> 	(aarch64_linux_get_ltag): New functions.
> 	* arch/aarch64-mte-linux.h (AARCH64_MTE_LOGICAL_TAG_START_BIT)
> 	(AARCH64_MTE_LOGICAL_MAX_VALUE): Define.
> 	(aarch64_mte_make_ltag_bits, aarch64_mte_make_ltag)
> 	(aarch64_mte_set_ltag, aarch64_mte_get_ltag): New prototypes.
> ---
>  gdb/aarch64-linux-tdep.c     | 210 +++++++++++++++++++++++++++++++++++
>  gdb/arch/aarch64-mte-linux.c |  41 ++++++-
>  gdb/arch/aarch64-mte-linux.h |  19 ++++
>  3 files changed, 269 insertions(+), 1 deletion(-)
> 
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index f113d1ea30..2fe88cf016 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.
>  
>        +------------+  ^
> @@ -1513,6 +1517,187 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
>    return {};
>  }
>  
> +/* Helper to get the allocation tag from a 64-bit ADDRESS.
> +
> +   Return the allocation tag if successful and nullopt otherwise.  */
> +
> +static gdb::optional<CORE_ADDR>
> +aarch64_mte_get_atag (CORE_ADDR address)
> +{
> +  gdb::byte_vector tags;
> +
> +  /* Attempt to fetch the allocation tag.  */
> +  if (!target_fetch_memtags (address, 0, tags, tag_allocation))
> +    return {};
> +
> +  /* Only one tag should've been returned.  Make sure we got exactly that.  */
> +  gdb_assert (tags.size () == 1);

The tags are returned by the target, possibly the remote target.  That
means that you could make GDB assert by returning it a memtag packet
with the wrong number of bytes.  And we don't want it to be possible to
make GDB assert when feeding it bad input.

I'd probably use error() here just for this reason.

> +/* Implement the set_memtags gdbarch method.  */
> +
> +static bool
> +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 true;

Can this can really happen?

> +
> +  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_mte_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 false;
> +
> +      /* 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 = aarch64_mte_get_tag_granules (addr, length,
> +					       AARCH64_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))
> +	return false;
> +    }
> +  return true;

I just realized that the gdbarch methods are overloaded, as they are
used to both set/get the logical tag of the pointer and set/get the
allocation tags of the allocated memory.  I think it would be easier to
understand to have four methods, get/set the local tags and get/set the
allocation tags.

The documentation in gdbarch.sh for get_memtag also only talks about the
logical tag (extracting the tag from the address).

Since this is internal stuff, I suggest we leave this patch as-is to
avoid some more churn, but please consider addressing it as a follow-up
patch to the series, if you agree.

> +}
> +
> +/* 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_mte_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;
> +
> +      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (addr);
> +
> +      if (!atag.has_value ())
> +	return nullptr;
> +
> +      tag = *atag;
> +    }
> +
> +  /* 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)));
> +}

I'll see in the following patches how gdbarch_linux_memtag_to_string is
used, but at first glance I think it would make sense for this method to
have the prototype:

  std::string gdbarch_memtag_to_string (struct gdbarch *gdbarch, value *tag);

Meaning that you would pass it a tag you already fetched (using
gdbarch_get_memtag).  This way if you already have a tag as a local
variable and you want to format it as a string, it doesn't require going
to the target.  I don't think you would need the tag type parameter in
this case, as we wouldn't care where the tag comes from, we'd just use
the passed-in value.

Also something that can be done as a follow-up patch.

> +
>  static void
>  aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>  {
> @@ -1570,6 +1755,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 match.  */
> +      set_gdbarch_memtag_matches_p (gdbarch,
> +				    aarch64_linux_memtag_matches_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, AARCH64_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 ede5f5f2b9..4461864a32 100644
> --- a/gdb/arch/aarch64-mte-linux.c
> +++ b/gdb/arch/aarch64-mte-linux.c
> @@ -22,7 +22,8 @@
>  /* See arch/aarch64-mte-linux.h */
>  
>  size_t
> -aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
> +aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
> +				    size_t granule_size)

Unintended change.

>  {
>    /* Start address */
>    CORE_ADDR s_addr = align_down (addr, granule_size);
> @@ -32,3 +33,41 @@ aarch64_mte_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
> +aarch64_mte_make_ltag_bits (CORE_ADDR value)
> +{
> +  return value & AARCH64_MTE_LOGICAL_MAX_VALUE;
> +}
> +
> +/* See arch/aarch64-mte-linux.h */
> +
> +CORE_ADDR
> +aarch64_mte_make_ltag (CORE_ADDR value)
> +{
> +  return aarch64_mte_make_ltag_bits (value)
> +	 << AARCH64_MTE_LOGICAL_TAG_START_BIT;

We would usually use parenthesis when wrapping this:

  return (aarch64_mte_make_ltag_bits (value)
	  << AARCH64_MTE_LOGICAL_TAG_START_BIT);

The argument being that Emacs aligns it correctly if you do that (not
that I care :)).

The patch LGTM with the nits fixed.

Simon

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

* Re: [PATCH v5 17/25] AArch64: Report tag violation error information
  2021-01-27 20:21 ` [PATCH v5 17/25] AArch64: Report tag violation error information Luis Machado
@ 2021-02-05  4:22   ` Simon Marchi
  2021-02-05 14:59     ` Luis Machado
  0 siblings, 1 reply; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  4:22 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 1063dd7a82..4ccee9c34e 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1700,6 +1700,69 @@ 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");
> +
> +      fault_addr
> +	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> +    }
> +  catch (const gdb_exception_error &exception)
> +    {
> +      exception_print (gdb_stderr, 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");

I guess there's no easy way of getting the logical address that was used
to attempt the memory access?  I think it would be nice to say something
like "Your pointer had logical tag X, but the pointed memory has
allocation tag Y".  But if we can't, we can't.

> +
> +      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (fault_addr);
> +
> +      if (!atag.has_value ())
> +	uiout->text (_("Allocation tag unavailable"));
> +      else
> +	{
> +	  uiout->text (_("Allocation tag "));
> +	  uiout->field_string ("allocation-tag", hex_string (*atag));
> +	}
> +    }
> +  else
> +    {
> +      uiout->text ("\n");
> +      uiout->text (_("Fault address unavailable"));
> +    }
> +}

I guess all of the `uiout->field_*` will appear as the stop event in MI?
I suppose that's fine, but we need to be careful to treat it as API and
not change it in a backwards-incompatible way.  Can you give it a try
with MI to see the result, see if it makes sense (if you haven't
already)?

And if this indeed adds new MI fields, they should be documented, in
theory.  Although I realize that there are equivalent fields in
i386-linux-tdep.c and sparc64-linux-tdep.c which aren't.

But otherwise, that LGTM.

Simon

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

* Re: [PATCH v5 20/25] New memory-tag commands
  2021-01-27 20:21 ` [PATCH v5 20/25] New memory-tag commands Luis Machado
@ 2021-02-05  4:49   ` Simon Marchi
  2021-02-05  4:52     ` Simon Marchi
  2021-02-08 18:59     ` Luis Machado
  0 siblings, 2 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  4:49 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> +/* Parse ARGS and extract ADDR and TAG.
> +   ARGS should have format <expression> <tag bytes>.  */
> +
> +static void
> +parse_with_logical_tag_input (const char *args, struct value **val,
> +			      gdb::byte_vector &tags,
> +			      value_print_options *print_opts)
> +{
> +  /* Fetch the address.  */
> +  std::string address_string = extract_string_maybe_quoted (&args);
> +
> +  /* Parse the address into a value.  */
> +  *val = process_print_command_args (address_string.c_str (), print_opts,
> +				     true);
> +
> +  /* Fetch the tag bytes.  */
> +  std::string tag_string = extract_string_maybe_quoted (&args);
> +
> +  /* Validate the input.  */
> +  if (address_string.empty () || tag_string.empty ())
> +    error (_("Missing arguments."));
> +
> +  if (tag_string.length () != 2)
> +    error (_("Error parsing tags argument. The tag should be 2 digits."));

Can't an hypothetical architecture use more than one byte for a tag?

>  void _initialize_printcmd ();
>  void
>  _initialize_printcmd ()
> @@ -2982,4 +3263,63 @@ 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."));
> +
> +  /* Memory tagging commands.  */
> +  add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
> +Generic command for printing and manipulating memory tag properties."),
> +		  &memory_tag_list, "memory-tag ", 0, &cmdlist);
> +  add_cmd ("print-logical-tag", class_vars,
> +	   memory_tag_print_logical_tag_command,
> +	   ("Print the logical tag for an address.\n\
> +Usage: memory-tag print-logical-tag <address>.\n\
> +<address> is an expression that evaluates to a pointer or memory address.\n\
> +GDB will print the logical tag associated with <address>.  The tag\n\

Instead of saying "GDB will print the...", use the infinite "Print the
...".  I would also swap the two sentences to say what the command says
first, before describing the argument.  Something like:

Print the logical tag associated with a pointer.  POINTER is an
expression that evaluates to a pointer.

Also, use capital letters to refer to arguments, in the help and in the
error messages too.  See this series for reference:

https://sourceware.org/pipermail/gdb-patches/2018-September/152361.html

> +interpretation is architecture-specific."),
> +	   &memory_tag_list);
> +  add_cmd ("print-allocation-tag", class_vars,
> +	   memory_tag_print_allocation_tag_command,
> +	   _("Print the allocation tag for an address.\n\
> +Usage: memory-tag print-allocation-tag <address>.\n\
> +<address> is an expression that evaluates to a pointer or memory address.\n\
> +GDB will print the allocation tag associated with <address>.  The tag\n\
> +interpretation is architecture-specific."),
> +	   &memory_tag_list);
> +  add_cmd ("with-logical-tag", class_vars, memory_tag_with_logical_tag_command,
> +	   _("Set the logical tag for an address.\n\
> +Usage: memory-tag with-logical-tag <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 print the\n\
> +resulting address with the updated tag."),
> +	   &memory_tag_list);
> +  add_cmd ("set-allocation-tag", class_vars,
> +	   memory_tag_set_allocation_tag_command,
> +	   _("Set the allocation tag for an address.\n\
> +Usage: memory-tag set-allocation-tag <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."),
> +	   &memory_tag_list);
> +  add_cmd ("check", class_vars, memory_tag_check_command,
> +	   _("Validate the logical tag against the allocation tag.\n\
> +Usage: memory-tag 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."),
> +	   &memory_tag_list);
>  }

I don't know if this has been discussed before, but something confuses
me about saying "evaluates to a pointer or memory address".  The way I
understand it is that logical tags are encoded into pointers, whereas
allocation tags are associated to memory addresses.  So I think it would
make more sense to use "pointer" for things related to logical tags and
"address" for things related to allocation tags.

With "memory-tag check", you would pass a pointer, and it verifies
whether the pointer's logical tag matches the pointed to memory address'
allocation tag, so that one involves both.

Otherwise, if the distinction is not so important or just confusing,
maybe just use "address" and drop "pointer", to make the text lighter?

Simon

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

* Re: [PATCH v5 21/25] Documentation for the new mtag commands
  2021-01-27 20:21 ` [PATCH v5 21/25] Documentation for the new mtag commands Luis Machado
  2021-01-28  3:31   ` Eli Zaretskii
@ 2021-02-05  4:50   ` Simon Marchi
  1 sibling, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  4:50 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

Maybe just update the subject to match the command name?

Simon

On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v4:
> 
> - Update the command names.
> 
> --
> 
> Document the new "memory-tag" 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 | 97 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 96 insertions(+), 1 deletion(-)
> 
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index a10a74d0c3..f751bdf4d3 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -10848,6 +10848,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{memory-tag} gives access to the various memory tagging
> +commands.
> +
> +The @code{memory-tag} commands are the following:
> +
> +@table @code
> +@kindex memory-tag print-logical-tag
> +@item memory-tag print-logical-tag @var{address_expression}
> +Print the logical tag stored at the address given by @var{address_expression}.
> +@kindex memory-tag with-logical-tag
> +@item memory-tag with-logical-tag @var{address_expression} @var{tag_bytes}
> +Print the address given by @var{address_expression}, augmented with a logical
> +tag of @var{tag_bytes}.
> +@kindex memory-tag print-allocation-tag
> +@item memory-tag print-allocation-tag @var{address_expression}
> +Print the allocation tag associated with the memory address given by
> +@var{address_expression}.
> +@kindex memory-tag setatag
> +@item memory-tag 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 memory-tag check
> +@item memory-tag 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
> @@ -24966,6 +25026,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
>  
> @@ -41023,7 +41118,7 @@ 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
> +@var{type} is the type of tag the request wants to fetch.  The type is a signed
>  integer.
>  
>  @var{tag bytes} is a sequence of hex encoded uninterpreted bytes which will be
> 

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

* Re: [PATCH v5 20/25] New memory-tag commands
  2021-02-05  4:49   ` Simon Marchi
@ 2021-02-05  4:52     ` Simon Marchi
  2021-02-08 18:59     ` Luis Machado
  1 sibling, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  4:52 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

>>  void _initialize_printcmd ();
>>  void
>>  _initialize_printcmd ()
>> @@ -2982,4 +3263,63 @@ 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."));
>> +
>> +  /* Memory tagging commands.  */
>> +  add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
>> +Generic command for printing and manipulating memory tag properties."),
>> +		  &memory_tag_list, "memory-tag ", 0, &cmdlist);
>> +  add_cmd ("print-logical-tag", class_vars,
>> +	   memory_tag_print_logical_tag_command,
>> +	   ("Print the logical tag for an address.\n\
>> +Usage: memory-tag print-logical-tag <address>.\n\
>> +<address> is an expression that evaluates to a pointer or memory address.\n\
>> +GDB will print the logical tag associated with <address>.  The tag\n\
> 
> Instead of saying "GDB will print the...", use the infinite "Print the
> ...".  I would also swap the two sentences to say what the command says
> first, before describing the argument.  Something like:
> 
> Print the logical tag associated with a pointer.  POINTER is an
> expression that evaluates to a pointer.

I just noticed that the very first sentence of the help is pretty much
the same thing as I wrote.  In that case, I think the "GDB will print
the..." sentence is simply redundant, I'd just remove it.

Simon

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

* Re: [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging
  2021-01-27 20:21 ` [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging Luis Machado
@ 2021-02-05  5:02   ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  5:02 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> @@ -1208,6 +1254,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 (target_supports_memory_tagging ()
> +      && gdbarch_tagged_address_p (target_gdbarch (), value))
> +    {
> +      gdb_assert (value && value_type (value));

!= nullptr twice

> @@ -3023,6 +3035,16 @@ will be replaced with either '{...}' or '(...)' depending on the language.\n\
>  Use \"unlimited\" to print the complete structure.")
>    },
>  
> +  boolean_option_def {
> +    "memory-tag-violations",
> +    [] (value_print_options *opt) { return &opt->memory_tag_violations; },
> +    show_memory_tag_violations, /* show_cmd_cb */
> +    N_("Set printing of memory tag violations for pointers."),
> +    N_("Show printing of memory tag violations for pointers."),
> +    N_("When logical tags in pointers do not match the allocation tags in\n\
> +memory, issue a warning."),

Related to what I asked you last time, whether all pointer dereferences
made in order to evaluate the value are checked or just the final
pointer value: the help message could wrongfully imply that all pointer
dereferences are checked and reported, when this isn't the case.  Could
you spin it as: "Issue a warning when the printed value is a pointer
whose logical tag doesn't match the allocation tag of the memory
location it points to"?  The important part being that it specifies that
the printed value is checked.

Otherwise, LGTM.  Thanks for doing the options change.

Simon

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

* Re: [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions
  2021-01-27 20:21 ` [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
  2021-01-28  3:31   ` Eli Zaretskii
@ 2021-02-05  5:04   ` Simon Marchi
  2021-02-08 20:44     ` Luis Machado
  1 sibling, 1 reply; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  5:04 UTC (permalink / raw)
  To: Luis Machado, gdb-patches



On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
> 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 f751bdf4d3..5b21991b10 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -9935,6 +9935,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}.

Is there a section that documents the print options, to document "set
print memory-tag-violations" and "print -memory-tag-violations"?

Simon

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

* Re: [PATCH v5 24/25] Add NEWS entry.
  2021-01-27 20:21 ` [PATCH v5 24/25] Add NEWS entry Luis Machado
  2021-01-28  3:32   ` Eli Zaretskii
@ 2021-02-05  5:06   ` Simon Marchi
  2021-02-08 20:44     ` Luis Machado
  1 sibling, 1 reply; 61+ messages in thread
From: Simon Marchi @ 2021-02-05  5:06 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
> Updates on v4:
> 
> - Update command names.
> 
> --
> 
> 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 | 36 ++++++++++++++++++++++++++++++++++--
>  1 file changed, 34 insertions(+), 2 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index d2ed28857b..a4e08491ee 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,21 @@
>  
>  *** Changes since 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.
> +
> +  - A new modifier 'm' for the "x" command, which displays allocation tags for a
> +    particular memory range.
> +
> +  - Display of memory tag mismatches by "print", for addresses and
> +    pointers, if memory tagging is supported by the architecture.

You might also want to mention the options added by your previous patch,
about memory-tag-violations.

Simon

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

* Re: [PATCH v5 05/25] GDBserver remote packet support for memory tagging
  2021-02-05  2:56   ` Simon Marchi
@ 2021-02-05 12:38     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-02-05 12:38 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/4/21 11:56 PM, Simon Marchi wrote:
>> diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
>> index cfdf1c1883..4e76f08ac5 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)
> 
> For new code, IWBN to follow the convention of putting the doc in the
> header, and putting /* See remote-utils.h.  */ here.
> 
> Otherwise, LGTM.

Thanks. I noticed the documentation is off. I updated it and moved it to 
the header file.

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

* Re: [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks
  2021-02-05  4:09   ` Simon Marchi
@ 2021-02-05 14:05     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-02-05 14:05 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/5/21 1:09 AM, Simon Marchi wrote:
> 
> 
> On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v4:
>>
>> - Update function names to be more scoped.
>> - Use of gdb::optional values.
>> - Fixed up gdbarch hooks.
>>
>> 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_mte_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 (aarch64_mte_make_ltag_bits)
>> 	(aarch64_mte_make_ltag, aarch64_linux_set_ltag)
>> 	(aarch64_linux_get_ltag): New functions.
>> 	* arch/aarch64-mte-linux.h (AARCH64_MTE_LOGICAL_TAG_START_BIT)
>> 	(AARCH64_MTE_LOGICAL_MAX_VALUE): Define.
>> 	(aarch64_mte_make_ltag_bits, aarch64_mte_make_ltag)
>> 	(aarch64_mte_set_ltag, aarch64_mte_get_ltag): New prototypes.
>> ---
>>   gdb/aarch64-linux-tdep.c     | 210 +++++++++++++++++++++++++++++++++++
>>   gdb/arch/aarch64-mte-linux.c |  41 ++++++-
>>   gdb/arch/aarch64-mte-linux.h |  19 ++++
>>   3 files changed, 269 insertions(+), 1 deletion(-)
>>
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index f113d1ea30..2fe88cf016 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.
>>   
>>         +------------+  ^
>> @@ -1513,6 +1517,187 @@ aarch64_linux_gcc_target_options (struct gdbarch *gdbarch)
>>     return {};
>>   }
>>   
>> +/* Helper to get the allocation tag from a 64-bit ADDRESS.
>> +
>> +   Return the allocation tag if successful and nullopt otherwise.  */
>> +
>> +static gdb::optional<CORE_ADDR>
>> +aarch64_mte_get_atag (CORE_ADDR address)
>> +{
>> +  gdb::byte_vector tags;
>> +
>> +  /* Attempt to fetch the allocation tag.  */
>> +  if (!target_fetch_memtags (address, 0, tags, tag_allocation))
>> +    return {};
>> +
>> +  /* Only one tag should've been returned.  Make sure we got exactly that.  */
>> +  gdb_assert (tags.size () == 1);
> 
> The tags are returned by the target, possibly the remote target.  That
> means that you could make GDB assert by returning it a memtag packet
> with the wrong number of bytes.  And we don't want it to be possible to
> make GDB assert when feeding it bad input.
> 
> I'd probably use error() here just for this reason.
> 


Right. That makes sense. I turned this into...

   if (tags.size () != 1)
     error (_("Target returned an unexpected number of tags."));


>> +/* Implement the set_memtags gdbarch method.  */
>> +
>> +static bool
>> +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 true;
> 
> Can this can really happen?
> 

In theory it could, if someone called gdbarch_set_memtags with an empty 
vector of tag bytes. Current code won't run into this.

So this is more of a sanity check. Might as well error out on this, 
instead of silently succeeding.

>> +
>> +  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_mte_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 false;
>> +
>> +      /* 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 = aarch64_mte_get_tag_granules (addr, length,
>> +					       AARCH64_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))
>> +	return false;
>> +    }
>> +  return true;
> 
> I just realized that the gdbarch methods are overloaded, as they are
> used to both set/get the logical tag of the pointer and set/get the
> allocation tags of the allocated memory.  I think it would be easier to
> understand to have four methods, get/set the local tags and get/set the
> allocation tags.

I can do a follow-up splitting the code into separate functions. As more 
tags are introduced (potentially), this will eventually be needed.

> 
> The documentation in gdbarch.sh for get_memtag also only talks about the
> logical tag (extracting the tag from the address).

That is an oversight. Addressed now.

> 
> Since this is internal stuff, I suggest we leave this patch as-is to
> avoid some more churn, but please consider addressing it as a follow-up
> patch to the series, if you agree.
> 
>> +}
>> +
>> +/* 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_mte_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;
>> +
>> +      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (addr);
>> +
>> +      if (!atag.has_value ())
>> +	return nullptr;
>> +
>> +      tag = *atag;
>> +    }
>> +
>> +  /* 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)));
>> +}
> 
> I'll see in the following patches how gdbarch_linux_memtag_to_string is
> used, but at first glance I think it would make sense for this method to
> have the prototype:
> 
>    std::string gdbarch_memtag_to_string (struct gdbarch *gdbarch, value *tag);
> 
> Meaning that you would pass it a tag you already fetched (using
> gdbarch_get_memtag).  This way if you already have a tag as a local
> variable and you want to format it as a string, it doesn't require going
> to the target.  I don't think you would need the tag type parameter in
> this case, as we wouldn't care where the tag comes from, we'd just use
> the passed-in value.
> 
> Also something that can be done as a follow-up patch.
> 

I think it would work. The code has changed a bit since it was first put 
together. The intention was to have a gdbarch hook to return a string 
representation of a tag so generic GDB code wouldn't have to worry about 
touching/manipulating arch-specific data.

Then again, value struct types are somewhat generic already.

>> +
>>   static void
>>   aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>>   {
>> @@ -1570,6 +1755,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 match.  */
>> +      set_gdbarch_memtag_matches_p (gdbarch,
>> +				    aarch64_linux_memtag_matches_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, AARCH64_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 ede5f5f2b9..4461864a32 100644
>> --- a/gdb/arch/aarch64-mte-linux.c
>> +++ b/gdb/arch/aarch64-mte-linux.c
>> @@ -22,7 +22,8 @@
>>   /* See arch/aarch64-mte-linux.h */
>>   
>>   size_t
>> -aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size)
>> +aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len,
>> +				    size_t granule_size)
> 
> Unintended change.
> 

Oops. Fixed.

>>   {
>>     /* Start address */
>>     CORE_ADDR s_addr = align_down (addr, granule_size);
>> @@ -32,3 +33,41 @@ aarch64_mte_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
>> +aarch64_mte_make_ltag_bits (CORE_ADDR value)
>> +{
>> +  return value & AARCH64_MTE_LOGICAL_MAX_VALUE;
>> +}
>> +
>> +/* See arch/aarch64-mte-linux.h */
>> +
>> +CORE_ADDR
>> +aarch64_mte_make_ltag (CORE_ADDR value)
>> +{
>> +  return aarch64_mte_make_ltag_bits (value)
>> +	 << AARCH64_MTE_LOGICAL_TAG_START_BIT;
> 
> We would usually use parenthesis when wrapping this:
> 
>    return (aarch64_mte_make_ltag_bits (value)
> 	  << AARCH64_MTE_LOGICAL_TAG_START_BIT);
> 
> The argument being that Emacs aligns it correctly if you do that (not
> that I care :)).

Fair enough. Fixed now.

> 
> The patch LGTM with the nits fixed
Thanks!

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

* Re: [PATCH v5 17/25] AArch64: Report tag violation error information
  2021-02-05  4:22   ` Simon Marchi
@ 2021-02-05 14:59     ` Luis Machado
  2021-02-05 16:13       ` Simon Marchi
  0 siblings, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-02-05 14:59 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/5/21 1:22 AM, Simon Marchi wrote:
>> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
>> index 1063dd7a82..4ccee9c34e 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -1700,6 +1700,69 @@ 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");
>> +
>> +      fault_addr
>> +	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
>> +    }
>> +  catch (const gdb_exception_error &exception)
>> +    {
>> +      exception_print (gdb_stderr, 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");
> 
> I guess there's no easy way of getting the logical address that was used
> to attempt the memory access?  I think it would be nice to say something
> like "Your pointer had logical tag X, but the pointed memory has
> allocation tag Y".  But if we can't, we can't.
> 

Yeah. I raised this last year with the kernel folks. It was a 
possibility back then, but not the way it was designed at first.

I checked again and it isn't clear if this is exposed in a convenient 
way, as it was enabled via a sigaction argument. GDB may need special 
handling to filter out the top byte from siginfo's si_addr.

I'll check with the latest RC.

>> +
>> +      gdb::optional<CORE_ADDR> atag = aarch64_mte_get_atag (fault_addr);
>> +
>> +      if (!atag.has_value ())
>> +	uiout->text (_("Allocation tag unavailable"));
>> +      else
>> +	{
>> +	  uiout->text (_("Allocation tag "));
>> +	  uiout->field_string ("allocation-tag", hex_string (*atag));
>> +	}
>> +    }
>> +  else
>> +    {
>> +      uiout->text ("\n");
>> +      uiout->text (_("Fault address unavailable"));
>> +    }
>> +}
> 
> I guess all of the `uiout->field_*` will appear as the stop event in MI?
> I suppose that's fine, but we need to be careful to treat it as API and
> not change it in a backwards-incompatible way.  Can you give it a try
> with MI to see the result, see if it makes sense (if you haven't
> already)?

Right. This is being exposed so MI can potentially use the information 
(as is done for i386-linux). Though I wouldn't say it is guaranteed to 
be kept the same.

Honestly, the goal is not to enable an MI MTE API right now. When the 
functionality is pushed and working well, then we can focus on making 
the MI layer MTE-aware.

The new commands, for example, don't have MI counterparts at this point.

Given only a handful of architectures are using tagged memory, I'm not 
even sure if it is worth coming up with an MI API yet.

> 
> And if this indeed adds new MI fields, they should be documented, in
> theory.  Although I realize that there are equivalent fields in
> i386-linux-tdep.c and sparc64-linux-tdep.c which aren't.

I have no problem documenting the current ones.

> 
> But otherwise, that LGTM.

Thanks!

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

* Re: [PATCH v5 17/25] AArch64: Report tag violation error information
  2021-02-05 14:59     ` Luis Machado
@ 2021-02-05 16:13       ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-02-05 16:13 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> Right. This is being exposed so MI can potentially use the information (as is done for i386-linux). Though I wouldn't say it is guaranteed to be kept the same.
> 
> Honestly, the goal is not to enable an MI MTE API right now. When the functionality is pushed and working well, then we can focus on making the MI layer MTE-aware.
> 
> The new commands, for example, don't have MI counterparts at this point.
> 
> Given only a handful of architectures are using tagged memory, I'm not even sure if it is worth coming up with an MI API yet.

I'm not talking about new MI commands, but MI output.  If these fields
are emitted today (with this patch series), someone MI frontend could
read and make use of them, so they should be considered API and not
change (in a backwards-incompatible way) in the future.  So we should at
least make sure that what this outputs does not paint us in a corner.

Simon

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

* Re: [PATCH v5 20/25] New memory-tag commands
  2021-02-05  4:49   ` Simon Marchi
  2021-02-05  4:52     ` Simon Marchi
@ 2021-02-08 18:59     ` Luis Machado
  2021-03-23 21:46       ` Simon Marchi
  1 sibling, 1 reply; 61+ messages in thread
From: Luis Machado @ 2021-02-08 18:59 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/5/21 1:49 AM, Simon Marchi wrote:
>> +/* Parse ARGS and extract ADDR and TAG.
>> +   ARGS should have format <expression> <tag bytes>.  */
>> +
>> +static void
>> +parse_with_logical_tag_input (const char *args, struct value **val,
>> +			      gdb::byte_vector &tags,
>> +			      value_print_options *print_opts)
>> +{
>> +  /* Fetch the address.  */
>> +  std::string address_string = extract_string_maybe_quoted (&args);
>> +
>> +  /* Parse the address into a value.  */
>> +  *val = process_print_command_args (address_string.c_str (), print_opts,
>> +				     true);
>> +
>> +  /* Fetch the tag bytes.  */
>> +  std::string tag_string = extract_string_maybe_quoted (&args);
>> +
>> +  /* Validate the input.  */
>> +  if (address_string.empty () || tag_string.empty ())
>> +    error (_("Missing arguments."));
>> +
>> +  if (tag_string.length () != 2)
>> +    error (_("Error parsing tags argument. The tag should be 2 digits."));
> 
> Can't an hypothetical architecture use more than one byte for a tag?
> 

It could. But it is unlikely, given architectures use spare bits of the 
virtual address.

We could solve this by having another gdbarch constant that tells us the 
size of a tag in a particular architecture. Then we check for size * 2 
characters. Or check for more than a couple characters, and let the 
architecture device if the tag value is sane or not.

What do you think?

>>   void _initialize_printcmd ();
>>   void
>>   _initialize_printcmd ()
>> @@ -2982,4 +3263,63 @@ 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."));
>> +
>> +  /* Memory tagging commands.  */
>> +  add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
>> +Generic command for printing and manipulating memory tag properties."),
>> +		  &memory_tag_list, "memory-tag ", 0, &cmdlist);
>> +  add_cmd ("print-logical-tag", class_vars,
>> +	   memory_tag_print_logical_tag_command,
>> +	   ("Print the logical tag for an address.\n\
>> +Usage: memory-tag print-logical-tag <address>.\n\
>> +<address> is an expression that evaluates to a pointer or memory address.\n\
>> +GDB will print the logical tag associated with <address>.  The tag\n\
> 
> Instead of saying "GDB will print the...", use the infinite "Print the
> ...".  I would also swap the two sentences to say what the command says
> first, before describing the argument.  Something like:

I don't have a preference, but the 'x' command, for example, does the 
opposite. I used it as reference.

--

   c = add_com ("x", class_vars, x_command, _("\
Examine memory: x/FMT ADDRESS.\n\
ADDRESS is an expression for the memory address to examine.\n\
FMT is a repeat count followed by a format letter and a size letter.\n\
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
   t(binary), f(float), a(address), i(instruction), c(char), s(string)\n\
   and z(hex, zero padded on the left).\n\
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
The specified number of objects of the specified size are printed\n\
according to the format.  If a negative number is specified, memory is\n\
examined backward from the address.\n\n\
Defaults for format and size letters are those previously used.\n\
Default count is 1.  Default address is following last thing printed\n\
with this command or \"print\"."));

--

Besides...

> 
> Print the logical tag associated with a pointer.  POINTER is an
> expression that evaluates to a pointer.

...this is almost exactly the first line of the command documentation.

Looking at 'x', it feels to me that the second portion of the 
documentation describes what GDB will acomplish in a more verbose 
manner, since the command's output is already described in the first line.

Is there a standard for these command documentation bits somewhere?

> 
> Also, use capital letters to refer to arguments, in the help and in the
> error messages too.  See this series for reference:

I'll get these fixed.

> 
> https://sourceware.org/pipermail/gdb-patches/2018-September/152361.html
> 
>> +interpretation is architecture-specific."),
>> +	   &memory_tag_list);
>> +  add_cmd ("print-allocation-tag", class_vars,
>> +	   memory_tag_print_allocation_tag_command,
>> +	   _("Print the allocation tag for an address.\n\
>> +Usage: memory-tag print-allocation-tag <address>.\n\
>> +<address> is an expression that evaluates to a pointer or memory address.\n\
>> +GDB will print the allocation tag associated with <address>.  The tag\n\
>> +interpretation is architecture-specific."),
>> +	   &memory_tag_list);
>> +  add_cmd ("with-logical-tag", class_vars, memory_tag_with_logical_tag_command,
>> +	   _("Set the logical tag for an address.\n\
>> +Usage: memory-tag with-logical-tag <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 print the\n\
>> +resulting address with the updated tag."),
>> +	   &memory_tag_list);
>> +  add_cmd ("set-allocation-tag", class_vars,
>> +	   memory_tag_set_allocation_tag_command,
>> +	   _("Set the allocation tag for an address.\n\
>> +Usage: memory-tag set-allocation-tag <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."),
>> +	   &memory_tag_list);
>> +  add_cmd ("check", class_vars, memory_tag_check_command,
>> +	   _("Validate the logical tag against the allocation tag.\n\
>> +Usage: memory-tag 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."),
>> +	   &memory_tag_list);
>>   }
> 
> I don't know if this has been discussed before, but something confuses
> me about saying "evaluates to a pointer or memory address".  The way I

It wasn't, and I appreciate you putting the time to go through these 
patches and making these observations. Thanks a lot.

> understand it is that logical tags are encoded into pointers, whereas
> allocation tags are associated to memory addresses.  So I think it would
> make more sense to use "pointer" for things related to logical tags and
> "address" for things related to allocation tags.

That's the correct understanding. Though in GDB, sometimes things get a 
bit fuzzy, and I may have exposed some of GDB's inner interpretation here.

For example, when you pass in a constant to a command. Is that a pointer 
or an address? Maybe an address that gets converted to a typed pointer?

For simplicity, I think we can go for pointers when talking about memory 
tags and memory when talking about allocation tags.

> 
> With "memory-tag check", you would pass a pointer, and it verifies
> whether the pointer's logical tag matches the pointed to memory address'
> allocation tag, so that one involves both.
> 
> Otherwise, if the distinction is not so important or just confusing,
> maybe just use "address" and drop "pointer", to make the text lighter?

I'll revise the documentation and address this. My goal is to have 
something short and meaningful.

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

* Re: [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions
  2021-02-05  5:04   ` Simon Marchi
@ 2021-02-08 20:44     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-02-08 20:44 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/5/21 2:04 AM, Simon Marchi wrote:
> 
> 
> On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
>> 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 f751bdf4d3..5b21991b10 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -9935,6 +9935,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}.
> 
> Is there a section that documents the print options, to document "set
> print memory-tag-violations" and "print -memory-tag-violations"?

No. I added documentation entries for those now.

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

* Re: [PATCH v5 24/25] Add NEWS entry.
  2021-02-05  5:06   ` Simon Marchi
@ 2021-02-08 20:44     ` Luis Machado
  0 siblings, 0 replies; 61+ messages in thread
From: Luis Machado @ 2021-02-08 20:44 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 2/5/21 2:06 AM, Simon Marchi wrote:
> On 2021-01-27 3:21 p.m., Luis Machado via Gdb-patches wrote:
>> Updates on v4:
>>
>> - Update command names.
>>
>> --
>>
>> 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 | 36 ++++++++++++++++++++++++++++++++++--
>>   1 file changed, 34 insertions(+), 2 deletions(-)
>>
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index d2ed28857b..a4e08491ee 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -3,6 +3,21 @@
>>   
>>   *** Changes since 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.
>> +
>> +  - A new modifier 'm' for the "x" command, which displays allocation tags for a
>> +    particular memory range.
>> +
>> +  - Display of memory tag mismatches by "print", for addresses and
>> +    pointers, if memory tagging is supported by the architecture.
> 
> You might also want to mention the options added by your previous patch,
> about memory-tag-violations.

Done now. Thanks!

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

* Re: [PATCH v5 20/25] New memory-tag commands
  2021-02-08 18:59     ` Luis Machado
@ 2021-03-23 21:46       ` Simon Marchi
  0 siblings, 0 replies; 61+ messages in thread
From: Simon Marchi @ 2021-03-23 21:46 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

On 2021-02-08 1:59 p.m., Luis Machado wrote:> On 2/5/21 1:49 AM, Simon Marchi wrote:
>>> +/* Parse ARGS and extract ADDR and TAG.
>>> +   ARGS should have format <expression> <tag bytes>.  */
>>> +
>>> +static void
>>> +parse_with_logical_tag_input (const char *args, struct value **val,
>>> +                  gdb::byte_vector &tags,
>>> +                  value_print_options *print_opts)
>>> +{
>>> +  /* Fetch the address.  */
>>> +  std::string address_string = extract_string_maybe_quoted (&args);
>>> +
>>> +  /* Parse the address into a value.  */
>>> +  *val = process_print_command_args (address_string.c_str (), print_opts,
>>> +                     true);
>>> +
>>> +  /* Fetch the tag bytes.  */
>>> +  std::string tag_string = extract_string_maybe_quoted (&args);
>>> +
>>> +  /* Validate the input.  */
>>> +  if (address_string.empty () || tag_string.empty ())
>>> +    error (_("Missing arguments."));
>>> +
>>> +  if (tag_string.length () != 2)
>>> +    error (_("Error parsing tags argument. The tag should be 2 digits."));
>>
>> Can't an hypothetical architecture use more than one byte for a tag?
>>
> 
> It could. But it is unlikely, given architectures use spare bits of the virtual address.
> 
> We could solve this by having another gdbarch constant that tells us the size of a tag in a particular architecture. Then we check for size * 2 characters. Or check for more than a couple characters, and let the architecture device if the tag value is sane or not.
> 
> What do you think?
> 
>>>   void _initialize_printcmd ();
>>>   void
>>>   _initialize_printcmd ()
>>> @@ -2982,4 +3263,63 @@ 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."));
>>> +
>>> +  /* Memory tagging commands.  */
>>> +  add_prefix_cmd ("memory-tag", class_vars, memory_tag_command, _("\
>>> +Generic command for printing and manipulating memory tag properties."),
>>> +          &memory_tag_list, "memory-tag ", 0, &cmdlist);
>>> +  add_cmd ("print-logical-tag", class_vars,
>>> +       memory_tag_print_logical_tag_command,
>>> +       ("Print the logical tag for an address.\n\
>>> +Usage: memory-tag print-logical-tag <address>.\n\
>>> +<address> is an expression that evaluates to a pointer or memory address.\n\
>>> +GDB will print the logical tag associated with <address>.  The tag\n\
>>
>> Instead of saying "GDB will print the...", use the infinite "Print the
>> ...".  I would also swap the two sentences to say what the command says
>> first, before describing the argument.  Something like:
> 
> I don't have a preference, but the 'x' command, for example, does the opposite. I used it as reference.
> 
> -- 
> 
>   c = add_com ("x", class_vars, x_command, _("\
> Examine memory: x/FMT ADDRESS.\n\
> ADDRESS is an expression for the memory address to examine.\n\
> FMT is a repeat count followed by a format letter and a size letter.\n\
> Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
>   t(binary), f(float), a(address), i(instruction), c(char), s(string)\n\
>   and z(hex, zero padded on the left).\n\
> Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
> The specified number of objects of the specified size are printed\n\
> according to the format.  If a negative number is specified, memory is\n\
> examined backward from the address.\n\n\
> Defaults for format and size letters are those previously used.\n\
> Default count is 1.  Default address is following last thing printed\n\
> with this command or \"print\"."));
> 
> -- 
> 
> Besides...
> 
>>
>> Print the logical tag associated with a pointer.  POINTER is an
>> expression that evaluates to a pointer.
> 
> ...this is almost exactly the first line of the command documentation.
> 
> Looking at 'x', it feels to me that the second portion of the documentation describes what GDB will acomplish in a more verbose manner, since the command's output is already described in the first line.

Indeed, I realized later that the very first line was already the
one-sentence description of what the command does (see my own reply to
this message).

> Is there a standard for these command documentation bits somewhere?

Not sure it's spelled out anywhere.  But IMO the first sentence should
always be a very high level explanation of what the command does, so you
can get a quick idea if this is what you're looking for without having
to read a whole paragraph.  Then I like when things (like description of
each argument) are nicely separated in paragraphs instead of one big
paragraph, so it's easy to scan and jump to what you are looking for.

>> understand it is that logical tags are encoded into pointers, whereas
>> allocation tags are associated to memory addresses.  So I think it would
>> make more sense to use "pointer" for things related to logical tags and
>> "address" for things related to allocation tags.
> 
> That's the correct understanding. Though in GDB, sometimes things get a bit fuzzy, and I may have exposed some of GDB's inner interpretation here.
> 
> For example, when you pass in a constant to a command. Is that a pointer or an address? Maybe an address that gets converted to a typed pointer?
> 
> For simplicity, I think we can go for pointers when talking about memory tags and memory when talking about allocation tags.

I suppose you meant "... and address when talking about allocation
tags".

What you have in v6 LGTM.

Simon

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

end of thread, other threads:[~2021-03-23 21:46 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-27 20:20 [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado
2021-01-27 20:20 ` [PATCH v5 01/25] New target methods for memory tagging support Luis Machado
2021-01-27 23:26   ` Lancelot SIX
2021-01-28 10:02     ` Luis Machado
2021-02-05  2:31   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 02/25] New gdbarch memory tagging hooks Luis Machado
2021-02-05  2:38   ` Simon Marchi
2021-02-05  3:58   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 03/25] Add GDB-side remote target support for memory tagging Luis Machado
2021-02-05  2:48   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 04/25] Unit testing for GDB-side remote memory tagging handling Luis Machado
2021-02-05  2:50   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 05/25] GDBserver remote packet support for memory tagging Luis Machado
2021-02-05  2:56   ` Simon Marchi
2021-02-05 12:38     ` Luis Machado
2021-01-27 20:20 ` [PATCH v5 06/25] Unit tests for gdbserver memory tagging remote packets Luis Machado
2021-01-27 20:20 ` [PATCH v5 07/25] Documentation for " Luis Machado
2021-01-28  3:30   ` Eli Zaretskii
2021-01-28  9:58     ` Luis Machado
2021-01-27 20:20 ` [PATCH v5 08/25] AArch64: Add MTE CPU feature check support Luis Machado
2021-02-05  3:05   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 09/25] AArch64: Add target description/feature for MTE registers Luis Machado
2021-01-27 20:20 ` [PATCH v5 10/25] AArch64: Add MTE register set support for GDB and gdbserver Luis Machado
2021-01-27 20:20 ` [PATCH v5 11/25] AArch64: Add MTE ptrace requests Luis Machado
2021-02-05  3:13   ` Simon Marchi
2021-01-27 20:20 ` [PATCH v5 12/25] AArch64: Implement memory tagging target methods for AArch64 Luis Machado
2021-02-05  3:30   ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 13/25] Convert char array to std::string in linux_find_memory_regions_full Luis Machado
2021-02-05  3:32   ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 14/25] Refactor parsing of /proc/<pid>/smaps Luis Machado
2021-02-05  3:38   ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 15/25] AArch64: Implement the memory tagging gdbarch hooks Luis Machado
2021-02-05  4:09   ` Simon Marchi
2021-02-05 14:05     ` Luis Machado
2021-01-27 20:21 ` [PATCH v5 16/25] AArch64: Add unit testing for logical tag set/get operations Luis Machado
2021-01-27 20:21 ` [PATCH v5 17/25] AArch64: Report tag violation error information Luis Machado
2021-02-05  4:22   ` Simon Marchi
2021-02-05 14:59     ` Luis Machado
2021-02-05 16:13       ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 18/25] AArch64: Add gdbserver MTE support Luis Machado
2021-01-27 20:21 ` [PATCH v5 19/25] AArch64: Add MTE register set support for core files Luis Machado
2021-01-27 20:21 ` [PATCH v5 20/25] New memory-tag commands Luis Machado
2021-02-05  4:49   ` Simon Marchi
2021-02-05  4:52     ` Simon Marchi
2021-02-08 18:59     ` Luis Machado
2021-03-23 21:46       ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 21/25] Documentation for the new mtag commands Luis Machado
2021-01-28  3:31   ` Eli Zaretskii
2021-02-05  4:50   ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 22/25] Extend "x" and "print" commands to support memory tagging Luis Machado
2021-02-05  5:02   ` Simon Marchi
2021-01-27 20:21 ` [PATCH v5 23/25] Document new "x" and "print" memory tagging extensions Luis Machado
2021-01-28  3:31   ` Eli Zaretskii
2021-02-05  5:04   ` Simon Marchi
2021-02-08 20:44     ` Luis Machado
2021-01-27 20:21 ` [PATCH v5 24/25] Add NEWS entry Luis Machado
2021-01-28  3:32   ` Eli Zaretskii
2021-02-05  5:06   ` Simon Marchi
2021-02-08 20:44     ` Luis Machado
2021-01-27 20:21 ` [PATCH v5 25/25] Add memory tagging testcases Luis Machado
2021-02-04 14:18 ` [PING] [PATCH v5 00/25] Memory Tagging Support + AArch64 Linux implementation Luis Machado

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).