]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[Morello] Add capability register set support
authorLuis Machado <luis.machado@arm.com>
Thu, 5 Mar 2020 17:02:22 +0000 (14:02 -0300)
committerLuis Machado <luis.machado@linaro.org>
Tue, 20 Oct 2020 18:05:22 +0000 (15:05 -0300)
This patch adds capability register set support to both GDB and GDBserver,
allowing the use of ptrace.

gdb/ChangeLog

2020-10-20  Luis Machado  <luis.machado@arm.com>

* aarch64-linux-nat.c: Include arch/aarch64-cap-linux.h.
(fetch_cregs_from_thread)
(store_cregs_to_thread): New functions.
(aarch64_linux_nat_target::fetch_registers): Modify to check for
capability registers.
* aarch64-linux-tdep.c: Include arch/aarch64-cap-linux.h.
* aarch64-tdep.c (aarch64_cannot_store_register): Check for capability
registers.
(aarch64_gdbarch_init): Also save the last capability register number.
* aarch64-tdep.h (struct gdbarch_tdep) <cap_reg_last>: New field.
* arch/aarch64-cap-linux.h (AARCH64_LINUX_CREGS_SIZE,
AARCH64_MORELLO_REGS_NUM, AARCH64_C_REGS_NUM): New constants.
* arch/aarch64.c: Remove FIXME comment.
* nat/aarch64-linux.h (user_morello_state): New struct.

gdbserver/ChangeLog

2020-10-20  Luis Machado  <luis.machado@arm.com>

* linux-aarch64-low.c: arch/aarch64-cap-linux.h.
(aarch64_store_cregset): New function.
(aarch64_regsets): Add capability register set.
(aarch64_sve_regsets): Likewise.

include/ChangeLog

2020-10-20  Luis Machado  <luis.machado@arm.com>

* elf/common.h (NT_ARM_MORELLO): Define.

12 files changed:
gdb/ChangeLog
gdb/aarch64-linux-nat.c
gdb/aarch64-linux-tdep.c
gdb/aarch64-tdep.c
gdb/aarch64-tdep.h
gdb/arch/aarch64-cap-linux.h
gdb/arch/aarch64.c
gdb/nat/aarch64-linux.h
gdbserver/ChangeLog
gdbserver/linux-aarch64-low.cc
include/ChangeLog
include/elf/common.h

index 34b102220a6dc3a497ba9fdaaea5f519c1a159f8..8c634d9fa9dbd5fecb6e280fc5ccc513830c9271 100644 (file)
@@ -1,3 +1,20 @@
+2020-10-20  Luis Machado  <luis.machado@arm.com>
+
+       * aarch64-linux-nat.c: Include arch/aarch64-cap-linux.h.
+       (fetch_cregs_from_thread)
+       (store_cregs_to_thread): New functions.
+       (aarch64_linux_nat_target::fetch_registers): Modify to check for
+       capability registers.
+       * aarch64-linux-tdep.c: Include arch/aarch64-cap-linux.h.
+       * aarch64-tdep.c (aarch64_cannot_store_register): Check for capability
+       registers.
+       (aarch64_gdbarch_init): Also save the last capability register number.
+       * aarch64-tdep.h (struct gdbarch_tdep) <cap_reg_last>: New field.
+       * arch/aarch64-cap-linux.h (AARCH64_LINUX_CREGS_SIZE,
+       AARCH64_MORELLO_REGS_NUM, AARCH64_C_REGS_NUM): New constants.
+       * arch/aarch64.c: Remove FIXME comment.
+       * nat/aarch64-linux.h (user_morello_state): New struct.
+
 2020-10-20  Luis Machado  <luis.machado@arm.com>
 
        * aarch64-linux-nat.c (aarch64_linux_nat_target::read_description):
index 7adc6075b7a356faa44f291eefd3f70e142343f0..7e1763e8eaca099e4e2706e0b1712124a010926f 100644 (file)
@@ -32,6 +32,7 @@
 #include "aarch32-linux-nat.h"
 #include "aarch32-tdep.h"
 #include "arch/arm.h"
+#include "arch/aarch64-cap-linux.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
 #include "nat/aarch64-sve-linux-ptrace.h"
@@ -459,6 +460,56 @@ fetch_pauth_masks_from_thread (struct regcache *regcache)
                        &pauth_regset[1]);
 }
 
