svn commit: r250309 - stable/9/sys/kern
Mikolaj Golub
trociny at FreeBSD.org
Mon May 6 20:58:02 UTC 2013
Author: trociny
Date: Mon May 6 20:58:02 2013
New Revision: 250309
URL: http://svnweb.freebsd.org/changeset/base/250309
Log:
MFC r249486:
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
Modified:
stable/9/sys/kern/imgact_elf.c
Directory Properties:
stable/9/sys/ (props changed)
Modified: stable/9/sys/kern/imgact_elf.c
==============================================================================
--- stable/9/sys/kern/imgact_elf.c Mon May 6 20:32:14 2013 (r250308)
+++ stable/9/sys/kern/imgact_elf.c Mon May 6 20:58:02 2013 (r250309)
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <sys/procfs.h>
#include <sys/racct.h>
#include <sys/resourcevar.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,
@@ -1040,14 +1041,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;
@@ -1074,14 +1096,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;
@@ -1092,6 +1154,7 @@ __elfN(coredump)(struct thread *td, stru
#endif
hdr = NULL;
+ TAILQ_INIT(¬elst);
#ifdef COMPRESS_USER_CORES
if (doing_compress) {
@@ -1120,30 +1183,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, ¬elst, ¬esz);
+ 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) {
@@ -1151,7 +1213,7 @@ __elfN(coredump)(struct thread *td, stru
goto done;
}
error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize,
- gzfile);
+ ¬elst, notesz, gzfile);
/* Write the contents of all of the writable segments. */
if (error == 0) {
@@ -1160,7 +1222,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);
@@ -1183,8 +1245,12 @@ done:
if (gzfile)
gzclose(gzfile);
#endif
-
- free(hdr, M_TEMP);
+ while ((ninfo = TAILQ_FIRST(¬elst)) != NULL) {
+ TAILQ_REMOVE(¬elst, ninfo, link);
+ free(ninfo, M_TEMP);
+ }
+ if (hdr != NULL)
+ free(hdr, M_TEMP);
return (error);
}
@@ -1301,44 +1367,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, ¶ms);
+ 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, ¬e, 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>
@@ -1358,50 +1574,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));
@@ -1411,139 +1592,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(¬e, (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
@@ -1638,6 +1780,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,
@@ -1648,8 +1792,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);
@@ -1664,7 +1813,6 @@ compress_core (gzFile file, char *inbuf,
error = EFAULT;
break;
}
- inbuf += chunk_len;
len -= chunk_len;
maybe_yield();
}
More information about the svn-src-stable-9
mailing list