Patchwork [AArch64,1/6] Add new "pauth" feature and native support

login
register
mail settings
Submitter Jiong Wang
Date Aug. 9, 2017, 12:21 p.m.
Message ID <21a7c0c7-45a0-6059-789f-d68e4cd03d37@foss.arm.com>
Download mbox | patch
Permalink /patch/22038/
State New
Headers show

Comments

Jiong Wang - Aug. 9, 2017, 12:21 p.m.
This patch teach GDB to return the new ARMv8.3-A Pointer Authentication feature
description when there is related support.

   * A new "pauth" feature description file is added.
     The new pointer authentication feature, "pauth", contains two virtual
     registers, "pauth_dmask" and "pauth_cmask".  Their values are supplied by
     kernel to GDB through ptrace interface.  They are masks to indicate which
     bits will be signature when data pointer or code pointer is signed.  Those
     bits will be set to "1" in the mask.

   * HWCAP is used to detect whether the hardware support exists.
     Currently we only support return address signing with A key, so using ptrace
     trial read would not be reliable as it will return successfully when other
     keys are used inside kernel.

The change on include/elf/common.h needs approval from Binutils maintainers.

gdb/
2017-08-09  Jiong Wang<jiong.wang@arm.com>
             Yao Qi<yao.qi@linaro.org>

	* aarch64-linux-nat.c (fetch_pauth_masks_from_thread): New
	function.
	(aarch64_linux_fetch_inferior_registers): Support pauth
	description.
	(aarch64_linux_read_description): Likewise.
	* aarch64-tdep.c: #include "features/aarch64-pauth.c".
	(aarch64_pauth_register_names): New register names array for
	pauth.
	(aarch64_cannot_store_register): New function.
	(aarch64_tdep_has_pauth_p): New function.
	(aarch64_gdbarch_init): Handle pauth description.  Initialize
	the optional "regnum" field.  Register cannot_store_register hook.
	(_initialize_aarch64_tdep): Call initialize_tdesc_aarch64_pauth.
	* aarch64-tdep.h (struct aarch64_optional_regnum): New structure
	type.
	(struct gdbarch_tdep) <regnum>: New field.
  	(tdesc_aarch64_pauth): New variable declaration.
	(aarch64_tdep_has_pauth_p): New function declaration.
	* nat/aarch64-linux.c: Include <sys/auxv.h>.
	(aarch64_host_hwcap): New function.
	* nat/aarch64-linux.h (HWCAP_APIA): New macro.
	(aarch64_host_hwcap): New function declaration.
	* features/Makefile (WHICH): Add aarch64-pauth.
	(XMLTOC): Add aarch64-pauth.xml.
	* features/aarch64-pauth-core.xml: New file.
	* features/aarch64-pauth.c: Generated.
	* features/aarch64-pauth.xml: New file.
	* regformats/aarch64-pauth.dat: Generated.

include/
	* elf/common.h (NT_ARM_PAC_MASK): New.

gdb/doc/
	* gdb.texinfo (AArch64 Features): New feature
	"org.gnu.gdb.aarch64.pauth".
