Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Apr 2013 19:59:38 +0000 (UTC)
From:      Mikolaj Golub <trociny@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r249486 - head/sys/kern
Message-ID:  <201304141959.r3EJxcZ3008562@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trociny
Date: Sun Apr 14 19:59:38 2013
New Revision: 249486
URL: http://svnweb.freebsd.org/changeset/base/249486

Log:
  Re-factor coredump routines.  For each type of notes an output
  function is provided, which is used either to calculate the note size
  or output it to sbuf.  On the first pass the notes are registered in a
  list and the resulting size is found, on the second pass the list is
  traversed outputing notes to sbuf.  For the sbuf a drain routine is
  provided that writes data to a core file.
  
  The main goal of the change is to make coredump to write notes
  directly to the core file, without preliminary preparing them all in a
  memory buffer.  Storing notes in memory is not a problem for the
  current, rather small, set of notes we write to the core, but it may
  becomes an issue when we start to store procstat notes.
  
  Reviewed by:	jhb (initial version), kib
  Discussed with:	jhb, kib
  MFC after:	3 weeks

Modified:
  head/sys/kern/imgact_elf.c

Modified: head/sys/kern/imgact_elf.c
==============================================================================
--- head/sys/kern/imgact_elf.c	Sun Apr 14 19:21:43 2013	(r249485)
+++ head/sys/kern/imgact_elf.c	Sun Apr 14 19:59:38 2013	(r249486)
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/racct.h>
 #include <sys/resourcevar.h>
 #include <sys/rwlock.h>
+#include <sys/sbuf.h>
 #include <sys/sf_buf.h>
 #include <sys/smp.h>
 #include <sys/systm.h>
@@ -104,8 +105,8 @@ SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(el
 #ifdef COMPRESS_USER_CORES
 static int compress_core(gzFile, char *, char *, unsigned int,
     struct thread * td);
-#define CORE_BUF_SIZE	(16 * 1024)
 #endif
+#define CORE_BUF_SIZE	(16 * 1024)
 
 int __elfN(fallback_brand) = -1;
 SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO,
@@ -1038,14 +1039,35 @@ struct sseg_closure {
 	size_t size;		/* Total size of all writable segments. */
 };
 
+typedef void (*outfunc_t)(void *, struct sbuf *, size_t *);
+
+struct note_info {
+	int		type;		/* Note type. */
+	outfunc_t 	outfunc; 	/* Output function. */
+	void		*outarg;	/* Argument for the output function. */
+	size_t		outsize;	/* Output size. */
+	TAILQ_ENTRY(note_info) link;	/* Link to the next note info. */
+};
+
+TAILQ_HEAD(note_info_list, note_info);
+
 static void cb_put_phdr(vm_map_entry_t, void *);
 static void cb_size_segment(vm_map_entry_t, void *);
 static void each_writable_segment(struct thread *, segment_callback, void *);
 static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *,
-    int, void *, size_t, gzFile);
-static void __elfN(puthdr)(struct thread *, void *, size_t *, int);
-static void __elfN(putnote)(void *, size_t *, const char *, int,
-    const void *, size_t);
+    int, void *, size_t, struct note_info_list *, size_t, gzFile);
+static void __elfN(prepare_notes)(struct thread *, struct note_info_list *,
+    size_t *);
+static void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t);
+static void __elfN(putnote)(struct note_info *, struct sbuf *);
+static size_t register_note(struct note_info_list *, int, outfunc_t, void *);
+static int sbuf_drain_core_output(void *, const char *, int);
+
+static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *);
+static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *);
+static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *);
+static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *);
+static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *);
 
 #ifdef COMPRESS_USER_CORES
 extern int compress_user_cores;
@@ -1072,14 +1094,54 @@ core_output(struct vnode *vp, void *base
 	return (error);
 }
 
