arm,arm64: Add a NT_ARM_TLS read-only register set.

This register set exposes the per-thread TLS register.  It matches the
layout used by Linux on arm64.  Linux does not implement this note for
32-bit arm.

Reviewed by:	andrew, markj
Sponsored by:	University of Cambridge, Google, Inc.
Differential Revision:	https://reviews.freebsd.org/D34595
This commit is contained in:
John Baldwin 2022-03-23 13:33:06 -07:00
parent add00c381e
commit b2cb74c22c
5 changed files with 75 additions and 0 deletions

View File

@ -1197,6 +1197,7 @@ note_type_freebsd_core(unsigned int nt)
case 0x102: return "NT_PPC_VSX (ppc VSX registers)";
case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)";
case 0x400: return "NT_ARM_VFP (arm VFP registers)";
case 0x401: return "NT_ARM_TLS (arm TLS register)";
case 0x406: return "NT_ARM_ADDR_MASK (arm address mask)";
default: return (note_type_unknown(nt));
}

View File

@ -67,6 +67,28 @@ static struct regset regset_arm_vfp = {
ELF_REGSET(regset_arm_vfp);
#endif
static bool
get_arm_tls(struct regset *rs, struct thread *td, void *buf,
size_t *sizep)
{
if (buf != NULL) {
KASSERT(*sizep == sizeof(td->td_pcb->pcb_regs.sf_tpidrurw),
("%s: invalid size", __func__));
memcpy(buf, &td->td_pcb->pcb_regs.sf_tpidrurw,
sizeof(td->td_pcb->pcb_regs.sf_tpidrurw));
}
*sizep = sizeof(td->td_pcb->pcb_regs.sf_tpidrurw);
return (true);
}
static struct regset regset_arm_tls = {
.note = NT_ARM_TLS,
.size = sizeof(uint32_t),
.get = get_arm_tls,
};
ELF_REGSET(regset_arm_tls);
int
cpu_ptrace(struct thread *td, int req, void *addr, int data)
{

View File

@ -81,6 +81,54 @@ static struct regset regset_arm_vfp = {
ELF32_REGSET(regset_arm_vfp);
#endif
static bool
get_arm64_tls(struct regset *rs, struct thread *td, void *buf,
size_t *sizep)
{
if (buf != NULL) {
KASSERT(*sizep == sizeof(td->td_pcb->pcb_tpidr_el0),
("%s: invalid size", __func__));
memcpy(buf, &td->td_pcb->pcb_tpidr_el0,
sizeof(td->td_pcb->pcb_tpidr_el0));
}
*sizep = sizeof(td->td_pcb->pcb_tpidr_el0);
return (true);
}
static struct regset regset_arm64_tls = {
.note = NT_ARM_TLS,
.size = sizeof(uint64_t),
.get = get_arm64_tls,
};
ELF_REGSET(regset_arm64_tls);
#ifdef COMPAT_FREEBSD32
static bool
get_arm_tls(struct regset *rs, struct thread *td, void *buf,
size_t *sizep)
{
if (buf != NULL) {
uint32_t tp;
KASSERT(*sizep == sizeof(uint32_t),
("%s: invalid size", __func__));
tp = (uint32_t)td->td_pcb->pcb_tpidr_el0;
memcpy(buf, &tp, sizeof(tp));
}
*sizep = sizeof(uint32_t);
return (true);
}
static struct regset regset_arm_tls = {
.note = NT_ARM_TLS,
.size = sizeof(uint32_t),
.get = get_arm_tls,
};
ELF32_REGSET(regset_arm_tls);
#endif
int
ptrace_set_pc(struct thread *td, u_long addr)
{

View File

@ -825,6 +825,7 @@ typedef struct {
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_X86_XSTATE 0x202 /* x86 XSAVE extended state. */
#define NT_ARM_VFP 0x400 /* ARM VFP registers */
#define NT_ARM_TLS 0x401 /* ARM TLS register */
#define NT_ARM_ADDR_MASK 0x406 /* arm64 address mask (e.g. for TBI) */
/* GNU note types. */

View File

@ -372,6 +372,9 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
elf_putregnote(NT_FPREGSET, tids[i], sb);
elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb);
elf_putnote(NT_PTLWPINFO, elf_note_ptlwpinfo, tids + i, sb);
#if defined(__aarch64__) || defined(__arm__)
elf_putregnote(NT_ARM_TLS, tids[i], sb);
#endif
#if (defined(ELFCORE_COMPAT_32) && defined(__aarch64__)) || defined(__arm__)
elf_putregnote(NT_ARM_VFP, tids[i], sb);
#endif