git: e0b7d19d4408 - stable/13 - arm,arm64: Add a NT_ARM_TLS read-only register set.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 13 May 2022 17:42:50 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=e0b7d19d4408953396d26dd60d64638d040d6f18

commit e0b7d19d4408953396d26dd60d64638d040d6f18
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-03-23 20:33:06 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-05-13 00:39:00 +0000

    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 fd8e75b66b56..fa3cdca3d682 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 d8acc58d0fd0..3edadbd72ddf 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 abf1991a51a6..44ca58a49156 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 30f717d32ac7..3c88b59cb5ce 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 42d90aaaf155..c3ef36938ea9 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