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:
Luis Machado
2022-07-28 02:09:04 +01:00
parent 2b6368f341
commit e8424a874d
8 changed files with 84 additions and 22 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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))

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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. */