This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[AArch64][6/6] Core file support for "pauth" feature
- From: Jiong Wang <jiong dot wang at foss dot arm dot com>
- To: GDB <gdb-patches at sourceware dot org>, Binutils <binutils at sourceware dot org>
- Date: Wed, 9 Aug 2017 13:23:42 +0100
- Subject: [AArch64][6/6] Core file support for "pauth" feature
- Authentication-results: sourceware.org; auth=none
This patch add coredump support for the new "pauth" feature. A few necessary
low level methods and descriptions are added accordingly.
2017-08-09 Jiong Wang <jiong.wang@arm.com>
bfd/
* elf-bfd.h (elfcore_write_aarch_pauth): New function declaration.
* elf.c (elfcore_grok_aarch_pauth): New function.
(elfcore_grok_note): Handle NT_ARM_PAUTH.
(elfcore_write_aarch_pauth): New function.
(elfcore_write_register_note): Handle ".reg-aarch-pauth" section.
gdb/
* aarch64-linux-tdep.c: #include "auxv.h".
#include "elf/common.h"
(aarch64_collect_pauth_regset): New function.
(aarch64_supply_pauth_regset): New function.
(aarch64_linux_pauthregset): New regset.
(aarch64_linux_iterate_over_regset_sections): Support
".reg-aarch64-pauth" section.
(aarch64_linux_core_read_description): New function.
(aarch64_linux_init_abi): Register core_read_description method.
* aarch64-linux-tdep.h (AARCH64_LINUX_SIZEOF_PAUTH): New define.
(HWCAP_APIA): New define.
(aarch64_linux_pauthregset): New variable declaration.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 92a8e02..d9b61ba 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2539,6 +2539,8 @@ extern char *elfcore_write_s390_gs_bc
(bfd *, char *, int *, const void *, int);
extern char *elfcore_write_arm_vfp
(bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_aarch_pauth
+ (bfd *, char *, int *, const void *, int);
extern char *elfcore_write_aarch_tls
(bfd *, char *, int *, const void *, int);
extern char *elfcore_write_aarch_hw_break
diff --git a/bfd/elf.c b/bfd/elf.c
index b99e297..30772cf 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9207,6 +9207,12 @@ elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
}
static bfd_boolean
+elfcore_grok_aarch_pauth (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-pauth", note);
+}
+
+static bfd_boolean
elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note)
{
return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note);
@@ -9699,6 +9705,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
else
return TRUE;
+ case NT_ARM_PAC_MASK:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_aarch_pauth (abfd, note);
+ else
+ return TRUE;
+
case NT_ARM_TLS:
if (note->namesz == 6
&& strcmp (note->namedata, "LINUX") == 0)
@@ -10794,6 +10807,18 @@ elfcore_write_arm_vfp (bfd *abfd,
}
char *
+elfcore_write_aarch_pauth (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *aarch_pauth,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARM_PAC_MASK, aarch_pauth, size);
+}
+
+char *
elfcore_write_aarch_tls (bfd *abfd,
char *buf,
int *bufsiz,
@@ -10875,6 +10900,8 @@ elfcore_write_register_note (bfd *abfd,
return elfcore_write_s390_gs_bc (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-arm-vfp") == 0)
return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-aarch-pauth") == 0)
+ return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-aarch-tls") == 0)
return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-aarch-hw-break") == 0)
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index ec6125a..56ca1ce 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -45,6 +45,8 @@
#include "record-full.h"
#include "linux-record.h"
+#include "auxv.h"
+#include "elf/common.h"
/* Signal frame handling.
@@ -217,6 +219,65 @@ const struct regset aarch64_linux_fpregset =
regcache_supply_regset, regcache_collect_regset
};
+/* Collect register REGNUM from REGCACHE and store its contents in the buffer
+ PAUTH_REGS which is of SIZE. REGSET is not used as for PAUTH regset the
+ register number inside GDB is dynamicly allocated so we are not using
+ register map in REGSET. */
+
+static void
+aarch64_collect_pauth_regset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *pauth_regs, size_t size)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ gdb_assert (size == AARCH64_LINUX_SIZEOF_PAUTH);
+ gdb_assert (regnum == -1);
+ gdb_assert (aarch64_tdep_has_pauth_p (tdep));
+
+ int dmask = tdep->regnum.pauth_reg_base;
+ int cmask = tdep->regnum.pauth_reg_base + 1;
+
+ memset (pauth_regs, 0, AARCH64_LINUX_SIZEOF_PAUTH);
+ regcache_raw_collect (regcache, dmask, pauth_regs);
+ regcache_raw_collect (regcache, cmask,
+ (gdb_byte *) pauth_regs + X_REGISTER_SIZE);
+
+ return;
+}
+
+/* Supply register REGNUM from the buffer PAUTH_REGS which is of SIZE to
+ REGCACHE. REGSET is not used as for PAUTH regset the register number inside
+ GDB is dynamicly allocated so we are not using register map in REGSET. */
+
+static void
+aarch64_supply_pauth_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *pauth_regs, size_t size)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ gdb_assert (size == AARCH64_LINUX_SIZEOF_PAUTH);
+ gdb_assert (regnum == -1);
+ gdb_assert (aarch64_tdep_has_pauth_p (tdep));
+
+ int dmask = tdep->regnum.pauth_reg_base;
+ int cmask = tdep->regnum.pauth_reg_base + 1;
+
+ regcache_raw_supply (regcache, dmask, pauth_regs);
+ regcache_raw_supply (regcache, cmask,
+ (gdb_byte *) pauth_regs + X_REGISTER_SIZE);
+
+ return;
+}
+
+const struct regset aarch64_linux_pauthregset =
+ {
+ NULL, aarch64_supply_pauth_regset, aarch64_collect_pauth_regset
+ };
+
/* Implement the "regset_from_core_section" gdbarch method. */
static void
@@ -225,10 +286,16 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
void *cb_data,
const struct regcache *regcache)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
cb (".reg", AARCH64_LINUX_SIZEOF_GREGSET, &aarch64_linux_gregset,
NULL, cb_data);
cb (".reg2", AARCH64_LINUX_SIZEOF_FPREGSET, &aarch64_linux_fpregset,
NULL, cb_data);
+
+ if (aarch64_tdep_has_pauth_p (tdep))
+ cb (".reg-aarch-pauth", AARCH64_LINUX_SIZEOF_PAUTH,
+ &aarch64_linux_pauthregset, NULL, cb_data);
}
/* Determine target description from core file. */
@@ -242,7 +309,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
if (target_auxv_search (target, AT_HWCAP, &aarch64_hwcap) != 1)
return NULL;
- return tdesc_aarch64;
+ return aarch64_hwcap & HWCAP_APIA ? tdesc_aarch64_pauth : tdesc_aarch64;
}
/* Implementation of `gdbarch_stap_is_single_operand', as defined in
diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h
index d0f9b12..580a8b8 100644
--- a/gdb/aarch64-linux-tdep.h
+++ b/gdb/aarch64-linux-tdep.h
@@ -29,6 +29,14 @@
are 4 bytes wide each, and the whole structure is padded to 128 bit
alignment. */
#define AARCH64_LINUX_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE)
+#define AARCH64_LINUX_SIZEOF_PAUTH (2 * X_REGISTER_SIZE)
extern const struct regset aarch64_linux_gregset;
extern const struct regset aarch64_linux_fpregset;
+extern const struct regset aarch64_linux_pauthregset;
+
+#ifndef HWCAP_APIA
+/* AArch64 GNU/Linux HWCAP values. These should be synced with kernel
+ definitions. */
+#define HWCAP_APIA (1 << 16)
+#endif