From 36dfedc923d68164dceb866d02affe5a41b9c249 Mon Sep 17 00:00:00 2001
From: jhb <jhb@FreeBSD.org>
Date: Tue, 7 Feb 2017 20:34:03 +0000
Subject: [PATCH] Copy the e_machine and e_flags fields from the binary into an
 ELF core dump.

In the kernel, cache the machine and flags fields from ELF header to use in
the ELF header of a core dump. For gcore, the copy these fields over from
the ELF header in the binary.

This matters for platforms which encode ABI information in the flags field
(such as o32 vs n32 on MIPS).

Reviewed by:	kib
Sponsored by:	DARPA / AFRL
Differential Revision:	https://reviews.freebsd.org/D9392
---
 sys/kern/imgact_elf.c   | 10 ++++------
 sys/sys/proc.h          |  5 ++++-
 usr.bin/gcore/elfcore.c | 23 +++++++++++++++--------
 3 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 03040f2fab71..3b79df109f04 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1055,6 +1055,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 	imgp->interpreted = 0;
 	imgp->reloc_base = addr;
 	imgp->proc->p_osrel = osrel;
+	imgp->proc->p_elf_machine = hdr->e_machine;
+	imgp->proc->p_elf_flags = hdr->e_flags;
 
 ret:
 	free(interp_buf, M_TEMP);
@@ -1655,15 +1657,11 @@ __elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs,
 	ehdr->e_ident[EI_ABIVERSION] = 0;
 	ehdr->e_ident[EI_PAD] = 0;
 	ehdr->e_type = ET_CORE;
-#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
-	ehdr->e_machine = ELF_ARCH32;
-#else
-	ehdr->e_machine = ELF_ARCH;
-#endif
+	ehdr->e_machine = td->td_proc->p_elf_machine;
 	ehdr->e_version = EV_CURRENT;
 	ehdr->e_entry = 0;
 	ehdr->e_phoff = sizeof(Elf_Ehdr);
-	ehdr->e_flags = 0;
+	ehdr->e_flags = td->td_proc->p_elf_flags;
 	ehdr->e_ehsize = sizeof(Elf_Ehdr);
 	ehdr->e_phentsize = sizeof(Elf_Phdr);
 	ehdr->e_shentsize = sizeof(Elf_Shdr);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index e7f3f2f49738..090f8ef6c0c9 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -617,8 +617,11 @@ struct proc {
 					       our subtree. */
 	u_int		p_xexit;	/* (c) Exit code. */
 	u_int		p_xsig;		/* (c) Stop/kill sig. */
+	uint16_t	p_elf_machine;	/* (x) ELF machine type */
+	uint64_t	p_elf_flags;	/* (x) ELF flags */
+	
 /* End area that is copied on creation. */
-#define	p_endcopy	p_xsig
+#define	p_endcopy	p_elf_flags
 	struct pgrp	*p_pgrp;	/* (c + e) Pointer to process group. */
 	struct knlist	*p_klist;	/* (c) Knotes attached to this proc. */
 	int		p_numthreads;	/* (c) Number of threads. */
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
index 541faece8d12..7c110e8af983 100644
--- a/usr.bin/gcore/elfcore.c
+++ b/usr.bin/gcore/elfcore.c
@@ -117,8 +117,8 @@ static void *elf_note_procstat_psstrings(void *, size_t *);
 static void *elf_note_procstat_rlimit(void *, size_t *);
 static void *elf_note_procstat_umask(void *, size_t *);
 static void *elf_note_procstat_vmmap(void *, size_t *);
-static void elf_puthdr(pid_t, vm_map_entry_t, void *, size_t, size_t, size_t,
-    int);
+static void elf_puthdr(int, pid_t, vm_map_entry_t, 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 freemap(vm_map_entry_t);
@@ -178,7 +178,7 @@ elf_detach(void)
  * Write an ELF coredump for the given pid to the given fd.
  */
 static void
-elf_coredump(int efd __unused, int fd, pid_t pid)
+elf_coredump(int efd, int fd, pid_t pid)
 {
 	vm_map_entry_t map;
 	struct sseg_closure seginfo;
@@ -230,7 +230,7 @@ elf_coredump(int efd __unused, int fd, pid_t pid)
 	hdr = sbuf_data(sb);
 	segoff = sbuf_len(sb);
 	/* Fill in the header. */
-	elf_puthdr(pid, map, hdr, hdrsize, notesz, segoff, seginfo.count);
+	elf_puthdr(efd, pid, map, hdr, hdrsize, notesz, segoff, seginfo.count);
 
 	n = write(fd, hdr, segoff);
 	if (n == -1)
@@ -420,14 +420,21 @@ elf_putnote(int type, notefunc_t notefunc, void *arg, struct sbuf *sb)
  * Generate the ELF coredump header.
  */
 static void
-elf_puthdr(pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize,
+elf_puthdr(int efd, pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize,
     size_t notesz, size_t segoff, int numsegs)
 {
-	Elf_Ehdr *ehdr;
+	Elf_Ehdr *ehdr, binhdr;
 	Elf_Phdr *phdr;
 	Elf_Shdr *shdr;
 	struct phdr_closure phc;
+	ssize_t cnt;
 
+	cnt = read(efd, &binhdr, sizeof(binhdr));
+	if (cnt < 0)
+		err(1, "Failed to re-read ELF header");
+	else if (cnt != sizeof(binhdr))
+		errx(1, "Failed to re-read ELF header");
+	
 	ehdr = (Elf_Ehdr *)hdr;
 
 	ehdr->e_ident[EI_MAG0] = ELFMAG0;
@@ -441,11 +448,11 @@ elf_puthdr(pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize,
 	ehdr->e_ident[EI_ABIVERSION] = 0;
 	ehdr->e_ident[EI_PAD] = 0;
 	ehdr->e_type = ET_CORE;
-	ehdr->e_machine = ELF_ARCH;
+	ehdr->e_machine = binhdr.e_machine;
 	ehdr->e_version = EV_CURRENT;
 	ehdr->e_entry = 0;
 	ehdr->e_phoff = sizeof(Elf_Ehdr);
-	ehdr->e_flags = 0;
+	ehdr->e_flags = binhdr.e_flags;
 	ehdr->e_ehsize = sizeof(Elf_Ehdr);
 	ehdr->e_phentsize = sizeof(Elf_Phdr);
 	ehdr->e_shentsize = sizeof(Elf_Shdr);