+/* Coredump output parameters for sbuf drain routine. */
+struct sbuf_drain_core_params {
+	off_t		offset;
+	struct ucred	*active_cred;
+	struct ucred	*file_cred;
+	struct thread	*td;
+	struct vnode	*vp;
+#ifdef COMPRESS_USER_CORES
+	gzFile		gzfile;
+#endif
+};
+
+/*
+ * Drain into a core file.
+ */
+static int
+sbuf_drain_core_output(void *arg, const char *data, int len)
+{
+	struct sbuf_drain_core_params *p;
+	int error;
+
+	p = (struct sbuf_drain_core_params *)arg;
+#ifdef COMPRESS_USER_CORES
+	if (p->gzfile != Z_NULL)
+		error = compress_core(p->gzfile, NULL, __DECONST(char *, data),
+		    len, p->td);
+	else
+#endif
+		error = vn_rdwr_inchunks(UIO_WRITE, p->vp,
+		    __DECONST(void *, data), len, p->offset, UIO_SYSSPACE,
+		    IO_UNIT | IO_DIRECT, p->active_cred, p->file_cred, NULL,
+		    p->td);
+	if (error != 0)
+		return (-error);
+	p->offset += len;
+	return (len);
+}
+
 int
 __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
 {
 	struct ucred *cred = td->td_ucred;
 	int error = 0;
 	struct sseg_closure seginfo;
+	struct note_info_list notelst;
+	struct note_info *ninfo;
 	void *hdr;
-	size_t hdrsize;
+	size_t hdrsize, notesz, coresize;
 
 	gzFile gzfile = Z_NULL;
 	char *core_buf = NULL;
@@ -1090,6 +1152,7 @@ __elfN(coredump)(struct thread *td, stru
 #endif
 
 	hdr = NULL;
+	TAILQ_INIT(&notelst);
 
 #ifdef COMPRESS_USER_CORES
         if (doing_compress) {
@@ -1118,30 +1181,29 @@ __elfN(coredump)(struct thread *td, stru
 	each_writable_segment(td, cb_size_segment, &seginfo);
 
 	/*
-	 * Calculate the size of the core file header area by making
-	 * a dry run of generating it.  Nothing is written, but the
-	 * size is calculated.
+	 * Collect info about the core file header area.
 	 */
-	hdrsize = 0;
-	__elfN(puthdr)(td, (void *)NULL, &hdrsize, seginfo.count);
+	hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count);
+	__elfN(prepare_notes)(td, &notelst, &notesz);
+	coresize = round_page(hdrsize + notesz) + seginfo.size;
 
 #ifdef RACCT
 	PROC_LOCK(td->td_proc);
-	error = racct_add(td->td_proc, RACCT_CORE, hdrsize + seginfo.size);
+	error = racct_add(td->td_proc, RACCT_CORE, coresize);
 	PROC_UNLOCK(td->td_proc);
 	if (error != 0) {
 		error = EFAULT;
 		goto done;
 	}
 #endif
-	if (hdrsize + seginfo.size >= limit) {
+	if (coresize >= limit) {
 		error = EFAULT;
 		goto done;
 	}
 
 	/*
 	 * Allocate memory for building the header, fill it up,
-	 * and write it out.
+	 * and write it out following the notes.
 	 */
 	hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
 	if (hdr == NULL) {
@@ -1149,7 +1211,7 @@ __elfN(coredump)(struct thread *td, stru
 		goto done;
 	}
 	error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize,
-	    gzfile);
+	    &notelst, notesz, gzfile);
 
 	/* Write the contents of all of the writable segments. */
 	if (error == 0) {
@@ -1158,7 +1220,7 @@ __elfN(coredump)(struct thread *td, stru
 		int i;
 
 		php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
-		offset = hdrsize;
+		offset = round_page(hdrsize + notesz);
 		for (i = 0; i < seginfo.count; i++) {
 			error = core_output(vp, (caddr_t)(uintptr_t)php->p_vaddr,
 			    php->p_filesz, offset, cred, NOCRED, curthread, core_buf, gzfile);
@@ -1181,8 +1243,12 @@ done:
 	if (gzfile)
 		gzclose(gzfile);
 #endif
-
-	free(hdr, M_TEMP);
+	while ((ninfo = TAILQ_FIRST(&notelst)) != NULL) {
+		TAILQ_REMOVE(&notelst, ninfo, link);
+		free(ninfo, M_TEMP);
+	}
+	if (hdr != NULL)
+		free(hdr, M_TEMP);
 
 	return (error);
 }
@@ -1299,44 +1365,194 @@ each_writable_segment(td, func, closure)
  * the page boundary.
  */
 static int
-__elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize, gzfile)
-	struct thread *td;
-	struct vnode *vp;
-	struct ucred *cred;
-	int numsegs;
-	size_t hdrsize;
-	void *hdr;
-	gzFile gzfile;
-{
-	size_t off;
+__elfN(corehdr)(struct thread *td, struct vnode *vp, struct ucred *cred,
+    int numsegs, void *hdr, size_t hdrsize, struct note_info_list *notelst,
+    size_t notesz, gzFile gzfile)
+{
+	struct sbuf_drain_core_params params;
+	struct note_info *ninfo;
+	struct sbuf *sb;
+	int error;
 
 	/* Fill in the header. */
 	bzero(hdr, hdrsize);
-	off = 0;
-	__elfN(puthdr)(td, hdr, &off, numsegs);
+	__elfN(puthdr)(td, hdr, hdrsize, numsegs, notesz);
 
-	if (!gzfile) {
-		/* Write it to the core file. */
-		return (vn_rdwr_inchunks(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
-			UIO_SYSSPACE, IO_UNIT | IO_DIRECT, cred, NOCRED, NULL,
-			td));
-	} else {
+	params.offset = 0;
+	params.active_cred = cred;
+	params.file_cred = NOCRED;
+	params.td = td;
+	params.vp = vp;
 #ifdef COMPRESS_USER_CORES
-		if (gzwrite(gzfile, hdr, hdrsize) != hdrsize) {
-			log(LOG_WARNING,
-			    "Failed to compress core file header for process"
-			    " %s.\n", curproc->p_comm);
-			return (EFAULT);
-		}
-		else {
-			return (0);
-		}
-#else
-		panic("shouldn't be here");
+	params.gzfile = gzfile;
 #endif
+	sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN);
+	sbuf_set_drain(sb, sbuf_drain_core_output, &params);
+	sbuf_start_section(sb, NULL);
+	sbuf_bcat(sb, hdr, hdrsize);
+	TAILQ_FOREACH(ninfo, notelst, link)
+	    __elfN(putnote)(ninfo, sb);
+	/* Align up to a page boundary for the program segments. */
+	sbuf_end_section(sb, -1, PAGE_SIZE, 0);
+	error = sbuf_finish(sb);
+	sbuf_delete(sb);
+
+	return (error);
+}
+
+static void
+__elfN(prepare_notes)(struct thread *td, struct note_info_list *list,
+    size_t *sizep)
+{
+	struct proc *p;
+	struct thread *thr;
+	size_t size;
+
+	p = td->td_proc;
+	size = 0;
+
+	size += register_note(list, NT_PRPSINFO, __elfN(note_prpsinfo), p);
+
+	/*
+	 * To have the debugger select the right thread (LWP) as the initial
+	 * thread, we dump the state of the thread passed to us in td first.
+	 * This is the thread that causes the core dump and thus likely to
+	 * be the right thread one wants to have selected in the debugger.
+	 */
+	thr = td;
+	while (thr != NULL) {
+		size += register_note(list, NT_PRSTATUS,
+		    __elfN(note_prstatus), thr);
+		size += register_note(list, NT_FPREGSET,
+		    __elfN(note_fpregset), thr);
+		size += register_note(list, NT_THRMISC,
+		    __elfN(note_thrmisc), thr);
+		size += register_note(list, -1,
+		    __elfN(note_threadmd), thr);
+
+		thr = (thr == td) ? TAILQ_FIRST(&p->p_threads) :
+		    TAILQ_NEXT(thr, td_plist);
+		if (thr == td)
+			thr = TAILQ_NEXT(thr, td_plist);
 	}
+
+	*sizep = size;
+}
+
+static void
+__elfN(puthdr)(struct thread *td, void *hdr, size_t hdrsize, int numsegs,
+    size_t notesz)
+{
+	Elf_Ehdr *ehdr;
+	Elf_Phdr *phdr;
+	struct phdr_closure phc;
+
+	ehdr = (Elf_Ehdr *)hdr;
+	phdr = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr));
+
+	ehdr->e_ident[EI_MAG0] = ELFMAG0;
+	ehdr->e_ident[EI_MAG1] = ELFMAG1;
+	ehdr->e_ident[EI_MAG2] = ELFMAG2;
+	ehdr->e_ident[EI_MAG3] = ELFMAG3;
+	ehdr->e_ident[EI_CLASS] = ELF_CLASS;
+	ehdr->e_ident[EI_DATA] = ELF_DATA;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+	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_version = EV_CURRENT;
+	ehdr->e_entry = 0;
+	ehdr->e_phoff = sizeof(Elf_Ehdr);
+	ehdr->e_flags = 0;
+	ehdr->e_ehsize = sizeof(Elf_Ehdr);
+	ehdr->e_phentsize = sizeof(Elf_Phdr);
+	ehdr->e_phnum = numsegs + 1;
+	ehdr->e_shentsize = sizeof(Elf_Shdr);
+	ehdr->e_shnum = 0;
+	ehdr->e_shstrndx = SHN_UNDEF;
+
+	/*
+	 * Fill in the program header entries.
+	 */
+
+	/* The note segement. */
+	phdr->p_type = PT_NOTE;
+	phdr->p_offset = hdrsize;
+	phdr->p_vaddr = 0;
+	phdr->p_paddr = 0;
+	phdr->p_filesz = notesz;
+	phdr->p_memsz = 0;
+	phdr->p_flags = PF_R;
+	phdr->p_align = sizeof(Elf32_Size);
+	phdr++;
+
+	/* All the writable segments from the program. */
+	phc.phdr = phdr;
+	phc.offset = round_page(hdrsize + notesz);
+	each_writable_segment(td, cb_put_phdr, &phc);
+}
+
+static size_t
+register_note(struct note_info_list *list, int type, outfunc_t out, void *arg)
+{
+	struct note_info *ninfo;
+	size_t size, notesize;
+
+	size = 0;
+	out(arg, NULL, &size);
+	ninfo = malloc(sizeof(*ninfo), M_TEMP, M_ZERO | M_WAITOK);
+	ninfo->type = type;
+	ninfo->outfunc = out;
+	ninfo->outarg = arg;
+	ninfo->outsize = size;
+	TAILQ_INSERT_TAIL(list, ninfo, link);
+
+	if (type == -1)
+		return (size);
+
+	notesize = sizeof(Elf_Note) +		/* note header */
+	    roundup2(8, sizeof(Elf32_Size)) +	/* note name ("FreeBSD") */
+	    roundup2(size, sizeof(Elf32_Size));	/* note description */
+
+	return (notesize);
+}
+
+static void
+__elfN(putnote)(struct note_info *ninfo, struct sbuf *sb)
+{
+	Elf_Note note;
+	ssize_t old_len;
+
+	if (ninfo->type == -1) {
+		ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
+		return;
+	}
+
+	note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
+	note.n_descsz = ninfo->outsize;
+	note.n_type = ninfo->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);
+	if (note.n_descsz == 0)
+		return;
+	sbuf_start_section(sb, &old_len);
+	ninfo->outfunc(ninfo->outarg, sb, &ninfo->outsize);
+	sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
 }
 
+/*
+ * Miscellaneous note out functions.
+ */
+
 #if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
 #include <compat/freebsd32/freebsd32.h>
 
@@ -1356,50 +1572,15 @@ typedef thrmisc_t elf_thrmisc_t;
 #endif
 
 static void
-__elfN(puthdr)(struct thread *td, void *dst, size_t *off, int numsegs)
+__elfN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep)
 {
-	struct {
-		elf_prstatus_t status;
-		elf_prfpregset_t fpregset;
-		elf_prpsinfo_t psinfo;
-		elf_thrmisc_t thrmisc;
-	} *tempdata;
-	elf_prstatus_t *status;
-	elf_prfpregset_t *fpregset;
-	elf_prpsinfo_t *psinfo;
-	elf_thrmisc_t *thrmisc;
 	struct proc *p;
-	struct thread *thr;
-	size_t ehoff, noteoff, notesz, phoff;
-
-	p = td->td_proc;
-
-	ehoff = *off;
-	*off += sizeof(Elf_Ehdr);
-
-	phoff = *off;
-	*off += (numsegs + 1) * sizeof(Elf_Phdr);
-
-	noteoff = *off;
-	/*
-	 * Don't allocate space for the notes if we're just calculating
-	 * the size of the header. We also don't collect the data.
-	 */
-	if (dst != NULL) {
-		tempdata = malloc(sizeof(*tempdata), M_TEMP, M_ZERO|M_WAITOK);
-		status = &tempdata->status;
-		fpregset = &tempdata->fpregset;
-		psinfo = &tempdata->psinfo;
-		thrmisc = &tempdata->thrmisc;
-	} else {
-		tempdata = NULL;
-		status = NULL;
-		fpregset = NULL;
-		psinfo = NULL;
-		thrmisc = NULL;
-	}
+	elf_prpsinfo_t *psinfo;
 
-	if (dst != NULL) {
+	p = (struct proc *)arg;
+	if (sb != NULL) {
+		KASSERT(*sizep == sizeof(*psinfo), ("invalid size"));
+		psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK);
 		psinfo->pr_version = PRPSINFO_VERSION;
 		psinfo->pr_psinfosz = sizeof(elf_prpsinfo_t);
 		strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
@@ -1409,139 +1590,100 @@ __elfN(puthdr)(struct thread *td, void *
 		 */
 		strlcpy(psinfo->pr_psargs, p->p_comm,
 		    sizeof(psinfo->pr_psargs));
+
+		sbuf_bcat(sb, psinfo, sizeof(*psinfo));
+		free(psinfo, M_TEMP);
 	}
-	__elfN(putnote)(dst, off, "FreeBSD", NT_PRPSINFO, psinfo,
-	    sizeof *psinfo);
+	*sizep = sizeof(*psinfo);
+}
 
-	/*
-	 * To have the debugger select the right thread (LWP) as the initial
-	 * thread, we dump the state of the thread passed to us in td first.
-	 * This is the thread that causes the core dump and thus likely to
-	 * be the right thread one wants to have selected in the debugger.
-	 */
-	thr = td;
-	while (thr != NULL) {
-		if (dst != NULL) {
-			status->pr_version = PRSTATUS_VERSION;
-			status->pr_statussz = sizeof(elf_prstatus_t);
-			status->pr_gregsetsz = sizeof(elf_gregset_t);
-			status->pr_fpregsetsz = sizeof(elf_fpregset_t);
-			status->pr_osreldate = osreldate;
-			status->pr_cursig = p->p_sig;
-			status->pr_pid = thr->td_tid;
+static void
+__elfN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct thread *td;
+	elf_prstatus_t *status;
+
+	td = (struct thread *)arg;
+	if (sb != NULL) {
+		KASSERT(*sizep == sizeof(*status), ("invalid size"));
+		status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK);
+		status->pr_version = PRSTATUS_VERSION;
+		status->pr_statussz = sizeof(elf_prstatus_t);
+		status->pr_gregsetsz = sizeof(elf_gregset_t);
+		status->pr_fpregsetsz = sizeof(elf_fpregset_t);
+		status->pr_osreldate = osreldate;
+		status->pr_cursig = td->td_proc->p_sig;
+		status->pr_pid = td->td_tid;
 #if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
-			fill_regs32(thr, &status->pr_reg);
-			fill_fpregs32(thr, fpregset);
+		fill_regs32(td, &status->pr_reg);
 #else
-			fill_regs(thr, &status->pr_reg);
-			fill_fpregs(thr, fpregset);
+		fill_regs(td, &status->pr_reg);
 #endif
-			memset(&thrmisc->_pad, 0, sizeof (thrmisc->_pad));
-			strcpy(thrmisc->pr_tname, thr->td_name);
-		}
-		__elfN(putnote)(dst, off, "FreeBSD", NT_PRSTATUS, status,
-		    sizeof *status);
-		__elfN(putnote)(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
-		    sizeof *fpregset);
-		__elfN(putnote)(dst, off, "FreeBSD", NT_THRMISC, thrmisc,
-		    sizeof *thrmisc);
-		/*
-		 * Allow for MD specific notes, as well as any MD
-		 * specific preparations for writing MI notes.
-		 */
-		__elfN(dump_thread)(thr, dst, off);
-
-		thr = (thr == td) ? TAILQ_FIRST(&p->p_threads) :
-		    TAILQ_NEXT(thr, td_plist);
-		if (thr == td)
-			thr = TAILQ_NEXT(thr, td_plist);
+		sbuf_bcat(sb, status, sizeof(*status));
+		free(status, M_TEMP);
 	}
+	*sizep = sizeof(*status);
+}
 
-	notesz = *off - noteoff;
-
-	if (dst != NULL)
-		free(tempdata, M_TEMP);
-
-	/* Align up to a page boundary for the program segments. */
-	*off = round_page(*off);
-
-	if (dst != NULL) {
-		Elf_Ehdr *ehdr;
-		Elf_Phdr *phdr;
-		struct phdr_closure phc;
+static void
+__elfN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct thread *td;
+	elf_prfpregset_t *fpregset;
 
-		/*
-		 * Fill in the ELF header.
-		 */
-		ehdr = (Elf_Ehdr *)((char *)dst + ehoff);
-		ehdr->e_ident[EI_MAG0] = ELFMAG0;
-		ehdr->e_ident[EI_MAG1] = ELFMAG1;
-		ehdr->e_ident[EI_MAG2] = ELFMAG2;
-		ehdr->e_ident[EI_MAG3] = ELFMAG3;
-		ehdr->e_ident[EI_CLASS] = ELF_CLASS;
-		ehdr->e_ident[EI_DATA] = ELF_DATA;
-		ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-		ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
-		ehdr->e_ident[EI_ABIVERSION] = 0;
-		ehdr->e_ident[EI_PAD] = 0;
-		ehdr->e_type = ET_CORE;
+	td = (struct thread *)arg;
+	if (sb != NULL) {
+		KASSERT(*sizep == sizeof(*fpregset), ("invalid size"));
+		fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK);
 #if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
-		ehdr->e_machine = ELF_ARCH32;
+		fill_fpregs32(td, fpregset);
 #else
-		ehdr->e_machine = ELF_ARCH;
+		fill_fpregs(td, fpregset);
 #endif
-		ehdr->e_version = EV_CURRENT;
-		ehdr->e_entry = 0;
-		ehdr->e_phoff = phoff;
-		ehdr->e_flags = 0;
-		ehdr->e_ehsize = sizeof(Elf_Ehdr);
-		ehdr->e_phentsize = sizeof(Elf_Phdr);
-		ehdr->e_phnum = numsegs + 1;
-		ehdr->e_shentsize = sizeof(Elf_Shdr);
-		ehdr->e_shnum = 0;
-		ehdr->e_shstrndx = SHN_UNDEF;
+		sbuf_bcat(sb, fpregset, sizeof(*fpregset));
+		free(fpregset, M_TEMP);
+	}
+	*sizep = sizeof(*fpregset);
+}
 
