git: 4965ac059da1 - main - gcore: Use PT_GETREGSET to fetch NT_PRSTATUS and NT_FPREGSET.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 10 Mar 2022 23:41:35 UTC
The branch main has been updated by jhb:

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

commit 4965ac059da1ff7f3dac8f9556dd82c619063105
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-03-10 23:40:44 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-03-10 23:40:44 +0000

    gcore: Use PT_GETREGSET to fetch NT_PRSTATUS and NT_FPREGSET.
    
    Add a elf_putregnote() helper to build the ELF note for a register
    set.  Once nice result of this approach is that this reuses the
    kernel's support for generating 32-bit register sets for 32-bit
    processes avoiding the need to duplicate that logic in elf32core.c.
    
    Reviewed by:    markj
    Sponsored by:   University of Cambridge, Google, Inc.
    Differential Revision:  https://reviews.freebsd.org/D34447
---
 usr.bin/gcore/elf32core.c | 59 --------------------------------
 usr.bin/gcore/elfcore.c   | 87 ++++++++++++++++++++---------------------------
 2 files changed, 37 insertions(+), 109 deletions(-)

diff --git a/usr.bin/gcore/elf32core.c b/usr.bin/gcore/elf32core.c
index 4e91fb0bc065..98e2408c4aa9 100644
--- a/usr.bin/gcore/elf32core.c
+++ b/usr.bin/gcore/elf32core.c
@@ -12,65 +12,6 @@
 #define	ELFCORE_COMPAT_32	1
 #include "elfcore.c"
 
-static void
-elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs)
-{
-#ifdef __amd64__
-	rd->r_gs = rs->r_gs;
-	rd->r_fs = rs->r_fs;
-	rd->r_es = rs->r_es;
-	rd->r_ds = rs->r_ds;
-	rd->r_edi = rs->r_rdi;
-	rd->r_esi = rs->r_rsi;
-	rd->r_ebp = rs->r_rbp;
-	rd->r_ebx = rs->r_rbx;
-	rd->r_edx = rs->r_rdx;
-	rd->r_ecx = rs->r_rcx;
-	rd->r_eax = rs->r_rax;
-	rd->r_eip = rs->r_rip;
-	rd->r_cs = rs->r_cs;
-	rd->r_eflags = rs->r_rflags;
-	rd->r_esp = rs->r_rsp;
-	rd->r_ss = rs->r_ss;
-#elif defined(__aarch64__)
-	int i;
-
-	for (i = 0; i < 13; i++)
-		rd->r[i] = rs->x[i];
-	rd->r_sp = rs->x[13];
-	rd->r_lr = rs->x[14];
-	rd->r_pc = rs->elr;
-	rd->r_cpsr = rs->spsr;
-#elif defined(__powerpc64__)
-	int i;
-
-	for (i = 0; i < 32; i++)
-		rd->fixreg[i] = rs->fixreg[i];
-	rd->lr = rs->lr;
-	rd->cr = rs->cr;
-	rd->xer = rs->xer;
-	rd->ctr = rs->ctr;
-	rd->pc = rs->pc;
-#else
-#error Unsupported architecture
-#endif
-}
-
-static void
-elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs)
-{
-#ifdef __amd64__
-	/* XXX this is wrong... */
-	memcpy(rd, rs, sizeof(*rd));
-#elif defined(__aarch64__)
-	/* ARM64TODO */
-#elif defined(__powerpc64__)
-	memcpy(rd, rs, sizeof(*rd));
-#else
-#error Unsupported architecture
-#endif
-}
-
 static void
 elf_convert_siginfo(struct siginfo32 *sid, siginfo_t *sis)
 {
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
index 9c5be76cfd7c..b93ef7ed92d6 100644
--- a/usr.bin/gcore/elfcore.c
+++ b/usr.bin/gcore/elfcore.c
@@ -89,8 +89,6 @@ typedef struct reg32   elfcore_gregset_t;
 typedef struct prpsinfo32 elfcore_prpsinfo_t;
 typedef struct prstatus32 elfcore_prstatus_t;
 typedef struct ptrace_lwpinfo32 elfcore_lwpinfo_t;
-static void elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs);
-static void elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs);
 static void elf_convert_lwpinfo(struct ptrace_lwpinfo32 *pld,
     struct ptrace_lwpinfo *pls);
 #else
@@ -99,8 +97,6 @@ typedef gregset_t  elfcore_gregset_t;
 typedef prpsinfo_t elfcore_prpsinfo_t;
 typedef prstatus_t elfcore_prstatus_t;
 typedef struct ptrace_lwpinfo elfcore_lwpinfo_t;
