From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1585) id 6B18138446BD; Fri, 9 Dec 2022 13:43:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6B18138446BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1670593395; bh=Vnyc4ievqcBEYMHLiCibXr81La7XF9KqABFrVErvXo4=; h=From:To:Subject:Date:From; b=XeI5/xSRN3m8BXo/NRTRnmF9+ojbQ0akuiXyib9xmqsNRUPTOr9FAbgrUl+xW9Xbq VIg/sy2E0Wx0wy+5KdisXaALhzVF5uSFJoHQ8pLGs+VsbCL/SLW8+J37ClCRPXSu8N Os++so0TQzmfvZjwI/2T/isiC3dKnKkjeyIk/SJM= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Luis Machado To: gdb-cvs@sourceware.org Subject: [binutils-gdb] [aarch64] Add TPIDR2 register support for Linux X-Act-Checkin: binutils-gdb X-Git-Author: Luis Machado X-Git-Refname: refs/heads/master X-Git-Oldrev: 73425813c1b6286fd589fcf0ef9335e8240137a9 X-Git-Newrev: ba60b96371b1cfdf5c4548545269f89bc42649ef Message-Id: <20221209134315.6B18138446BD@sourceware.org> Date: Fri, 9 Dec 2022 13:43:15 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dba60b96371b1= cfdf5c4548545269f89bc42649ef commit ba60b96371b1cfdf5c4548545269f89bc42649ef Author: Luis Machado Date: Mon Aug 22 17:04:41 2022 +0100 [aarch64] Add TPIDR2 register support for Linux =20 With the AArch64 Scalable Matrix Extension we have a new TPIDR2 registe= r, and it will be added to the existing NT_ARM_TLS register set. Kernel patche= s are being reviewed here: =20 https://lore.kernel.org/linux-arm-kernel/20220818170111.351889-1-brooni= e@kernel.org/ =20 From GDB's perspective, we handle it in a similar way to the existing T= PIDR register. But we need to consider cases of systems that only have TPIDR= and systems that have both TPIDR and TPIDR2. =20 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. =20 That means we can remove the gdb/features/aarch64-tls.xml file and repl= ace the existing gdb/features/aarch64-tls.c auto-generated file with a new file= that dynamically generates the target description containing either TPIDR al= one or TPIDR and TPIDR2. =20 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. =20 The core file read/write code has been updated to support TPIDR2 as wel= l. =20 On GDBserver's side, there is a small change to the find_regno function= to expose a non-throwing version of it. =20 It always seemed strange to me how find_regno causes the whole operatio= n to abort if it doesn't find a particular register name. The patch moves co= de from find_regno into find_regno_no_throw and makes find_regno call find_regno_no_throw instead. =20 This allows us to do register name lookups to find a particular register number without risking erroring out if nothing is found. =20 The patch also adjusts the feature detection code for aarch64-fbsd, sin= ce the infrastructure is shared amongst all aarch64 targets. I haven't add= ed code to support TPIDR2 in aarch64-fbsd though, as I'm not sure when/if that will happen. Diff: --- 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(-) 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 =3D gdbarch_tdep (gdbar= ch); if (tdep->has_tls ()) fetch_regset (regcache, regnum, NT_ARM_TLS, - &aarch64_fbsd_tls_regset, tdep->tls_regnum); + &aarch64_fbsd_tls_regset, tdep->tls_regnum_base); } =20 /* Store register REGNUM back into the inferior. If REGNUM is -1, do @@ -112,7 +112,7 @@ aarch64_fbsd_nat_target::store_registers (struct regcac= he *regcache, aarch64_gdbarch_tdep *tdep =3D gdbarch_tdep (gdbar= ch); if (tdep->has_tls ()) store_regset (regcache, regnum, NT_ARM_TLS, - &aarch64_fbsd_tls_regset, tdep->tls_regnum); + &aarch64_fbsd_tls_regset, tdep->tls_regnum_base); } =20 /* 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 =3D have_regset (inferior_ptid, NT_ARM_TLS) !=3D 0; + features.tls =3D have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0; return aarch64_read_description (features); } =20 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_fpreg= map[] =3D { 0 } }; =20 -/* Register numbers are relative to tdep->tls_regnum. */ +/* Register numbers are relative to tdep->tls_regnum_base. */ =20 static const struct regcache_map_entry aarch64_fbsd_tls_regmap[] =3D { @@ -151,7 +151,7 @@ aarch64_fbsd_supply_tls_regset (const struct regset *re= gset, struct gdbarch *gdbarch =3D regcache->arch (); aarch64_gdbarch_tdep *tdep =3D gdbarch_tdep (gdbar= ch); =20 - regcache->supply_regset (regset, tdep->tls_regnum, regnum, buf, size); + regcache->supply_regset (regset, tdep->tls_regnum_base, regnum, buf, siz= e); } =20 static void @@ -162,7 +162,7 @@ aarch64_fbsd_collect_tls_regset (const struct regset *r= egset, struct gdbarch *gdbarch =3D regcache->arch (); aarch64_gdbarch_tdep *tdep =3D gdbarch_tdep (gdbar= ch); =20 - regcache->collect_regset (regset, tdep->tls_regnum, regnum, buf, size); + regcache->collect_regset (regset, tdep->tls_regnum_base, regnum, buf, si= ze); } =20 const struct regset aarch64_fbsd_tls_regset =3D @@ -201,7 +201,7 @@ aarch64_fbsd_core_read_description (struct gdbarch *gdb= arch, asection *tls =3D bfd_get_section_by_name (abfd, ".reg-aarch-tls"); =20 aarch64_features features; - features.tls =3D tls !=3D nullptr; + features.tls =3D tls !=3D nullptr? 1 : 0; =20 return aarch64_read_description (features); } @@ -218,10 +218,10 @@ aarch64_fbsd_get_thread_local_address (struct gdbarch= *gdbarch, ptid_t ptid, regcache =3D get_thread_arch_regcache (current_inferior ()->process_targ= et (), ptid, gdbarch); =20 - target_fetch_registers (regcache, tdep->tls_regnum); + target_fetch_registers (regcache, tdep->tls_regnum_base); =20 ULONGEST tpidr; - if (regcache->cooked_read (tdep->tls_regnum, &tpidr) !=3D REG_VALID) + if (regcache->cooked_read (tdep->tls_regnum_base, &tpidr) !=3D REG_VALID) error (_("Unable to fetch %%tpidr")); =20 /* %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 =3D gdbarch_tdep (regcache->arch ()); - int regno =3D tdep->tls_regnum; + int regno =3D tdep->tls_regnum_base; =20 gdb_assert (regno !=3D -1); + gdb_assert (tdep->tls_register_count > 0); =20 - uint64_t tpidr =3D 0; + uint64_t tpidrs[tdep->tls_register_count] =3D { 0 }; struct iovec iovec; - - iovec.iov_base =3D &tpidr; - iovec.iov_len =3D sizeof (tpidr); + iovec.iov_base =3D tpidrs; + iovec.iov_len =3D sizeof (tpidrs); =20 int tid =3D get_ptrace_pid (regcache->ptid ()); if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) !=3D 0) - perror_with_name (_("unable to fetch TLS register")); + perror_with_name (_("unable to fetch TLS registers")); =20 - regcache->raw_supply (regno, &tpidr); + for (int i =3D 0; i < tdep->tls_register_count; i++) + regcache->raw_supply (regno + i, &tpidrs[i]); } =20 /* 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 =3D gdbarch_tdep (regcache->arch ()); - int regno =3D tdep->tls_regnum; + int regno =3D tdep->tls_regnum_base; =20 gdb_assert (regno !=3D -1); + gdb_assert (tdep->tls_register_count > 0); =20 - uint64_t tpidr =3D 0; + uint64_t tpidrs[tdep->tls_register_count] =3D { 0 }; =20 - if (REG_VALID !=3D regcache->get_register_status (regno)) - return; + for (int i =3D 0; i < tdep->tls_register_count; i++) + { + if (REG_VALID !=3D regcache->get_register_status (regno + i)) + continue; =20 - regcache->raw_collect (regno, (char *) &tpidr); + regcache->raw_collect (regno + i, (char *) &tpidrs[i]); + } =20 struct iovec iovec; - - iovec.iov_base =3D &tpidr; - iovec.iov_len =3D sizeof (tpidr); + iovec.iov_base =3D &tpidrs; + iovec.iov_len =3D sizeof (tpidrs); =20 int tid =3D get_ptrace_pid (regcache->ptid ()); if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TLS, &iovec) !=3D 0) @@ -531,7 +535,9 @@ aarch64_fetch_registers (struct regcache *regcache, int= regno) && (regno =3D=3D tdep->mte_reg_base)) fetch_mteregs_from_thread (regcache); =20 - if (tdep->has_tls () && regno =3D=3D tdep->tls_regnum) + if (tdep->has_tls () + && regno >=3D tdep->tls_regnum_base + && regno < tdep->tls_regnum_base + tdep->tls_register_count) fetch_tlsregs_from_thread (regcache); } =20 @@ -607,7 +613,9 @@ aarch64_store_registers (struct regcache *regcache, int= regno) && (regno =3D=3D tdep->mte_reg_base)) store_mteregs_to_thread (regcache); =20 - if (tdep->has_tls () && regno =3D=3D tdep->tls_regnum) + if (tdep->has_tls () + && regno >=3D tdep->tls_regnum_base + && regno < tdep->tls_regnum_base + tdep->tls_register_count) store_tlsregs_to_thread (regcache); } =20 @@ -788,7 +796,7 @@ aarch64_linux_nat_target::read_description () features.vq =3D aarch64_sve_get_vq (tid); features.pauth =3D hwcap & AARCH64_HWCAP_PACA; features.mte =3D hwcap2 & HWCAP2_MTE; - features.tls =3D true; + features.tls =3D aarch64_tls_register_count (tid); =20 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 gd= barch *gdbarch, "MTE registers", cb_data); } =20 + /* Handle the TLS registers. */ if (tdep->has_tls ()) { + gdb_assert (tdep->tls_regnum_base !=3D -1); + gdb_assert (tdep->tls_register_count > 0); + + int sizeof_tls_regset + =3D AARCH64_TLS_REGISTER_SIZE * tdep->tls_register_count; + const struct regcache_map_entry tls_regmap[] =3D { - { 1, tdep->tls_regnum, 8 }, + { tdep->tls_register_count, tdep->tls_regnum_base, + AARCH64_TLS_REGISTER_SIZE }, { 0 } }; =20 const struct regset aarch64_linux_tls_regset =3D { - tls_regmap, regcache_supply_regset, regcache_collect_regset + tls_regmap, regcache_supply_regset, regcache_collect_regset, + REGSET_VARIABLE_SIZE }; =20 - 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); } } =20 @@ -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 =3D bfd_get_section_by_name (abfd, ".reg-aarch-tls"); gdb::optional auxv =3D target_read_auxv_raw (target); CORE_ADDR hwcap =3D linux_get_hwcap (auxv, target, gdbarch); CORE_ADDR hwcap2 =3D linux_get_hwcap2 (auxv, target, gdbarch); @@ -788,7 +795,16 @@ aarch64_linux_core_read_description (struct gdbarch *g= dbarch, features.vq =3D aarch64_linux_core_read_vq (gdbarch, abfd); features.pauth =3D hwcap & AARCH64_HWCAP_PACA; features.mte =3D hwcap2 & HWCAP2_MTE; - features.tls =3D tls !=3D nullptr; + + /* Handle the TLS section. */ + asection *tls =3D bfd_get_section_by_name (abfd, ".reg-aarch-tls"); + if (tls !=3D nullptr) + { + size_t size =3D bfd_section_size (tls); + /* Convert the size to the number of actual registers, by + dividing by 8. */ + features.tls =3D size / AARCH64_TLS_REGISTER_SIZE; + } =20 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) =20 -/* 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; =20 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 targ= et_desc *tdesc) =3D (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth") !=3D nu= llptr); features.mte =3D (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte") !=3D null= ptr); - features.tls - =3D (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls") !=3D null= ptr); + + const struct tdesc_feature *tls_feature + =3D tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.tls"); + + if (tls_feature !=3D nullptr) + { + /* We have TLS registers. Find out how many. */ + if (tdesc_unnumbered_register (tls_feature, "tpidr2")) + features.tls =3D 2; + else + features.tls =3D 1; + } =20 return features; } @@ -3526,7 +3536,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struc= t gdbarch_list *arches) bool valid_p =3D true; int i, num_regs =3D 0, num_pseudo_regs =3D 0; int first_pauth_regnum =3D -1, ra_sign_state_offset =3D -1; - int first_mte_regnum =3D -1, tls_regnum =3D -1; + int first_mte_regnum =3D -1, first_tls_regnum =3D -1; uint64_t vq =3D aarch64_get_tdesc_vq (info.target_desc); =20 if (vq > AARCH64_MAX_SVE_VQ) @@ -3614,15 +3624,38 @@ aarch64_gdbarch_init (struct gdbarch_info info, str= uct gdbarch_list *arches) } =20 /* Add the TLS register. */ + int tls_register_count =3D 0; if (feature_tls !=3D nullptr) { - tls_regnum =3D num_regs; - /* Validate the descriptor provides the mandatory TLS register - and allocate its number. */ - valid_p =3D tdesc_numbered_register (feature_tls, tdesc_data.get (), - tls_regnum, "tpidr"); + first_tls_regnum =3D num_regs; =20 - num_regs++; + /* Look for the TLS registers. tpidr is required, but tpidr2 is + optional. */ + valid_p + =3D tdesc_numbered_register (feature_tls, tdesc_data.get (), + first_tls_regnum, "tpidr"); + + if (valid_p) + { + tls_register_count++; + + bool has_tpidr2 + =3D 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 +=3D tls_register_count; + } + else + { + warning (_("Provided TLS register feature doesn't contain " + "required tpidr register.")); + return nullptr; + } } =20 /* Add the pauth registers. */ @@ -3675,7 +3708,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struc= t gdbarch_list *arches) tdep->pauth_reg_base =3D first_pauth_regnum; tdep->ra_sign_state_regnum =3D -1; tdep->mte_reg_base =3D first_mte_regnum; - tdep->tls_regnum =3D tls_regnum; + tdep->tls_regnum_base =3D first_tls_regnum; + tdep->tls_register_count =3D tls_register_count; =20 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 !=3D -1; } =20 - /* TLS register. This is -1 if the TLS register is not available. */ - int tls_regnum =3D 0; + /* TLS registers. This is -1 if the TLS registers are not available. */ + int tls_regnum_base =3D 0; + int tls_register_count =3D 0; =20 bool has_tls() const { - return tls_regnum !=3D -1; + return tls_regnum_base !=3D -1; } =20 /* 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 =3D create_feature_aarch64_mte (tdesc.get (), regnum); =20 - if (features.tls) - regnum =3D create_feature_aarch64_tls (tdesc.get (), regnum); + /* TLS registers. */ + if (features.tls > 0) + regnum =3D create_feature_aarch64_tls (tdesc.get (), regnum, features.= tls); =20 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 =20 bool pauth =3D false; bool mte =3D false; - bool tls =3D false; + + /* A positive TLS value indicates the number of TLS registers available.= */ + uint8_t tls =3D 0; }; =20 inline bool operator=3D=3D(const aarch64_features &lhs, const aarch64_feat= ures &rhs) @@ -56,7 +58,9 @@ namespace std h =3D features.vq; h =3D h << 1 | features.pauth; h =3D h << 1 | features.mte; - h =3D h << 1 | features.tls; + /* Shift by two bits for now. We may need to increase this in the f= uture + if more TLS registers get added. */ + h =3D h << 2 | features.tls; return h; } }; @@ -96,7 +100,9 @@ enum aarch64_regnum AARCH64_LAST_V_ARG_REGNUM =3D AARCH64_V0_REGNUM + 7 }; =20 -#define V_REGISTER_SIZE 16 +/* Sizes of various AArch64 registers. */ +#define AARCH64_TLS_REGISTER_SIZE 8 +#define V_REGISTER_SIZE 16 =20 /* 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 =20 -#define AARCH64_TLS_REGS_SIZE (8) - /* There are a number of ways of expressing the current SVE vector size: =20 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 =3D 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 . = */ =20 #include "gdbsupport/tdesc.h" =20 +/* 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 c= ount) { + /* TPIDR is always present. */ + gdb_assert (count >=3D 1); + struct tdesc_feature *feature; =20 feature =3D 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 @@ - - - - - - - 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, =20 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 =3D tls_regs; + iovec.iov_len =3D 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) !=3D 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_prochand= le *ph, lwpid_t lwpid, int idx, void **base, int is_64bit_p); =20 +/* 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, co= nst void *buf) static void aarch64_fill_tlsregset (struct regcache *regcache, void *buf) { + gdb_byte *tls_buf =3D (gdb_byte *) buf; int tls_regnum =3D find_regno (regcache->tdesc, "tpidr"); =20 - collect_register (regcache, tls_regnum, buf); + collect_register (regcache, tls_regnum, tls_buf); + + /* Read TPIDR2, if it exists. */ + gdb::optional regnum =3D find_regno_no_throw (regcache->tdesc, "tpi= dr2"); + + if (regnum.has_value ()) + collect_register (regcache, *regnum, tls_buf + sizeof (uint64_t)); } =20 /* Store TLS register to regcache. */ @@ -302,9 +309,16 @@ aarch64_fill_tlsregset (struct regcache *regcache, voi= d *buf) static void aarch64_store_tlsregset (struct regcache *regcache, const void *buf) { + gdb_byte *tls_buf =3D (gdb_byte *) buf; int tls_regnum =3D find_regno (regcache->tdesc, "tpidr"); =20 - supply_register (regcache, tls_regnum, buf); + supply_register (regcache, tls_regnum, tls_buf); + + /* Write TPIDR2, if it exists. */ + gdb::optional regnum =3D find_regno_no_throw (regcache->tdesc, "tpi= dr2"); + + if (regnum.has_value ()) + supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t)); } =20 bool @@ -795,8 +809,8 @@ aarch64_adjust_register_sets (const struct aarch64_feat= ures &features) regset->size =3D AARCH64_LINUX_SIZEOF_MTE; break; case NT_ARM_TLS: - if (features.tls) - regset->size =3D AARCH64_TLS_REGS_SIZE; + if (features.tls > 0) + regset->size =3D 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 =3D linux_get_hwcap (8) & AARCH64_HWCAP_PACA; /* A-profile MTE is 64-bit only. */ features.mte =3D linux_get_hwcap2 (8) & HWCAP2_MTE; - features.tls =3D true; + features.tls =3D aarch64_tls_register_count (tid); =20 current_process ()->tdesc =3D aarch64_linux_read_description (featur= es); =20 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, cha= r *buf) hex2bin (buf, registers, len / 2); } =20 -int -find_regno (const struct target_desc *tdesc, const char *name) +/* See regcache.h */ + +gdb::optional +find_regno_no_throw (const struct target_desc *tdesc, const char *name) { for (int i =3D 0; i < tdesc->reg_defs.size (); ++i) { if (strcmp (name, find_register_by_number (tdesc, i).name) =3D=3D 0) return i; } - internal_error ("Unknown register %s requested", - name); + return {}; +} + +int +find_regno (const struct target_desc *tdesc, const char *name) +{ + gdb::optional regnum =3D find_regno_no_throw (tdesc, name); + + if (regnum.has_value ()) + return *regnum; + + internal_error ("Unknown register %s requested", name); } =20 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 *tde= sc); =20 int register_size (const struct target_desc *tdesc, int n); =20 +/* No throw version of find_regno. If NAME is not a known register, return + an empty value. */ +gdb::optional find_regno_no_throw (const struct target_desc *tdesc, + const char *name); + int find_regno (const struct target_desc *tdesc, const char *name); =20 void supply_register (struct regcache *regcache, int n, const void *buf);