Eli Zaretskii - Aug. 9, 2017, 4:08 p.m.
> From: Jiong Wang <jiong.wang@foss.arm.com>
> Date: Wed, 9 Aug 2017 13:21:33 +0100
> 
> This patch teach GDB to return the new ARMv8.3-A Pointer Authentication feature
> description when there is related support.
> 
>    * A new "pauth" feature description file is added.
>      The new pointer authentication feature, "pauth", contains two virtual
>      registers, "pauth_dmask" and "pauth_cmask".  Their values are supplied by
>      kernel to GDB through ptrace interface.  They are masks to indicate which
>      bits will be signature when data pointer or code pointer is signed.  Those
>      bits will be set to "1" in the mask.
> 
>    * HWCAP is used to detect whether the hardware support exists.
>      Currently we only support return address signing with A key, so using ptrace
>      trial read would not be reliable as it will return successfully when other
>      keys are used inside kernel.
> 
> The change on include/elf/common.h needs approval from Binutils maintainers.
> 
> gdb/
> 2017-08-09  Jiong Wang<jiong.wang@arm.com>
>              Yao Qi<yao.qi@linaro.org>
> 
> 	* aarch64-linux-nat.c (fetch_pauth_masks_from_thread): New
> 	function.
> 	(aarch64_linux_fetch_inferior_registers): Support pauth
> 	description.
> 	(aarch64_linux_read_description): Likewise.
> 	* aarch64-tdep.c: #include "features/aarch64-pauth.c".
> 	(aarch64_pauth_register_names): New register names array for
> 	pauth.
> 	(aarch64_cannot_store_register): New function.
> 	(aarch64_tdep_has_pauth_p): New function.
> 	(aarch64_gdbarch_init): Handle pauth description.  Initialize
> 	the optional "regnum" field.  Register cannot_store_register hook.
> 	(_initialize_aarch64_tdep): Call initialize_tdesc_aarch64_pauth.
> 	* aarch64-tdep.h (struct aarch64_optional_regnum): New structure
> 	type.
> 	(struct gdbarch_tdep) <regnum>: New field.
>   	(tdesc_aarch64_pauth): New variable declaration.
> 	(aarch64_tdep_has_pauth_p): New function declaration.
> 	* nat/aarch64-linux.c: Include <sys/auxv.h>.
> 	(aarch64_host_hwcap): New function.
> 	* nat/aarch64-linux.h (HWCAP_APIA): New macro.
> 	(aarch64_host_hwcap): New function declaration.
> 	* features/Makefile (WHICH): Add aarch64-pauth.
> 	(XMLTOC): Add aarch64-pauth.xml.
> 	* features/aarch64-pauth-core.xml: New file.
> 	* features/aarch64-pauth.c: Generated.
> 	* features/aarch64-pauth.xml: New file.
> 	* regformats/aarch64-pauth.dat: Generated.
> 
> include/
> 	* elf/common.h (NT_ARM_PAC_MASK): New.
> 
> gdb/doc/
> 	* gdb.texinfo (AArch64 Features): New feature
> 	"org.gnu.gdb.aarch64.pauth".

Thanks, the patch for gdb.texinfo is approved.
Nick Clifton - Aug. 9, 2017, 4:19 p.m.
Hi Jiong,

> The change on include/elf/common.h needs approval from Binutils maintainers.

> include/
>      * elf/common.h (NT_ARM_PAC_MASK): New.

Approved.

Cheers
  Nick

Patch

diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 3f5b30e..93eed48 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -342,6 +342,34 @@  store_fpregs_to_thread (const struct regcache *regcache)
     }
 }
 
+/* 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)
+{
+  int ret, tid;
+  struct iovec iovec;
+  uint64_t pauth_regset[2] = {0, 0};
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int dmask, cmask;
+
+  tid = ptid_get_lwp (inferior_ptid);
+
+  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."));
+
+  dmask = tdep->regnum.pauth_reg_base;
+  cmask = tdep->regnum.pauth_reg_base + 1;
+  regcache_raw_supply (regcache, dmask, &pauth_regset[0]);
+  regcache_raw_supply (regcache, cmask, &pauth_regset[1]);
+}
+
 /* Implement the "to_fetch_register" target_ops method.  */
 
 static void