-#define elf_convert_gregset(d,s)	*d = *s
-#define elf_convert_fpregset(d,s)	*d = *s
 #define	elf_convert_lwpinfo(d,s)	*d = *s
 #endif
 
@@ -111,9 +107,7 @@ static void cb_size_segment(struct map_entry *, void *);
 static void each_dumpable_segment(struct map_entry *, segment_callback,
     void *closure);
 static void elf_detach(void);	/* atexit() handler. */
-static void *elf_note_fpregset(void *, size_t *);
 static void *elf_note_prpsinfo(void *, size_t *);
-static void *elf_note_prstatus(void *, size_t *);
 static void *elf_note_thrmisc(void *, size_t *);
 static void *elf_note_ptlwpinfo(void *, size_t *);
 #if defined(__arm__)
@@ -139,6 +133,7 @@ static void elf_puthdr(int, pid_t, struct map_entry *, void *, size_t, size_t,
     size_t, int);
 static void elf_putnote(int, notefunc_t, void *, struct sbuf *);
 static void elf_putnotes(pid_t, struct sbuf *, size_t *);
+static void elf_putregnote(int, lwpid_t, struct sbuf *);
 static void freemap(struct map_entry *);
 static struct map_entry *readmap(pid_t);
 static void *procstat_sysctl(void *, int, size_t, size_t *sizep);
@@ -376,8 +371,8 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
 	elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb);
 
 	for (i = 0; i < threads; ++i) {
-		elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb);
-		elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb);
+		elf_putregnote(NT_PRSTATUS, tids[i], sb);
+		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(__arm__)
@@ -414,6 +409,40 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
 	*sizep = size;
 }
 
+/*
+ * Emit one register set note section to sbuf.
+ */
+static void
+elf_putregnote(int type, lwpid_t tid, struct sbuf *sb)
+{
+	Elf_Note note;
+	struct iovec iov;
+	ssize_t old_len;
+
+	iov.iov_base = NULL;
+	iov.iov_len = 0;
+	if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
+		return;
+	iov.iov_base = calloc(1, iov.iov_len);
+	if (iov.iov_base == NULL)
+		errx(1, "out of memory");
+	if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
+		errx(1, "failed to fetch register set %d", type);
+
+	note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
+	note.n_descsz = iov.iov_len;
+	note.n_type = type;
+
+	sbuf_bcat(sb, &note, sizeof(note));
+	sbuf_start_section(sb, &old_len);
+	sbuf_bcat(sb, "FreeBSD", note.n_namesz);
+	sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
+	sbuf_start_section(sb, &old_len);
+	sbuf_bcat(sb, iov.iov_base, iov.iov_len);
+	sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
+	free(iov.iov_base);
+}
+
 /*
  * Emit one note section to sbuf.
  */
@@ -654,48 +683,6 @@ elf_note_prpsinfo(void *arg, size_t *sizep)
 	return (psinfo);
 }
 
-static void *
-elf_note_prstatus(void *arg, size_t *sizep)
-{
-	lwpid_t tid;
-	elfcore_prstatus_t *status;
-	struct reg greg;
-
-	tid = *(lwpid_t *)arg;
-	status = calloc(1, sizeof(*status));
-	if (status == NULL)
-		errx(1, "out of memory");
-	status->pr_version = PRSTATUS_VERSION;
-	status->pr_statussz = sizeof(*status);
-	status->pr_gregsetsz = sizeof(elfcore_gregset_t);
-	status->pr_fpregsetsz = sizeof(elfcore_fpregset_t);
-	status->pr_osreldate = __FreeBSD_version;
-	status->pr_pid = tid;
-	ptrace(PT_GETREGS, tid, (void *)&greg, 0);
-	elf_convert_gregset(&status->pr_reg, &greg);
-
-	*sizep = sizeof(*status);
-	return (status);
-}
-
-static void *
-elf_note_fpregset(void *arg, size_t *sizep)
-{
-	lwpid_t tid;
-	elfcore_fpregset_t *fpregset;
-	fpregset_t fpreg;
-
-	tid = *(lwpid_t *)arg;
-	fpregset = calloc(1, sizeof(*fpregset));
-	if (fpregset == NULL)
-		errx(1, "out of memory");
-	ptrace(PT_GETFPREGS, tid, (void *)&fpreg, 0);
-	elf_convert_fpregset(fpregset, &fpreg);
-
-	*sizep = sizeof(*fpregset);
-	return (fpregset);
-}
-
 static void *
 elf_note_thrmisc(void *arg, size_t *sizep)
 {