+/* Fill GDB's register array with the capability register values
+   from the current thread.  */
+
+static void
+fetch_cregs_from_thread (struct regcache *regcache)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  gdb_assert (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64);
+
+  int tid = regcache->ptid ().lwp ();
+
+  struct user_morello_state cregset;
+  struct iovec iovec;
+  iovec.iov_base = &cregset;
+  iovec.iov_len = sizeof (cregset);
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_MORELLO, &iovec) < 0)
+    perror_with_name (_("Unable to fetch capability registers."));
+
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
+  /* Fetch the C registers.  */
+  int regno, i;
+  for (regno = tdep->cap_reg_base, i = 0;
+       regno < tdep->cap_reg_base + AARCH64_C_REGS_NUM;
+       regno++, i++)
+    regcache->raw_supply (regno, &cregset.cregs[i]);
+
+  /* Fetch the other registers.  */
+  regcache->raw_supply (regno++, &cregset.pcc);
+  regcache->raw_supply (regno++, &cregset.csp);
+  regcache->raw_supply (regno++, &cregset.ddc);
+  regcache->raw_supply (regno++, &cregset.ctpidr);
+  regcache->raw_supply (regno++, &cregset.rcsp);
+  regcache->raw_supply (regno++, &cregset.rddc);
+  regcache->raw_supply (regno++, &cregset.rctpidr);
+  regcache->raw_supply (regno++, &cregset.cid);
+  regcache->raw_supply (regno++, &cregset.tag_map);
+  regcache->raw_supply (regno++, &cregset.cctlr);
+}
+
+/* Store to the current thread the valid capability register
+   values in the GDB's register array.  */
+
+static void
+store_cregs_to_thread (const struct regcache *regcache)
+{
+  /* Can't modify capability registers, do nothing.  */
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
@@ -477,7 +528,13 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
 
       if (tdep->has_pauth ())
        fetch_pauth_masks_from_thread (regcache);
+
+      if (tdep->has_capability ())
+       fetch_cregs_from_thread (regcache);
     }
+  else if (tdep->has_capability () && regno >= tdep->cap_reg_base
+          && regno < tdep->cap_reg_base + AARCH64_MORELLO_REGS_NUM)
+    fetch_cregs_from_thread (regcache);
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
   else if (tdep->has_sve ())
@@ -508,9 +565,25 @@ aarch64_linux_nat_target::store_registers (struct regcache *regcache,
        store_sveregs_to_thread (regcache);
       else
        store_fpregs_to_thread (regcache);
+
+      if (tdep->has_capability ())
+       {
+         /* Due to the aliasing of X/C registers and due to register merging
+            by the kernel (see documentation in the kernel), we should force
+            a read of the C registers whenever the X registers are written
+            to.  */
+         fetch_cregs_from_thread (regcache);
+         store_cregs_to_thread (regcache);
+       }
     }
+  else if (tdep->has_capability () && regno >= tdep->cap_reg_base
+          && regno < tdep->cap_reg_base + AARCH64_MORELLO_REGS_NUM)
+    store_cregs_to_thread (regcache);
   else if (regno < AARCH64_V0_REGNUM)
-    store_gregs_to_thread (regcache);
+    {
+      store_gregs_to_thread (regcache);
+      fetch_cregs_from_thread (regcache);
+    }
   else if (tdep->has_sve ())
     store_sveregs_to_thread (regcache);
   else
index 3819b7ab09dc0b411b15173324ad06f69d1ea05c..46a0a25f953a64a38d339bd0df637a5fac198521 100644 (file)
@@ -25,6 +25,7 @@
 #include "linux-tdep.h"
 #include "aarch64-tdep.h"
 #include "aarch64-linux-tdep.h"
+#include "arch/aarch64-cap-linux.h"
 #include "osabi.h"
 #include "solib-svr4.h"
 #include "symtab.h"
