diff options
-rw-r--r-- | gdb/aarch64-fbsd-nat.c | 6 | ||||
-rw-r--r-- | gdb/aarch64-fbsd-tdep.c | 12 | ||||
-rw-r--r-- | gdb/aarch64-linux-nat.c | 44 | ||||
-rw-r--r-- | gdb/aarch64-linux-tdep.c | 30 | ||||
-rw-r--r-- | gdb/aarch64-linux-tdep.h | 3 | ||||
-rw-r--r-- | gdb/aarch64-tdep.c | 54 | ||||
-rw-r--r-- | gdb/aarch64-tdep.h | 7 | ||||
-rw-r--r-- | gdb/arch/aarch64.c | 5 | ||||
-rw-r--r-- | gdb/arch/aarch64.h | 14 | ||||
-rw-r--r-- | gdb/features/Makefile | 1 | ||||
-rw-r--r-- | gdb/features/aarch64-tls.c | 35 | ||||
-rw-r--r-- | gdb/features/aarch64-tls.xml | 11 | ||||
-rw-r--r-- | gdb/nat/aarch64-linux.c | 21 | ||||
-rw-r--r-- | gdb/nat/aarch64-linux.h | 4 | ||||
-rw-r--r-- | gdbserver/linux-aarch64-low.cc | 24 | ||||
-rw-r--r-- | gdbserver/regcache.cc | 20 | ||||
-rw-r--r-- | gdbserver/regcache.h | 5 |
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); |