AArch64: Add MTE register set support for GDB and gdbserver

AArch64 MTE support in the Linux kernel exposes a new register
through ptrace.  This patch adds the required code to support it.

include/ChangeLog:

2021-03-24  Luis Machado  <luis.machado@linaro.org>

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

gdb/ChangeLog:

2021-03-24  Luis Machado  <luis.machado@linaro.org>

	* aarch64-linux-nat.c (fetch_mteregs_from_thread): New function.
	(store_mteregs_to_thread): New function.
	(aarch64_linux_nat_target::fetch_registers): Update to call
	fetch_mteregs_from_thread.
	(aarch64_linux_nat_target::store_registers): Update to call
	store_mteregs_to_thread.
	* 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:

2021-03-24  Luis Machado  <luis.machado@linaro.org>

	* linux-aarch64-low.cc (aarch64_fill_mteregset): New function.
	(aarch64_store_mteregset): New function.
	(aarch64_regsets): Add MTE register set entry.
	(aarch64_sve_regsets): Add MTE register set entry.
This commit is contained in:
Luis Machado 2020-06-15 13:59:40 -03:00
parent c1bd443b4d
commit 5e984dbf35
8 changed files with 158 additions and 0 deletions

View File

@ -1,3 +1,18 @@
2021-03-24 Luis Machado <luis.machado@linaro.org>
* aarch64-linux-nat.c (fetch_mteregs_from_thread): New function.
(store_mteregs_to_thread): New function.
(aarch64_linux_nat_target::fetch_registers): Update to call
fetch_mteregs_from_thread.
(aarch64_linux_nat_target::store_registers): Update to call
store_mteregs_to_thread.
* 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.
2021-03-24 Luis Machado <luis.machado@linaro.org>
* aarch64-linux-nat.c

View File

@ -461,6 +461,58 @@ 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_mteregs_from_thread (struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
int regno = tdep->mte_reg_base;
gdb_assert (regno != -1);
uint64_t tag_ctl = 0;
struct iovec iovec;
iovec.iov_base = &tag_ctl;
iovec.iov_len = sizeof (tag_ctl);
int tid = get_ptrace_pid (regcache->ptid ());
if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0)
perror_with_name (_("unable to fetch MTE registers."));
regcache->raw_supply (regno, &tag_ctl);
}
/* Store to the current thread the valid MTE register set in the GDB's
register array. */
static void
store_mteregs_to_thread (struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
int regno = tdep->mte_reg_base;
gdb_assert (regno != -1);
uint64_t tag_ctl = 0;
if (REG_VALID != regcache->get_register_status (regno))
return;
regcache->raw_collect (regno, (char *) &tag_ctl);
struct iovec iovec;
iovec.iov_base = &tag_ctl;
iovec.iov_len = sizeof (tag_ctl);
int tid = get_ptrace_pid (regcache->ptid ());
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0)
perror_with_name (_("unable to store MTE registers."));
}
/* Implement the "fetch_registers" target_ops method. */
void
@ -479,6 +531,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_mteregs_from_thread (regcache);
}
else if (regno < AARCH64_V0_REGNUM)
fetch_gregs_from_thread (regcache);
@ -493,6 +548,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))
fetch_mteregs_from_thread (regcache);
}
/* Implement the "store_registers" target_ops method. */
@ -510,6 +570,9 @@ aarch64_linux_nat_target::store_registers (struct regcache *regcache,
store_sveregs_to_thread (regcache);
else
store_fpregs_to_thread (regcache);
if (tdep->has_mte ())
store_mteregs_to_thread (regcache);
}
else if (regno < AARCH64_V0_REGNUM)
store_gregs_to_thread (regcache);
@ -517,6 +580,11 @@ aarch64_linux_nat_target::store_registers (struct regcache *regcache,
store_sveregs_to_thread (regcache);
else
store_fpregs_to_thread (regcache);
/* Store MTE registers. */
if (tdep->has_mte ()
&& (regno == tdep->mte_reg_base))
store_mteregs_to_thread (regcache);
}
/* Fill register REGNO (if it is a general-purpose register) in

View File

@ -172,6 +172,12 @@ static const char *const aarch64_pauth_register_names[] =
"pauth_cmask"
};
static const char *const aarch64_mte_register_names[] =
{
/* Tag Control Register. */
"tag_ctl"
};
/* AArch64 prologue cache structure. */
struct aarch64_prologue_cache
{
@ -3346,6 +3352,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
@ -3383,6 +3390,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;
@ -3453,6 +3462,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.get (),
first_mte_regnum + i,
aarch64_mte_register_names[i]);
num_regs += i;
}
if (!valid_p)
return nullptr;
@ -3470,6 +3493,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);

View File

@ -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,

View File

@ -25,4 +25,7 @@
#define HWCAP2_MTE (1 << 18)
#endif
/* The MTE regset consists of a single 64-bit register. */
#define AARCH64_LINUX_SIZEOF_MTE 8
#endif /* ARCH_AARCH64_LINUX_H */

View File

@ -1,3 +1,10 @@
2021-03-24 Luis Machado <luis.machado@linaro.org>
* linux-aarch64-low.cc (aarch64_fill_mteregset): New function.
(aarch64_store_mteregset): New function.
(aarch64_regsets): Add MTE register set entry.
(aarch64_sve_regsets): Add MTE register set entry.
2021-03-24 Luis Machado <luis.machado@linaro.org>
* linux-aarch64-ipa.cc (get_ipa_tdesc): Update call to

View File

@ -261,6 +261,29 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
&pauth_regset[1]);
}
/* Fill BUF with the MTE registers from the regcache. */
static void
aarch64_fill_mteregset (struct regcache *regcache, void *buf)
{
uint64_t *mte_regset = (uint64_t *) buf;
int mte_base = find_regno (regcache->tdesc, "tag_ctl");
collect_register (regcache, mte_base, mte_regset);
}
/* 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, "tag_ctl");
/* Tag Control register */
supply_register (regcache, mte_base, mte_regset);
}
bool
aarch64_target::low_supports_breakpoints ()
{
@ -706,6 +729,9 @@ 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_TAGGED_ADDR_CTRL,
AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, aarch64_fill_mteregset,
aarch64_store_mteregset },
NULL_REGSET
};
@ -735,6 +761,9 @@ 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_TAGGED_ADDR_CTRL,
AARCH64_LINUX_SIZEOF_MTE, OPTIONAL_REGS, aarch64_fill_mteregset,
aarch64_store_mteregset },
NULL_REGSET
};

View File

@ -672,6 +672,9 @@
/* note name must be "LINUX". */
#define NT_ARM_PAC_MASK 0x406 /* AArch pointer authentication code masks */
/* note name must be "LINUX". */
#define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* AArch64 tagged address control
(prctl()) */
/* note name must be "LINUX". */
#define NT_ARC_V2 0x600 /* ARC HS accumulator/extra registers. */
/* note name must be "LINUX". */
#define NT_RISCV_CSR 0x900 /* RISC-V Control and Status Registers */