@@ -349,15 +377,30 @@  aarch64_linux_fetch_inferior_registers (struct target_ops *ops,
 					struct regcache *regcache,
 					int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  bool has_pauth_p = aarch64_tdep_has_pauth_p (tdep);
+
   if (regno == -1)
     {
       fetch_gregs_from_thread (regcache);
       fetch_fpregs_from_thread (regcache);
+
+      if (has_pauth_p)
+	fetch_pauth_masks_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
-  else
+  else if (regno <= AARCH64_FPCR_REGNUM)
     fetch_fpregs_from_thread (regcache);
+  else if (has_pauth_p)
+    {
+      int dmask = tdep->regnum.pauth_reg_base;
+      int cmask = tdep->regnum.pauth_reg_base + 1;
+
+      if (regno == cmask || regno == dmask)
+	fetch_pauth_masks_from_thread (regcache);
+    }
 }
 
 /* Implement the "to_store_register" target_ops method.  */
@@ -501,7 +544,13 @@  aarch64_linux_read_description (struct target_ops *ops)
   if (ret == 0)
     return tdesc_arm_with_neon;
   else
-    return tdesc_aarch64;
+    {
+      CORE_ADDR hwcap = 0;
+
+      aarch64_host_hwcap (&hwcap);
+
+      return hwcap & HWCAP_APIA ? tdesc_aarch64_pauth : tdesc_aarch64;
+    }
 }
 
 /* Convert a native/host siginfo object, into/from the siginfo in the
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 75bb00f..7a3493c 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -57,6 +57,7 @@ 
 #include "record-full.h"
 
 #include "features/aarch64.c"
+#include "features/aarch64-pauth.c"
 
 #include "arch/aarch64-insn.h"
 
@@ -157,6 +158,14 @@  static const char *const aarch64_v_register_names[] =
   "fpcr"
 };
 
+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
 {
@@ -196,6 +205,16 @@  show_aarch64_debug (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("AArch64 debugging is %s.\n"), value);
 }
 
+/* Return TRUE if pointer authentication feature is available from those cached
+   information in TDEP in which case pauth_reg_base inside optional regnum
+   structure is not -1.  Return FALSE otherwise.  */
+
+bool
+aarch64_tdep_has_pauth_p (struct gdbarch_tdep *tdep)
+{
+  return tdep->regnum.pauth_reg_base != -1;
+}
+
 namespace {
 
 /* Abstract instruction reader.  */
@@ -2403,6 +2422,19 @@  aarch64_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
   gdb_assert_not_reached ("regnum out of bound");
 }
 
+/* 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);
+  int dmask = tdep->regnum.pauth_reg_base;
+  int cmask = tdep->regnum.pauth_reg_base + 1;
+
+  /* Pointer authentication registers are read-only.  */
+  return (regnum == cmask || regnum == dmask);
+}
+
 /* Callback function for user_reg_add.  */
 
 static struct value *
@@ -2854,9 +2886,11 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   const struct target_desc *tdesc = info.target_desc;
   int i;
   int valid_p = 1;
-  const struct tdesc_feature *feature;
+  const struct tdesc_feature *feature, *feature_pauth;
   int num_regs = 0;
   int num_pseudo_regs = 0;
+  struct aarch64_optional_regnum *regnum;
+  int first_pauth_regnum = -1;
 
   /* Ensure we always have a target descriptor.  */
   if (!tdesc_has_registers (tdesc))
@@ -2885,7 +2919,7 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (feature)
     {
       /* Validate the descriptor provides the mandatory V registers
-         and allocate their numbers.  */
+	 and allocate their numbers.  */
       for (i = 0; i < ARRAY_SIZE (aarch64_v_register_names); i++)
 	valid_p &=
 	  tdesc_numbered_register (feature, tdesc_data, AARCH64_V0_REGNUM + i,
@@ -2900,6 +2934,22 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       num_pseudo_regs += 32;	/* add the Bn scalar register pseudos */
     }
 
+  /* Look for the PAUTH registers.  */
+  feature_pauth = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.pauth");
+  if (feature_pauth)
+    {
+      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);
@@ -2914,6 +2964,11 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        best_arch != NULL;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
+      /* pauth status needs to be identical to match.  */
+      if (aarch64_tdep_has_pauth_p (gdbarch_tdep (best_arch->gdbarch))
+	  != (feature_pauth != NULL))
+	continue;
+
       /* Found a match.  */
       break;
     }
