aboutsummaryrefslogtreecommitdiff
path: root/gdb/amd64-linux-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/amd64-linux-tdep.c')
-rw-r--r--gdb/amd64-linux-tdep.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index a7868c3..13e9c0e 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1,6 +1,6 @@
/* Target-dependent code for GNU/Linux x86-64.
- Copyright (C) 2001-2024 Free Software Foundation, Inc.
+ Copyright (C) 2001-2025 Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
This file is part of GDB.
@@ -33,7 +33,10 @@
#include "amd64-linux-tdep.h"
#include "i386-linux-tdep.h"
#include "linux-tdep.h"
+#include "solib-svr4-linux.h"
+#include "svr4-tls-tdep.h"
#include "gdbsupport/x86-xstate.h"
+#include "inferior.h"
#include "amd64-tdep.h"
#include "solib-svr4.h"
@@ -1832,6 +1835,39 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
return (addr & amd64_linux_lam_untag_mask ());
}
+/* 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 svr4_tls_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)
@@ -1862,6 +1898,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,
+ svr4_tls_get_thread_local_address);
+ svr4_tls_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);
@@ -2092,8 +2131,7 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->i386_syscall_record = amd64_linux_syscall_record;
/* GNU/Linux uses SVR4-style shared libraries. */
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, linux_lp64_fetch_link_map_offsets);
+ set_solib_svr4_ops (gdbarch, make_linux_lp64_svr4_solib_ops);
/* Register DTrace handlers. */
set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
@@ -2306,13 +2344,10 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->i386_syscall_record = amd64_x32_linux_syscall_record;
/* GNU/Linux uses SVR4-style shared libraries. */
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, linux_ilp32_fetch_link_map_offsets);
+ set_solib_svr4_ops (gdbarch, make_linux_ilp32_svr4_solib_ops);
}
-void _initialize_amd64_linux_tdep ();
-void
-_initialize_amd64_linux_tdep ()
+INIT_GDB_FILE (amd64_linux_tdep)
{
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_LINUX, amd64_linux_init_abi);