]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdbserver: Add optional runtime register set type.
authorChristina Schimpe <christina.schimpe@intel.com>
Mon, 18 Dec 2023 17:47:09 +0000 (18:47 +0100)
committerChristina Schimpe <christina.schimpe@intel.com>
Fri, 29 Aug 2025 17:02:08 +0000 (17:02 +0000)
Some register sets can be activated and deactivated by the OS during the runtime of
a process.  One example register is the Intel CET shadow stack pointer.  This patch
adds a new type of register set to handle such cases.  We shouldn't deactivate these
regsets and should not show a warning if the register set is not active but supported
by the kernel.  However, it is safe to deactivate them, if they are unsupported by the
kernel.  To differentiate those scenarios we can use the errno returned by the ptrace
call.

Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Approved-By: Luis Machado <luis.machado@arm.com>
gdbserver/linux-low.cc
gdbserver/linux-low.h

index 39642705b0d8bc614e7da84f0d0e1c34cd045b12..e8c4eb8a78d159111b750c04d2d54fe32fe08bba 100644 (file)
@@ -5006,23 +5006,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
       if (res < 0)
        {
          if (errno == EIO
-             || (errno == EINVAL && regset->type == OPTIONAL_REGS))
+             || (errno == EINVAL
+                 && (regset->type == OPTIONAL_REGS
+                     || regset->type == OPTIONAL_RUNTIME_REGS)))
            {
              /* If we get EIO on a regset, or an EINVAL and the regset is
-                optional, do not try it again for this process mode.  */
+                optional, do not try it again for this process mode.
+                Even if the regset can be enabled at runtime it is safe
+                to deactivate the regset in case of EINVAL, as we know
+                the regset itself was the invalid argument of the ptrace
+                call which means that it's unsupported by the kernel.  */
              disable_regset (regsets_info, regset);
            }
-         else if (errno == ENODATA)
+         else if (errno == ENODATA
+                  || (errno == ENODEV
+                      && regset->type == OPTIONAL_RUNTIME_REGS)
+                  || errno == ESRCH)
            {
-             /* ENODATA may be returned if the regset is currently
-                not "active".  This can happen in normal operation,
-                so suppress the warning in this case.  */
-           }
-         else if (errno == ESRCH)
-           {
-             /* At this point, ESRCH should mean the process is
-                already gone, in which case we simply ignore attempts
-                to read its registers.  */
+             /* ENODATA or ENODEV may be returned if the regset is
+                currently not "active".  For ENODEV we additionally check
+                if the register set is of type OPTIONAL_RUNTIME_REGS.
+                This can happen in normal operation, so suppress the
+                warning in this case.
+                ESRCH should mean the process is already gone at this
+                point, in which case we simply ignore attempts to read
+                its registers.  */
            }
          else
            {
@@ -5104,12 +5112,26 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
       if (res < 0)
        {
          if (errno == EIO
-             || (errno == EINVAL && regset->type == OPTIONAL_REGS))
+             || (errno == EINVAL
+                  && (regset->type == OPTIONAL_REGS
+                      || regset->type == OPTIONAL_RUNTIME_REGS)))
            {
              /* If we get EIO on a regset, or an EINVAL and the regset is
-                optional, do not try it again for this process mode.  */
+                optional, do not try it again for this process mode.
+                Even if the regset can be enabled at runtime it is safe
+                to deactivate the regset in case of EINVAL, as we know
+                the regset itself was the invalid argument of the ptrace
+                call which means that it's unsupported by the kernel.  */
              disable_regset (regsets_info, regset);
            }
+         else if (errno == ENODEV
+                  && regset->type == OPTIONAL_RUNTIME_REGS)
+           {
+             /* If we get ENODEV on a regset and the regset can be
+                enabled at runtime try it again for this process mode.
+                This can happen in normal operation, so suppress the
+                warning in this case.  */
+           }
          else if (errno == ESRCH)
            {
              /* At this point, ESRCH should mean the process is
index e1c88ee0bb2cb64f7f1400f926e45e901d977333..5710e49d9500153d19c7b306bc92005e5ee8234a 100644 (file)
@@ -42,7 +42,12 @@ enum regset_type {
   GENERAL_REGS,
   FP_REGS,
   EXTENDED_REGS,
-  OPTIONAL_REGS, /* Do not error if the regset cannot be accessed.  */
+  OPTIONAL_REGS, /* Do not error if the regset cannot be accessed.
+                   Disable the regset instead.  */
+  OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed
+                           dependent on the execution flow.  For such
+                           access errors don't show a warning and don't
+                           disable the regset.  */
 };
 
 /* The arch's regsets array initializer must be terminated with a NULL