@@ -2932,6 +2987,7 @@  aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->lowest_pc = 0x20;
   tdep->jb_pc = -1;		/* Longjump support not enabled by default.  */
   tdep->jb_elt_size = 8;
+  tdep->regnum.pauth_reg_base = first_pauth_regnum;
 
   set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
@@ -2967,6 +3023,8 @@  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);
+  if (aarch64_tdep_has_pauth_p (tdep))
+    set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
 
   /* ABI */
   set_gdbarch_short_bit (gdbarch, 16);
@@ -3057,6 +3115,7 @@  _initialize_aarch64_tdep (void)
 		    aarch64_dump_tdep);
 
   initialize_tdesc_aarch64 ();
+  initialize_tdesc_aarch64_pauth ();
 
   /* Debug this file's internals.  */
   add_setshow_boolean_cmd ("aarch64", class_maintenance, &aarch64_debug, _("\
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 85c6a97..5ece079 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -75,6 +75,13 @@  enum aarch64_regnum
    single-stepped instruction.  */
 #define DISPLACED_MODIFIED_INSNS 1
 
+/* Indexes for various registers in optional features.  */
+struct aarch64_optional_regnum
+{
+  /* First pauth register number.  */
+  int pauth_reg_base;
+};
+
 /* Target-dependent structure in gdbarch.  */
 struct gdbarch_tdep
 {
@@ -97,9 +104,12 @@  struct gdbarch_tdep
 
   /* syscall record.  */
   int (*aarch64_syscall_record) (struct regcache *regcache, unsigned long svc_number);
+
+  struct aarch64_optional_regnum regnum;
 };
 
 extern struct target_desc *tdesc_aarch64;
+extern struct target_desc *tdesc_aarch64_pauth;
 
 extern int aarch64_process_record (struct gdbarch *gdbarch,
                                struct regcache *regcache, CORE_ADDR addr);
@@ -117,4 +127,6 @@  void aarch64_displaced_step_fixup (struct gdbarch *gdbarch,
 int aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch,
 					  struct displaced_step_closure *closure);
 
+bool aarch64_tdep_has_pauth_p (struct gdbarch_tdep *tdep);
+
 #endif /* aarch64-tdep.h */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 17b4c69..e504eb4 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -41175,6 +41175,9 @@  The @samp{org.gnu.gdb.aarch64.fpu} feature is optional.  If present,
 it should contain registers @samp{v0} through @samp{v31}, @samp{fpsr},
 and @samp{fpcr}.
 
+The @samp{org.gnu.gdb.aarch64.pauth} feature is optional.  If present,
+it should contain registers @samp{pauth_dmask} and @samp{pauth_cmask}.
+
 @node ARC Features
 @subsection ARC Features
 @cindex target descriptions, ARC Features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 670f8f3..3e5d07e 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -44,6 +44,7 @@ 
 #   make GDB=/path/to/gdb XMLTOC="xml files" cfiles
 
 WHICH = aarch64 \
+	aarch64-pauth \
 	arm/arm-with-iwmmxt arm/arm-with-vfpv2 arm/arm-with-vfpv3 \
 	arm/arm-with-neon \
 	i386/i386 i386/i386-linux \
@@ -129,6 +130,7 @@  OUTPUTS = $(patsubst %,$(outdir)/%.dat,$(WHICH))
 # to make on the command line.
 XMLTOC = \
 	aarch64.xml \
+	aarch64-pauth.xml \
 	arc-v2.xml \
 	arc-arcompact.xml \
 	arm/arm-with-iwmmxt.xml \
diff --git a/gdb/features/aarch64-pauth-core.xml b/gdb/features/aarch64-pauth-core.xml
new file mode 100644
index 0000000..b9f2700
--- /dev/null
+++ b/gdb/features/aarch64-pauth-core.xml
@@ -0,0 +1,13 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2017 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.pauth">
+  <reg name="pauth_dmask" bitsize="64"/>
+  <reg name="pauth_cmask" bitsize="64"/>
+</feature>
+
diff --git a/gdb/features/aarch64-pauth.c b/gdb/features/aarch64-pauth.c
new file mode 100644
index 0000000..b1034bb
--- /dev/null
+++ b/gdb/features/aarch64-pauth.c
@@ -0,0 +1,195 @@ 
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: aarch64-pauth.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_aarch64_pauth;
+static void
+initialize_tdesc_aarch64_pauth (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+  struct tdesc_type *field_type;
+  struct tdesc_type *type;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("aarch64"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.core");
+  type = tdesc_create_flags (feature, "cpsr_flags", 4);
+  tdesc_add_flag (type, 0, "SP");
+  tdesc_add_flag (type, 1, "");
+  tdesc_add_bitfield (type, "EL", 2, 3);
+  tdesc_add_flag (type, 4, "nRW");
+  tdesc_add_flag (type, 5, "");
+  tdesc_add_flag (type, 6, "F");
+  tdesc_add_flag (type, 7, "I");
+  tdesc_add_flag (type, 8, "A");
+  tdesc_add_flag (type, 9, "D");
+  tdesc_add_flag (type, 20, "IL");
+  tdesc_add_flag (type, 21, "SS");
+  tdesc_add_flag (type, 28, "V");
+  tdesc_add_flag (type, 29, "C");
+  tdesc_add_flag (type, 30, "Z");
+  tdesc_add_flag (type, 31, "N");
+
+  tdesc_create_reg (feature, "x0", 0, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x1", 1, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x2", 2, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x3", 3, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x4", 4, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x5", 5, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x6", 6, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x7", 7, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x8", 8, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x9", 9, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x10", 10, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x11", 11, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x12", 12, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x13", 13, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x14", 14, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x15", 15, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x16", 16, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x17", 17, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x18", 18, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x19", 19, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x20", 20, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x21", 21, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x22", 22, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x23", 23, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x24", 24, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x25", 25, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x26", 26, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x27", 27, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x28", 28, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x29", 29, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "x30", 30, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "sp", 31, 1, NULL, 64, "data_ptr");
+  tdesc_create_reg (feature, "pc", 32, 1, NULL, 64, "code_ptr");
+  tdesc_create_reg (feature, "cpsr", 33, 1, NULL, 32, "cpsr_flags");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.fpu");
+  field_type = tdesc_named_type (feature, "ieee_double");
+  tdesc_create_vector (feature, "v2d", field_type, 2);
+
+  field_type = tdesc_named_type (feature, "uint64");
+  tdesc_create_vector (feature, "v2u", field_type, 2);
+
+  field_type = tdesc_named_type (feature, "int64");
+  tdesc_create_vector (feature, "v2i", field_type, 2);
+
+  field_type = tdesc_named_type (feature, "ieee_single");
+  tdesc_create_vector (feature, "v4f", field_type, 4);
+
+  field_type = tdesc_named_type (feature, "uint32");
+  tdesc_create_vector (feature, "v4u", field_type, 4);
+
+  field_type = tdesc_named_type (feature, "int32");
+  tdesc_create_vector (feature, "v4i", field_type, 4);
+
+  field_type = tdesc_named_type (feature, "uint16");
+  tdesc_create_vector (feature, "v8u", field_type, 8);
+
+  field_type = tdesc_named_type (feature, "int16");
+  tdesc_create_vector (feature, "v8i", field_type, 8);
+
+  field_type = tdesc_named_type (feature, "uint8");
+  tdesc_create_vector (feature, "v16u", field_type, 16);
+
+  field_type = tdesc_named_type (feature, "int8");
+  tdesc_create_vector (feature, "v16i", field_type, 16);
+
+  field_type = tdesc_named_type (feature, "uint128");
+  tdesc_create_vector (feature, "v1u", field_type, 1);
+
+  field_type = tdesc_named_type (feature, "int128");
+  tdesc_create_vector (feature, "v1i", field_type, 1);
+
+  type = tdesc_create_union (feature, "vnd");
+  field_type = tdesc_named_type (feature, "v2d");
+  tdesc_add_field (type, "f", field_type);
+  field_type = tdesc_named_type (feature, "v2u");
+  tdesc_add_field (type, "u", field_type);
+  field_type = tdesc_named_type (feature, "v2i");
+  tdesc_add_field (type, "s", field_type);
+
+  type = tdesc_create_union (feature, "vns");
+  field_type = tdesc_named_type (feature, "v4f");
+  tdesc_add_field (type, "f", field_type);
+  field_type = tdesc_named_type (feature, "v4u");
+  tdesc_add_field (type, "u", field_type);
+  field_type = tdesc_named_type (feature, "v4i");
+  tdesc_add_field (type, "s", field_type);
+
+  type = tdesc_create_union (feature, "vnh");
+  field_type = tdesc_named_type (feature, "v8u");
+  tdesc_add_field (type, "u", field_type);
+  field_type = tdesc_named_type (feature, "v8i");
+  tdesc_add_field (type, "s", field_type);
+
+  type = tdesc_create_union (feature, "vnb");
+  field_type = tdesc_named_type (feature, "v16u");
+  tdesc_add_field (type, "u", field_type);
+  field_type = tdesc_named_type (feature, "v16i");
+  tdesc_add_field (type, "s", field_type);
+
+  type = tdesc_create_union (feature, "vnq");
+  field_type = tdesc_named_type (feature, "v1u");
+  tdesc_add_field (type, "u", field_type);
+  field_type = tdesc_named_type (feature, "v1i");
+  tdesc_add_field (type, "s", field_type);
+
+  type = tdesc_create_union (feature, "aarch64v");
+  field_type = tdesc_named_type (feature, "vnd");
+  tdesc_add_field (type, "d", field_type);
+  field_type = tdesc_named_type (feature, "vns");
+  tdesc_add_field (type, "s", field_type);
+  field_type = tdesc_named_type (feature, "vnh");
+  tdesc_add_field (type, "h", field_type);
+  field_type = tdesc_named_type (feature, "vnb");
+  tdesc_add_field (type, "b", field_type);
+  field_type = tdesc_named_type (feature, "vnq");
+  tdesc_add_field (type, "q", field_type);
+
+  tdesc_create_reg (feature, "v0", 34, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v1", 35, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v2", 36, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v3", 37, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v4", 38, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v5", 39, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v6", 40, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v7", 41, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v8", 42, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v9", 43, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v10", 44, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v11", 45, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v12", 46, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v13", 47, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v14", 48, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v15", 49, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v16", 50, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v17", 51, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v18", 52, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v19", 53, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v20", 54, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v21", 55, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v22", 56, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v23", 57, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v24", 58, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v25", 59, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v26", 60, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v27", 61, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v28", 62, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v29", 63, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v30", 64, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "v31", 65, 1, NULL, 128, "aarch64v");
+  tdesc_create_reg (feature, "fpsr", 66, 1, NULL, 32, "int");
+  tdesc_create_reg (feature, "fpcr", 67, 1, NULL, 32, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.pauth");
+  tdesc_create_reg (feature, "pauth_dmask", 68, 1, NULL, 64, "int");
+  tdesc_create_reg (feature, "pauth_cmask", 69, 1, NULL, 64, "int");
+
+  tdesc_aarch64_pauth = result;
+}
diff --git a/gdb/features/aarch64-pauth.xml b/gdb/features/aarch64-pauth.xml
new file mode 100644
index 0000000..faa7e31
--- /dev/null
+++ b/gdb/features/aarch64-pauth.xml
@@ -0,0 +1,15 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2017 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>aarch64</architecture>
+  <xi:include href="aarch64-core.xml"/>
+  <xi:include href="aarch64-fpu.xml"/>
+  <xi:include href="aarch64-pauth-core.xml"/>
+</target>
+
diff --git a/gdb/nat/aarch64-linux.c b/gdb/nat/aarch64-linux.c
index 388eee8..978900c 100644
--- a/gdb/nat/aarch64-linux.c
+++ b/gdb/nat/aarch64-linux.c
@@ -237,3 +237,35 @@  aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 
   return PS_OK;
 }
+
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
+/* Get the HWCAP from the process of GDB or GDBserver.  If success,
+   save it in *VALP.  */
+
+void
+aarch64_host_hwcap (CORE_ADDR *valp)
+{
+#ifdef HAVE_GETAUXVAL
+  *valp = getauxval (AT_HWCAP);
+#else
+  CORE_ADDR data[2];
+  FILE *f = fopen ("/proc/self/auxv", "r");
+
+  if (f == NULL)
+    return;
+
+  while (fread (data, sizeof (data), 1, f) > 0)
+    {
+      if (data[0] == AT_HWCAP)
+	{
+	  *valp = data[1];
+	  break;
+	}
+    }
+
+  fclose (f);
+#endif /* HAVE_GETAUXVAL */
+}
diff --git a/gdb/nat/aarch64-linux.h b/gdb/nat/aarch64-linux.h
index 191e1c6..ae211ff 100644
--- a/gdb/nat/aarch64-linux.h
+++ b/gdb/nat/aarch64-linux.h
@@ -126,4 +126,12 @@  ps_err_e aarch64_ps_get_thread_area (struct ps_prochandle *ph,
 				       lwpid_t lwpid, int idx, void **base,
 				       int is_64bit_p);
 
+#ifndef HWCAP_APIA
+/* AArch64 GNU/Linux HWCAP values.  These should be synced with kernel
+   definitions.  */
+#define HWCAP_APIA (1 << 16)
+#endif
+
+void aarch64_host_hwcap (CORE_ADDR *valp);
+
 #endif /* AARCH64_LINUX_H */
diff --git a/gdb/regformats/aarch64-pauth.dat b/gdb/regformats/aarch64-pauth.dat
new file mode 100644
index 0000000..9f8fdf8
--- /dev/null
+++ b/gdb/regformats/aarch64-pauth.dat
@@ -0,0 +1,75 @@ 
+# THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi :set ro:
+# Generated from: aarch64-pauth.xml
+name:aarch64_pauth
+xmltarget:aarch64-pauth.xml
+expedite:x29,sp,pc
+64:x0
+64:x1
+64:x2
+64:x3
+64:x4
+64:x5
+64:x6
+64:x7
+64:x8
+64:x9
+64:x10
+64:x11
+64:x12
+64:x13
+64:x14
+64:x15
+64:x16
+64:x17
+64:x18
+64:x19
+64:x20
+64:x21
+64:x22
+64:x23
+64:x24
+64:x25
+64:x26
+64:x27
+64:x28
+64:x29
+64:x30
+64:sp
+64:pc
+32:cpsr
+128:v0
+128:v1
+128:v2
+128:v3
+128:v4
+128:v5
+128:v6
+128:v7
+128:v8
+128:v9
+128:v10
+128:v11
+128:v12
+128:v13
+128:v14
+128:v15
+128:v16
+128:v17
+128:v18
+128:v19
+128:v20
+128:v21
+128:v22
+128:v23
+128:v24
+128:v25
+128:v26
+128:v27
+128:v28
+128:v29
+128:v30
+128:v31
+32:fpsr
+32:fpcr
+64:pauth_dmask
+64:pauth_cmask
diff --git a/include/elf/common.h b/include/elf/common.h
index 3a144f0..48847de 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -613,6 +613,8 @@ 
 					/*   note name must be "LINUX".  */
 #define NT_ARM_SVE	0x405		/* AArch SVE registers.  */
 					/*   note name must be "LINUX".  */
+#define NT_ARM_PAC_MASK	0x406		/* AArch PAC mask registers.  */
+					/*   note name must be "LINUX".  */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */