summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/aarch64-fbsd-nat.c6
-rw-r--r--gdb/aarch64-fbsd-tdep.c12
-rw-r--r--gdb/aarch64-linux-nat.c44
-rw-r--r--gdb/aarch64-linux-tdep.c30
-rw-r--r--gdb/aarch64-linux-tdep.h3
-rw-r--r--gdb/aarch64-tdep.c54
-rw-r--r--gdb/aarch64-tdep.h7
-rw-r--r--gdb/arch/aarch64.c5
-rw-r--r--gdb/arch/aarch64.h14
-rw-r--r--gdb/features/Makefile1
-rw-r--r--gdb/features/aarch64-tls.c35
-rw-r--r--gdb/features/aarch64-tls.xml11
-rw-r--r--gdb/nat/aarch64-linux.c21
-rw-r--r--gdb/nat/aarch64-linux.h4
-rw-r--r--gdbserver/linux-aarch64-low.cc24
-rw-r--r--gdbserver/regcache.cc20
-rw-r--r--gdbserver/regcache.h5
17 files changed, 215 insertions, 81 deletions
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);