]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Improve Morello feature detection
authorLuis Machado <luis.machado@arm.com>
Thu, 28 Jul 2022 01:09:04 +0000 (02:09 +0100)
committerLuis Machado <luis.machado@arm.com>
Wed, 3 Aug 2022 09:28:03 +0000 (10:28 +0100)
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.

gdb/aarch64-linux-nat.c
gdb/aarch64-linux-tdep.c
gdb/arch/aarch64-cap-linux.h
gdb/nat/aarch64-cap-linux.c
gdb/nat/aarch64-cap-linux.h
gdb/nat/linux-ptrace.c
gdb/nat/linux-ptrace.h
gdbserver/linux-aarch64-low.cc

index d5cf037d47bb756e1de5ec7f180536c978d3a73f..dc9ca2d313defcf20d0291640348a92973a3c2e6 100644 (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);
index 06497e29161ba16ab607c3bc26bd1dbe389c430f..07b616105243b518782583f3d42712a97df90c76 100644 (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);
index 0c8fe2d9d552c4c0f76bc2f43abbbbdf8f46cbb1..83b9d33cffc499f6fd701d4af41f7976515d5b11 100644 (file)
 #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))
index 62a4dcdff723702830c09521e229c38bef54022e..cff76de909a8fb365cfeeddd77065f13a459dc0d 100644 (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;
+}
index ff38bccaf6e01148d16e49f15cfaaaa329e64c8a..8adfb9bfb39b09d32f42ee4561c1dc9e6458695d 100644 (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 */
index 5335d6909228b01ab960a8c57a007d0f909898c5..766ddc0dbd1d691b9adb48bf8d4a58468a2743db 100644 (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
index 65568301f224dc8d9e6693b9641993dfa08ef667..5481ee8a3f112dec27f5d662f6d6c441b84f0583 100644 (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 */
index 1f63e8dda34ca8e388ceea6ff8f2683055c4d83d..3d7f3235eb771e9af5905c5bf704a9867831ab8d 100644 (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.  */