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.c124
1 files changed, 113 insertions, 11 deletions
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index d7662ca..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"
@@ -43,6 +46,7 @@
#include "target-descriptions.h"
#include "expop.h"
#include "arch/amd64-linux-tdesc.h"
+#include "inferior.h"
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
@@ -50,6 +54,10 @@
#include "record-full.h"
#include "linux-record.h"
+#include <string_view>
+
+#define DEFAULT_TAG_MASK 0xffffffffffffffffULL
+
/* Mapping between the general-purpose registers in `struct user'
format and GDB's register cache layout. */
@@ -86,6 +94,8 @@ int amd64_linux_gregset_reg_offset[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
+ /* MPX is deprecated. Yet we keep this to not give the registers below
+ a new number. That could break older gdbservers. */
-1, -1, -1, -1, /* MPX registers BND0 ... BND3. */
-1, -1, /* MPX registers BNDCFGU and BNDSTATUS. */
-1, -1, -1, -1, -1, -1, -1, -1, /* xmm16 ... xmm31 (AVX512) */
@@ -405,7 +415,7 @@ amd64_canonicalize_syscall (enum amd64_syscall syscall_number)
case amd64_sys_mmap:
case amd64_x32_sys_mmap:
- return gdb_sys_mmap2;
+ return gdb_sys_old_mmap;
case amd64_sys_mprotect:
case amd64_x32_sys_mprotect:
@@ -549,6 +559,10 @@ amd64_canonicalize_syscall (enum amd64_syscall syscall_number)
case amd64_x32_sys_accept:
return gdb_sys_accept;
+ case amd64_sys_accept4:
+ case amd64_x32_sys_accept4:
+ return gdb_sys_accept4;
+
case amd64_sys_sendto:
case amd64_x32_sys_sendto:
return gdb_sys_sendto;
@@ -1765,6 +1779,95 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
}
}
+/* Extract the untagging mask based on the currently active linear address
+ masking (LAM) mode, which is stored in the /proc/<pid>/status file.
+ If we cannot extract the untag mask (for example, if we don't have
+ execution), we assume address tagging is not enabled and return the
+ DEFAULT_TAG_MASK. */
+
+static CORE_ADDR
+amd64_linux_lam_untag_mask ()
+{
+ if (!target_has_execution ())
+ return DEFAULT_TAG_MASK;
+
+ inferior *inf = current_inferior ();
+ if (inf->fake_pid_p)
+ return DEFAULT_TAG_MASK;
+
+ const std::string filename = string_printf ("/proc/%d/status", inf->pid);
+ gdb::unique_xmalloc_ptr<char> status_file
+ = target_fileio_read_stralloc (nullptr, filename.c_str ());
+
+ if (status_file == nullptr)
+ return DEFAULT_TAG_MASK;
+
+ std::string_view status_file_view (status_file.get ());
+ constexpr std::string_view untag_mask_str = "untag_mask:\t";
+ const size_t found = status_file_view.find (untag_mask_str);
+ if (found != std::string::npos)
+ {
+ const char* start = status_file_view.data() + found
+ + untag_mask_str.length ();
+ char* endptr;
+ errno = 0;
+ unsigned long long result = std::strtoul (start, &endptr, 0);
+ if (errno != 0 || endptr == start)
+ error (_("Failed to parse untag_mask from file %s."),
+ std::string (filename).c_str ());
+
+ return result;
+ }
+
+ return DEFAULT_TAG_MASK;
+}
+
+/* Adjust watchpoint address based on the currently active linear address
+ masking (LAM) mode using the untag mask. Check each time for a new
+ mask, as LAM is enabled at runtime. */
+
+static CORE_ADDR
+amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
+ CORE_ADDR addr)
+{
+ /* Clear insignificant bits of a target address using the untag
+ mask. */
+ 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)
@@ -1795,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);
@@ -1817,8 +1923,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);
- set_gdbarch_get_siginfo_type (gdbarch, x86_linux_get_siginfo_type);
- set_gdbarch_report_signal_info (gdbarch, i386_linux_report_signal_info);
+ set_gdbarch_remove_non_address_bits_watchpoint
+ (gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
}
static void
@@ -2025,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);
@@ -2239,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);