+2021-03-24  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.
+
 2021-03-22  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>
 
        * inferiors.h (struct process_info) <all_dlls, dlls_changed>: New
 
     }
 }
 
-void
-decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr)
+/* See remote-utils.h.  */
+
+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;
 
       *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
 
 
 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,
+
+/* Given an input string FROM, decode MEM_ADDR_PTR, a memory address in hex
+   form,  and LEN_PTR, a length argument in hex form, from the pattern
+   "<MEM_ADDR_PTR>,<LEN_PTR><END_MARKER>", with END_MARKER 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);
+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);
 
   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
       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;
   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
                     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.  */
 
       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 ();
   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;
       cs.swbreak_feature = 0;
       cs.hwbreak_feature = 0;
       cs.vCont_supported = 0;
+      cs.memory_tagging_feature = false;
 
       remote_open (port);
 
 
 
   int current_traceframe = -1;
 
+  /* If true, memory tagging features are supported.  */
+  bool memory_tagging_feature = false;
+
 };
 
 client_state &get_client_state ();
 
   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)
 {
 
 #include "gdbsupport/array-view.h"
 #include "gdbsupport/btrace-common.h"
 #include <vector>
+#include "gdbsupport/byte-vector.h"
 
 struct emit_ops;
 struct buffer;
 
   /* 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;
 #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 ()