aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@linaro.org>2020-06-15 13:59:40 -0300
committerLuis Machado <luis.machado@linaro.org>2020-06-25 13:23:38 -0300
commit471cecca46b70be2ac3dc73141f7946ddb7934af (patch)
tree5347a5ddd4441c716736a416cc27891474be2e06
parent156168cd706887705ddff30e1531c644b6e447a8 (diff)
downloadgdb-471cecca46b70be2ac3dc73141f7946ddb7934af.zip
gdb-471cecca46b70be2ac3dc73141f7946ddb7934af.tar.gz
gdb-471cecca46b70be2ac3dc73141f7946ddb7934af.tar.bz2
AArch64: Add MTE register set support for GDB and gdbserver
AArch64 MTE support in the Linux kernel exposes a couple new read-only registers through ptrace. This patch adds the required code to support them. include/ChangeLog: YYYY-MM-DD Luis Machado <luis.machado@linaro.org> * elf/common.h (NT_ARM_MTE): Define. gdb/ChangeLog: YYYY-MM-DD Luis Machado <luis.machado@linaro.org> * aarch64-linux-nat.c (fetch_mte_from_thread): New function. (aarch64_linux_nat_target::fetch_registers): Update to call fetch_mte_from_thread. * aarch64-linux-tdep.c (aarch64_linux_iterate_over_regset_sections): Handle MTE register section. * aarch64-tdep.c (aarch64_mte_register_names): New struct. (aarch64_cannot_store_register): Handle MTE registers. (aarch64_gdbarch_init): Initialize and setup MTE registers. * aarch64-tdep.h (gdbarch_tdep) <mte_reg_base>: New field. <has_mte>: New method. * arch/aarch64-linux.h (AARCH64_LINUX_SIZEOF_MTE): Define. gdbserver/ChangeLog: YYYY-MM-DD Luis Machado <luis.machado@linaro.org> * linux-aarch64-low.cc (aarch64_store_mteregset): New function. (aarch64_regsets): Add MTE register set entry. (aarch64_sve_regsets): Add MTE register set entry.
-rw-r--r--gdb/aarch64-linux-nat.c31
-rw-r--r--gdb/aarch64-linux-tdep.c21
-rw-r--r--gdb/aarch64-tdep.c43
-rw-r--r--gdb/aarch64-tdep.h9
-rw-r--r--gdb/arch/aarch64-mte-linux.h3
-rw-r--r--gdbserver/linux-aarch64-low.cc21
-rw-r--r--include/elf/common.h2
7 files changed, 125 insertions, 5 deletions
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 1392ec4..63e1395 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -461,6 +461,29 @@ fetch_pauth_masks_from_thread (struct regcache *regcache)
&pauth_regset[1]);
}
+/* Fill GDB's register array with the MTE register values from
+ the current thread. */
+
+static void
+fetch_mte_from_thread (struct regcache *regcache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+ int ret;
+ struct iovec iovec;
+ uint64_t mte_regset[2] = {0, 0};
+ int tid = regcache->ptid ().lwp ();
+
+ iovec.iov_base = &mte_regset;
+ iovec.iov_len = sizeof (mte_regset);
+
+ ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_MTE, &iovec);
+ if (ret != 0)
+ perror_with_name (_("unable to fetch MTE registers."));
+
+ regcache->raw_supply (tdep->mte_reg_base, &mte_regset[0]);
+ regcache->raw_supply (tdep->mte_reg_base + 1, &mte_regset[1]);
+}
+
/* Implement the "fetch_registers" target_ops method. */
void
@@ -479,6 +502,9 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
if (tdep->has_pauth ())
fetch_pauth_masks_from_thread (regcache);
+
+ if (tdep->has_mte ())
+ fetch_mte_from_thread (regcache);
}
else if (regno < AARCH64_V0_REGNUM)
fetch_gregs_from_thread (regcache);
@@ -493,6 +519,11 @@ aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
|| regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
fetch_pauth_masks_from_thread (regcache);
}
+
+ /* Fetch individual MTE registers. */
+ if (tdep->has_mte ()
+ && (regno == tdep->mte_reg_base || regno == (tdep->mte_reg_base + 1)))
+ fetch_mte_from_thread (regcache);
}
/* Implement the "store_registers" target_ops method. */
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 53f9d9f..fa76d87 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -645,6 +645,27 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
AARCH64_LINUX_SIZEOF_PAUTH, &aarch64_linux_pauth_regset,
"pauth registers", cb_data);
}
+
+ /* Handle MTE register set. */
+ if (tdep->has_mte ())
+ {
+ /* FIXME: This is still a WIP, awaiting further details from the Linuxkernel. */
+ /* Create this on the fly in order to handle the variable location. */
+ const struct regcache_map_entry mte_regmap[] =
+ {
+ { 2, tdep->mte_reg_base, 8},
+ { 0 }
+ };
+
+ const struct regset aarch64_linux_mte_regset =
+ {
+ mte_regmap, regcache_supply_regset, regcache_collect_regset
+ };
+
+ cb (".reg-aarch-mte", AARCH64_LINUX_SIZEOF_MTE,
+ AARCH64_LINUX_SIZEOF_MTE, &aarch64_linux_mte_regset,
+ "MTE registers", cb_data);
+ }
}
/* Implement the "core_read_description" gdbarch method. */
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 536f6f3..992507e 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -176,6 +176,14 @@ static const char *const aarch64_pauth_register_names[] =
"pauth_cmask"
};
+static const char *const aarch64_mte_register_names[] =
+{
+ /* System Control Top Level Register. */
+ "sctlr",
+ /* Tag Control Register. */
+ "gcr"
+};
+
/* AArch64 prologue cache structure. */
struct aarch64_prologue_cache
{
@@ -3202,12 +3210,19 @@ aarch64_cannot_store_register (struct gdbarch *gdbarch, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (!tdep->has_pauth ())
- return 0;
+ /* Is this a PAC register? */
+ if (tdep->has_pauth ()
+ && (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
+ || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base)))
+ return 1;
+
+ /* Is this a MTE register? */
+ if (tdep->has_mte ()
+ && (regnum == tdep->mte_reg_base || regnum == (tdep->mte_reg_base + 1)))
+ return 1;
- /* 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));
+ /* No restrictions on register store. */
+ return 0;
}
/* Initialize the current architecture based on INFO. If possible,
@@ -3225,6 +3240,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
bool valid_p = true;
int i, num_regs = 0, num_pseudo_regs = 0;
int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
+ int first_mte_regnum = -1;
/* Use the vector length passed via the target info. Here -1 is used for no
SVE, and 0 is unset. If unset then use the vector length from the existing
@@ -3262,6 +3278,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
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");
+ const struct tdesc_feature *feature_mte
+ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.mte");
if (feature_core == nullptr)
return nullptr;
@@ -3332,6 +3350,20 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
num_pseudo_regs += 1; /* Count RA_STATE pseudo register. */
}
+ /* Add the MTE registers. */
+ if (feature_mte != NULL)
+ {
+ first_mte_regnum = num_regs;
+ /* Validate the descriptor provides the mandatory MTE registers and
+ allocate their numbers. */
+ for (i = 0; i < ARRAY_SIZE (aarch64_mte_register_names); i++)
+ valid_p &= tdesc_numbered_register (feature_mte, tdesc_data,
+ first_mte_regnum + i,
+ aarch64_mte_register_names[i]);
+
+ num_regs += i;
+ }
+
if (!valid_p)
{
tdesc_data_cleanup (tdesc_data);
@@ -3352,6 +3384,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->pauth_reg_base = first_pauth_regnum;
tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
: pauth_ra_state_offset + num_regs;
+ tdep->mte_reg_base = first_mte_regnum;
set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index 4f8b19a..eb01e31 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -100,6 +100,15 @@ struct gdbarch_tdep
{
return pauth_reg_base != -1;
}
+
+ /* First MTE register. This is -1 if no MTE registers are available. */
+ int mte_reg_base;
+
+ /* Returns true if the target supports MTE. */
+ bool has_mte () const
+ {
+ return mte_reg_base != -1;
+ }
};
const target_desc *aarch64_read_description (uint64_t vq, bool pauth_p,
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index c6a91c2..423d4de 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -25,4 +25,7 @@
#define HWCAP2_MTE (1 << 18)
#endif
+/* The MTE regset consists of 2 registers of 64-bit size. */
+#define AARCH64_LINUX_SIZEOF_MTE (2 * 64)
+
#endif /* ARCH_AARCH64_LINUX_H */
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 60d60a4..b2a8640 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -261,6 +261,23 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
&pauth_regset[1]);
}
+/* Store the MTE registers to regcache. */
+
+static void
+aarch64_store_mteregset (struct regcache *regcache, const void *buf)
+{
+ uint64_t *mte_regset = (uint64_t *) buf;
+ int mte_base = find_regno (regcache->tdesc, "sctlr");
+
+ if (mte_base == 0)
+ return;
+
+ /* SCTLR register */
+ supply_register (regcache, mte_base, &mte_regset[0]);
+ /* GCR register */
+ supply_register (regcache, mte_base + 1, &mte_regset[1]);
+}
+
bool
aarch64_target::low_supports_breakpoints ()
{
@@ -684,6 +701,8 @@ static struct regset_info aarch64_regsets[] =
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
NULL, aarch64_store_pauthregset },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MTE,
+ AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, NULL, aarch64_store_mteregset },
NULL_REGSET
};
@@ -713,6 +732,8 @@ 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 },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MTE,
+ AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, NULL, aarch64_store_mteregset },
NULL_REGSET
};
diff --git a/include/elf/common.h b/include/elf/common.h
index 4d94c4f..33c773e 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -653,6 +653,8 @@
/* note name must be "LINUX". */
#define NT_ARM_PAC_MASK 0x406 /* AArch pointer authentication code masks */
/* note name must be "LINUX". */
+#define NT_ARM_MTE 0x407 /* AArch MTE 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. */