-		/*
-		 * Fill in the program header entries.
-		 */
-		phdr = (Elf_Phdr *)((char *)dst + phoff);
+static void
+__elfN(note_thrmisc)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct thread *td;
+	elf_thrmisc_t thrmisc;
 
-		/* The note segement. */
-		phdr->p_type = PT_NOTE;
-		phdr->p_offset = noteoff;
-		phdr->p_vaddr = 0;
-		phdr->p_paddr = 0;
-		phdr->p_filesz = notesz;
-		phdr->p_memsz = 0;
-		phdr->p_flags = PF_R;
-		phdr->p_align = sizeof(Elf32_Size);
-		phdr++;
-
-		/* All the writable segments from the program. */
-		phc.phdr = phdr;
-		phc.offset = *off;
-		each_writable_segment(td, cb_put_phdr, &phc);
+	td = (struct thread *)arg;
+	if (sb != NULL) {
+		KASSERT(*sizep == sizeof(thrmisc), ("invalid size"));
+		bzero(&thrmisc._pad, sizeof(thrmisc._pad));
+		strcpy(thrmisc.pr_tname, td->td_name);
+		sbuf_bcat(sb, &thrmisc, sizeof(thrmisc));
 	}
+	*sizep = sizeof(thrmisc);
 }
 
