mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-25 16:57:52 +00:00
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.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "gdbsupport/common-defs.h"
|
||||
#include "gdb_ptrace.h"
|
||||
#include "aarch64-cap-linux.h"
|
||||
#include <sys/uio.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user