public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] [AArch64] Add TPIDR2 register support for Linux
@ 2022-09-23 13:46 Luis Machado
  2022-09-23 16:42 ` John Baldwin
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Luis Machado @ 2022-09-23 13:46 UTC (permalink / raw)
  To: gdb-patches

With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
it will be added to the existing NT_ARM_TLS register set. Kernel patches are
being reviewed here:

https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/

From GDB's perspective, we handle it in a similar way to the existing TPIDR
register. But we need to consider cases of systems that only have TPIDR and
systems that have both TPIDR and TPIDR2.

With that in mind, the following patch adds the required code to support
TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
dynamically-generated target description as opposed to a static target
description containing only TPIDR.

That means we can remove the gdb/features/aarch64-tls.xml file and replace the
existing gdb/features/aarch64-tls.c auto-generated file with a new file that
dynamically generates the target description containing either TPIDR alone or
TPIDR and TPIDR2.

In the future, when *BSD's start to support this register, they can just
enable it as is being done for the AArch64 Linux target.

The core file read/write code has been updated to support TPIDR2 as well.

On GDBserver's side, there is a small change to the find_regno function to
expose a non-throwing version of it.

It always seemed strange to me how find_regno causes the whole operation to
abort if it doesn't find a particular register name. The patch moves code
from find_regno into find_regno_no_throw and makes find_regno call
find_regno_no_throw instead.

This allows us to do register name lookups to find a particular register
number without risking erroring out if nothing is found.

The patch also adjusts the feature detection code for aarch64-fbsd, since
the infrastructure is shared amongst all aarch64 targets. I haven't added
code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
that will happen.
---
 gdb/aarch64-fbsd-nat.c         |  2 +-
 gdb/aarch64-fbsd-tdep.c        |  2 +-
 gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
 gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
 gdb/aarch64-linux-tdep.h       |  3 ---
 gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
 gdb/aarch64-tdep.h             |  3 ++-
 gdb/arch/aarch64.c             |  5 ++--
 gdb/arch/aarch64.h             | 14 +++++++----
 gdb/features/Makefile          |  1 -
 gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
 gdb/features/aarch64-tls.xml   | 11 ---------
 gdb/nat/aarch64-linux.c        | 17 +++++++++++++
 gdb/nat/aarch64-linux.h        |  4 +++
 gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
 gdbserver/regcache.cc          | 17 +++++++++++--
 gdbserver/regcache.h           |  5 ++++
 17 files changed, 183 insertions(+), 68 deletions(-)
 delete mode 100644 gdb/features/aarch64-tls.xml

diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
index 708ddc40d58..40941f138d9 100644
--- a/gdb/aarch64-fbsd-nat.c
+++ b/gdb/aarch64-fbsd-nat.c
@@ -149,7 +149,7 @@ const struct target_desc *
 aarch64_fbsd_nat_target::read_description ()
 {
   aarch64_features features;
-  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
+  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
   return aarch64_read_description (features);
 }
 
diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
index 4a6b4115234..c9971434777 100644
--- a/gdb/aarch64-fbsd-tdep.c
+++ b/gdb/aarch64-fbsd-tdep.c
@@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
   asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
 
   aarch64_features features;
-  features.tls = tls != nullptr;
+  features.tls = tls != nullptr? 1 : 0;
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index eda79ec6d35..03eec37a6c4 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
   int regno = tdep->tls_regnum;
 
-  gdb_assert (regno != -1);
+  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
-      perror_with_name (_("unable to fetch TLS register"));
+      perror_with_name (_("unable to fetch TLS registers"));
 
-  regcache->raw_supply (regno, &tpidr);
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    regcache->raw_supply (regno + i, &tpidrs[i]);
 }
 
 /* Store to the current thread the valid TLS register set in GDB's
@@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
   int regno = tdep->tls_regnum;
 
-  gdb_assert (regno != -1);
+  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
 
-  if (REG_VALID != regcache->get_register_status (regno))
-    return;
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    {
+      if (REG_VALID != regcache->get_register_status (regno + i))
+	continue;
 
-  regcache->raw_collect (regno, (char *) &tpidr);
+      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
+    }
 
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = &tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
@@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
       && (regno == tdep->mte_reg_base))
     store_mteregs_to_thread (regcache);
 
-  if (tdep->has_tls () && regno == tdep->tls_regnum)
+  if (tdep->has_tls ()
+      && regno >= tdep->tls_regnum
+      && regno < tdep->tls_regnum + tdep->tls_register_count)
     store_tlsregs_to_thread (regcache);
 }
 
@@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
   features.vq = aarch64_sve_get_vq (tid);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = true;
+  features.tls = aarch64_tls_register_count (tid);
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 15773c75da8..d6ca3ae7228 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  "MTE registers", cb_data);
     }
 
+  /* Handle the TLS registers.  */
   if (tdep->has_tls ())
     {
+      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
+      int sizeof_tls_regset
+	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
+
       const struct regcache_map_entry tls_regmap[] =
 	{
-	  { 1, tdep->tls_regnum, 8 },
+	  { tdep->tls_register_count, tdep->tls_regnum,
+	    AARCH64_TLS_REGISTER_SIZE },
 	  { 0 }
 	};
 
@@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  tls_regmap, regcache_supply_regset, regcache_collect_regset
 	};
 
-      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
-	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
-	  "TLS register", cb_data);
+      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
+	  &aarch64_linux_tls_regset, "TLS register", cb_data);
     }
 }
 
@@ -778,7 +783,6 @@ static const struct target_desc *
 aarch64_linux_core_read_description (struct gdbarch *gdbarch,
 				     struct target_ops *target, bfd *abfd)
 {
-  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
   CORE_ADDR hwcap = linux_get_hwcap (target);
   CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
 
@@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
   features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = tls != nullptr;
+
+  /* Handle the TLS section.  */
+  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
+  if (tls != nullptr)
+    {
+      size_t size = bfd_section_size (tls);
+      /* Convert the size to the number of actual registers, by
+	 dividing by 8.  */
+      features.tls = size >> 3;
+    }
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
index 9a7e4339dba..8ae33efc605 100644
--- a/gdb/aarch64-linux-tdep.h
+++ b/gdb/aarch64-linux-tdep.h
@@ -39,9 +39,6 @@
 /* The MTE regset consists of a 64-bit register.  */
 #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
 
-/* The TLS regset consists of a single register.  */
-#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
-
 extern const struct regset aarch64_linux_gregset;
 extern const struct regset aarch64_linux_fpregset;
 
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index d0387044934..5d82f1993a4 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
   features.mte
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
-  features.tls
-      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
+
+  const struct tdesc_feature *tls_feature
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
+
+  if (tls_feature != nullptr)
+    {
+      /* We have TLS registers.  Find out how many.  */
+      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
+	features.tls = 2;
+      else
+	features.tls = 1;
+    }
 
   return features;
 }
@@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
-  int first_mte_regnum = -1, tls_regnum = -1;
+  int first_mte_regnum = -1, first_tls_regnum = -1;
+  int tls_register_count = 0;
   uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
 
   if (vq > AARCH64_MAX_SVE_VQ)
@@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Add the TLS register.  */
   if (feature_tls != nullptr)
     {
-      tls_regnum = num_regs;
-      /* Validate the descriptor provides the mandatory TLS register
-	 and allocate its number.  */
-      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
-					 tls_regnum, "tpidr");
+      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
+      first_tls_regnum = num_regs;
+
+      /* Look for the TLS registers.  */
+      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
+	{
+	  valid_p
+	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
+				       first_tls_regnum + tls_register_count,
+				       tls_register_names[i]);
+	  if (valid_p)
+	    tls_register_count++;
+	}
+      valid_p = true;
+
+      if (tls_register_count == 0)
+	warning (_("Provided TLS register feature doesn't contain "
+		   "any registers."));
 
-      num_regs++;
+      num_regs += tls_register_count;
     }
 
   /* Add the pauth registers.  */
@@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
 				: ra_sign_state_offset + num_regs;
   tdep->mte_reg_base = first_mte_regnum;
-  tdep->tls_regnum = tls_regnum;
+  tdep->tls_regnum = first_tls_regnum;
+  tdep->tls_register_count = tls_register_count;
 
   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 d8513023c37..8166df0ada8 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
     return mte_reg_base != -1;
   }
 
-  /* TLS register.  This is -1 if the TLS register is not available.  */
+  /* TLS registers.  This is -1 if the TLS registers are not available.  */
   int tls_regnum = 0;
+  int tls_register_count = 0;
 
   bool has_tls() const
   {
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index 0f73286f145..565c5e7a81c 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
   if (features.mte)
     regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
 
-  if (features.tls)
-    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
+  /* TLS registers.  */
+  if (features.tls > 0)
+    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
 
   return tdesc.release ();
 }
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index 8e3fd36726a..b1a6ce3ef0e 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -33,7 +33,9 @@ struct aarch64_features
 
   bool pauth = false;
   bool mte = false;
-  bool tls = false;
+
+  /* A positive TLS value indicates the number of TLS registers available.  */
+  uint8_t tls = 0;
 };
 
 inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
@@ -56,7 +58,9 @@ namespace std
       h = features.vq;
       h = h << 1 | features.pauth;
       h = h << 1 | features.mte;
-      h = h << 1 | features.tls;
+      /* Shift by two bits for now.  We may need to increase this in the future
+	 if more TLS registers get added.  */
+      h = h << 2 | features.tls;
       return h;
     }
   };
@@ -96,7 +100,9 @@ enum aarch64_regnum
   AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
 };
 
-#define V_REGISTER_SIZE 16
+/* Sizes of various AArch64 registers.  */
+#define AARCH64_TLS_REGISTER_SIZE 8
+#define V_REGISTER_SIZE	  16
 
 /* Pseudo register base numbers.  */
 #define AARCH64_Q0_REGNUM 0
@@ -117,8 +123,6 @@ enum aarch64_regnum
 #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
 #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
 
-#define	AARCH64_TLS_REGS_SIZE (8)
-
 /* There are a number of ways of expressing the current SVE vector size:
 
    VL : Vector Length.
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 4bc85962dfe..037f900b58b 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-fpu.xml \
 	aarch64-pauth.xml \
 	aarch64-mte.xml \
-	aarch64-tls.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
 	arc/v2-core.xml \
diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
index 30d730dffba..8a59d26b353 100644
--- a/gdb/features/aarch64-tls.c
+++ b/gdb/features/aarch64-tls.c
@@ -1,14 +1,43 @@
-/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
-  Original: aarch64-tls.xml */
+/* Copyright (C) 2022 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/tdesc.h"
 
+/* This function is NOT auto generated from xml.
+
+   Create the aarch64 description containing the TLS registers.  TPIDR is
+   always available, but TPIDR2 is only available on some systems.
+
+   COUNT is the number of registers in this set.  The minimum is 1.  */
+
 static int
-create_feature_aarch64_tls (struct target_desc *result, long regnum)
+create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
 {
+  /* TPIDR is always present.  */
+  gdb_assert (count >= 1);
+
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
   tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
+
+  /* Add TPIDR2.  */
+  if (count > 1)
+    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
+
   return regnum;
 }
diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
deleted file mode 100644
index f6437785f71..00000000000
--- a/gdb/features/aarch64-tls.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<!-- Copyright (C) 2022 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.tls">
-  <reg name="tpidr" bitsize="64" type="data_ptr"/>
-</feature>
diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
index 421d1ecb53c..017c30948a9 100644
--- a/gdb/nat/aarch64-linux.c
+++ b/gdb/nat/aarch64-linux.c
@@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 
   return PS_OK;
 }
+
+/* See nat/aarch64-linux.h */
+
+int
+aarch64_tls_register_count (int tid)
+{
+  uint64_t tls_regs[2];
+  struct iovec iovec;
+  iovec.iov_base = tls_regs;
+  iovec.iov_len = sizeof (tls_regs);
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
+    return 1;
+
+  /* TPIDR2 is available.  */
+  return 2;
+}
diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
index 1777ce32522..517cbb33963 100644
--- a/gdb/nat/aarch64-linux.h
+++ b/gdb/nat/aarch64-linux.h
@@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 				       lwpid_t lwpid, int idx, void **base,
 				       int is_64bit_p);
 
+/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
+   used for aarch64 state.  */
+int aarch64_tls_register_count (int tid);
+
 #endif /* NAT_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index db508696261..b657a265ee7 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
 static void
 aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  collect_register (regcache, tls_regnum, buf);
+  collect_register (regcache, tls_regnum, tls_buf);
+
+  /* Read TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 /* Store TLS register to regcache.  */
@@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 static void
 aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  supply_register (regcache, tls_regnum, buf);
+  supply_register (regcache, tls_regnum, tls_buf);
+
+  /* Write TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 bool
@@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
 	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
 	  break;
 	case NT_ARM_TLS:
-	  if (features.tls)
-	    regset->size = AARCH64_TLS_REGS_SIZE;
+	  if (features.tls > 0)
+	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
 	  break;
 	default:
 	  gdb_assert_not_reached ("Unknown register set found.");
@@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
       features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
       /* A-profile MTE is 64-bit only.  */
       features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
-      features.tls = true;
+      features.tls = aarch64_tls_register_count (tid);
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
 
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index 27491efc52d..0b0d0855db3 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
   hex2bin (buf, registers, len / 2);
 }
 
-int
-find_regno (const struct target_desc *tdesc, const char *name)
+/* See regcache.h */
+
+gdb::optional<int>
+find_regno_no_throw (const struct target_desc *tdesc, const char *name)
 {
   for (int i = 0; i < tdesc->reg_defs.size (); ++i)
     {
       if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
 	return i;
     }
+  return {};
+}
+
+int
+find_regno (const struct target_desc *tdesc, const char *name)
+{
+  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
+
+  if (regnum.has_value ())
+    return *regnum;
+
   internal_error (__FILE__, __LINE__, "Unknown register %s requested",
 		  name);
 }
diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
index 731c18d16e2..b67eefbe04b 100644
--- a/gdbserver/regcache.h
+++ b/gdbserver/regcache.h
@@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
 
 int register_size (const struct target_desc *tdesc, int n);
 
+/* No throw version of find_regno.  If NAME is not a known register, return
+   an empty value.  */
+gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
+					const char *name);
+
 int find_regno (const struct target_desc *tdesc, const char *name);
 
 void supply_register (struct regcache *regcache, int n, const void *buf);
-- 
2.25.1


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

* Re: [PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
@ 2022-09-23 16:42 ` John Baldwin
  2022-10-04  8:53 ` [PING][PATCH] " Luis Machado
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: John Baldwin @ 2022-09-23 16:42 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

On 9/23/22 6:46 AM, Luis Machado wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>  From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.

The fbsd bits look fine to me.

-- 
John Baldwin

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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
  2022-09-23 16:42 ` John Baldwin
