[binutils-gdb] gdb: LoongArch: Add internal TLS support
Tiezhu Yang via Gdb-cvs <[email protected]> Sat, 18 Jul 2026 11:27:59 +0000 (GMT)
| Newsgroups | gmane.comp.gdb.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D0fb12bd362c3= 87d1d8ad19616a8c4fba562a5ae3 commit 0fb12bd362c387d1d8ad19616a8c4fba562a5ae3 Author: Hui Li <[email protected]> Date: Mon Jul 13 18:37:24 2026 +0800 gdb: LoongArch: Add internal TLS support =20 Implements the LoongArch-specific get_tls_dtv_addr() and uses svr4_tls_register_tls_methods() to register it, together with svr4_tls_get_thread_local_address as the get_thread_local_address gdbarch method, to support internal TLS address lookup. =20 LoongArch doesn't need get_tls_dtp_offset since musl's DTP_OFFSET is defined as 0. =20 This is the LoongArch version of commit c34309bea22 ("Internal TLS support for aarch64, x86_64, riscv, ppc64, and s390x"). =20 Depends-On: bfc3ac0d13b ("LoongArch: Support R_LARCH_TLS_DTPREL32/64 used in debug section") =20 Before: =20 make check-gdb TESTS=3D"gdb.base/tls-nothreads.exp" =3D=3D=3D gdb Summary =3D=3D=3D =20 # of expected passes 101 # of known failures 48 =20 make check-gdb TESTS=3D"gdb.base/tls-dlobj.exp" =3D=3D=3D gdb Summary =3D=3D=3D =20 # of expected passes 261 =20 After: =20 make check-gdb TESTS=3D"gdb.base/tls-nothreads.exp" =3D=3D=3D gdb Summary =3D=3D=3D =20 # of expected passes 302 =20 make check-gdb TESTS=3D"gdb.base/tls-dlobj.exp" =3D=3D=3D gdb Summary =3D=3D=3D =20 # of expected passes 523 =20 Signed-off-by: Hui Li <[email protected]> Approved-By: Simon Marchi <[email protected]> Signed-off-by: Tiezhu Yang <[email protected]> Diff: --- gdb/arch/loongarch.h | 1 + gdb/configure.tgt | 2 +- gdb/loongarch-linux-tdep.c | 53 +++++++++++++++++++++++++++= ++++ gdb/testsuite/gdb.base/tls-common.exp.tcl | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h index ee9d378afd6..ec3d0d195c9 100644 --- a/gdb/arch/loongarch.h +++ b/gdb/arch/loongarch.h @@ -26,6 +26,7 @@ enum loongarch_regnum { LOONGARCH_RA_REGNUM =3D 1, /* Return Address. */ + LOONGARCH_TP_REGNUM =3D 2, /* Thread Pointer. */ LOONGARCH_SP_REGNUM =3D 3, /* Stack Pointer. */ LOONGARCH_A0_REGNUM =3D 4, /* First Argument/Return Value. */ LOONGARCH_A7_REGNUM =3D 11, /* Seventh Argument/Syscall Number. */ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 362de60065c..7313b31e42a 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -374,7 +374,7 @@ loongarch*-*-linux*) # Target: LoongArch running Linux gdb_target_obs=3D"loongarch-linux-tdep.o glibc-tdep.o \ linux-tdep.o solib-svr4.o solib-svr4-linux.o \ - linux-record.o" + linux-record.o svr4-tls-tdep.o" ;; =20 m32c-*-*) diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c index bab84fd126a..4879fe1954d 100644 --- a/gdb/loongarch-linux-tdep.c +++ b/gdb/loongarch-linux-tdep.c @@ -26,6 +26,7 @@ #include "linux-record.h" #include "linux-tdep.h" #include "solib-svr4-linux.h" +#include "svr4-tls-tdep.h" #include "loongarch-tdep.h" #include "record-full.h" #include "regset.h" @@ -1137,6 +1138,56 @@ init_loongarch_linux_record_tdep (struct gdbarch *gd= barch) loongarch_linux_record_tdep.arg7 =3D LOONGARCH_A0_REGNUM + 6; } =20 +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +loongarch_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + svr4_tls_libc libc) +{ + /* On LoongArch, the thread pointer is found in TP. */ + regcache *regcache + =3D get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + target_fetch_registers (regcache, LOONGARCH_TP_REGNUM); + ULONGEST thr_ptr; + if (regcache->cooked_read (LOONGARCH_TP_REGNUM, &thr_ptr) !=3D REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + + CORE_ADDR dtv_ptr_addr; + switch (libc) + { + case svr4_tls_libc_musl: + /* MUSL: The DTV pointer is found at the very end of the pthread + struct which is located *before* the thread pointer. I.e. + the thread pointer will be just beyond the end of the struct, + so the address of the DTV pointer is found one pointer-size + before the thread pointer. */ + dtv_ptr_addr =3D thr_ptr - (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + break; + case svr4_tls_libc_glibc: + /* GLIBC: The thread pointer (TP) points just beyond the end of + the TCB (thread control block). On LoongArch, this struct + (tcbhead_t) is defined to contain two pointers. The first is + a pointer to the DTV and the second is a pointer to private + data. So the DTV pointer address is found two pointer-size + before thread pointer. */ + dtv_ptr_addr =3D thr_ptr - 2 * (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_B= IT); + break; + default: + throw_error (TLS_GENERIC_ERROR, _("Unknown LoongArch C library")); + break; + } + + gdb::byte_vector buf (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + if (target_read_memory (dtv_ptr_addr, buf.data (), buf.size ()) !=3D 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin =3D builtin_type (gdbarch); + CORE_ADDR dtv_addr =3D gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + /* Initialize LoongArch Linux ABI info. */ =20 static void @@ -1158,6 +1209,8 @@ loongarch_linux_init_abi (struct gdbarch_info info, s= truct gdbarch *gdbarch) =20 /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_l= ink_map); + set_gdbarch_get_thread_local_address (gdbarch, svr4_tls_get_thread_local= _address); + svr4_tls_register_tls_methods (info, gdbarch, loongarch_linux_get_tls_dt= v_addr); =20 /* Prepend tramp frame unwinder for signal. */ tramp_frame_prepend_unwinder (gdbarch, &loongarch_linux_rt_sigframe); diff --git a/gdb/testsuite/gdb.base/tls-common.exp.tcl b/gdb/testsuite/gdb.= base/tls-common.exp.tcl index 06cab649519..53ed1ca4d8a 100644 --- a/gdb/testsuite/gdb.base/tls-common.exp.tcl +++ b/gdb/testsuite/gdb.base/tls-common.exp.tcl @@ -26,7 +26,7 @@ require {is_any_target "*-*-linux*"} =20 set internal_tls_linux_targets {"x86_64-*-linux*" "aarch64-*-linux*" "riscv*-*-linux*" "powerpc64*-*-linux*" - "s390x*-*-linux*"} + "s390x*-*-linux*" "loongarch*-*-linux*"} =20 # The "maint set force-internal-tls-address-lookup" command is only # available for certain Linux architectures. Don't attempt to force