+/*
+ * Allow for MD specific notes, as well as any MD
+ * specific preparations for writing MI notes.
+ */
 static void
-__elfN(putnote)(void *dst, size_t *off, const char *name, int type,
-    const void *desc, size_t descsz)
+__elfN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep)
 {
-	Elf_Note note;
+	struct thread *td;
+	void *buf;
+	size_t size;
 
-	note.n_namesz = strlen(name) + 1;
-	note.n_descsz = descsz;
-	note.n_type = type;
-	if (dst != NULL)
-		bcopy(&note, (char *)dst + *off, sizeof note);
-	*off += sizeof note;
-	if (dst != NULL)
-		bcopy(name, (char *)dst + *off, note.n_namesz);
-	*off += roundup2(note.n_namesz, sizeof(Elf32_Size));
-	if (dst != NULL)
-		bcopy(desc, (char *)dst + *off, note.n_descsz);
-	*off += roundup2(note.n_descsz, sizeof(Elf32_Size));
+	td = (struct thread *)arg;
+	size = *sizep;
+	buf = NULL;
+	if (size != 0 && sb != NULL)
+		buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK);
+	size = 0;
+	__elfN(dump_thread)(td, buf, &size);
+	KASSERT(*sizep == size, ("invalid size"));
+	if (size != 0 && sb != NULL)
+		sbuf_bcat(sb, buf, size);
+	*sizep = size;
 }
 
 static boolean_t