index 0f25e97e4cc16494792979859030a1320c477e19..c9c9e262dd44a3f671210fb231d9b4e02a16f999 100644 (file)
@@ -3354,12 +3354,20 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (!tdep->has_pauth ())
-    return 0;
+  if (tdep->has_pauth ())
+    {
+      /* Pointer authentication registers are read-only.  */
+      return (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+             || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
+    }
 
-  /* Pointer authentication registers are read-only.  */
-  return (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
-         || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base));
+  if (tdep->has_capability ())
+    {
+      /* Capability register set is read-only for now.  */
+      return (regnum >= tdep->cap_reg_base && regnum < tdep->cap_reg_last);
+    }
+
+  return 0;
 }
 
 /* Initialize the current architecture based on INFO.  If possible,
@@ -3492,6 +3500,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   const struct tdesc_feature *feature_capability
       = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.capability");
   int first_cap_regnum = -1;
+  int last_cap_regnum = -1;
 
   if (feature_capability != nullptr)
     {
@@ -3500,10 +3509,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       for (i = 0; i < ARRAY_SIZE (aarch64_c_register_names); i++)
        valid_p &= tdesc_numbered_register (feature_capability,
                                            tdesc_data.get (),
-                                           AARCH64_C0_REGNUM + i,
+                                           first_cap_regnum + i,
                                            aarch64_c_register_names[i]);
 
-      num_regs = AARCH64_C0_REGNUM + i;
+      last_cap_regnum = first_cap_regnum + i - 1;
+      num_regs += i;
     }
 
   if (!valid_p)
@@ -3525,6 +3535,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                                : pauth_ra_state_offset + num_regs;
 
   tdep->cap_reg_base = first_cap_regnum;
+  tdep->cap_reg_last = last_cap_regnum;
 
   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
index d0d85f4ce7b4991b8e419e9a28c4459e4252d0c8..3a2c30c47f360680b253fc6c4291eeced7643977 100644 (file)
@@ -108,7 +108,10 @@ struct gdbarch_tdep
     return pauth_reg_base != -1;
   }
 
+  /* First register from the capability set.  */
   int cap_reg_base;
+  /* Last register from the capability set.  */
+  int cap_reg_last;
 
   /* Returns true if the target supports capabilities.  */
   bool has_capability () const
index 1445d4f0ce9e448cf5c8459c46d61bfe955b8e83..7fd0ec9aaf9658420f6ae40e0f2950f6afe843f5 100644 (file)
 /* Morello HWCAP bit.  */
 #define HWCAP2_MORELLO (1 << 19)
 
+/* Size of the Capability register set.  */
+#define AARCH64_LINUX_CREGS_SIZE ((39 * 16) + (2 * 8))
+
+/* 39 128-bit C registers plus 2 64-bit registers.  */
+#define AARCH64_MORELLO_REGS_NUM 41
+#define AARCH64_C_REGS_NUM 31
+
 #endif /*ARCH_AARCH64_LINUX_H */
index a2a571f2b237f502887eb00f11d8cc761a2075ff..38cf34d2094dc8eb4396b66286318283471cd727 100644 (file)
@@ -49,10 +49,6 @@ aarch64_create_target_description (uint64_t vq, bool pauth_p,
   if (pauth_p)
     regnum = create_feature_aarch64_pauth (tdesc.get (), regnum);
 
-  /* FIXME-Morello: We need to append the capability registers to
-     the existing target description.  Figure out how to do that.
-     Maybe replace the general purpose register description with
-     the capability registers.  */
   if (capability_p)
     regnum = create_feature_aarch64_capability (tdesc.get (), regnum);
 
index 3c4481a978da4684360424b30dc8debc593ca33d..3ac3ac350f474a36066fe53fa3d906febeed85fb 100644 (file)
 /* Defines ps_err_e, struct ps_prochandle.  */
 #include "gdb_proc_service.h"
 
+/* Struct defining the layout of the capability register set.  */
+struct user_morello_state {
+       /* General capability registers.  */
+       unsigned __int128 cregs[31];
+       /* Capability program counter.  */
+       unsigned __int128 pcc;
+       /* Capability stack pointer.  */
+       unsigned __int128 csp;
+       /* Default data capability.  */
+       unsigned __int128 ddc;
+       unsigned __int128 ctpidr;
+       unsigned __int128 rcsp;
+       unsigned __int128 rddc;
+       unsigned __int128 rctpidr;
+       /* Compartment ID register.  */
+       unsigned __int128 cid;
+       /* Bitmap storing the tags of all the capability registers.
+          The tag for register <reg> is stored at bit index
+          MORELLO_PT_TAG_MAP_REG_BIT(<reg>) in tag_map.  */
+       uint64_t        tag_map;
+       /* Capability control register.  */
+       uint64_t        cctlr;
+};
+
 typedef int compat_int_t;
 typedef unsigned int compat_uptr_t;
 
index d4f6c68e4a74bf32ad7f0ae15e94cb96284bc448..7a4aa4eed2747d60424a167d00e89dbfbd126965 100644 (file)
@@ -1,3 +1,10 @@
+2020-10-20  Luis Machado  <luis.machado@arm.com>
+
+       * linux-aarch64-low.c: arch/aarch64-cap-linux.h.
+       (aarch64_store_cregset): New function.
+       (aarch64_regsets): Add capability register set.
+       (aarch64_sve_regsets): Likewise.
+
 2020-10-20  Luis Machado  <luis.machado@arm.com>
 
        * linux-aarch64-ipa.cc (get_ipa_tdesc): Update.
index d9fa43a67e0416b38a952afce2d813011a17e7e3..940399d381b391b1faa86ce9fe90fc3c0ec85a2a 100644 (file)
@@ -23,6 +23,7 @@
 #include "linux-low.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
+#include "arch/aarch64-cap-linux.h"
 #include "arch/aarch64-insn.h"
 #include "linux-aarch32-low.h"
 #include "elf/common.h"
@@ -260,13 +261,43 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
                   &pauth_regset[1]);
 }
 