@ 2022-10-04  8:53 ` Luis Machado
  2022-10-10 12:19 ` Luis Machado
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-10-04  8:53 UTC (permalink / raw)
  To: gdb-patches

Looking for a global maintainer review of the generic code bits.
On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
  2022-09-23 16:42 ` John Baldwin
  2022-10-04  8:53 ` [PING][PATCH] " Luis Machado
@ 2022-10-10 12:19 ` Luis Machado
  2022-10-17 10:03 ` Luis Machado
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-10-10 12:19 UTC (permalink / raw)
  To: gdb-patches

On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (2 preceding siblings ...)
  2022-10-10 12:19 ` Luis Machado
@ 2022-10-17 10:03 ` Luis Machado
  2022-10-25 13:52 ` Luis Machado
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-10-17 10:03 UTC (permalink / raw)
  To: gdb-patches

On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (3 preceding siblings ...)
  2022-10-17 10:03 ` Luis Machado
@ 2022-10-25 13:52 ` Luis Machado
  2022-11-10  1:01 ` Luis Machado
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-10-25 13:52 UTC (permalink / raw)
  To: gdb-patches

On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (4 preceding siblings ...)
  2022-10-25 13:52 ` Luis Machado
@ 2022-11-10  1:01 ` Luis Machado
  2022-11-29 22:19 ` Luis Machado
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-11-10  1:01 UTC (permalink / raw)
  To: gdb-patches

On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* [PING][PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (5 preceding siblings ...)
  2022-11-10  1:01 ` Luis Machado
@ 2022-11-29 22:19 ` Luis Machado
  2022-12-05 20:36 ` [PATCH] " Simon Marchi
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-11-29 22:19 UTC (permalink / raw)
  To: gdb-patches

On 9/23/22 14:46, Luis Machado via Gdb-patches wrote:
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  2 +-
>   gdb/aarch64-fbsd-tdep.c        |  2 +-
>   gdb/aarch64-linux-nat.c        | 38 +++++++++++++++-------------
>   gdb/aarch64-linux-tdep.c       | 25 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 ---
>   gdb/aarch64-tdep.c             | 45 ++++++++++++++++++++++++++--------
>   gdb/aarch64-tdep.h             |  3 ++-
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++++++---
>   gdb/features/aarch64-tls.xml   | 11 ---------
>   gdb/nat/aarch64-linux.c        | 17 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 ++++++++++++++----
>   gdbserver/regcache.cc          | 17 +++++++++++--
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 183 insertions(+), 68 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index 708ddc40d58..40941f138d9 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -149,7 +149,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 4a6b4115234..c9971434777 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -179,7 +179,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -467,19 +467,21 @@ store_tlsregs_to_thread (struct regcache *regcache)
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>     int regno = tdep->tls_regnum;
>   
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -607,7 +609,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum
> +      && regno < tdep->tls_regnum + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +792,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 15773c75da8..d6ca3ae7228 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -753,11 +753,17 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum != -1 && tdep->tls_register_count > 0);
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
> @@ -766,9 +772,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  tls_regmap, regcache_supply_regset, regcache_collect_regset
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -778,7 +783,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     CORE_ADDR hwcap = linux_get_hwcap (target);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (target);
>   
> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index d0387044934..5d82f1993a4 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3399,8 +3399,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3454,7 +3464,8 @@ 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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
> +  int tls_register_count = 0;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     /* Add the TLS register.  */
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;
> +
> +      if (tls_register_count == 0)
> +	warning (_("Provided TLS register feature doesn't contain "
> +		   "any registers."));
>   
> -      num_regs++;
> +      num_regs += tls_register_count;
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3601,7 +3625,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->ra_sign_state_regnum = (feature_pauth == NULL) ? -1
>   				: ra_sign_state_offset + num_regs;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>     int tls_regnum = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 4bc85962dfe..037f900b58b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -198,7 +198,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 27491efc52d..0b0d0855db3 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,14 +244,27 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
>     internal_error (__FILE__, __LINE__, "Unknown register %s requested",
>   		  name);
>   }
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);


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

