From e0b7d19d4408953396d26dd60d64638d040d6f18 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 23 Mar 2022 13:33:06 -0700 Subject: [PATCH] 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 (cherry picked from commit b2cb74c22c4f7087f342cf50b116b040de6bdc6c) --- contrib/elftoolchain/readelf/readelf.c | 1 + sys/arm/arm/ptrace_machdep.c | 22 ++++++++++++ sys/arm64/arm64/ptrace_machdep.c | 48 ++++++++++++++++++++++++++ sys/sys/elf_common.h | 1 + usr.bin/gcore/elfcore.c | 3 ++ 5 files changed, 75 insertions(+) diff --git a/contrib/elftoolchain/readelf/readelf.c b/contrib/elftoolchain/readelf/readelf.c index fd8e75b66b5..fa3cdca3d68 100644 --- a/contrib/elftoolchain/readelf/readelf.c +++ b/contrib/elftoolchain/readelf/readelf.c @@ -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)); } diff --git a/sys/arm/arm/ptrace_machdep.c b/sys/arm/arm/ptrace_machdep.c index d8acc58d0fd..3edadbd72dd 100644 --- a/sys/arm/arm/ptrace_machdep.c +++ b/sys/arm/arm/ptrace_machdep.c @@ -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) { diff --git a/sys/arm64/arm64/ptrace_machdep.c b/sys/arm64/arm64/ptrace_machdep.c index abf1991a51a..44ca58a4915 100644 --- a/sys/arm64/arm64/ptrace_machdep.c +++ b/sys/arm64/arm64/ptrace_machdep.c @@ -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) { diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index 30f717d32ac..3c88b59cb5c 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -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 */ /* GNU note types. */ #define NT_GNU_ABI_TAG 1 diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c index 42d90aaaf15..c3ef36938ea 100644 --- a/usr.bin/gcore/elfcore.c +++ b/usr.bin/gcore/elfcore.c @@ -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 -- 2.45.0