From patchwork Fri Oct 25 02:26:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Buettner X-Patchwork-Id: 99523 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9A5483858423 for ; Fri, 25 Oct 2024 03:38:20 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id DC23B3858C53 for ; Fri, 25 Oct 2024 03:35:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DC23B3858C53 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DC23B3858C53 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729827319; cv=none; b=Z8KWqocPKoQx9JWJUSRr9XcP4vytLfas4Vzb9+CXbPmRiKlKfOOuL9OyvDLj+RJsP7Mvj/iw8qoSPQZlNjlP8jcCMRExUXIe7LvCzGluWSc4nXIcdeHSgbGqLoMp4RUdWQTWebCfO+cHCeurZ45wwytAk9QGzOKcbxvbk+2gwU8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729827319; c=relaxed/simple; bh=E9qwXdyo9iqcuCUnrjF2p+I3/O/JfxIs8lNqa6ntaEg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Y+DzBpzYgG2sFOSEdZv9ksUlfgXSVk1Po1mSvGCsq8oN4Ixln9QRNFPMhRV8aFYybnj5+snIQOIzKNdNSu8E9S9nVZj/Y3pdpAgGwwcNn/cCMXfkWh7eZcNpUAeAIQn5MFn+TYm9KE8Emsz6ItUuz10o8Qfd3+qM5Cey2oqoEqQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729827308; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0i/w5Vbpc23AnxbFg15QXqxTs+MJG/1c55biK/4pL1E=; b=KFW2UNbVKanJ5O/qi4tWWtDKFE+iMGn7uelpCFAEeeN1x+KswsdG0t7pYKDvGguO2/2nOj rB0bECVuNLujj15AsKnNFiWpfNSfQtvS1A44oLyx+60XE4wfXosKQEk15D4DdXaj12lnC0 pzFoLn32NL5N1Mk3F0uI5ME5oqfvlWc= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-116-Cmbog7RvOXikIiTcxDhreQ-1; Thu, 24 Oct 2024 23:35:07 -0400 X-MC-Unique: Cmbog7RvOXikIiTcxDhreQ-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0B1E51955F43; Fri, 25 Oct 2024 03:35:06 +0000 (UTC) Received: from f41-1.lan (unknown [10.22.64.38]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 62705300018D; Fri, 25 Oct 2024 03:35:04 +0000 (UTC) From: Kevin Buettner To: gdb-patches@sourceware.org Cc: Kevin Buettner , Luis Machado Subject: [PATCH v3 05/11] Internal TLS support for aarch64, x86_64, riscv, ppc64, and s390x Date: Thu, 24 Oct 2024 19:26:23 -0700 Message-ID: <20241025033431.36274-6-kevinb@redhat.com> In-Reply-To: <20241025033431.36274-1-kevinb@redhat.com> References: <20241025033431.36274-1-kevinb@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org For each architecture, aarch64, x86_64, riscv, ppc64, and s390x, this commit defines a suitable 'get_tls_dtv_addr' method and, when necessary, a 'get_tls_dtp_offset' method. It also registers linux_get_thread_local_address, defined in linux-tdep.c (in an earlier commit), as the get_thread_local_address gdbarch method. It also registers its architecture specific code using linux_register_tls_methods(). Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=24548 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31563 Reviewed-By: Luis Machado --- gdb/aarch64-linux-tdep.c | 55 ++++++++++++++++++++++++++++ gdb/amd64-linux-tdep.c | 37 +++++++++++++++++++ gdb/ppc-linux-tdep.c | 62 ++++++++++++++++++++++++++++++++ gdb/riscv-linux-tdep.c | 78 ++++++++++++++++++++++++++++++++++++++++ gdb/s390-linux-tdep.c | 43 ++++++++++++++++++++++ 5 files changed, 275 insertions(+) diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index c608a84bc71..89423a233f2 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -35,6 +35,7 @@ #include "target/target.h" #include "expop.h" #include "auxv.h" +#include "inferior.h" #include "regcache.h" #include "regset.h" @@ -2693,6 +2694,57 @@ aarch64_use_target_description_from_corefile_notes (gdbarch *gdbarch, return true; } +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +aarch64_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + linux_libc libc) +{ + /* On aarch64, the thread pointer is found in the TPIDR register. + Note that this is the first register in the TLS feature - see + features/aarch64-tls.c - and it will always be present. */ + regcache *regcache + = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + target_fetch_registers (regcache, tdep->tls_regnum_base); + ULONGEST thr_ptr; + if (regcache->cooked_read (tdep->tls_regnum_base, &thr_ptr) != REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + + CORE_ADDR dtv_ptr_addr; + switch (libc) + { + case linux_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 = thr_ptr - (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + break; + case linux_libc_glibc: + /* GLIBC: The thread pointer (tpidr) points at the TCB (thread control + block). On aarch64, 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 the same as the thread pointer. */ + dtv_ptr_addr = thr_ptr; + break; + default: + throw_error (TLS_GENERIC_ERROR, _("Unknown aarch64 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 ()) != 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR dtv_addr = gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + static void aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -2714,6 +2766,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + set_gdbarch_get_thread_local_address (gdbarch, + linux_get_thread_local_address); + linux_register_tls_methods (info, gdbarch, aarch64_linux_get_tls_dtv_addr); /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 77de8211d86..7512448d987 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -34,6 +34,7 @@ #include "i386-linux-tdep.h" #include "linux-tdep.h" #include "gdbsupport/x86-xstate.h" +#include "inferior.h" #include "amd64-tdep.h" #include "solib-svr4.h" @@ -1767,6 +1768,39 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch, } } +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +amd64_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + enum linux_libc libc) +{ + /* On x86-64, the thread pointer is found in the fsbase register. */ + regcache *regcache + = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + target_fetch_registers (regcache, AMD64_FSBASE_REGNUM); + ULONGEST fsbase; + if (regcache->cooked_read (AMD64_FSBASE_REGNUM, &fsbase) != REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + + /* The thread pointer (fsbase) points at the TCB (thread control + block). The first two members of this struct are both pointers, + where the first will be a pointer to the TCB (i.e. it points at + itself) and the second will be a pointer to the DTV (dynamic + thread vector). There are many other fields too, but the one + we care about here is the DTV pointer. Compute the address + of the DTV pointer, fetch it, and convert it to an address. */ + CORE_ADDR dtv_ptr_addr = fsbase + gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; + gdb::byte_vector buf (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + if (target_read_memory (dtv_ptr_addr, buf.data (), buf.size ()) != 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR dtv_addr = gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + static void amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, int num_disp_step_buffers) @@ -1797,6 +1831,9 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + set_gdbarch_get_thread_local_address (gdbarch, + linux_get_thread_local_address); + linux_register_tls_methods (info, gdbarch, amd64_linux_get_tls_dtv_addr); /* GNU/Linux uses SVR4-style shared libraries. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 8a5eea765c2..42a4bc71263 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -2070,6 +2070,63 @@ ppc64_linux_gcc_target_options (struct gdbarch *gdbarch) return ""; } +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +ppc64_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + enum linux_libc libc) +{ + /* On ppc64, the thread pointer is found in r13. Fetch this + register. */ + regcache *regcache + = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + int thread_pointer_regnum = PPC_R0_REGNUM + 13; + target_fetch_registers (regcache, thread_pointer_regnum); + ULONGEST thr_ptr; + if (regcache->cooked_read (thread_pointer_regnum, &thr_ptr) != REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + + /* The thread pointer (r13) is an address that is 0x7000 ahead of + the *end* of the TCB (thread control block). The field + holding the DTV address is at the very end of the TCB. + Therefore, the DTV pointer address can be found by + subtracting (0x7000+8) from the thread pointer. Compute the + address of the DTV pointer, fetch it, and convert it to an + address. */ + CORE_ADDR dtv_ptr_addr = thr_ptr - 0x7000 - 8; + gdb::byte_vector buf (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + if (target_read_memory (dtv_ptr_addr, buf.data (), buf.size ()) != 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR dtv_addr = gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + +/* For internal TLS lookup, return the DTP offset, which is the offset + to subtract from a DTV entry, in order to obtain the address of the + TLS block. */ + +static ULONGEST +ppc_linux_get_tls_dtp_offset (struct gdbarch *gdbarch, ptid_t ptid, + linux_libc libc) +{ + if (libc == linux_libc_musl) + { + /* This value is DTP_OFFSET, which represents the value to + subtract from the DTV entry. For PPC, it can be found in + MUSL's arch/powerpc64/pthread_arch.h and + arch/powerpc32/pthread_arch.h. (Both values are the same.) + It represents the value to subtract from the DTV entry, once + it has been fetched from the DTV array. */ + return 0x8000; + } + else + return 0; +} + static displaced_step_prepare_status ppc_linux_displaced_step_prepare (gdbarch *arch, thread_info *thread, CORE_ADDR &displaced_pc) @@ -2283,6 +2340,11 @@ ppc_linux_init_abi (struct gdbarch_info info, set_gdbarch_gnu_triplet_regexp (gdbarch, ppc64_gnu_triplet_regexp); /* Set GCC target options. */ set_gdbarch_gcc_target_options (gdbarch, ppc64_linux_gcc_target_options); + /* Internal thread local address support. */ + set_gdbarch_get_thread_local_address (gdbarch, + linux_get_thread_local_address); + linux_register_tls_methods (info, gdbarch, ppc64_linux_get_tls_dtv_addr, + ppc_linux_get_tls_dtp_offset); } set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description); diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c index ff478cf4c28..31d90a32ce4 100644 --- a/gdb/riscv-linux-tdep.c +++ b/gdb/riscv-linux-tdep.c @@ -25,6 +25,7 @@ #include "tramp-frame.h" #include "trad-frame.h" #include "gdbarch.h" +#include "inferior.h" /* The following value is derived from __NR_rt_sigreturn in from the Linux source tree. */ @@ -173,6 +174,79 @@ riscv_linux_syscall_next_pc (const frame_info_ptr &frame) return pc + 4 /* Length of the ECALL insn. */; } +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +riscv_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + linux_libc libc) +{ + /* On RISC-V, the thread pointer is found in TP. */ + regcache *regcache + = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + int thread_pointer_regnum = RISCV_TP_REGNUM; + target_fetch_registers (regcache, thread_pointer_regnum); + ULONGEST thr_ptr; + if (regcache->cooked_read (thread_pointer_regnum, &thr_ptr) != REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + + CORE_ADDR dtv_ptr_addr; + switch (libc) + { + case linux_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 + = thr_ptr - (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + break; + case linux_libc_glibc: + /* GLIBC: The thread pointer (TP) points just beyond the end of + the TCB (thread control block). On RISC-V, 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 16 bytes (i.e. the size of + two pointers) before thread pointer. */ + + dtv_ptr_addr + = thr_ptr - 2 * (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + break; + default: + throw_error (TLS_GENERIC_ERROR, _("Unknown RISC-V 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 ()) != 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR dtv_addr = gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + +/* For internal TLS lookup, return the DTP offset, which is the offset + to subtract from a DTV entry, in order to obtain the address of the + TLS block. */ + +static ULONGEST +riscv_linux_get_tls_dtp_offset (struct gdbarch *gdbarch, ptid_t ptid, + linux_libc libc) +{ + if (libc == linux_libc_musl) + { + /* This value is DTP_OFFSET in MUSL's arch/riscv64/pthread_arch.h. + It represents the value to subtract from the DTV entry, once + it has been loaded. */ + return 0x800; + } + else + return 0; +} + /* Initialize RISC-V Linux ABI info. */ static void @@ -198,6 +272,10 @@ riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + set_gdbarch_get_thread_local_address (gdbarch, + linux_get_thread_local_address); + linux_register_tls_methods (info, gdbarch, riscv_linux_get_tls_dtv_addr, + riscv_linux_get_tls_dtp_offset); set_gdbarch_iterate_over_regset_sections (gdbarch, riscv_linux_iterate_over_regset_sections); diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c index bc1db550d2e..17055d9f7b5 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -40,6 +40,7 @@ #include "target.h" #include "trad-frame.h" #include "xml-syscall.h" +#include "inferior.h" #include "features/s390-linux32v1.c" #include "features/s390-linux32v2.c" @@ -1123,6 +1124,45 @@ s390_init_linux_record_tdep (struct linux_record_tdep *record_tdep, record_tdep->ioctl_FIOQSIZE = 0x545e; } +/* Fetch and return the TLS DTV (dynamic thread vector) address for PTID. + Throw a suitable TLS error if something goes wrong. */ + +static CORE_ADDR +s390_linux_get_tls_dtv_addr (struct gdbarch *gdbarch, ptid_t ptid, + enum linux_libc libc) +{ + /* On S390, the thread pointer is found in two registers A0 and A1 + (or, using gdb naming, acr0 and acr1) A0 contains the top 32 + bits of the address and A1 contains the bottom 32 bits. */ + regcache *regcache + = get_thread_arch_regcache (current_inferior (), ptid, gdbarch); + target_fetch_registers (regcache, S390_A0_REGNUM); + target_fetch_registers (regcache, S390_A1_REGNUM); + ULONGEST thr_ptr_lo, thr_ptr_hi, thr_ptr; + if (regcache->cooked_read (S390_A0_REGNUM, &thr_ptr_hi) != REG_VALID + || regcache->cooked_read (S390_A1_REGNUM, &thr_ptr_lo) != REG_VALID) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch thread pointer")); + thr_ptr = (thr_ptr_hi << 32) + thr_ptr_lo; + + /* The thread pointer points at the TCB (thread control block). The + first two members of this struct are both pointers, where the + first will be a pointer to the TCB (i.e. it points at itself) + and the second will be a pointer to the DTV (dynamic thread + vector). There are many other fields too, but the one we care + about here is the DTV pointer. Compute the address of the DTV + pointer, fetch it, and convert it to an address. */ + CORE_ADDR dtv_ptr_addr + = thr_ptr + gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; + gdb::byte_vector buf (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + if (target_read_memory (dtv_ptr_addr, buf.data (), buf.size ()) != 0) + throw_error (TLS_GENERIC_ERROR, _("Unable to fetch DTV address")); + + const struct builtin_type *builtin = builtin_type (gdbarch); + CORE_ADDR dtv_addr = gdbarch_pointer_to_address + (gdbarch, builtin->builtin_data_ptr, buf.data ()); + return dtv_addr; +} + /* Initialize OSABI common for GNU/Linux on 31- and 64-bit systems. */ static void @@ -1151,6 +1191,9 @@ s390_linux_init_abi_any (struct gdbarch_info info, struct gdbarch *gdbarch) /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + set_gdbarch_get_thread_local_address (gdbarch, + linux_get_thread_local_address); + linux_register_tls_methods (info, gdbarch, s390_linux_get_tls_dtv_addr); /* Support reverse debugging. */ set_gdbarch_process_record_signal (gdbarch, s390_linux_record_signal);