]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Handle C regset write warnings better in GDBServer
authorLuis Machado <luis.machado@linaro.org>
Mon, 29 Nov 2021 12:19:39 +0000 (09:19 -0300)
committerLuis Machado <luis.machado@linaro.org>
Mon, 20 Dec 2021 13:54:49 +0000 (10:54 -0300)
GDBServer handles register reads/writes a bit differently compared to GDB.

Since C register writes are only allowed with cheri.ptrace_forge_cap=1,
GDBServer will keep issuing warnings if such setting is 0.

This patch improves it by issuing a single more helpful warning to the
user. If cheri.ptrace_forge_cap is flipped, the warning will be issued
again appropriately to remind the user about it.

Bug-ID: https://git.morello-project.org/morello/binutils-gdb/-/issues/5

gdbserver/linux-aarch64-low.cc
gdbserver/linux-low.cc
gdbserver/linux-low.h

index 94f2fdaca0362a2fe4fb2aec0749b89a56f1da3b..85313789ce813939e2c88f6042dd16df78713d88 100644 (file)
@@ -691,39 +691,6 @@ aarch64_target::low_new_fork (process_info *parent,
   *child->priv->arch_private = *parent->priv->arch_private;
 }
 
-/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
-#define AARCH64_HWCAP_PACA (1 << 30)
-
-/* Implementation of linux target ops method "low_arch_setup".  */
-
-void
-aarch64_target::low_arch_setup ()
-{
-  unsigned int machine;
-  int is_elf64;
-  int tid;
-
-  tid = lwpid_of (current_thread);
-
-  is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
-
-  if (is_elf64)
-    {
-      uint64_t vq = aarch64_sve_get_vq (tid);
-      unsigned long hwcap = linux_get_hwcap (8);
-      unsigned long hwcap2 = linux_get_hwcap2 (8);
-      bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
-      bool capability_p = hwcap2 & HWCAP2_MORELLO;
-
-      current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p,
-                                                                 capability_p);
-    }
-  else
-    current_process ()->tdesc = aarch32_linux_read_description ();
-
-  aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
-}
-
 /* Wrapper for aarch64_sve_regs_copy_to_reg_buf.  */
 
 static void
@@ -755,7 +722,9 @@ static struct regset_info aarch64_regsets[] =
   /* FIXME-Morello: Fixup the register set size.  */
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
     AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
-    aarch64_fill_cregset, aarch64_store_cregset },
+    aarch64_fill_cregset, aarch64_store_cregset, nullptr,
+    "cheri.ptrace_forge_cap"
+  },
   NULL_REGSET
 };
 
@@ -788,7 +757,9 @@ static struct regset_info aarch64_sve_regsets[] =
   /* FIXME-Morello: Fixup the register set size.  */
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
     AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
-    aarch64_fill_cregset, aarch64_store_cregset },
+    aarch64_fill_cregset, aarch64_store_cregset, nullptr,
+    "cheri.ptrace_forge_cap"
+  },
   NULL_REGSET
 };
 
@@ -806,6 +777,45 @@ static struct regs_info regs_info_aarch64_sve =
     &aarch64_sve_regsets_info,
   };
 
+/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h.  */
+#define AARCH64_HWCAP_PACA (1 << 30)
+
+/* Implementation of linux target ops method "low_arch_setup".  */
+
+void
+aarch64_target::low_arch_setup ()
+{
+  unsigned int machine;
+  int is_elf64;
+  int tid;
+
+  tid = lwpid_of (current_thread);
+
+  is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
+
+  if (is_elf64)
+    {
+      uint64_t vq = aarch64_sve_get_vq (tid);
+      unsigned long hwcap = linux_get_hwcap (8);
+      unsigned long hwcap2 = linux_get_hwcap2 (8);
+      bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
+      bool capability_p = hwcap2 & HWCAP2_MORELLO;
+
+      current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p,
+                                                                 capability_p);
+
+      /* Re-enable warnings for register sets with sysctl settings.  */
+      aarch64_regsets[4].sysctl_write_should_warn = true;
+      aarch64_sve_regsets[4].sysctl_write_should_warn = true;
+    }
+  else
+    current_process ()->tdesc = aarch32_linux_read_description ();
+
+  aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
+}
+
+
+
 /* Implementation of linux target ops method "get_regs_info".  */
 
 const regs_info *
index 24509f173634bb01dbf86d76317d4bc64319d6a4..7fe0be3f065c8102ec6468bd552c54e59da702b8 100644 (file)
@@ -5242,6 +5242,16 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
              free (buf);
              return 0;
            }
+         else if (errno == EPERM && regset->sysctl_write_permission != nullptr)
+           {
+             if (regset->sysctl_write_should_warn)
+               {
+                 warning ("Unable to store registers.\n"
+                          "Please run \"sysctl %s=1\".",
+                          regset->sysctl_write_permission);
+                 regset->sysctl_write_should_warn = false;
+               }
+           }
          else
            {
              perror ("Warning: ptrace(regsets_store_inferior_registers)");
@@ -5249,6 +5259,17 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
        }
       else if (regset->type == GENERAL_REGS)
        saw_general_regs = 1;
+      else
+       {
+         /* We've succeeded in writing the registers. If this register set
+            has a sysctl permission flag and the warnings are disabled,
+            re-enable it so we can issue a warning next time the write
+            attempt fails.  */
+         if (regset->sysctl_write_permission != nullptr
+             && !regset->sysctl_write_should_warn)
+           regset->sysctl_write_should_warn = true;
+       }
+
       free (buf);
     }
   if (saw_general_regs)
index bd6f402afbf5b8cc22f13a289aeed0ec3b8e99d1..503f23d3702881ccd7171739cab342aa4451b008 100644 (file)
@@ -48,7 +48,7 @@ enum regset_type {
 /* The arch's regsets array initializer must be terminated with a NULL
    regset.  */
 #define NULL_REGSET \
-  { 0, 0, 0, -1, (enum regset_type) -1, NULL, NULL }
+  { 0, 0, 0, -1, (enum regset_type) -1, nullptr, nullptr, nullptr, nullptr }
 
 struct regset_info
 {
@@ -60,6 +60,13 @@ struct regset_info
   enum regset_type type;
   regset_fill_func fill_function;
   regset_store_func store_function;
+  /* The name of the sysctl flag that controls read/write permission for this
+     particular register set.  If it is nullptr, it means there is no such
+     switch.  */
+  const char *sysctl_read_permission = nullptr;
+  const char *sysctl_write_permission = nullptr;
+  bool sysctl_read_should_warn = true;
+  bool sysctl_write_should_warn = true;
 };
 
 /* Aggregation of all the supported regsets of a given