diff options
Diffstat (limited to 'gdb/amd64-linux-tdep.c')
-rw-r--r-- | gdb/amd64-linux-tdep.c | 124 |
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); |