+2020-10-20 Luis Machado <luis.machado@arm.com>
+
+ * aarch64-linux-nat.c: Include arch/aarch64-cap-linux.h.
+ (fetch_cregs_from_thread)
+ (store_cregs_to_thread): New functions.
+ (aarch64_linux_nat_target::fetch_registers): Modify to check for
+ capability registers.
+ * aarch64-linux-tdep.c: Include arch/aarch64-cap-linux.h.
+ * aarch64-tdep.c (aarch64_cannot_store_register): Check for capability
+ registers.
+ (aarch64_gdbarch_init): Also save the last capability register number.
+ * aarch64-tdep.h (struct gdbarch_tdep) <cap_reg_last>: New field.
+ * arch/aarch64-cap-linux.h (AARCH64_LINUX_CREGS_SIZE,
+ AARCH64_MORELLO_REGS_NUM, AARCH64_C_REGS_NUM): New constants.
+ * arch/aarch64.c: Remove FIXME comment.
+ * nat/aarch64-linux.h (user_morello_state): New struct.
+
2020-10-20 Luis Machado <luis.machado@arm.com>
* aarch64-linux-nat.c (aarch64_linux_nat_target::read_description):
#include "aarch32-linux-nat.h"
#include "aarch32-tdep.h"
#include "arch/arm.h"
+#include "arch/aarch64-cap-linux.h"
#include "nat/aarch64-linux.h"
#include "nat/aarch64-linux-hw-point.h"
#include "nat/aarch64-sve-linux-ptrace.h"
&pauth_regset[1]);
}
+/* Fill GDB's register array with the capability register values
+ from the current thread. */
+
+static void
+fetch_cregs_from_thread (struct regcache *regcache)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ gdb_assert (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64);
+
+ int tid = regcache->ptid ().lwp ();
+
+ struct user_morello_state cregset;
+ struct iovec iovec;
+ iovec.iov_base = &cregset;
+ iovec.iov_len = sizeof (cregset);
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_MORELLO, &iovec) < 0)
+ perror_with_name (_("Unable to fetch capability registers."));
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
+ /* Fetch the C registers. */
+ int regno, i;
+ for (regno = tdep->cap_reg_base, i = 0;
+ regno < tdep->cap_reg_base + AARCH64_C_REGS_NUM;
+ regno++, i++)
+ regcache->raw_supply (regno, &cregset.cregs[i]);
+
+ /* Fetch the other registers. */
+ regcache->raw_supply (regno++, &cregset.pcc);
+ regcache->raw_supply (regno++, &cregset.csp);
+ regcache->raw_supply (regno++, &cregset.ddc);
+ regcache->raw_supply (regno++, &cregset.ctpidr);
+ regcache->raw_supply (regno++, &cregset.rcsp);
+ regcache->raw_supply (regno++, &cregset.rddc);
+ regcache->raw_supply (regno++, &cregset.rctpidr);
+ regcache->raw_supply (regno++, &cregset.cid);
+ regcache->raw_supply (regno++, &cregset.tag_map);
+ regcache->raw_supply (regno++, &cregset.cctlr);
+}
+
+/* Store to the current thread the valid capability register
+ values in the GDB's register array. */
+
+static void
+store_cregs_to_thread (const struct regcache *regcache)
+{
+ /* Can't modify capability registers, do nothing. */
+}
+
/* Implement the "fetch_registers" target_ops method. */
void
if (tdep->has_pauth ())
fetch_pauth_masks_from_thread (regcache);
+
+ if (tdep->has_capability ())
+ fetch_cregs_from_thread (regcache);
}
+ else if (tdep->has_capability () && regno >= tdep->cap_reg_base
+ && regno < tdep->cap_reg_base + AARCH64_MORELLO_REGS_NUM)
+ fetch_cregs_from_thread (regcache);
else if (regno < AARCH64_V0_REGNUM)
fetch_gregs_from_thread (regcache);
else if (tdep->has_sve ())
store_sveregs_to_thread (regcache);
else
store_fpregs_to_thread (regcache);
+
+ if (tdep->has_capability ())
+ {
+ /* Due to the aliasing of X/C registers and due to register merging
+ by the kernel (see documentation in the kernel), we should force
+ a read of the C registers whenever the X registers are written
+ to. */
+ fetch_cregs_from_thread (regcache);
+ store_cregs_to_thread (regcache);
+ }
}
+ else if (tdep->has_capability () && regno >= tdep->cap_reg_base
+ && regno < tdep->cap_reg_base + AARCH64_MORELLO_REGS_NUM)
+ store_cregs_to_thread (regcache);
else if (regno < AARCH64_V0_REGNUM)
- store_gregs_to_thread (regcache);
+ {
+ store_gregs_to_thread (regcache);
+ fetch_cregs_from_thread (regcache);
+ }
else if (tdep->has_sve ())
store_sveregs_to_thread (regcache);
else
#include "linux-tdep.h"
#include "aarch64-tdep.h"
#include "aarch64-linux-tdep.h"
+#include "arch/aarch64-cap-linux.h"
#include "osabi.h"
#include "solib-svr4.h"
#include "symtab.h"
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (!tdep->has_pauth ())
- return 0;
+ if (tdep->has_pauth ())
+ {
+ /* 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));
+ }
- /* 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));
+ if (tdep->has_capability ())
+ {
+ /* Capability register set is read-only for now. */
+ return (regnum >= tdep->cap_reg_base && regnum < tdep->cap_reg_last);
+ }
+
+ return 0;
}
/* Initialize the current architecture based on INFO. If possible,
const struct tdesc_feature *feature_capability
= tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.capability");
int first_cap_regnum = -1;
+ int last_cap_regnum = -1;
if (feature_capability != nullptr)
{
for (i = 0; i < ARRAY_SIZE (aarch64_c_register_names); i++)
valid_p &= tdesc_numbered_register (feature_capability,
tdesc_data.get (),
- AARCH64_C0_REGNUM + i,
+ first_cap_regnum + i,
aarch64_c_register_names[i]);
- num_regs = AARCH64_C0_REGNUM + i;
+ last_cap_regnum = first_cap_regnum + i - 1;
+ num_regs += i;
}
if (!valid_p)
: pauth_ra_state_offset + num_regs;
tdep->cap_reg_base = first_cap_regnum;
+ tdep->cap_reg_last = last_cap_regnum;
set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
return pauth_reg_base != -1;
}
+ /* First register from the capability set. */
int cap_reg_base;
+ /* Last register from the capability set. */
+ int cap_reg_last;
/* Returns true if the target supports capabilities. */
bool has_capability () const
/* Morello HWCAP bit. */
#define HWCAP2_MORELLO (1 << 19)
+/* Size of the Capability register set. */
+#define AARCH64_LINUX_CREGS_SIZE ((39 * 16) + (2 * 8))
+
+/* 39 128-bit C registers plus 2 64-bit registers. */
+#define AARCH64_MORELLO_REGS_NUM 41
+#define AARCH64_C_REGS_NUM 31
+
#endif /*ARCH_AARCH64_LINUX_H */
if (pauth_p)
regnum = create_feature_aarch64_pauth (tdesc.get (), regnum);
- /* FIXME-Morello: We need to append the capability registers to
- the existing target description. Figure out how to do that.
- Maybe replace the general purpose register description with
- the capability registers. */
if (capability_p)
regnum = create_feature_aarch64_capability (tdesc.get (), regnum);
/* Defines ps_err_e, struct ps_prochandle. */
#include "gdb_proc_service.h"
+/* Struct defining the layout of the capability register set. */
+struct user_morello_state {
+ /* General capability registers. */
+ unsigned __int128 cregs[31];
+ /* Capability program counter. */
+ unsigned __int128 pcc;
+ /* Capability stack pointer. */
+ unsigned __int128 csp;
+ /* Default data capability. */
+ unsigned __int128 ddc;
+ unsigned __int128 ctpidr;
+ unsigned __int128 rcsp;
+ unsigned __int128 rddc;
+ unsigned __int128 rctpidr;
+ /* Compartment ID register. */
+ unsigned __int128 cid;
+ /* Bitmap storing the tags of all the capability registers.
+ The tag for register <reg> is stored at bit index
+ MORELLO_PT_TAG_MAP_REG_BIT(<reg>) in tag_map. */
+ uint64_t tag_map;
+ /* Capability control register. */
+ uint64_t cctlr;
+};
+
typedef int compat_int_t;
typedef unsigned int compat_uptr_t;
+2020-10-20 Luis Machado <luis.machado@arm.com>
+
+ * linux-aarch64-low.c: arch/aarch64-cap-linux.h.
+ (aarch64_store_cregset): New function.
+ (aarch64_regsets): Add capability register set.
+ (aarch64_sve_regsets): Likewise.
+
2020-10-20 Luis Machado <luis.machado@arm.com>
* linux-aarch64-ipa.cc (get_ipa_tdesc): Update.
#include "linux-low.h"
#include "nat/aarch64-linux.h"
#include "nat/aarch64-linux-hw-point.h"
+#include "arch/aarch64-cap-linux.h"
#include "arch/aarch64-insn.h"
#include "linux-aarch32-low.h"
#include "elf/common.h"
&pauth_regset[1]);
}
+/* Capability registers store hook implementation. */
+
+static void
+aarch64_store_cregset (struct regcache *regcache, const void *buf)
+{
+ const struct user_morello_state *cregset
+ = (const struct user_morello_state *) buf;
+
+ int cregs_base = find_regno (regcache->tdesc, "c0");
+
+ /* Fetch the C registers. */
+ int i, regno;
+ for (regno = cregs_base, i = 0;
+ regno < cregs_base + AARCH64_C_REGS_NUM;
+ regno++, i++)
+ supply_register (regcache, regno, &cregset->cregs[i]);
+
+ /* Fetch the other registers. */
+ supply_register (regcache, regno++, &cregset->pcc);
+ supply_register (regcache, regno++, &cregset->csp);
+ supply_register (regcache, regno++, &cregset->ddc);
+ supply_register (regcache, regno++, &cregset->ctpidr);
+ supply_register (regcache, regno++, &cregset->rcsp);
+ supply_register (regcache, regno++, &cregset->rddc);
+ supply_register (regcache, regno++, &cregset->rctpidr);
+ supply_register (regcache, regno++, &cregset->cid);
+ supply_register (regcache, regno++, &cregset->tag_map);
+ supply_register (regcache, regno++, &cregset->cctlr);
+}
+
bool
aarch64_target::low_supports_breakpoints ()
{
return true;
}
-/* Implementation of linux target ops method "low_get_pc". */
+/* Implementation of linux_target_ops method "get_pc". */
CORE_ADDR
aarch64_target::low_get_pc (regcache *regcache)
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
NULL, aarch64_store_pauthregset },
+ /* FIXME-Morello: Fixup the register set size. */
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
+ AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
+ nullptr, aarch64_store_cregset },
NULL_REGSET
};
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_PAC_MASK,
AARCH64_PAUTH_REGS_SIZE, OPTIONAL_REGS,
NULL, aarch64_store_pauthregset },
+ /* FIXME-Morello: Fixup the register set size. */
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
+ AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
+ nullptr, aarch64_store_cregset },
NULL_REGSET
};
+2020-10-20 Luis Machado <luis.machado@arm.com>
+
+ * elf/common.h (NT_ARM_MORELLO): Define.
+
2020-10-20 Luis Machado <luis.machado@arm.com>
* dwarf2.def (DW_ATE_CHERI_signed_intcap)
/* note name must be "LINUX". */
#define NT_ARM_PAC_MASK 0x406 /* AArch pointer authentication code masks */
/* note name must be "LINUX". */
+#define NT_ARM_MORELLO 0x410 /* AArch capability 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. */