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
This commit is contained in:
Mikolaj Golub 2013-04-14 19:59:38 +00:00
parent 8fa3a54014
commit bd3902134c

View File

@ -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 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
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);
__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;
elf_prpsinfo_t *psinfo;
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;
}
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);
/*
* 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;
#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
fill_regs32(thr, &status->pr_reg);
fill_fpregs32(thr, fpregset);
#else
fill_regs(thr, &status->pr_reg);
fill_fpregs(thr, fpregset);
#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);
}
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;
/*
* 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;
#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 = 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);
}
*sizep = sizeof(*psinfo);
}
static void
__elfN(putnote)(void *dst, size_t *off, const char *name, int type,
const void *desc, size_t descsz)
__elfN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep)
{
Elf_Note note;
struct thread *td;
elf_prstatus_t *status;
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;
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(td, &status->pr_reg);
#else
fill_regs(td, &status->pr_reg);
#endif
sbuf_bcat(sb, status, sizeof(*status));
free(status, M_TEMP);
}
*sizep = sizeof(*status);
}
static void
__elfN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep)
{
struct thread *td;
elf_prfpregset_t *fpregset;
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
fill_fpregs32(td, fpregset);
#else
fill_fpregs(td, fpregset);
#endif
sbuf_bcat(sb, fpregset, sizeof(*fpregset));
free(fpregset, M_TEMP);
}
*sizep = sizeof(*fpregset);
}
static void
__elfN(note_thrmisc)(void *arg, struct sbuf *sb, size_t *sizep)
{
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);
}
/*
* 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();
}