+/* Capability registers store hook implementation.  */
+
+static void
+aarch64_store_cregset (struct regcache *regcache, const void *buf)
+{
+  const struct user_morello_state *cregset
+      = (const struct user_morello_state *) buf;
+
+  int cregs_base = find_regno (regcache->tdesc, "c0");
+
+  /* Fetch the C registers.  */
+  int i, regno;
+  for (regno = cregs_base, i = 0;
+       regno < cregs_base + AARCH64_C_REGS_NUM;
+       regno++, i++)
+    supply_register (regcache, regno, &cregset->cregs[i]);
+
+  /* Fetch the other registers.  */
+  supply_register (regcache, regno++, &cregset->pcc);
+  supply_register (regcache, regno++, &cregset->csp);
+  supply_register (regcache, regno++, &cregset->ddc);
+  supply_register (regcache, regno++, &cregset->ctpidr);
+  supply_register (regcache, regno++, &cregset->rcsp);
+  supply_register (regcache, regno++, &cregset->rddc);
+  supply_register (regcache, regno++, &cregset->rctpidr);
+  supply_register (regcache, regno++, &cregset->cid);
+  supply_register (regcache, regno++, &cregset->tag_map);
+  supply_register (regcache, regno++, &cregset->cctlr);
+}
+
 bool
 aarch64_target::low_supports_breakpoints ()
 {
   return true;
 }
 
-/* Implementation of linux target ops method "low_get_pc".  */
+/* Implementation of linux_target_ops method "get_pc".  */
 
 CORE_ADDR
 aarch64_target::low_get_pc (regcache *regcache)
@@ -682,6 +713,10 @@ static struct regset_info aarch64_regsets[] =
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
     AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
     NULL, aarch64_store_pauthregset },
+  /* FIXME-Morello: Fixup the register set size.  */
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
+    AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
+    nullptr, aarch64_store_cregset },
   NULL_REGSET
 };
 
@@ -711,6 +746,10 @@ static struct regset_info aarch64_sve_regsets[] =
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
     AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
     NULL, aarch64_store_pauthregset },
+  /* FIXME-Morello: Fixup the register set size.  */
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
+    AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
+    nullptr, aarch64_store_cregset },
   NULL_REGSET
 };
 
index 86f78d471416eff1472869bebdd1e73cb440bf93..1093514929ca4d5ff368dcedb2bdb7f9d7d7457c 100644 (file)
@@ -1,3 +1,7 @@
+2020-10-20  Luis Machado  <luis.machado@arm.com>
+
+       * elf/common.h (NT_ARM_MORELLO): Define.
+
 2020-10-20  Luis Machado  <luis.machado@arm.com>
 
        * dwarf2.def (DW_ATE_CHERI_signed_intcap)
index b3c30e0e2f726a1702dd0773033cb6ae40ae3f05..3980a0749ffb025a7df81aa62028896769f3b5d7 100644 (file)
                                        /*   note name must be "LINUX".  */
 #define NT_ARM_PAC_MASK        0x406           /* AArch pointer authentication code masks */
                                        /*   note name must be "LINUX".  */
+#define NT_ARM_MORELLO 0x410           /* AArch capability registers */
+                                       /* Note name must be "LINUX".  */
+
 #define NT_ARC_V2      0x600           /* ARC HS accumulator/extra registers.  */
                                        /*   note name must be "LINUX".  */
 #define NT_SIGINFO     0x53494749      /* Fields of siginfo_t.  */