summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/imgact_elf.c560
1 files changed, 354 insertions, 206 deletions
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 813e37a..f4659c3 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -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(elf, __ELF_WORD_SIZE), CTLFLAG_RW, 0,
#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, size_t len, off_t offset,
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, struct vnode *vp, off_t limit, int flags)
#endif
hdr = NULL;
+ TAILQ_INIT(&notelst);
#ifdef COMPRESS_USER_CORES
if (doing_compress) {
@@ -1118,30 +1181,29 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
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, struct vnode *vp, off_t limit, int flags)
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, struct vnode *vp, off_t limit, int flags)
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;
+__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)
{
- size_t off;
+ 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);
-
- 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 {
+ __elfN(puthdr)(td, hdr, hdrsize, numsegs, notesz);
+
+ 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);
- }
+ 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
- panic("shouldn't be here");
+ 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 *dst, size_t *off, int numsegs)
*/
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;
-
- /*
- * Fill in the program header entries.
- */
- phdr = (Elf_Phdr *)((char *)dst + phoff);
-
- /* 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);
+ sbuf_bcat(sb, fpregset, sizeof(*fpregset));
+ free(fpregset, M_TEMP);
}
+ *sizep = sizeof(*fpregset);
}
static void
-__elfN(putnote)(void *dst, size_t *off, const char *name, int type,
- const void *desc, size_t descsz)
+__elfN(note_thrmisc)(void *arg, struct sbuf *sb, size_t *sizep)
{
- Elf_Note note;
+ struct thread *td;
+ elf_thrmisc_t thrmisc;
+
+ 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);
+}
- 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));
+/*
+ * Allow for MD specific notes, as well as any MD
+ * specific preparations for writing MI notes.
+ */
+static void
+__elfN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+ struct thread *td;
+ void *buf;
+ size_t 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), __elfN(execsw));
* 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, char *dest_buf, unsigned int len,
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, char *dest_buf, unsigned int len,
error = EFAULT;
break;
}
- inbuf += chunk_len;
len -= chunk_len;
maybe_yield();
}
OpenPOWER on IntegriCloud