diff options
Diffstat (limited to 'gdb/aarch64-linux-tdep.c')
-rw-r--r-- | gdb/aarch64-linux-tdep.c | 103 |
1 files changed, 83 insertions, 20 deletions
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 2d156ad..dd35eaf 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux AArch64. - Copyright (C) 2009-2024 Free Software Foundation, Inc. + Copyright (C) 2009-2025 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GDB. @@ -23,7 +23,9 @@ #include "extract-store-integer.h" #include "gdbarch.h" #include "glibc-tdep.h" +#include "solib-svr4-linux.h" #include "linux-tdep.h" +#include "svr4-tls-tdep.h" #include "aarch64-tdep.h" #include "aarch64-linux-tdep.h" #include "osabi.h" @@ -35,6 +37,7 @@ #include "target/target.h" #include "expop.h" #include "auxv.h" +#include "inferior.h" #include "regcache.h" #include "regset.h" @@ -2038,11 +2041,17 @@ enum aarch64_syscall { static enum gdb_syscall aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number) { -#define SYSCALL_MAP(SYSCALL) case aarch64_sys_##SYSCALL: \ - return gdb_sys_##SYSCALL +#define SYSCALL_MAP(SYSCALL) \ + case aarch64_sys_ ## SYSCALL: \ + return gdb_sys_ ## SYSCALL -#define UNSUPPORTED_SYSCALL_MAP(SYSCALL) case aarch64_sys_##SYSCALL: \ - return gdb_sys_no_syscall +#define SYSCALL_MAP_RENAME(SYSCALL, GDB_SYSCALL) \ + case aarch64_sys_ ## SYSCALL: \ + return GDB_SYSCALL; + +#define UNSUPPORTED_SYSCALL_MAP(SYSCALL) \ + case aarch64_sys_ ## SYSCALL: \ + return gdb_sys_no_syscall switch (syscall_number) { @@ -2269,8 +2278,7 @@ aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number) SYSCALL_MAP (clone); SYSCALL_MAP (execve); - case aarch64_sys_mmap: - return gdb_sys_mmap2; + SYSCALL_MAP_RENAME (mmap, gdb_sys_old_mmap); SYSCALL_MAP (fadvise64); SYSCALL_MAP (swapon); @@ -2291,7 +2299,7 @@ aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number) SYSCALL_MAP (move_pages); UNSUPPORTED_SYSCALL_MAP (rt_tgsigqueueinfo); UNSUPPORTED_SYSCALL_MAP (perf_event_open); - UNSUPPORTED_SYSCALL_MAP (accept4); + SYSCALL_MAP (accept4); UNSUPPORTED_SYSCALL_MAP (recvmmsg); SYSCALL_MAP (wait4); @@ -2312,9 +2320,14 @@ aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number) UNSUPPORTED_SYSCALL_MAP (sched_setattr); UNSUPPORTED_SYSCALL_MAP (sched_getattr); SYSCALL_MAP (getrandom); - default: - return gdb_sys_no_syscall; - } + + default: + return gdb_sys_no_syscall; + } + +#undef SYSCALL_MAP +#undef SYSCALL_MAP_RENAME +#undef UNSUPPORTED_SYSCALL_MAP } /* Retrieve the syscall number at a ptrace syscall-stop, either on syscall entry @@ -2587,8 +2600,8 @@ aarch64_linux_fill_memtag_section (struct gdbarch *gdbarch, asection *osec) static_cast<int> (memtag_type::allocation))) { warning (_("Failed to read MTE tags from memory range [%s,%s)."), - phex_nz (start_address, sizeof (start_address)), - phex_nz (end_address, sizeof (end_address))); + phex_nz (start_address), + phex_nz (end_address)); return false; } @@ -2691,6 +2704,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, + svr4_tls_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<aarch64_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 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 = thr_ptr - (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + break; + case svr4_tls_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) { @@ -2705,13 +2769,14 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->lowest_pc = 0x8000; linux_init_abi (info, gdbarch, 1); - - 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); /* 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, aarch64_linux_get_tls_dtv_addr); /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); @@ -2972,12 +3037,10 @@ aarch64_linux_ltag_tests (void) } } -} // namespace selftests +} /* namespace selftests */ #endif /* GDB_SELF_TEST */ -void _initialize_aarch64_linux_tdep (); -void -_initialize_aarch64_linux_tdep () +INIT_GDB_FILE (aarch64_linux_tdep) { gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX, aarch64_linux_init_abi); |