@@ -1636,6 +1778,8 @@ EXEC_SET(__CONCAT(elf, __ELF_WORD_SIZE),
  * routine gzwrite().  This copying is necessary because the content of the VM
  * segment may change between the compression pass and the crc-computation pass
  * in gzwrite().  This is because realtime threads may preempt the UNIX kernel.
+ *
+ * If inbuf is NULL it is assumed that data is already copied to 'dest_buf'.
  */
 static int
 compress_core (gzFile file, char *inbuf, char *dest_buf, unsigned int len,
@@ -1646,8 +1790,13 @@ compress_core (gzFile file, char *inbuf,
 	unsigned int chunk_len;
 
 	while (len) {
-		chunk_len = (len > CORE_BUF_SIZE) ? CORE_BUF_SIZE : len;
-		copyin(inbuf, dest_buf, chunk_len);
+		if (inbuf != NULL) {
+			chunk_len = (len > CORE_BUF_SIZE) ? CORE_BUF_SIZE : len;
+			copyin(inbuf, dest_buf, chunk_len);
+			inbuf += chunk_len;
+		} else {
+			chunk_len = len;
+		}
 		len_compressed = gzwrite(file, dest_buf, chunk_len);
 
 		EVENTHANDLER_INVOKE(app_coredump_progress, td, len_compressed);
@@ -1662,7 +1811,6 @@ compress_core (gzFile file, char *inbuf,
 			error = EFAULT;
 			break;
 		}
-		inbuf += chunk_len;
 		len -= chunk_len;
 		maybe_yield();
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304141959.r3EJxcZ3008562>