[v2,3/8] AArch64: Read pauth registers

Message ID 20190306133325.2531-4-alan.hayward@arm.com
State New, archived
Headers

Commit Message

Alan Hayward March 6, 2019, 1:33 p.m. UTC
  Initialise the pauth registers when creating a target description, and store
the regnum of the first pauth register.

Use ptrace to read the registers in the pauth feature.

Do not allow the registers to be written.

2019-03-06  Alan Hayward  <alan.hayward@arm.com>
	    Jiong Wang  <jiong.wang@arm.com>

	* aarch64-linux-nat.c (fetch_pauth_masks_from_thread): New
	function.
	(aarch64_linux_nat_target::fetch_registers): Read pauth registers.
	* aarch64-tdep.c (aarch64_cannot_store_register): New function.
	(aarch64_gdbarch_init): Add puth registers.
	* aarch64-tdep.h (struct gdbarch_tdep): Add pauth features.
	* arch/aarch64.h (AARCH64_PAUTH_DMASK_REGNUM): New define.
	(AARCH64_PAUTH_CMASK_REGNUM): Likewise.
---
 gdb/aarch64-linux-nat.c | 33 +++++++++++++++++++++++++++++++
 gdb/aarch64-tdep.c      | 43 +++++++++++++++++++++++++++++++++++++++++
 gdb/aarch64-tdep.h      |  8 ++++++++
 gdb/arch/aarch64.h      |  3 +++
 4 files changed, 87 insertions(+)
  

Comments

Simon Marchi March 21, 2019, 8:56 p.m. UTC | #1
On 2019-03-06 8:33 a.m., Alan Hayward wrote:
> @@ -445,6 +473,11 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
>       fetch_sveregs_from_thread (regcache);
>     else
>       fetch_fpregs_from_thread (regcache);
> +
> +  if (tdep->has_pauth ())
> +    if (regno == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
> +	|| regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
> +      fetch_pauth_masks_from_thread (regcache);
>   }

Just this nit:

The "outer" if should have curly braces.

Ref: 
https://www.gnu.org/prep/standards/html_node/Syntactic-Conventions.html#Syntactic-Conventions

Simon
  

Patch

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 8a7006165e..094d4e1d1c 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -423,6 +423,31 @@  store_sveregs_to_thread (struct regcache *regcache)
     perror_with_name (_("Unable to store sve registers"));
 }
 
+/* Fill GDB's register array with the pointer authentication mask values from
+   the current thread.  */
+
+static void
+fetch_pauth_masks_from_thread (struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+  int ret;
+  struct iovec iovec;
+  uint64_t pauth_regset[2] = {0, 0};
+  int tid = regcache->ptid ().lwp ();
+
+  iovec.iov_base = &pauth_regset;
+  iovec.iov_len = sizeof (pauth_regset);
+
+  ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK, &iovec);
+  if (ret != 0)
+    perror_with_name (_("unable to fetch pauth registers."));
+
+  regcache->raw_supply (AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base),
+			&pauth_regset[0]);
+  regcache->raw_supply (AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base),
+			&pauth_regset[1]);
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
@@ -438,6 +463,9 @@  aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
 	fetch_sveregs_from_thread (regcache);
       else
 	fetch_fpregs_from_thread (regcache);
+
+      if (tdep->has_pauth ())
+	fetch_pauth_masks_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
@@ -445,6 +473,11 @@  aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
     fetch_sveregs_from_thread (regcache);
   else
     fetch_fpregs_from_thread (regcache);
+
+  if (tdep->has_pauth ())
+    if (regno == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+	|| regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
+      fetch_pauth_masks_from_thread (regcache);
 }
 
 /* Implement the "store_registers" target_ops method.  */
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 0518837a1f..66fdd7bf05 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -175,6 +175,14 @@  static const char *const aarch64_sve_register_names[] =
   "ffr", "vg"
 };
 
+static const char *const aarch64_pauth_register_names[] =
+{
+  /* Authentication mask for data pointer.  */
+  "pauth_dmask",
+  /* Authentication mask for code pointer.  */
+  "pauth_cmask"
+};
+
 /* AArch64 prologue cache structure.  */
 struct aarch64_prologue_cache
 {
@@ -2936,6 +2944,21 @@  aarch64_add_reggroups (struct gdbarch *gdbarch)
   reggroup_add (gdbarch, restore_reggroup);
 }
 
+/* Implement the "cannot_store_register" gdbarch method.  */
+
+static int
+aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (!tdep->has_pauth ())
+    return 0;
+
+  /* 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));
+}
+
 /* Initialize the current architecture based on INFO.  If possible,
    re-use an architecture from ARCHES, which is a list of
    architectures already created during this debugging session.
@@ -2956,8 +2979,10 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   const struct tdesc_feature *feature_core;
   const struct tdesc_feature *feature_fpu;
   const struct tdesc_feature *feature_sve;
+  const struct tdesc_feature *feature_pauth;
   int num_regs = 0;
   int num_pseudo_regs = 0;
+  int first_pauth_regnum = -1;
 
   /* Ensure we always have a target description.  */
   if (!tdesc_has_registers (tdesc))
@@ -2967,6 +2992,7 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core");
   feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu");
   feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve");
+  feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
 
   if (feature_core == NULL)
     return NULL;
@@ -3021,6 +3047,21 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       num_pseudo_regs += 32;	/* add the Bn scalar register pseudos */
     }
 
+  /* Add the pauth registers.  */
+  if (feature_pauth != NULL)
+    {
+      first_pauth_regnum = num_regs;
+
+      /* Validate the descriptor provides the mandatory PAUTH registers and
+	 allocate their numbers.  */
+      for (i = 0; i < ARRAY_SIZE (aarch64_pauth_register_names); i++)
+	valid_p &= tdesc_numbered_register (feature_pauth, tdesc_data,
+					    first_pauth_regnum + i,
+					    aarch64_pauth_register_names[i]);
+
+      num_regs += i;
+    }
+
   if (!valid_p)
     {
       tdesc_data_cleanup (tdesc_data);
@@ -3054,6 +3095,7 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->jb_pc = -1;		/* Longjump support not enabled by default.  */
   tdep->jb_elt_size = 8;
   tdep->vq = aarch64_get_tdesc_vq (tdesc);
+  tdep->pauth_reg_base = first_pauth_regnum;
 
   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
@@ -3084,6 +3126,7 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_tdesc_pseudo_register_type (gdbarch, aarch64_pseudo_register_type);
   set_tdesc_pseudo_register_reggroup_p (gdbarch,
 					aarch64_pseudo_register_reggroup_p);
+  set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
 
   /* ABI */
   set_gdbarch_short_bit (gdbarch, 16);
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 3db6bee9f3..f9fc8965f0 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -87,6 +87,14 @@  struct gdbarch_tdep
   {
     return vq != 0;
   }
+
+  int pauth_reg_base;
+
+  /* Returns true if the target supports pauth.  */
+  bool has_pauth () const
+  {
+    return pauth_reg_base != -1;
+  }
 };
 
 const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p);
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index 4fe6d02f6e..8c80b7be62 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -66,6 +66,9 @@  enum aarch64_regnum
 #define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32)
 #define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32)
 
+#define AARCH64_PAUTH_DMASK_REGNUM(pauth_reg_base) (pauth_reg_base)
+#define AARCH64_PAUTH_CMASK_REGNUM(pauth_reg_base) (pauth_reg_base + 1)
+
 #define AARCH64_X_REGS_NUM 31
 #define AARCH64_V_REGS_NUM 32
 #define AARCH64_SVE_Z_REGS_NUM AARCH64_V_REGS_NUM