* Re: [PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (6 preceding siblings ...)
  2022-11-29 22:19 ` Luis Machado
@ 2022-12-05 20:36 ` Simon Marchi
  2022-12-06  9:50   ` Luis Machado
  2022-12-06 13:16 ` [PATCH v3] [aarch64] " Luis Machado
  2022-12-07 10:30 ` [PATCH v4] " Luis Machado
  9 siblings, 1 reply; 14+ messages in thread
From: Simon Marchi @ 2022-12-05 20:36 UTC (permalink / raw)
  To: Luis Machado, gdb-patches

> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index eda79ec6d35..03eec37a6c4 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>      = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>    int regno = tdep->tls_regnum;
>  
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
Check just one thing per gdb_assert.

> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>    features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>    features.pauth = hwcap & AARCH64_HWCAP_PACA;
>    features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size >> 3;

Why not write it as `size / 8`?  Or, `size / AARCH64_TLS_REGISTER_SIZE`?

> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>    /* Add the TLS register.  */
>    if (feature_tls != nullptr)
>      {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
> +
> +      /* Look for the TLS registers.  */
> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
> +	{
> +	  valid_p
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[i]);
> +	  if (valid_p)
> +	    tls_register_count++;
> +	}
> +      valid_p = true;

It would seem better to just use a different variable inside the loop,
if you don't want it to affect valid_p.  If valid_p is false before
entering the loop, you still set it to true afterwards, is that what you
want?

It seems to me like you would want the lookup of tpidr to affect
valid_p, as it would be invalid to have the tls feature without tpidr,
but the lookup of tpidr2 to not affect valid_p.

> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
> index d8513023c37..8166df0ada8 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>      return mte_reg_base != -1;
>    }
>  
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>    int tls_regnum = 0;
> +  int tls_register_count = 0;

Perhaps rename tls_regnum to tls_regnum_base, since it not longer
represents just one register.

> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..017c30948a9 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>  
>    return PS_OK;
>  }
> +
> +/* See nat/aarch64-linux.h */

Dot and double space.

> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available.  */
> +  return 2;

Can you explain what is happening here?  How does checking for success
reading NT_ARM_TLS telly ou that TPIDR2 exists?

Simon


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

* Re: [PATCH] [AArch64] Add TPIDR2 register support for Linux
  2022-12-05 20:36 ` [PATCH] " Simon Marchi
@ 2022-12-06  9:50   ` Luis Machado
  0 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-12-06  9:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

Hi Simon,

Thanks for the review.

On 12/5/22 20:36, Simon Marchi wrote:
>> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
>> index eda79ec6d35..03eec37a6c4 100644
>> --- a/gdb/aarch64-linux-nat.c
>> +++ b/gdb/aarch64-linux-nat.c
>> @@ -442,19 +442,19 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
>>     int regno = tdep->tls_regnum;
>>   
>> -  gdb_assert (regno != -1);
>> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
> Check just one thing per gdb_assert.

Fixed.

> 
>> @@ -786,7 +790,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>>     features.mte = hwcap2 & HWCAP2_MTE;
>> -  features.tls = tls != nullptr;
>> +
>> +  /* Handle the TLS section.  */
>> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>> +  if (tls != nullptr)
>> +    {
>> +      size_t size = bfd_section_size (tls);
>> +      /* Convert the size to the number of actual registers, by
>> +	 dividing by 8.  */
>> +      features.tls = size >> 3;
> 
> Why not write it as `size / 8`?  Or, `size / AARCH64_TLS_REGISTER_SIZE`?
> 

Fixed.

>> @@ -3544,13 +3555,26 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>>     /* Add the TLS register.  */
>>     if (feature_tls != nullptr)
>>       {
>> -      tls_regnum = num_regs;
>> -      /* Validate the descriptor provides the mandatory TLS register
>> -	 and allocate its number.  */
>> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
>> -					 tls_regnum, "tpidr");
>> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
>> +      first_tls_regnum = num_regs;
>> +
>> +      /* Look for the TLS registers.  */
>> +      for (i = 0; i < ARRAY_SIZE (tls_register_names); i++)
>> +	{
>> +	  valid_p
>> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
>> +				       first_tls_regnum + tls_register_count,
>> +				       tls_register_names[i]);
>> +	  if (valid_p)
>> +	    tls_register_count++;
>> +	}
>> +      valid_p = true;
> 
> It would seem better to just use a different variable inside the loop,
> if you don't want it to affect valid_p.  If valid_p is false before
> entering the loop, you still set it to true afterwards, is that what you
> want?
> 
> It seems to me like you would want the lookup of tpidr to affect
> valid_p, as it would be invalid to have the tls feature without tpidr,
> but the lookup of tpidr2 to not affect valid_p.
> 

Yes, indeed. I've switched this to using a different bool for the tpidr2 check.

>> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
>> index d8513023c37..8166df0ada8 100644
>> --- a/gdb/aarch64-tdep.h
>> +++ b/gdb/aarch64-tdep.h
>> @@ -111,8 +111,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>>       return mte_reg_base != -1;
>>     }
>>   
>> -  /* TLS register.  This is -1 if the TLS register is not available.  */
>> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
>>     int tls_regnum = 0;
>> +  int tls_register_count = 0;
> 
> Perhaps rename tls_regnum to tls_regnum_base, since it not longer
> represents just one register.
> 

Yeah. I deferred renaming this to avoid having more churn in the patch.

Done now.

>> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
>> index 421d1ecb53c..017c30948a9 100644
>> --- a/gdb/nat/aarch64-linux.c
>> +++ b/gdb/nat/aarch64-linux.c
>> @@ -250,3 +250,20 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>>   
>>     return PS_OK;
>>   }
>> +
>> +/* See nat/aarch64-linux.h */
> 
> Dot and double space.
> 
>> +
>> +int
>> +aarch64_tls_register_count (int tid)
>> +{
>> +  uint64_t tls_regs[2];
>> +  struct iovec iovec;
>> +  iovec.iov_base = tls_regs;
>> +  iovec.iov_len = sizeof (tls_regs);
>> +
>> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
>> +    return 1;
>> +
>> +  /* TPIDR2 is available.  */
>> +  return 2;
> 
> Can you explain what is happening here?  How does checking for success
> reading NT_ARM_TLS telly ou that TPIDR2 exists?

If you attempt a read of two registers - sizeof (tls_regs) - and it fails, it means the Linux Kernel doesn't
support TPIDR2. Otherwise, it does.

I'll add a comment making this a bit more clear.

> 
> Simon
> 
I'll send an updated version.

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

* [PATCH v3] [aarch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (7 preceding siblings ...)
  2022-12-05 20:36 ` [PATCH] " Simon Marchi
@ 2022-12-06 13:16 ` Luis Machado
  2022-12-06 14:41   ` Simon Marchi
  2022-12-07 10:30 ` [PATCH v4] " Luis Machado
  9 siblings, 1 reply; 14+ messages in thread
From: Luis Machado @ 2022-12-06 13:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: simon.marchi, jhb

Updates on v3:

- Addressed review comments. Variable renaming and more code comments.

Updates on v2:

- Added missing REGISTER_SIZE_VARIABLE to the tls regset, preventing a warning
when GDB finds a section that doesn't match the regset size.

---

With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
it will be added to the existing NT_ARM_TLS register set. Kernel patches are
being reviewed here:

https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/

From GDB's perspective, we handle it in a similar way to the existing TPIDR
register. But we need to consider cases of systems that only have TPIDR and
systems that have both TPIDR and TPIDR2.

With that in mind, the following patch adds the required code to support
TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
dynamically-generated target description as opposed to a static target
description containing only TPIDR.

That means we can remove the gdb/features/aarch64-tls.xml file and replace the
existing gdb/features/aarch64-tls.c auto-generated file with a new file that
dynamically generates the target description containing either TPIDR alone or
TPIDR and TPIDR2.

In the future, when *BSD's start to support this register, they can just
enable it as is being done for the AArch64 Linux target.

The core file read/write code has been updated to support TPIDR2 as well.

On GDBserver's side, there is a small change to the find_regno function to
expose a non-throwing version of it.

It always seemed strange to me how find_regno causes the whole operation to
abort if it doesn't find a particular register name. The patch moves code
from find_regno into find_regno_no_throw and makes find_regno call
find_regno_no_throw instead.

This allows us to do register name lookups to find a particular register
number without risking erroring out if nothing is found.

The patch also adjusts the feature detection code for aarch64-fbsd, since
the infrastructure is shared amongst all aarch64 targets. I haven't added
code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
that will happen.
---
 gdb/aarch64-fbsd-nat.c         |  6 ++--
 gdb/aarch64-fbsd-tdep.c        | 12 ++++----
 gdb/aarch64-linux-nat.c        | 43 ++++++++++++++------------
 gdb/aarch64-linux-tdep.c       | 30 +++++++++++++-----
 gdb/aarch64-linux-tdep.h       |  3 --
 gdb/aarch64-tdep.c             | 56 ++++++++++++++++++++++++++++------
 gdb/aarch64-tdep.h             |  7 +++--
 gdb/arch/aarch64.c             |  5 +--
 gdb/arch/aarch64.h             | 14 ++++++---
 gdb/features/Makefile          |  1 -
 gdb/features/aarch64-tls.c     | 35 +++++++++++++++++++--
 gdb/features/aarch64-tls.xml   | 11 -------
 gdb/nat/aarch64-linux.c        | 21 +++++++++++++
 gdb/nat/aarch64-linux.h        |  4 +++
 gdbserver/linux-aarch64-low.cc | 24 ++++++++++++---
 gdbserver/regcache.cc          | 20 +++++++++---
 gdbserver/regcache.h           |  5 +++
 17 files changed, 215 insertions(+), 82 deletions(-)
 delete mode 100644 gdb/features/aarch64-tls.xml

diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
index ecf7e4fb5a7..05fd641de32 100644
--- a/gdb/aarch64-fbsd-nat.c
+++ b/gdb/aarch64-fbsd-nat.c
@@ -93,7 +93,7 @@ aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache,
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
   if (tdep->has_tls ())
     fetch_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
-			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
+			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
 }
 
 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
@@ -112,7 +112,7 @@ aarch64_fbsd_nat_target::store_registers (struct regcache *regcache,
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
   if (tdep->has_tls ())
     store_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
-			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
+			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
 }
 
 /* Implement the target read_description method.  */
@@ -121,7 +121,7 @@ const struct target_desc *
 aarch64_fbsd_nat_target::read_description ()
 {
   aarch64_features features;
-  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
+  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
   return aarch64_read_description (features);
 }
 
diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
index 39d19355105..4df7e311b3c 100644
--- a/gdb/aarch64-fbsd-tdep.c
+++ b/gdb/aarch64-fbsd-tdep.c
@@ -50,7 +50,7 @@ static const struct regcache_map_entry aarch64_fbsd_fpregmap[] =
     { 0 }
   };
 
-/* Register numbers are relative to tdep->tls_regnum.  */
+/* Register numbers are relative to tdep->tls_regnum_base.  */
 
 static const struct regcache_map_entry aarch64_fbsd_tls_regmap[] =
   {
@@ -151,7 +151,7 @@ aarch64_fbsd_supply_tls_regset (const struct regset *regset,
   struct gdbarch *gdbarch = regcache->arch ();
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
-  regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size);
+  regcache->supply_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
 }
 
 static void
@@ -162,7 +162,7 @@ aarch64_fbsd_collect_tls_regset (const struct regset *regset,
   struct gdbarch *gdbarch = regcache->arch ();
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
-  regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size);
+  regcache->collect_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
 }
 
 const struct regset aarch64_fbsd_tls_regset =
@@ -201,7 +201,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
   asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
 
   aarch64_features features;
-  features.tls = tls != nullptr;
+  features.tls = tls != nullptr? 1 : 0;
 
   return aarch64_read_description (features);
 }
@@ -218,10 +218,10 @@ aarch64_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
   regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
 				       ptid, gdbarch);
 
-  target_fetch_registers (regcache, tdep->tls_regnum);
+  target_fetch_registers (regcache, tdep->tls_regnum_base);
 
   ULONGEST tpidr;
-  if (regcache->cooked_read (tdep->tls_regnum, &tpidr) != REG_VALID)
+  if (regcache->cooked_read (tdep->tls_regnum_base, &tpidr) != REG_VALID)
     error (_("Unable to fetch %%tpidr"));
 
   /* %tpidr points to the TCB whose first member is the dtv
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index caefcb36485..ca77aca6c2a 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -440,21 +440,22 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
 {
   aarch64_gdbarch_tdep *tdep
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
-  int regno = tdep->tls_regnum;
+  int regno = tdep->tls_regnum_base;
 
   gdb_assert (regno != -1);
+  gdb_assert (tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
-      perror_with_name (_("unable to fetch TLS register"));
+      perror_with_name (_("unable to fetch TLS registers"));
 
-  regcache->raw_supply (regno, &tpidr);
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    regcache->raw_supply (regno + i, &tpidrs[i]);
 }
 
 /* Store to the current thread the valid TLS register set in GDB's
@@ -465,21 +466,23 @@ store_tlsregs_to_thread (struct regcache *regcache)
 {
   aarch64_gdbarch_tdep *tdep
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
-  int regno = tdep->tls_regnum;
+  int regno = tdep->tls_regnum_base;
 
-  gdb_assert (regno != -1);
+  gdb_assert (regno != -1 && tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
 
-  if (REG_VALID != regcache->get_register_status (regno))
-    return;
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    {
+      if (REG_VALID != regcache->get_register_status (regno + i))
+	continue;
 
-  regcache->raw_collect (regno, (char *) &tpidr);
+      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
+    }
 
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = &tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
@@ -531,7 +534,7 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
       && (regno == tdep->mte_reg_base))
     fetch_mteregs_from_thread (regcache);
 
-  if (tdep->has_tls () && regno == tdep->tls_regnum)
+  if (tdep->has_tls () && regno == tdep->tls_regnum_base)
     fetch_tlsregs_from_thread (regcache);
 }
 
@@ -607,7 +610,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
       && (regno == tdep->mte_reg_base))
     store_mteregs_to_thread (regcache);
 
-  if (tdep->has_tls () && regno == tdep->tls_regnum)
+  if (tdep->has_tls ()
+      && regno >= tdep->tls_regnum_base
+      && regno < tdep->tls_regnum_base + tdep->tls_register_count)
     store_tlsregs_to_thread (regcache);
 }
 
@@ -788,7 +793,7 @@ aarch64_linux_nat_target::read_description ()
   features.vq = aarch64_sve_get_vq (tid);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = true;
+  features.tls = aarch64_tls_register_count (tid);
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index a321aee036a..69eb1b030bf 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -754,22 +754,30 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  "MTE registers", cb_data);
     }
 
+  /* Handle the TLS registers.  */
   if (tdep->has_tls ())
     {
+      gdb_assert (tdep->tls_regnum_base != -1);
+      gdb_assert (tdep->tls_register_count > 0);
+
+      int sizeof_tls_regset
+	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
+
       const struct regcache_map_entry tls_regmap[] =
 	{
-	  { 1, tdep->tls_regnum, 8 },
+	  { tdep->tls_register_count, tdep->tls_regnum_base,
+	    AARCH64_TLS_REGISTER_SIZE },
 	  { 0 }
 	};
 
       const struct regset aarch64_linux_tls_regset =
 	{
-	  tls_regmap, regcache_supply_regset, regcache_collect_regset
+	  tls_regmap, regcache_supply_regset, regcache_collect_regset,
+	  REGSET_VARIABLE_SIZE
 	};
 
-      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
-	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
-	  "TLS register", cb_data);
+      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
+	  &aarch64_linux_tls_regset, "TLS register", cb_data);
     }
 }
 
@@ -779,7 +787,6 @@ static const struct target_desc *
 aarch64_linux_core_read_description (struct gdbarch *gdbarch,
 				     struct target_ops *target, bfd *abfd)
 {
-  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
   gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
   CORE_ADDR hwcap = linux_get_hwcap (auxv, target, gdbarch);
   CORE_ADDR hwcap2 = linux_get_hwcap2 (auxv, target, gdbarch);
@@ -788,7 +795,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
   features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = tls != nullptr;
+
+  /* Handle the TLS section.  */
+  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
+  if (tls != nullptr)
+    {
+      size_t size = bfd_section_size (tls);
+      /* Convert the size to the number of actual registers, by
+	 dividing by 8.  */
+      features.tls = size / AARCH64_TLS_REGISTER_SIZE;
+    }
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
index 9a7e4339dba..8ae33efc605 100644
--- a/gdb/aarch64-linux-tdep.h
+++ b/gdb/aarch64-linux-tdep.h
@@ -39,9 +39,6 @@
 /* The MTE regset consists of a 64-bit register.  */
 #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
 
-/* The TLS regset consists of a single register.  */
-#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
-
 extern const struct regset aarch64_linux_gregset;
 extern const struct regset aarch64_linux_fpregset;
 
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index cf20bb40b78..e27996da776 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -3465,8 +3465,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
   features.mte
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
-  features.tls
-      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
+
+  const struct tdesc_feature *tls_feature
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
+
+  if (tls_feature != nullptr)
+    {
+      /* We have TLS registers.  Find out how many.  */
+      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
+	features.tls = 2;
+      else
+	features.tls = 1;
+    }
 
   return features;
 }
@@ -3526,7 +3536,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, ra_sign_state_offset = -1;
-  int first_mte_regnum = -1, tls_regnum = -1;
+  int first_mte_regnum = -1, first_tls_regnum = -1;
   uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
 
   if (vq > AARCH64_MAX_SVE_VQ)
@@ -3614,15 +3624,40 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   /* Add the TLS register.  */
+  int tls_register_count = 0;
   if (feature_tls != nullptr)
     {
-      tls_regnum = num_regs;
-      /* Validate the descriptor provides the mandatory TLS register
-	 and allocate its number.  */
-      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
-					 tls_regnum, "tpidr");
+      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
+      first_tls_regnum = num_regs;
 
-      num_regs++;
+      /* Look for the TLS registers.  tpidr is required, but tpidr2 is
+	 optional.  */
+      valid_p
+	= tdesc_numbered_register (feature_tls, tdesc_data.get (),
+				   first_tls_regnum,
+				   tls_register_names[0]);
+
+      if (valid_p)
+	{
+	  tls_register_count++;
+
+	  bool has_tpidr2
+	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
+				       first_tls_regnum + tls_register_count,
+				       tls_register_names[tls_register_count]);
+
+	  /* Figure out how many TLS registers we have.  */
+	  if (has_tpidr2)
+	    tls_register_count++;
+
+	  num_regs += tls_register_count;
+	}
+      else
+	{
+	  warning (_("Provided TLS register feature doesn't contain "
+		     "required tpidr register."));
+	  return nullptr;
+	}
     }
 
   /* Add the pauth registers.  */
@@ -3675,7 +3710,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->ra_sign_state_regnum = -1;
   tdep->mte_reg_base = first_mte_regnum;
-  tdep->tls_regnum = tls_regnum;
+  tdep->tls_regnum_base = first_tls_regnum;
+  tdep->tls_register_count = tls_register_count;
 
   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 55ccf2e777d..ff94c0a23b0 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -111,12 +111,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
     return mte_reg_base != -1;
   }
 
-  /* TLS register.  This is -1 if the TLS register is not available.  */
-  int tls_regnum = 0;
+  /* TLS registers.  This is -1 if the TLS registers are not available.  */
+  int tls_regnum_base = 0;
+  int tls_register_count = 0;
 
   bool has_tls() const
   {
-    return tls_regnum != -1;
+    return tls_regnum_base != -1;
   }
 
   /* The W pseudo-registers.  */
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index 0f73286f145..565c5e7a81c 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
   if (features.mte)
     regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
 
-  if (features.tls)
-    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
+  /* TLS registers.  */
+  if (features.tls > 0)
+    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
 
   return tdesc.release ();
 }
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index 8e3fd36726a..b1a6ce3ef0e 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -33,7 +33,9 @@ struct aarch64_features
 
   bool pauth = false;
   bool mte = false;
-  bool tls = false;
+
+  /* A positive TLS value indicates the number of TLS registers available.  */
+  uint8_t tls = 0;
 };
 
 inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
@@ -56,7 +58,9 @@ namespace std
       h = features.vq;
       h = h << 1 | features.pauth;
       h = h << 1 | features.mte;
-      h = h << 1 | features.tls;
+      /* Shift by two bits for now.  We may need to increase this in the future
+	 if more TLS registers get added.  */
+      h = h << 2 | features.tls;
       return h;
     }
   };
@@ -96,7 +100,9 @@ enum aarch64_regnum
   AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
 };
 
-#define V_REGISTER_SIZE 16
+/* Sizes of various AArch64 registers.  */
+#define AARCH64_TLS_REGISTER_SIZE 8
+#define V_REGISTER_SIZE	  16
 
 /* Pseudo register base numbers.  */
 #define AARCH64_Q0_REGNUM 0
@@ -117,8 +123,6 @@ enum aarch64_regnum
 #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
 #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
 
-#define	AARCH64_TLS_REGS_SIZE (8)
-
 /* There are a number of ways of expressing the current SVE vector size:
 
    VL : Vector Length.
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index c3e07809db3..f260849636b 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -202,7 +202,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-fpu.xml \
 	aarch64-pauth.xml \
 	aarch64-mte.xml \
-	aarch64-tls.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
 	arc/v2-core.xml \
diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
index 30d730dffba..8a59d26b353 100644
--- a/gdb/features/aarch64-tls.c
+++ b/gdb/features/aarch64-tls.c
@@ -1,14 +1,43 @@
-/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
-  Original: aarch64-tls.xml */
+/* Copyright (C) 2022 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/tdesc.h"
 
+/* This function is NOT auto generated from xml.
+
+   Create the aarch64 description containing the TLS registers.  TPIDR is
+   always available, but TPIDR2 is only available on some systems.
+
+   COUNT is the number of registers in this set.  The minimum is 1.  */
+
 static int
-create_feature_aarch64_tls (struct target_desc *result, long regnum)
+create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
 {
+  /* TPIDR is always present.  */
+  gdb_assert (count >= 1);
+
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
   tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
+
+  /* Add TPIDR2.  */
+  if (count > 1)
+    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
+
   return regnum;
 }
diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
deleted file mode 100644
index f6437785f71..00000000000
--- a/gdb/features/aarch64-tls.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<!-- Copyright (C) 2022 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.tls">
-  <reg name="tpidr" bitsize="64" type="data_ptr"/>
-</feature>
diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
index 421d1ecb53c..07aaeaa01da 100644
--- a/gdb/nat/aarch64-linux.c
+++ b/gdb/nat/aarch64-linux.c
@@ -250,3 +250,24 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 
   return PS_OK;
 }
+
+/* See nat/aarch64-linux.h.  */
+
+int
+aarch64_tls_register_count (int tid)
+{
+  uint64_t tls_regs[2];
+  struct iovec iovec;
+  iovec.iov_base = tls_regs;
+  iovec.iov_len = sizeof (tls_regs);
+
+  /* Attempt to read both TPIDR and TPIDR2.  If the request fails, it means
+     the Linux Kernel does not support TPIDR2.
+
+     Otherwise the Linux Kernel supports both TPIDR and TPIDR2.  */
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
+    return 1;
+
+  /* TPIDR2 is available as well.  */
+  return 2;
+}
diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
index 1777ce32522..517cbb33963 100644
--- a/gdb/nat/aarch64-linux.h
+++ b/gdb/nat/aarch64-linux.h
@@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 				       lwpid_t lwpid, int idx, void **base,
 				       int is_64bit_p);
 
+/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
+   used for aarch64 state.  */
+int aarch64_tls_register_count (int tid);
+
 #endif /* NAT_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index db508696261..b657a265ee7 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
 static void
 aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  collect_register (regcache, tls_regnum, buf);
+  collect_register (regcache, tls_regnum, tls_buf);
+
+  /* Read TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 /* Store TLS register to regcache.  */
@@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 static void
 aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  supply_register (regcache, tls_regnum, buf);
+  supply_register (regcache, tls_regnum, tls_buf);
+
+  /* Write TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 bool
@@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
 	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
 	  break;
 	case NT_ARM_TLS:
-	  if (features.tls)
-	    regset->size = AARCH64_TLS_REGS_SIZE;
+	  if (features.tls > 0)
+	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
 	  break;
 	default:
 	  gdb_assert_not_reached ("Unknown register set found.");
@@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
       features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
       /* A-profile MTE is 64-bit only.  */
       features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
-      features.tls = true;
+      features.tls = aarch64_tls_register_count (tid);
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
 
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index 5cbcea978a0..1c84ef674bf 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -244,16 +244,28 @@ registers_from_string (struct regcache *regcache, char *buf)
   hex2bin (buf, registers, len / 2);
 }
 
-int
-find_regno (const struct target_desc *tdesc, const char *name)
+/* See regcache.h */
+
+gdb::optional<int>
+find_regno_no_throw (const struct target_desc *tdesc, const char *name)
 {
   for (int i = 0; i < tdesc->reg_defs.size (); ++i)
     {
       if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
 	return i;
     }
-  internal_error ("Unknown register %s requested",
-		  name);
+  return {};
+}
+
+int
+find_regno (const struct target_desc *tdesc, const char *name)
+{
+  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
+
+  if (regnum.has_value ())
+    return *regnum;
+
+  internal_error ("Unknown register %s requested", name);
 }
 
 static void
diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
index 731c18d16e2..b67eefbe04b 100644
--- a/gdbserver/regcache.h
+++ b/gdbserver/regcache.h
@@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
 
 int register_size (const struct target_desc *tdesc, int n);
 
+/* No throw version of find_regno.  If NAME is not a known register, return
+   an empty value.  */
+gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
+					const char *name);
+
 int find_regno (const struct target_desc *tdesc, const char *name);
 
 void supply_register (struct regcache *regcache, int n, const void *buf);
-- 
2.25.1


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

* Re: [PATCH v3] [aarch64] Add TPIDR2 register support for Linux
  2022-12-06 13:16 ` [PATCH v3] [aarch64] " Luis Machado
@ 2022-12-06 14:41   ` Simon Marchi
  0 siblings, 0 replies; 14+ messages in thread
From: Simon Marchi @ 2022-12-06 14:41 UTC (permalink / raw)
  To: Luis Machado, gdb-patches; +Cc: jhb

On 12/6/22 08:16, Luis Machado wrote:
> Updates on v3:
> 
> - Addressed review comments. Variable renaming and more code comments.
> 
> Updates on v2:
> 
> - Added missing REGISTER_SIZE_VARIABLE to the tls regset, preventing a warning
> when GDB finds a section that doesn't match the regset size.

A few comments below, with those fixed:

Approved-By: Simon Marchi <simon.marchi@efficios.com>

> @@ -465,21 +466,23 @@ store_tlsregs_to_thread (struct regcache *regcache)
>  {
>    aarch64_gdbarch_tdep *tdep
>      = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> -  int regno = tdep->tls_regnum;
> +  int regno = tdep->tls_regnum_base;
>  
> -  gdb_assert (regno != -1);
> +  gdb_assert (regno != -1 && tdep->tls_register_count > 0);

Split this assert.

>  
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>  
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>  
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>  
>    struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>  
>    int tid = get_ptrace_pid (regcache->ptid ());
>    if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -531,7 +534,7 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
>        && (regno == tdep->mte_reg_base))
>      fetch_mteregs_from_thread (regcache);
>  
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls () && regno == tdep->tls_regnum_base)
>      fetch_tlsregs_from_thread (regcache);

Should this condition be changed, like the one in
aarch64_store_registers?

> @@ -3614,15 +3624,40 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>      }
>  
>    /* Add the TLS register.  */
> +  int tls_register_count = 0;
>    if (feature_tls != nullptr)
>      {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      const char *tls_register_names[2] = { "tpidr", "tpidr2" };
> +      first_tls_regnum = num_regs;
>  
> -      num_regs++;
> +      /* Look for the TLS registers.  tpidr is required, but tpidr2 is
> +	 optional.  */
> +      valid_p
> +	= tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				   first_tls_regnum,
> +				   tls_register_names[0]);
> +
> +      if (valid_p)
> +	{
> +	  tls_register_count++;
> +
> +	  bool has_tpidr2
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       tls_register_names[tls_register_count]);

Since each call is about a specific register, I would suggest getting
rid of tls_register_names and in-line the name, it will be clearer IMO.

Simon

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

* [PATCH v4] [aarch64] Add TPIDR2 register support for Linux
  2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
                   ` (8 preceding siblings ...)
  2022-12-06 13:16 ` [PATCH v3] [aarch64] " Luis Machado
@ 2022-12-07 10:30 ` Luis Machado
  2022-12-09 13:43   ` Luis Machado
  9 siblings, 1 reply; 14+ messages in thread
From: Luis Machado @ 2022-12-07 10:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: simon.marchi, jhb

Here's what I plan to push. John, could you please validate this works on
BSD's side?

Updates on v4:

- Some more reviewer comments.
- Fixup conditional expression when storing tls registers.

Updates on v3:

- Addressed review comments. Variable renaming and more code comments.

Updates on v2:

- Added missing REGISTER_SIZE_VARIABLE to the tls regset, preventing a warning
when GDB finds a section that doesn't match the regset size.

---

With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
it will be added to the existing NT_ARM_TLS register set. Kernel patches are
being reviewed here:

https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/

From GDB's perspective, we handle it in a similar way to the existing TPIDR
register. But we need to consider cases of systems that only have TPIDR and
systems that have both TPIDR and TPIDR2.

With that in mind, the following patch adds the required code to support
TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
dynamically-generated target description as opposed to a static target
description containing only TPIDR.

That means we can remove the gdb/features/aarch64-tls.xml file and replace the
existing gdb/features/aarch64-tls.c auto-generated file with a new file that
dynamically generates the target description containing either TPIDR alone or
TPIDR and TPIDR2.

In the future, when *BSD's start to support this register, they can just
enable it as is being done for the AArch64 Linux target.

The core file read/write code has been updated to support TPIDR2 as well.

On GDBserver's side, there is a small change to the find_regno function to
expose a non-throwing version of it.

It always seemed strange to me how find_regno causes the whole operation to
abort if it doesn't find a particular register name. The patch moves code
from find_regno into find_regno_no_throw and makes find_regno call
find_regno_no_throw instead.

This allows us to do register name lookups to find a particular register
number without risking erroring out if nothing is found.

The patch also adjusts the feature detection code for aarch64-fbsd, since
the infrastructure is shared amongst all aarch64 targets. I haven't added
code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
that will happen.
---
 gdb/aarch64-fbsd-nat.c         |  6 ++--
 gdb/aarch64-fbsd-tdep.c        | 12 ++++----
 gdb/aarch64-linux-nat.c        | 44 +++++++++++++++------------
 gdb/aarch64-linux-tdep.c       | 30 ++++++++++++++-----
 gdb/aarch64-linux-tdep.h       |  3 --
 gdb/aarch64-tdep.c             | 54 +++++++++++++++++++++++++++-------
 gdb/aarch64-tdep.h             |  7 +++--
 gdb/arch/aarch64.c             |  5 ++--
 gdb/arch/aarch64.h             | 14 +++++----
 gdb/features/Makefile          |  1 -
 gdb/features/aarch64-tls.c     | 35 ++++++++++++++++++++--
 gdb/features/aarch64-tls.xml   | 11 -------
 gdb/nat/aarch64-linux.c        | 21 +++++++++++++
 gdb/nat/aarch64-linux.h        |  4 +++
 gdbserver/linux-aarch64-low.cc | 24 +++++++++++----
 gdbserver/regcache.cc          | 20 ++++++++++---
 gdbserver/regcache.h           |  5 ++++
 17 files changed, 215 insertions(+), 81 deletions(-)
 delete mode 100644 gdb/features/aarch64-tls.xml

diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
index ecf7e4fb5a7..05fd641de32 100644
--- a/gdb/aarch64-fbsd-nat.c
+++ b/gdb/aarch64-fbsd-nat.c
@@ -93,7 +93,7 @@ aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache,
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
   if (tdep->has_tls ())
     fetch_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
-			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
+			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
 }
 
 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
@@ -112,7 +112,7 @@ aarch64_fbsd_nat_target::store_registers (struct regcache *regcache,
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
   if (tdep->has_tls ())
     store_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
-			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
+			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
 }
 
 /* Implement the target read_description method.  */
@@ -121,7 +121,7 @@ const struct target_desc *
 aarch64_fbsd_nat_target::read_description ()
 {
   aarch64_features features;
-  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
+  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
   return aarch64_read_description (features);
 }
 
diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
index 39d19355105..4df7e311b3c 100644
--- a/gdb/aarch64-fbsd-tdep.c
+++ b/gdb/aarch64-fbsd-tdep.c
@@ -50,7 +50,7 @@ static const struct regcache_map_entry aarch64_fbsd_fpregmap[] =
     { 0 }
   };
 
-/* Register numbers are relative to tdep->tls_regnum.  */
+/* Register numbers are relative to tdep->tls_regnum_base.  */
 
 static const struct regcache_map_entry aarch64_fbsd_tls_regmap[] =
   {
@@ -151,7 +151,7 @@ aarch64_fbsd_supply_tls_regset (const struct regset *regset,
   struct gdbarch *gdbarch = regcache->arch ();
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
-  regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size);
+  regcache->supply_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
 }
 
 static void
@@ -162,7 +162,7 @@ aarch64_fbsd_collect_tls_regset (const struct regset *regset,
   struct gdbarch *gdbarch = regcache->arch ();
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
-  regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size);
+  regcache->collect_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
 }
 
 const struct regset aarch64_fbsd_tls_regset =
@@ -201,7 +201,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
   asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
 
   aarch64_features features;
-  features.tls = tls != nullptr;
+  features.tls = tls != nullptr? 1 : 0;
 
   return aarch64_read_description (features);
 }
@@ -218,10 +218,10 @@ aarch64_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
   regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
 				       ptid, gdbarch);
 
-  target_fetch_registers (regcache, tdep->tls_regnum);
+  target_fetch_registers (regcache, tdep->tls_regnum_base);
 
   ULONGEST tpidr;
-  if (regcache->cooked_read (tdep->tls_regnum, &tpidr) != REG_VALID)
+  if (regcache->cooked_read (tdep->tls_regnum_base, &tpidr) != REG_VALID)
     error (_("Unable to fetch %%tpidr"));
 
   /* %tpidr points to the TCB whose first member is the dtv
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index caefcb36485..0f4d0af8af6 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -440,21 +440,22 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
 {
   aarch64_gdbarch_tdep *tdep
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
-  int regno = tdep->tls_regnum;
+  int regno = tdep->tls_regnum_base;
 
   gdb_assert (regno != -1);
+  gdb_assert (tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
-      perror_with_name (_("unable to fetch TLS register"));
+      perror_with_name (_("unable to fetch TLS registers"));
 
-  regcache->raw_supply (regno, &tpidr);
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    regcache->raw_supply (regno + i, &tpidrs[i]);
 }
 
 /* Store to the current thread the valid TLS register set in GDB's
@@ -465,21 +466,24 @@ store_tlsregs_to_thread (struct regcache *regcache)
 {
   aarch64_gdbarch_tdep *tdep
     = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
-  int regno = tdep->tls_regnum;
+  int regno = tdep->tls_regnum_base;
 
   gdb_assert (regno != -1);
+  gdb_assert (tdep->tls_register_count > 0);
 
-  uint64_t tpidr = 0;
+  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
 
-  if (REG_VALID != regcache->get_register_status (regno))
-    return;
+  for (int i = 0; i < tdep->tls_register_count; i++)
+    {
+      if (REG_VALID != regcache->get_register_status (regno + i))
+	continue;
 
-  regcache->raw_collect (regno, (char *) &tpidr);
+      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
+    }
 
   struct iovec iovec;
-
-  iovec.iov_base = &tpidr;
-  iovec.iov_len = sizeof (tpidr);
+  iovec.iov_base = &tpidrs;
+  iovec.iov_len = sizeof (tpidrs);
 
   int tid = get_ptrace_pid (regcache->ptid ());
   if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
@@ -531,7 +535,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
       && (regno == tdep->mte_reg_base))
     fetch_mteregs_from_thread (regcache);
 
-  if (tdep->has_tls () && regno == tdep->tls_regnum)
+  if (tdep->has_tls ()
+      && regno >= tdep->tls_regnum_base
+      && regno < tdep->tls_regnum_base + tdep->tls_register_count)
     fetch_tlsregs_from_thread (regcache);
 }
 
@@ -607,7 +613,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
       && (regno == tdep->mte_reg_base))
     store_mteregs_to_thread (regcache);
 
-  if (tdep->has_tls () && regno == tdep->tls_regnum)
+  if (tdep->has_tls ()
+      && regno >= tdep->tls_regnum_base
+      && regno < tdep->tls_regnum_base + tdep->tls_register_count)
     store_tlsregs_to_thread (regcache);
 }
 
@@ -788,7 +796,7 @@ aarch64_linux_nat_target::read_description ()
   features.vq = aarch64_sve_get_vq (tid);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = true;
+  features.tls = aarch64_tls_register_count (tid);
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index a321aee036a..69eb1b030bf 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -754,22 +754,30 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  "MTE registers", cb_data);
     }
 
+  /* Handle the TLS registers.  */
   if (tdep->has_tls ())
     {
+      gdb_assert (tdep->tls_regnum_base != -1);
+      gdb_assert (tdep->tls_register_count > 0);
+
+      int sizeof_tls_regset
+	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
+
       const struct regcache_map_entry tls_regmap[] =
 	{
-	  { 1, tdep->tls_regnum, 8 },
+	  { tdep->tls_register_count, tdep->tls_regnum_base,
+	    AARCH64_TLS_REGISTER_SIZE },
 	  { 0 }
 	};
 
       const struct regset aarch64_linux_tls_regset =
 	{
-	  tls_regmap, regcache_supply_regset, regcache_collect_regset
+	  tls_regmap, regcache_supply_regset, regcache_collect_regset,
+	  REGSET_VARIABLE_SIZE
 	};
 
-      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
-	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
-	  "TLS register", cb_data);
+      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
+	  &aarch64_linux_tls_regset, "TLS register", cb_data);
     }
 }
 
@@ -779,7 +787,6 @@ static const struct target_desc *
 aarch64_linux_core_read_description (struct gdbarch *gdbarch,
 				     struct target_ops *target, bfd *abfd)
 {
-  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
   gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
   CORE_ADDR hwcap = linux_get_hwcap (auxv, target, gdbarch);
   CORE_ADDR hwcap2 = linux_get_hwcap2 (auxv, target, gdbarch);
@@ -788,7 +795,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
   features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
   features.pauth = hwcap & AARCH64_HWCAP_PACA;
   features.mte = hwcap2 & HWCAP2_MTE;
-  features.tls = tls != nullptr;
+
+  /* Handle the TLS section.  */
+  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
+  if (tls != nullptr)
+    {
+      size_t size = bfd_section_size (tls);
+      /* Convert the size to the number of actual registers, by
+	 dividing by 8.  */
+      features.tls = size / AARCH64_TLS_REGISTER_SIZE;
+    }
 
   return aarch64_read_description (features);
 }
diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
index 9a7e4339dba..8ae33efc605 100644
--- a/gdb/aarch64-linux-tdep.h
+++ b/gdb/aarch64-linux-tdep.h
@@ -39,9 +39,6 @@
 /* The MTE regset consists of a 64-bit register.  */
 #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
 
-/* The TLS regset consists of a single register.  */
-#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
-
 extern const struct regset aarch64_linux_gregset;
 extern const struct regset aarch64_linux_fpregset;
 
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index cf20bb40b78..024385a9fd8 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -3465,8 +3465,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
   features.mte
       = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
-  features.tls
-      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
+
+  const struct tdesc_feature *tls_feature
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
+
+  if (tls_feature != nullptr)
+    {
+      /* We have TLS registers.  Find out how many.  */
+      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
+	features.tls = 2;
+      else
+	features.tls = 1;
+    }
 
   return features;
 }
@@ -3526,7 +3536,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, ra_sign_state_offset = -1;
-  int first_mte_regnum = -1, tls_regnum = -1;
+  int first_mte_regnum = -1, first_tls_regnum = -1;
   uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
 
   if (vq > AARCH64_MAX_SVE_VQ)
@@ -3614,15 +3624,38 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   /* Add the TLS register.  */
+  int tls_register_count = 0;
   if (feature_tls != nullptr)
     {
-      tls_regnum = num_regs;
-      /* Validate the descriptor provides the mandatory TLS register
-	 and allocate its number.  */
-      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
-					 tls_regnum, "tpidr");
+      first_tls_regnum = num_regs;
 
-      num_regs++;
+      /* Look for the TLS registers.  tpidr is required, but tpidr2 is
+	 optional.  */
+      valid_p
+	= tdesc_numbered_register (feature_tls, tdesc_data.get (),
+				   first_tls_regnum, "tpidr");
+
+      if (valid_p)
+	{
+	  tls_register_count++;
+
+	  bool has_tpidr2
+	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
+				       first_tls_regnum + tls_register_count,
+				       "tpidr2");
+
+	  /* Figure out how many TLS registers we have.  */
+	  if (has_tpidr2)
+	    tls_register_count++;
+
+	  num_regs += tls_register_count;
+	}
+      else
+	{
+	  warning (_("Provided TLS register feature doesn't contain "
+		     "required tpidr register."));
+	  return nullptr;
+	}
     }
 
   /* Add the pauth registers.  */
@@ -3675,7 +3708,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->ra_sign_state_regnum = -1;
   tdep->mte_reg_base = first_mte_regnum;
-  tdep->tls_regnum = tls_regnum;
+  tdep->tls_regnum_base = first_tls_regnum;
+  tdep->tls_register_count = tls_register_count;
 
   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 55ccf2e777d..ff94c0a23b0 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -111,12 +111,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
     return mte_reg_base != -1;
   }
 
-  /* TLS register.  This is -1 if the TLS register is not available.  */
-  int tls_regnum = 0;
+  /* TLS registers.  This is -1 if the TLS registers are not available.  */
+  int tls_regnum_base = 0;
+  int tls_register_count = 0;
 
   bool has_tls() const
   {
-    return tls_regnum != -1;
+    return tls_regnum_base != -1;
   }
 
   /* The W pseudo-registers.  */
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index 0f73286f145..565c5e7a81c 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
   if (features.mte)
     regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
 
-  if (features.tls)
-    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
+  /* TLS registers.  */
+  if (features.tls > 0)
+    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
 
   return tdesc.release ();
 }
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index 8e3fd36726a..b1a6ce3ef0e 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -33,7 +33,9 @@ struct aarch64_features
 
   bool pauth = false;
   bool mte = false;
-  bool tls = false;
+
+  /* A positive TLS value indicates the number of TLS registers available.  */
+  uint8_t tls = 0;
 };
 
 inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
@@ -56,7 +58,9 @@ namespace std
       h = features.vq;
       h = h << 1 | features.pauth;
       h = h << 1 | features.mte;
-      h = h << 1 | features.tls;
+      /* Shift by two bits for now.  We may need to increase this in the future
+	 if more TLS registers get added.  */
+      h = h << 2 | features.tls;
       return h;
     }
   };
@@ -96,7 +100,9 @@ enum aarch64_regnum
   AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
 };
 
-#define V_REGISTER_SIZE 16
+/* Sizes of various AArch64 registers.  */
+#define AARCH64_TLS_REGISTER_SIZE 8
+#define V_REGISTER_SIZE	  16
 
 /* Pseudo register base numbers.  */
 #define AARCH64_Q0_REGNUM 0
@@ -117,8 +123,6 @@ enum aarch64_regnum
 #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
 #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
 
-#define	AARCH64_TLS_REGS_SIZE (8)
-
 /* There are a number of ways of expressing the current SVE vector size:
 
    VL : Vector Length.
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index c3e07809db3..f260849636b 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -202,7 +202,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-fpu.xml \
 	aarch64-pauth.xml \
 	aarch64-mte.xml \
-	aarch64-tls.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
 	arc/v2-core.xml \
diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
index 30d730dffba..8a59d26b353 100644
--- a/gdb/features/aarch64-tls.c
+++ b/gdb/features/aarch64-tls.c
@@ -1,14 +1,43 @@
-/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
-  Original: aarch64-tls.xml */
+/* Copyright (C) 2022 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/tdesc.h"
 
+/* This function is NOT auto generated from xml.
+
+   Create the aarch64 description containing the TLS registers.  TPIDR is
+   always available, but TPIDR2 is only available on some systems.
+
+   COUNT is the number of registers in this set.  The minimum is 1.  */
+
 static int
-create_feature_aarch64_tls (struct target_desc *result, long regnum)
+create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
 {
+  /* TPIDR is always present.  */
+  gdb_assert (count >= 1);
+
   struct tdesc_feature *feature;
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
   tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
+
+  /* Add TPIDR2.  */
+  if (count > 1)
+    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
+
   return regnum;
 }
diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
deleted file mode 100644
index f6437785f71..00000000000
--- a/gdb/features/aarch64-tls.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<!-- Copyright (C) 2022 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.tls">
-  <reg name="tpidr" bitsize="64" type="data_ptr"/>
-</feature>
diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
index 421d1ecb53c..07aaeaa01da 100644
--- a/gdb/nat/aarch64-linux.c
+++ b/gdb/nat/aarch64-linux.c
@@ -250,3 +250,24 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 
   return PS_OK;
 }
+
+/* See nat/aarch64-linux.h.  */
+
+int
+aarch64_tls_register_count (int tid)
+{
+  uint64_t tls_regs[2];
+  struct iovec iovec;
+  iovec.iov_base = tls_regs;
+  iovec.iov_len = sizeof (tls_regs);
+
+  /* Attempt to read both TPIDR and TPIDR2.  If the request fails, it means
+     the Linux Kernel does not support TPIDR2.
+
+     Otherwise the Linux Kernel supports both TPIDR and TPIDR2.  */
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
+    return 1;
+
+  /* TPIDR2 is available as well.  */
+  return 2;
+}
diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
index 1777ce32522..517cbb33963 100644
--- a/gdb/nat/aarch64-linux.h
+++ b/gdb/nat/aarch64-linux.h
@@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 				       lwpid_t lwpid, int idx, void **base,
 				       int is_64bit_p);
 
+/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
+   used for aarch64 state.  */
+int aarch64_tls_register_count (int tid);
+
 #endif /* NAT_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index db508696261..b657a265ee7 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
 static void
 aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  collect_register (regcache, tls_regnum, buf);
+  collect_register (regcache, tls_regnum, tls_buf);
+
+  /* Read TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 /* Store TLS register to regcache.  */
@@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
 static void
 aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
 {
+  gdb_byte *tls_buf = (gdb_byte *) buf;
   int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
 
-  supply_register (regcache, tls_regnum, buf);
+  supply_register (regcache, tls_regnum, tls_buf);
+
+  /* Write TPIDR2, if it exists.  */
+  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
+
+  if (regnum.has_value ())
+    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
 }
 
 bool
@@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
 	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
 	  break;
 	case NT_ARM_TLS:
-	  if (features.tls)
-	    regset->size = AARCH64_TLS_REGS_SIZE;
+	  if (features.tls > 0)
+	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
 	  break;
 	default:
 	  gdb_assert_not_reached ("Unknown register set found.");
@@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
       features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
       /* A-profile MTE is 64-bit only.  */
       features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
-      features.tls = true;
+      features.tls = aarch64_tls_register_count (tid);
 
       current_process ()->tdesc = aarch64_linux_read_description (features);
 
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index 5cbcea978a0..1c84ef674bf 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -244,16 +244,28 @@ registers_from_string (struct regcache *regcache, char *buf)
   hex2bin (buf, registers, len / 2);
 }
 
-int
-find_regno (const struct target_desc *tdesc, const char *name)
+/* See regcache.h */
+
+gdb::optional<int>
+find_regno_no_throw (const struct target_desc *tdesc, const char *name)
 {
   for (int i = 0; i < tdesc->reg_defs.size (); ++i)
     {
       if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
 	return i;
     }
-  internal_error ("Unknown register %s requested",
-		  name);
+  return {};
+}
+
+int
+find_regno (const struct target_desc *tdesc, const char *name)
+{
+  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
+
+  if (regnum.has_value ())
+    return *regnum;
+
+  internal_error ("Unknown register %s requested", name);
 }
 
 static void
diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
index 731c18d16e2..b67eefbe04b 100644
--- a/gdbserver/regcache.h
+++ b/gdbserver/regcache.h
@@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
 
 int register_size (const struct target_desc *tdesc, int n);
 
+/* No throw version of find_regno.  If NAME is not a known register, return
+   an empty value.  */
+gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
+					const char *name);
+
 int find_regno (const struct target_desc *tdesc, const char *name);
 
 void supply_register (struct regcache *regcache, int n, const void *buf);
-- 
2.25.1


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

* Re: [PATCH v4] [aarch64] Add TPIDR2 register support for Linux
  2022-12-07 10:30 ` [PATCH v4] " Luis Machado
@ 2022-12-09 13:43   ` Luis Machado
  0 siblings, 0 replies; 14+ messages in thread
From: Luis Machado @ 2022-12-09 13:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: simon.marchi, jhb

On 12/7/22 10:30, Luis Machado via Gdb-patches wrote:
> Here's what I plan to push. John, could you please validate this works on
> BSD's side?
> 
> Updates on v4:
> 
> - Some more reviewer comments.
> - Fixup conditional expression when storing tls registers.
> 
> Updates on v3:
> 
> - Addressed review comments. Variable renaming and more code comments.
> 
> Updates on v2:
> 
> - Added missing REGISTER_SIZE_VARIABLE to the tls regset, preventing a warning
> when GDB finds a section that doesn't match the regset size.
> 
> ---
> 
> With the AArch64 Scalable Matrix Extension we have a new TPIDR2 register, and
> it will be added to the existing NT_ARM_TLS register set. Kernel patches are
> being reviewed here:
> 
> https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-broonie@kernel.org/
> 
>>From GDB's perspective, we handle it in a similar way to the existing TPIDR
> register. But we need to consider cases of systems that only have TPIDR and
> systems that have both TPIDR and TPIDR2.
> 
> With that in mind, the following patch adds the required code to support
> TPIDR2 and turns the org.gnu.gdb.aarch64.tls feature into a
> dynamically-generated target description as opposed to a static target
> description containing only TPIDR.
> 
> That means we can remove the gdb/features/aarch64-tls.xml file and replace the
> existing gdb/features/aarch64-tls.c auto-generated file with a new file that
> dynamically generates the target description containing either TPIDR alone or
> TPIDR and TPIDR2.
> 
> In the future, when *BSD's start to support this register, they can just
> enable it as is being done for the AArch64 Linux target.
> 
> The core file read/write code has been updated to support TPIDR2 as well.
> 
> On GDBserver's side, there is a small change to the find_regno function to
> expose a non-throwing version of it.
> 
> It always seemed strange to me how find_regno causes the whole operation to
> abort if it doesn't find a particular register name. The patch moves code
> from find_regno into find_regno_no_throw and makes find_regno call
> find_regno_no_throw instead.
> 
> This allows us to do register name lookups to find a particular register
> number without risking erroring out if nothing is found.
> 
> The patch also adjusts the feature detection code for aarch64-fbsd, since
> the infrastructure is shared amongst all aarch64 targets. I haven't added
> code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if
> that will happen.
> ---
>   gdb/aarch64-fbsd-nat.c         |  6 ++--
>   gdb/aarch64-fbsd-tdep.c        | 12 ++++----
>   gdb/aarch64-linux-nat.c        | 44 +++++++++++++++------------
>   gdb/aarch64-linux-tdep.c       | 30 ++++++++++++++-----
>   gdb/aarch64-linux-tdep.h       |  3 --
>   gdb/aarch64-tdep.c             | 54 +++++++++++++++++++++++++++-------
>   gdb/aarch64-tdep.h             |  7 +++--
>   gdb/arch/aarch64.c             |  5 ++--
>   gdb/arch/aarch64.h             | 14 +++++----
>   gdb/features/Makefile          |  1 -
>   gdb/features/aarch64-tls.c     | 35 ++++++++++++++++++++--
>   gdb/features/aarch64-tls.xml   | 11 -------
>   gdb/nat/aarch64-linux.c        | 21 +++++++++++++
>   gdb/nat/aarch64-linux.h        |  4 +++
>   gdbserver/linux-aarch64-low.cc | 24 +++++++++++----
>   gdbserver/regcache.cc          | 20 ++++++++++---
>   gdbserver/regcache.h           |  5 ++++
>   17 files changed, 215 insertions(+), 81 deletions(-)
>   delete mode 100644 gdb/features/aarch64-tls.xml
> 
> diff --git a/gdb/aarch64-fbsd-nat.c b/gdb/aarch64-fbsd-nat.c
> index ecf7e4fb5a7..05fd641de32 100644
> --- a/gdb/aarch64-fbsd-nat.c
> +++ b/gdb/aarch64-fbsd-nat.c
> @@ -93,7 +93,7 @@ aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache,
>     aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>     if (tdep->has_tls ())
>       fetch_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
> -			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
> +			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
>   }
>   
>   /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
> @@ -112,7 +112,7 @@ aarch64_fbsd_nat_target::store_registers (struct regcache *regcache,
>     aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>     if (tdep->has_tls ())
>       store_regset<uint64_t> (regcache, regnum, NT_ARM_TLS,
> -			    &aarch64_fbsd_tls_regset, tdep->tls_regnum);
> +			    &aarch64_fbsd_tls_regset, tdep->tls_regnum_base);
>   }
>   
>   /* Implement the target read_description method.  */
> @@ -121,7 +121,7 @@ const struct target_desc *
>   aarch64_fbsd_nat_target::read_description ()
>   {
>     aarch64_features features;
> -  features.tls = have_regset (inferior_ptid, NT_ARM_TLS) != 0;
> +  features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0;
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-fbsd-tdep.c b/gdb/aarch64-fbsd-tdep.c
> index 39d19355105..4df7e311b3c 100644
> --- a/gdb/aarch64-fbsd-tdep.c
> +++ b/gdb/aarch64-fbsd-tdep.c
> @@ -50,7 +50,7 @@ static const struct regcache_map_entry aarch64_fbsd_fpregmap[] =
>       { 0 }
>     };
>   
> -/* Register numbers are relative to tdep->tls_regnum.  */
> +/* Register numbers are relative to tdep->tls_regnum_base.  */
>   
>   static const struct regcache_map_entry aarch64_fbsd_tls_regmap[] =
>     {
> @@ -151,7 +151,7 @@ aarch64_fbsd_supply_tls_regset (const struct regset *regset,
>     struct gdbarch *gdbarch = regcache->arch ();
>     aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>   
> -  regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size);
> +  regcache->supply_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
>   }
>   
>   static void
> @@ -162,7 +162,7 @@ aarch64_fbsd_collect_tls_regset (const struct regset *regset,
>     struct gdbarch *gdbarch = regcache->arch ();
>     aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>   
> -  regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size);
> +  regcache->collect_regset (regset, tdep->tls_regnum_base, regnum, buf, size);
>   }
>   
>   const struct regset aarch64_fbsd_tls_regset =
> @@ -201,7 +201,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdbarch,
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>   
>     aarch64_features features;
> -  features.tls = tls != nullptr;
> +  features.tls = tls != nullptr? 1 : 0;
>   
>     return aarch64_read_description (features);
>   }
> @@ -218,10 +218,10 @@ aarch64_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
>     regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
>   				       ptid, gdbarch);
>   
> -  target_fetch_registers (regcache, tdep->tls_regnum);
> +  target_fetch_registers (regcache, tdep->tls_regnum_base);
>   
>     ULONGEST tpidr;
> -  if (regcache->cooked_read (tdep->tls_regnum, &tpidr) != REG_VALID)
> +  if (regcache->cooked_read (tdep->tls_regnum_base, &tpidr) != REG_VALID)
>       error (_("Unable to fetch %%tpidr"));
>   
>     /* %tpidr points to the TCB whose first member is the dtv
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index caefcb36485..0f4d0af8af6 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -440,21 +440,22 @@ fetch_tlsregs_from_thread (struct regcache *regcache)
>   {
>     aarch64_gdbarch_tdep *tdep
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> -  int regno = tdep->tls_regnum;
> +  int regno = tdep->tls_regnum_base;
>   
>     gdb_assert (regno != -1);
> +  gdb_assert (tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> -      perror_with_name (_("unable to fetch TLS register"));
> +      perror_with_name (_("unable to fetch TLS registers"));
>   
> -  regcache->raw_supply (regno, &tpidr);
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    regcache->raw_supply (regno + i, &tpidrs[i]);
>   }
>   
>   /* Store to the current thread the valid TLS register set in GDB's
> @@ -465,21 +466,24 @@ store_tlsregs_to_thread (struct regcache *regcache)
>   {
>     aarch64_gdbarch_tdep *tdep
>       = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> -  int regno = tdep->tls_regnum;
> +  int regno = tdep->tls_regnum_base;
>   
>     gdb_assert (regno != -1);
> +  gdb_assert (tdep->tls_register_count > 0);
>   
> -  uint64_t tpidr = 0;
> +  uint64_t tpidrs[tdep->tls_register_count] = { 0 };
>   
> -  if (REG_VALID != regcache->get_register_status (regno))
> -    return;
> +  for (int i = 0; i < tdep->tls_register_count; i++)
> +    {
> +      if (REG_VALID != regcache->get_register_status (regno + i))
> +	continue;
>   
> -  regcache->raw_collect (regno, (char *) &tpidr);
> +      regcache->raw_collect (regno + i, (char *) &tpidrs[i]);
> +    }
>   
>     struct iovec iovec;
> -
> -  iovec.iov_base = &tpidr;
> -  iovec.iov_len = sizeof (tpidr);
> +  iovec.iov_base = &tpidrs;
> +  iovec.iov_len = sizeof (tpidrs);
>   
>     int tid = get_ptrace_pid (regcache->ptid ());
>     if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> @@ -531,7 +535,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       fetch_mteregs_from_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum_base
> +      && regno < tdep->tls_regnum_base + tdep->tls_register_count)
>       fetch_tlsregs_from_thread (regcache);
>   }
>   
> @@ -607,7 +613,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
>         && (regno == tdep->mte_reg_base))
>       store_mteregs_to_thread (regcache);
>   
> -  if (tdep->has_tls () && regno == tdep->tls_regnum)
> +  if (tdep->has_tls ()
> +      && regno >= tdep->tls_regnum_base
> +      && regno < tdep->tls_regnum_base + tdep->tls_register_count)
>       store_tlsregs_to_thread (regcache);
>   }
>   
> @@ -788,7 +796,7 @@ aarch64_linux_nat_target::read_description ()
>     features.vq = aarch64_sve_get_vq (tid);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = true;
> +  features.tls = aarch64_tls_register_count (tid);
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index a321aee036a..69eb1b030bf 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -754,22 +754,30 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
>   	  "MTE registers", cb_data);
>       }
>   
> +  /* Handle the TLS registers.  */
>     if (tdep->has_tls ())
>       {
> +      gdb_assert (tdep->tls_regnum_base != -1);
> +      gdb_assert (tdep->tls_register_count > 0);
> +
> +      int sizeof_tls_regset
> +	= AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count;
> +
>         const struct regcache_map_entry tls_regmap[] =
>   	{
> -	  { 1, tdep->tls_regnum, 8 },
> +	  { tdep->tls_register_count, tdep->tls_regnum_base,
> +	    AARCH64_TLS_REGISTER_SIZE },
>   	  { 0 }
>   	};
>   
>         const struct regset aarch64_linux_tls_regset =
>   	{
> -	  tls_regmap, regcache_supply_regset, regcache_collect_regset
> +	  tls_regmap, regcache_supply_regset, regcache_collect_regset,
> +	  REGSET_VARIABLE_SIZE
>   	};
>   
> -      cb (".reg-aarch-tls", AARCH64_LINUX_SIZEOF_TLSREGSET,
> -	  AARCH64_LINUX_SIZEOF_TLSREGSET, &aarch64_linux_tls_regset,
> -	  "TLS register", cb_data);
> +      cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset,
> +	  &aarch64_linux_tls_regset, "TLS register", cb_data);
>       }
>   }
>   
> @@ -779,7 +787,6 @@ static const struct target_desc *
>   aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>   				     struct target_ops *target, bfd *abfd)
>   {
> -  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
>     CORE_ADDR hwcap = linux_get_hwcap (auxv, target, gdbarch);
>     CORE_ADDR hwcap2 = linux_get_hwcap2 (auxv, target, gdbarch);
> @@ -788,7 +795,16 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
>     features.vq = aarch64_linux_core_read_vq (gdbarch, abfd);
>     features.pauth = hwcap & AARCH64_HWCAP_PACA;
>     features.mte = hwcap2 & HWCAP2_MTE;
> -  features.tls = tls != nullptr;
> +
> +  /* Handle the TLS section.  */
> +  asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
> +  if (tls != nullptr)
> +    {
> +      size_t size = bfd_section_size (tls);
> +      /* Convert the size to the number of actual registers, by
> +	 dividing by 8.  */
> +      features.tls = size / AARCH64_TLS_REGISTER_SIZE;
> +    }
>   
>     return aarch64_read_description (features);
>   }
> diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
> index 9a7e4339dba..8ae33efc605 100644
> --- a/gdb/aarch64-linux-tdep.h
> +++ b/gdb/aarch64-linux-tdep.h
> @@ -39,9 +39,6 @@
>   /* The MTE regset consists of a 64-bit register.  */
>   #define AARCH64_LINUX_SIZEOF_MTE_REGSET (8)
>   
> -/* The TLS regset consists of a single register.  */
> -#define AARCH64_LINUX_SIZEOF_TLSREGSET (X_REGISTER_SIZE)
> -
>   extern const struct regset aarch64_linux_gregset;
>   extern const struct regset aarch64_linux_fpregset;
>   
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index cf20bb40b78..024385a9fd8 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -3465,8 +3465,18 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") != nullptr);
>     features.mte
>         = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") != nullptr);
> -  features.tls
> -      = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") != nullptr);
> +
> +  const struct tdesc_feature *tls_feature
> +    = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls");
> +
> +  if (tls_feature != nullptr)
> +    {
> +      /* We have TLS registers.  Find out how many.  */
> +      if (tdesc_unnumbered_register (tls_feature, "tpidr2"))
> +	features.tls = 2;
> +      else
> +	features.tls = 1;
> +    }
>   
>     return features;
>   }
> @@ -3526,7 +3536,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, ra_sign_state_offset = -1;
> -  int first_mte_regnum = -1, tls_regnum = -1;
> +  int first_mte_regnum = -1, first_tls_regnum = -1;
>     uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
>   
>     if (vq > AARCH64_MAX_SVE_VQ)
> @@ -3614,15 +3624,38 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>       }
>   
>     /* Add the TLS register.  */
> +  int tls_register_count = 0;
>     if (feature_tls != nullptr)
>       {
> -      tls_regnum = num_regs;
> -      /* Validate the descriptor provides the mandatory TLS register
> -	 and allocate its number.  */
> -      valid_p = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> -					 tls_regnum, "tpidr");
> +      first_tls_regnum = num_regs;
>   
> -      num_regs++;
> +      /* Look for the TLS registers.  tpidr is required, but tpidr2 is
> +	 optional.  */
> +      valid_p
> +	= tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				   first_tls_regnum, "tpidr");
> +
> +      if (valid_p)
> +	{
> +	  tls_register_count++;
> +
> +	  bool has_tpidr2
> +	    = tdesc_numbered_register (feature_tls, tdesc_data.get (),
> +				       first_tls_regnum + tls_register_count,
> +				       "tpidr2");
> +
> +	  /* Figure out how many TLS registers we have.  */
> +	  if (has_tpidr2)
> +	    tls_register_count++;
> +
> +	  num_regs += tls_register_count;
> +	}
> +      else
> +	{
> +	  warning (_("Provided TLS register feature doesn't contain "
> +		     "required tpidr register."));
> +	  return nullptr;
> +	}
>       }
>   
>     /* Add the pauth registers.  */
> @@ -3675,7 +3708,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->pauth_reg_base = first_pauth_regnum;
>     tdep->ra_sign_state_regnum = -1;
>     tdep->mte_reg_base = first_mte_regnum;
> -  tdep->tls_regnum = tls_regnum;
> +  tdep->tls_regnum_base = first_tls_regnum;
> +  tdep->tls_register_count = tls_register_count;
>   
>     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 55ccf2e777d..ff94c0a23b0 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -111,12 +111,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return mte_reg_base != -1;
>     }
>   
> -  /* TLS register.  This is -1 if the TLS register is not available.  */
> -  int tls_regnum = 0;
> +  /* TLS registers.  This is -1 if the TLS registers are not available.  */
> +  int tls_regnum_base = 0;
> +  int tls_register_count = 0;
>   
>     bool has_tls() const
>     {
> -    return tls_regnum != -1;
> +    return tls_regnum_base != -1;
>     }
>   
>     /* The W pseudo-registers.  */
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 0f73286f145..565c5e7a81c 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -53,8 +53,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.mte)
>       regnum = create_feature_aarch64_mte (tdesc.get (), regnum);
>   
> -  if (features.tls)
> -    regnum = create_feature_aarch64_tls (tdesc.get (), regnum);
> +  /* TLS registers.  */
> +  if (features.tls > 0)
> +    regnum = create_feature_aarch64_tls (tdesc.get (), regnum, features.tls);
>   
>     return tdesc.release ();
>   }
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index 8e3fd36726a..b1a6ce3ef0e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -33,7 +33,9 @@ struct aarch64_features
>   
>     bool pauth = false;
>     bool mte = false;
> -  bool tls = false;
> +
> +  /* A positive TLS value indicates the number of TLS registers available.  */
> +  uint8_t tls = 0;
>   };
>   
>   inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
> @@ -56,7 +58,9 @@ namespace std
>         h = features.vq;
>         h = h << 1 | features.pauth;
>         h = h << 1 | features.mte;
> -      h = h << 1 | features.tls;
> +      /* Shift by two bits for now.  We may need to increase this in the future
> +	 if more TLS registers get added.  */
> +      h = h << 2 | features.tls;
>         return h;
>       }
>     };
> @@ -96,7 +100,9 @@ enum aarch64_regnum
>     AARCH64_LAST_V_ARG_REGNUM = AARCH64_V0_REGNUM + 7
>   };
>   
> -#define V_REGISTER_SIZE 16
> +/* Sizes of various AArch64 registers.  */
> +#define AARCH64_TLS_REGISTER_SIZE 8
> +#define V_REGISTER_SIZE	  16
>   
>   /* Pseudo register base numbers.  */
>   #define AARCH64_Q0_REGNUM 0
> @@ -117,8 +123,6 @@ enum aarch64_regnum
>   #define AARCH64_NUM_REGS AARCH64_FPCR_REGNUM + 1
>   #define AARCH64_SVE_NUM_REGS AARCH64_SVE_VG_REGNUM + 1
>   
> -#define	AARCH64_TLS_REGS_SIZE (8)
> -
>   /* There are a number of ways of expressing the current SVE vector size:
>   
>      VL : Vector Length.
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index c3e07809db3..f260849636b 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -202,7 +202,6 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-fpu.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
> -	aarch64-tls.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
>   	arc/v2-core.xml \
> diff --git a/gdb/features/aarch64-tls.c b/gdb/features/aarch64-tls.c
> index 30d730dffba..8a59d26b353 100644
> --- a/gdb/features/aarch64-tls.c
> +++ b/gdb/features/aarch64-tls.c
> @@ -1,14 +1,43 @@
> -/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> -  Original: aarch64-tls.xml */
> +/* Copyright (C) 2022 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/tdesc.h"
>   
> +/* This function is NOT auto generated from xml.
> +
> +   Create the aarch64 description containing the TLS registers.  TPIDR is
> +   always available, but TPIDR2 is only available on some systems.
> +
> +   COUNT is the number of registers in this set.  The minimum is 1.  */
> +
>   static int
> -create_feature_aarch64_tls (struct target_desc *result, long regnum)
> +create_feature_aarch64_tls (struct target_desc *result, long regnum, int count)
>   {
> +  /* TPIDR is always present.  */
> +  gdb_assert (count >= 1);
> +
>     struct tdesc_feature *feature;
>   
>     feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.tls");
>     tdesc_create_reg (feature, "tpidr", regnum++, 1, NULL, 64, "data_ptr");
> +
> +  /* Add TPIDR2.  */
> +  if (count > 1)
> +    tdesc_create_reg (feature, "tpidr2", regnum++, 1, NULL, 64, "data_ptr");
> +
>     return regnum;
>   }
> diff --git a/gdb/features/aarch64-tls.xml b/gdb/features/aarch64-tls.xml
> deleted file mode 100644
> index f6437785f71..00000000000
> --- a/gdb/features/aarch64-tls.xml
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -<?xml version="1.0"?>
> -<!-- Copyright (C) 2022 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.tls">
> -  <reg name="tpidr" bitsize="64" type="data_ptr"/>
> -</feature>
> diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
> index 421d1ecb53c..07aaeaa01da 100644
> --- a/gdb/nat/aarch64-linux.c
> +++ b/gdb/nat/aarch64-linux.c
> @@ -250,3 +250,24 @@ aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   
>     return PS_OK;
>   }
> +
> +/* See nat/aarch64-linux.h.  */
> +
> +int
> +aarch64_tls_register_count (int tid)
> +{
> +  uint64_t tls_regs[2];
> +  struct iovec iovec;
> +  iovec.iov_base = tls_regs;
> +  iovec.iov_len = sizeof (tls_regs);
> +
> +  /* Attempt to read both TPIDR and TPIDR2.  If the request fails, it means
> +     the Linux Kernel does not support TPIDR2.
> +
> +     Otherwise the Linux Kernel supports both TPIDR and TPIDR2.  */
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
> +    return 1;
> +
> +  /* TPIDR2 is available as well.  */
> +  return 2;
> +}
> diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
> index 1777ce32522..517cbb33963 100644
> --- a/gdb/nat/aarch64-linux.h
> +++ b/gdb/nat/aarch64-linux.h
> @@ -129,4 +129,8 @@ ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
>   				       lwpid_t lwpid, int idx, void **base,
>   				       int is_64bit_p);
>   
> +/* Return the number of TLS registers in the NT_ARM_TLS set.  This is only
> +   used for aarch64 state.  */
> +int aarch64_tls_register_count (int tid);
> +
>   #endif /* NAT_AARCH64_LINUX_H */
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index db508696261..b657a265ee7 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -292,9 +292,16 @@ aarch64_store_mteregset (struct regcache *regcache, const void *buf)
>   static void
>   aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  collect_register (regcache, tls_regnum, buf);
> +  collect_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Read TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   /* Store TLS register to regcache.  */
> @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, void *buf)
>   static void
>   aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
>   {
> +  gdb_byte *tls_buf = (gdb_byte *) buf;
>     int tls_regnum  = find_regno (regcache->tdesc, "tpidr");
>   
> -  supply_register (regcache, tls_regnum, buf);
> +  supply_register (regcache, tls_regnum, tls_buf);
> +
> +  /* Write TPIDR2, if it exists.  */
> +  gdb::optional<int> regnum = find_regno_no_throw (regcache->tdesc, "tpidr2");
> +
> +  if (regnum.has_value ())
> +    supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
>   }
>   
>   bool
> @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	    regset->size = AARCH64_LINUX_SIZEOF_MTE;
>   	  break;
>   	case NT_ARM_TLS:
> -	  if (features.tls)
> -	    regset->size = AARCH64_TLS_REGS_SIZE;
> +	  if (features.tls > 0)
> +	    regset->size = AARCH64_TLS_REGISTER_SIZE * features.tls;
>   	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
> @@ -829,7 +843,7 @@ aarch64_target::low_arch_setup ()
>         features.pauth = linux_get_hwcap (8) & AARCH64_HWCAP_PACA;
>         /* A-profile MTE is 64-bit only.  */
>         features.mte = linux_get_hwcap2 (8) & HWCAP2_MTE;
> -      features.tls = true;
> +      features.tls = aarch64_tls_register_count (tid);
>   
>         current_process ()->tdesc = aarch64_linux_read_description (features);
>   
> diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
> index 5cbcea978a0..1c84ef674bf 100644
> --- a/gdbserver/regcache.cc
> +++ b/gdbserver/regcache.cc
> @@ -244,16 +244,28 @@ registers_from_string (struct regcache *regcache, char *buf)
>     hex2bin (buf, registers, len / 2);
>   }
>   
> -int
> -find_regno (const struct target_desc *tdesc, const char *name)
> +/* See regcache.h */
> +
> +gdb::optional<int>
> +find_regno_no_throw (const struct target_desc *tdesc, const char *name)
>   {
>     for (int i = 0; i < tdesc->reg_defs.size (); ++i)
>       {
>         if (strcmp (name, find_register_by_number (tdesc, i).name) == 0)
>   	return i;
>       }
> -  internal_error ("Unknown register %s requested",
> -		  name);
> +  return {};
> +}
> +
> +int
> +find_regno (const struct target_desc *tdesc, const char *name)
> +{
> +  gdb::optional<int> regnum = find_regno_no_throw (tdesc, name);
> +
> +  if (regnum.has_value ())
> +    return *regnum;
> +
> +  internal_error ("Unknown register %s requested", name);
>   }
>   
>   static void
> diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h
> index 731c18d16e2..b67eefbe04b 100644
> --- a/gdbserver/regcache.h
> +++ b/gdbserver/regcache.h
> @@ -110,6 +110,11 @@ int register_cache_size (const struct target_desc *tdesc);
>   
>   int register_size (const struct target_desc *tdesc, int n);
>   
> +/* No throw version of find_regno.  If NAME is not a known register, return
> +   an empty value.  */
> +gdb::optional<int> find_regno_no_throw (const struct target_desc *tdesc,
> +					const char *name);
> +
>   int find_regno (const struct target_desc *tdesc, const char *name);
>   
>   void supply_register (struct regcache *regcache, int n, const void *buf);

Pushed now.

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

end of thread, other threads:[~2022-12-09 13:43 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-23 13:46 [PATCH] [AArch64] Add TPIDR2 register support for Linux Luis Machado
2022-09-23 16:42 ` John Baldwin
2022-10-04  8:53 ` [PING][PATCH] " Luis Machado
2022-10-10 12:19 ` Luis Machado
2022-10-17 10:03 ` Luis Machado
2022-10-25 13:52 ` Luis Machado
2022-11-10  1:01 ` Luis Machado
2022-11-29 22:19 ` Luis Machado
2022-12-05 20:36 ` [PATCH] " Simon Marchi
2022-12-06  9:50   ` Luis Machado
2022-12-06 13:16 ` [PATCH v3] [aarch64] " Luis Machado
2022-12-06 14:41   ` Simon Marchi
2022-12-07 10:30 ` [PATCH v4] " Luis Machado
2022-12-09 13:43   ` 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).