From: Luis Machado Date: Thu, 28 Jul 2022 01:09:04 +0000 (+0100) Subject: Improve Morello feature detection X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e8424a874d37006e239664b6fbff3c6980e68ab7;p=thirdparty%2Fbinutils-gdb.git Improve Morello feature detection Given HWCAP2_MORELLO changed for Linux Kernel 5.18, this breaks Morello GDB's heuristic for detecting the Morello feature. When possible, switch to detecting the Morello feature through the availability of the NT_ARM_MORELLO register set (which means PTRACE_PEEKCAP and PTRACE_POKECAP are also available). For corefiles, switch to using the presence of the Morello register set section. For extended-remote mode, check for the two possible values of HWCAP2_MORELLO. --- diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index d5cf037d47b..dc9ca2d313d 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -765,9 +765,9 @@ aarch64_linux_nat_target::read_description () return aarch32_read_description (); CORE_ADDR hwcap = linux_get_hwcap (this); - CORE_ADDR hwcap2 = linux_get_hwcap2 (this); bool pauth_p = hwcap & AARCH64_HWCAP_PACA; - bool capability_p = hwcap2 & HWCAP2_MORELLO; + /* We cannot use HWCAP2_MORELLO to check for Morello support. */ + bool capability_p = aarch64_supports_morello (tid); return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, capability_p); diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 06497e29161..07b61610524 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -767,9 +767,11 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, struct target_ops *target, bfd *abfd) { CORE_ADDR hwcap = linux_get_hwcap (target); - CORE_ADDR hwcap2 = linux_get_hwcap2 (target); bool pauth_p = hwcap & AARCH64_HWCAP_PACA; - bool capability_p = hwcap2 & HWCAP2_MORELLO; + /* We cannot use HWCAP2_MORELLO to check for Morello support. Check if + we have a NT_ARM_MORELLO register set dump instead. */ + bool capability_p = + (bfd_get_section_by_name (abfd, ".reg-aarch-morello") != nullptr); return aarch64_read_description (aarch64_linux_core_read_vq (gdbarch, abfd), pauth_p, capability_p); diff --git a/gdb/arch/aarch64-cap-linux.h b/gdb/arch/aarch64-cap-linux.h index 0c8fe2d9d55..83b9d33cffc 100644 --- a/gdb/arch/aarch64-cap-linux.h +++ b/gdb/arch/aarch64-cap-linux.h @@ -20,8 +20,15 @@ #ifndef ARCH_AARCH64_CAP_LINUX_H #define ARCH_AARCH64_CAP_LINUX_H -/* Morello HWCAP bit. */ -#define HWCAP2_MORELLO (1 << 19) +#include "gdbsupport/common-defs.h" +#include "gdbsupport/byte-vector.h" + +/* The HWCAP values are not being used to identify Morello anymore, but are + kept here for reference in case someone has a need for them. */ +/* Morello HWCAP bit V1, before Linux Kernel 5.18. */ +#define HWCAP2_MORELLO_V1 (1 << 19) +/* Morello HWCAP bit V2, after Linux Kernel 5.18. */ +#define HWCAP2_MORELLO_V2 (1UL << 31) /* Size of the Capability register set. */ #define AARCH64_LINUX_CREGS_SIZE ((39 * 16) + (2 * 8)) diff --git a/gdb/nat/aarch64-cap-linux.c b/gdb/nat/aarch64-cap-linux.c index 62a4dcdff72..cff76de909a 100644 --- a/gdb/nat/aarch64-cap-linux.c +++ b/gdb/nat/aarch64-cap-linux.c @@ -18,6 +18,8 @@ #include "gdbsupport/common-defs.h" #include "gdb_ptrace.h" #include "aarch64-cap-linux.h" +#include +#include "elf/common.h" /* Helper function to display various possible errors when reading Morello capabilities from memory. */ @@ -98,3 +100,22 @@ aarch64_linux_write_capability (int tid, CORE_ADDR address, return true; } + +/* See aach64-cap-linux.h */ + +bool +aarch64_supports_morello (int tid) +{ + struct user_morello_state cregset; + struct iovec iovec; + iovec.iov_base = &cregset; + iovec.iov_len = sizeof (cregset); + + /* Attempt to fetch NT_ARM_MORELLO. If it is supported, that means Morello + features are supported and that PTRACE_PEEKCAP and PTRACE_POKECAP are + also supported. */ + if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_MORELLO, &iovec) < 0) + return false; + + return true; +} diff --git a/gdb/nat/aarch64-cap-linux.h b/gdb/nat/aarch64-cap-linux.h index ff38bccaf6e..8adfb9bfb39 100644 --- a/gdb/nat/aarch64-cap-linux.h +++ b/gdb/nat/aarch64-cap-linux.h @@ -72,4 +72,14 @@ extern bool aarch64_linux_read_capability (int tid, CORE_ADDR address, extern bool aarch64_linux_write_capability (int tid, CORE_ADDR address, const user_cap &cap); + +/* Return true if the target supports Morello features (NT_ARM_MORELLO register + set, PTRACE_PEEKCAP and PTRACE_POKECAP). If it does, it means we are + dealing with a Morello Linux Kernel. This is needed because we can't + rely on the HWCAP2_MORELLO value anymore, given it has changed. + + Return false otherwise. */ + +extern bool aarch64_supports_morello (int tid); + #endif /* NAT_AARCH64_CAP_LINUX_H */ diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c index 5335d690922..766ddc0dbd1 100644 --- a/gdb/nat/linux-ptrace.c +++ b/gdb/nat/linux-ptrace.c @@ -81,8 +81,8 @@ EXTERN_C void linux_ptrace_test_ret_to_nx_instr (void); /* Kill CHILD. WHO is used to report warnings. */ -static void -kill_child (pid_t child, const char *who) +void +linux_kill_child (pid_t child, const char *who) { pid_t got_pid; int kill_status; @@ -202,7 +202,7 @@ linux_ptrace_test_ret_to_nx (void) { warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"), status); - kill_child (child, "linux_ptrace_test_ret_to_nx"); + linux_kill_child (child, "linux_ptrace_test_ret_to_nx"); return; } @@ -212,7 +212,7 @@ linux_ptrace_test_ret_to_nx (void) warning (_("linux_ptrace_test_ret_to_nx: " "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"), (int) WSTOPSIG (status)); - kill_child (child, "linux_ptrace_test_ret_to_nx"); + linux_kill_child (child, "linux_ptrace_test_ret_to_nx"); return; } @@ -230,7 +230,7 @@ linux_ptrace_test_ret_to_nx (void) # error "!__i386__ && !__x86_64__" #endif - kill_child (child, "linux_ptrace_test_ret_to_nx"); + linux_kill_child (child, "linux_ptrace_test_ret_to_nx"); /* + 1 is there as x86* stops after the 'int3' instruction. */ if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1) @@ -336,10 +336,10 @@ static void linux_test_for_tracesysgood (int child_pid); static void linux_test_for_tracefork (int child_pid); static void linux_test_for_exitkill (int child_pid); -/* Determine ptrace features available on this target. */ +/* Create a child for testing ptrace features and return its pid. */ -void -linux_check_ptrace_features (void) +int +linux_create_child_for_ptrace_testing () { int child_pid, ret, status; @@ -362,6 +362,17 @@ linux_check_ptrace_features (void) error (_("linux_check_ptrace_features: waitpid: unexpected status %d."), status); + return child_pid; +} + + +/* Determine ptrace features available on this target. */ + +void +linux_check_ptrace_features (void) +{ + int child_pid = linux_create_child_for_ptrace_testing (); + linux_test_for_tracesysgood (child_pid); linux_test_for_tracefork (child_pid); @@ -369,7 +380,7 @@ linux_check_ptrace_features (void) linux_test_for_exitkill (child_pid); /* Kill child_pid. */ - kill_child (child_pid, "linux_check_ptrace_features"); + linux_kill_child (child_pid, "linux_check_ptrace_features"); } /* Determine if PTRACE_O_TRACESYSGOOD can be used to catch @@ -452,7 +463,7 @@ linux_test_for_tracefork (int child_pid) /* Do some cleanup and kill the grandchild. */ my_waitpid (second_pid, &second_status, 0); - kill_child (second_pid, "linux_test_for_tracefork"); + linux_kill_child (second_pid, "linux_test_for_tracefork"); } } else diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h index 65568301f22..5481ee8a3f1 100644 --- a/gdb/nat/linux-ptrace.h +++ b/gdb/nat/linux-ptrace.h @@ -195,5 +195,6 @@ extern int linux_supports_tracesysgood (void); extern int linux_ptrace_get_extended_event (int wstat); extern int linux_is_extended_waitstatus (int wstat); extern int linux_wstatus_maybe_breakpoint (int wstat); - +extern void linux_kill_child (pid_t child, const char *who); +extern int linux_create_child_for_ptrace_testing (); #endif /* NAT_LINUX_PTRACE_H */ diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc index 1f63e8dda34..3d7f3235eb7 100644 --- a/gdbserver/linux-aarch64-low.cc +++ b/gdbserver/linux-aarch64-low.cc @@ -830,9 +830,9 @@ aarch64_target::low_arch_setup () { uint64_t vq = aarch64_sve_get_vq (tid); unsigned long hwcap = linux_get_hwcap (); - unsigned long hwcap2 = linux_get_hwcap2 (); bool pauth_p = hwcap & AARCH64_HWCAP_PACA; - bool capability_p = hwcap2 & HWCAP2_MORELLO; + /* We cannot use HWCAP2_MORELLO to check for Morello support. */ + bool capability_p = aarch64_supports_morello (tid); current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p, capability_p); @@ -3385,14 +3385,24 @@ aarch64_target::breakpoint_kind_from_current_state (CORE_ADDR *pcptr) return arm_breakpoint_kind_from_current_state (pcptr); } +static bool +aarch64_supports_morello_features () +{ + /* Spawn a child for testing. */ + int child_pid = linux_create_child_for_ptrace_testing (); + bool ret = aarch64_supports_morello (child_pid); + /* Kill child_pid. */ + linux_kill_child (child_pid, "aarch64_check_ptrace_features"); + return ret; +} + /* Implementation of targets ops method "supports_qxfer_capability. */ bool aarch64_target::supports_qxfer_capability () { - unsigned long hwcap2 = linux_get_hwcap2 (); - - return (hwcap2 & HWCAP2_MORELLO) != 0; + /* Do a live ptrace feature check instead of using HWCAP bits. */ + return aarch64_supports_morello_features (); } /* Implementation of targets ops method "qxfer_capability. */