Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/imgact_elf.c
Show All 27 Lines | |||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_capsicum.h" | #include "opt_capsicum.h" | ||||
#include "opt_compat.h" | #include "opt_compat.h" | ||||
#include "opt_core.h" | #include "opt_gzio.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/exec.h> | #include <sys/exec.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/gzio.h> | |||||
#include <sys/imgact.h> | #include <sys/imgact.h> | ||||
#include <sys/imgact_elf.h> | #include <sys/imgact_elf.h> | ||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
#include <sys/mman.h> | #include <sys/mman.h> | ||||
Show All 14 Lines | |||||
#include <sys/syscall.h> | #include <sys/syscall.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/sysent.h> | #include <sys/sysent.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/user.h> | #include <sys/user.h> | ||||
#include <net/zlib.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
Show All 18 Lines | |||||
static boolean_t __elfN(check_note)(struct image_params *imgp, | static boolean_t __elfN(check_note)(struct image_params *imgp, | ||||
Elf_Brandnote *checknote, int32_t *osrel); | Elf_Brandnote *checknote, int32_t *osrel); | ||||
static vm_prot_t __elfN(trans_prot)(Elf_Word); | static vm_prot_t __elfN(trans_prot)(Elf_Word); | ||||
static Elf_Word __elfN(untrans_prot)(vm_prot_t); | static Elf_Word __elfN(untrans_prot)(vm_prot_t); | ||||
SYSCTL_NODE(_kern, OID_AUTO, __CONCAT(elf, __ELF_WORD_SIZE), CTLFLAG_RW, 0, | 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); | |||||
#endif | |||||
#define CORE_BUF_SIZE (16 * 1024) | #define CORE_BUF_SIZE (16 * 1024) | ||||
int __elfN(fallback_brand) = -1; | int __elfN(fallback_brand) = -1; | ||||
SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, | SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, | ||||
fallback_brand, CTLFLAG_RWTUN, &__elfN(fallback_brand), 0, | fallback_brand, CTLFLAG_RWTUN, &__elfN(fallback_brand), 0, | ||||
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) " brand of last resort"); | __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) " brand of last resort"); | ||||
static int elf_legacy_coredump = 0; | static int elf_legacy_coredump = 0; | ||||
SYSCTL_INT(_debug, OID_AUTO, __elfN(legacy_coredump), CTLFLAG_RW, | SYSCTL_INT(_debug, OID_AUTO, __elfN(legacy_coredump), CTLFLAG_RW, | ||||
▲ Show 20 Lines • Show All 941 Lines • ▼ Show 20 Lines | struct note_info { | ||||
outfunc_t outfunc; /* Output function. */ | outfunc_t outfunc; /* Output function. */ | ||||
void *outarg; /* Argument for the output function. */ | void *outarg; /* Argument for the output function. */ | ||||
size_t outsize; /* Output size. */ | size_t outsize; /* Output size. */ | ||||
TAILQ_ENTRY(note_info) link; /* Link to the next note info. */ | TAILQ_ENTRY(note_info) link; /* Link to the next note info. */ | ||||
}; | }; | ||||
TAILQ_HEAD(note_info_list, note_info); | TAILQ_HEAD(note_info_list, note_info); | ||||
/* Coredump output parameters. */ | |||||
struct coredump_params { | |||||
off_t offset; | |||||
struct ucred *active_cred; | |||||
struct ucred *file_cred; | |||||
struct thread *td; | |||||
struct vnode *vp; | |||||
struct gzio_stream *gzs; | |||||
}; | |||||
static void cb_put_phdr(vm_map_entry_t, void *); | static void cb_put_phdr(vm_map_entry_t, void *); | ||||
static void cb_size_segment(vm_map_entry_t, void *); | static void cb_size_segment(vm_map_entry_t, void *); | ||||
static int core_write(struct coredump_params *, void *, size_t, off_t, | |||||
enum uio_seg); | |||||
static void each_writable_segment(struct thread *, segment_callback, void *); | static void each_writable_segment(struct thread *, segment_callback, void *); | ||||
static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *, | static int __elfN(corehdr)(struct coredump_params *, int, void *, size_t, | ||||
int, void *, size_t, struct note_info_list *, size_t, gzFile); | struct note_info_list *, size_t); | ||||
static void __elfN(prepare_notes)(struct thread *, struct note_info_list *, | static void __elfN(prepare_notes)(struct thread *, struct note_info_list *, | ||||
size_t *); | size_t *); | ||||
static void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t); | static void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t); | ||||
static void __elfN(putnote)(struct note_info *, struct sbuf *); | static void __elfN(putnote)(struct note_info *, struct sbuf *); | ||||
static size_t register_note(struct note_info_list *, int, outfunc_t, void *); | static size_t register_note(struct note_info_list *, int, outfunc_t, void *); | ||||
static int sbuf_drain_core_output(void *, const char *, int); | static int sbuf_drain_core_output(void *, const char *, int); | ||||
static int sbuf_drain_count(void *arg, const char *data, int len); | static int sbuf_drain_count(void *arg, const char *data, int len); | ||||
static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *); | static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_prpsinfo)(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_prstatus)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_threadmd)(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 *); | static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); | static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *); | static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *); | ||||
static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *); | static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_files(void *, struct sbuf *, size_t *); | static void note_procstat_files(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_groups(void *, struct sbuf *, size_t *); | static void note_procstat_groups(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_osrel(void *, struct sbuf *, size_t *); | static void note_procstat_osrel(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_rlimit(void *, struct sbuf *, size_t *); | static void note_procstat_rlimit(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_umask(void *, struct sbuf *, size_t *); | static void note_procstat_umask(void *, struct sbuf *, size_t *); | ||||
static void note_procstat_vmmap(void *, struct sbuf *, size_t *); | static void note_procstat_vmmap(void *, struct sbuf *, size_t *); | ||||
#ifdef COMPRESS_USER_CORES | #ifdef GZIO | ||||
extern int compress_user_cores; | |||||
extern int compress_user_cores_gzlevel; | extern int compress_user_cores_gzlevel; | ||||
#endif | |||||
/* | |||||
* Write out a core segment to the compression stream. | |||||
*/ | |||||
static int | static int | ||||
core_output(struct vnode *vp, void *base, size_t len, off_t offset, | compress_chunk(struct coredump_params *p, char *base, char *buf, u_int len) | ||||
struct ucred *active_cred, struct ucred *file_cred, | { | ||||
struct thread *td, char *core_buf, gzFile gzfile) { | u_int chunk_len; | ||||
int error; | int error; | ||||
if (gzfile) { | |||||
#ifdef COMPRESS_USER_CORES | while (len > 0) { | ||||
error = compress_core(gzfile, base, core_buf, len, td); | chunk_len = MIN(len, CORE_BUF_SIZE); | ||||
#else | copyin(base, buf, chunk_len); | ||||
panic("shouldn't be here"); | error = gzio_write(p->gzs, buf, chunk_len); | ||||
#endif | if (error != 0) | ||||
} else { | break; | ||||
error = vn_rdwr_inchunks(UIO_WRITE, vp, base, len, offset, | base += chunk_len; | ||||
UIO_USERSPACE, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, | len -= chunk_len; | ||||
active_cred, file_cred, NULL, td); | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Coredump output parameters for sbuf drain routine. */ | static int | ||||
struct sbuf_drain_core_params { | core_gz_write(void *base, size_t len, off_t offset, void *arg) | ||||
off_t offset; | { | ||||
struct ucred *active_cred; | |||||
struct ucred *file_cred; | return (core_write((struct coredump_params *)arg, base, len, offset, | ||||
struct thread *td; | UIO_SYSSPACE)); | ||||
struct vnode *vp; | } | ||||
#ifdef COMPRESS_USER_CORES | #endif /* GZIO */ | ||||
gzFile gzfile; | |||||
static int | |||||
core_write(struct coredump_params *p, void *base, size_t len, off_t offset, | |||||
enum uio_seg seg) | |||||
{ | |||||
return (vn_rdwr_inchunks(UIO_WRITE, p->vp, base, len, offset, | |||||
seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED, | |||||
p->active_cred, p->file_cred, NULL, p->td)); | |||||
} | |||||
static int | |||||
core_output(void *base, size_t len, off_t offset, struct coredump_params *p, | |||||
void *tmpbuf) | |||||
{ | |||||
#ifdef GZIO | |||||
if (p->gzs != NULL) | |||||
return (compress_chunk(p, base, tmpbuf, len)); | |||||
#endif | #endif | ||||
}; | return (core_write(p, base, len, offset, UIO_USERSPACE)); | ||||
} | |||||
/* | /* | ||||
* Drain into a core file. | * Drain into a core file. | ||||
*/ | */ | ||||
static int | static int | ||||
sbuf_drain_core_output(void *arg, const char *data, int len) | sbuf_drain_core_output(void *arg, const char *data, int len) | ||||
{ | { | ||||
struct sbuf_drain_core_params *p; | struct coredump_params *p; | ||||
int error, locked; | int error, locked; | ||||
p = (struct sbuf_drain_core_params *)arg; | p = (struct coredump_params *)arg; | ||||
/* | /* | ||||
* Some kern_proc out routines that print to this sbuf may | * Some kern_proc out routines that print to this sbuf may | ||||
* call us with the process lock held. Draining with the | * call us with the process lock held. Draining with the | ||||
* non-sleepable lock held is unsafe. The lock is needed for | * non-sleepable lock held is unsafe. The lock is needed for | ||||
* those routines when dumping a live process. In our case we | * those routines when dumping a live process. In our case we | ||||
* can safely release the lock before draining and acquire | * can safely release the lock before draining and acquire | ||||
* again after. | * again after. | ||||
*/ | */ | ||||
locked = PROC_LOCKED(p->td->td_proc); | locked = PROC_LOCKED(p->td->td_proc); | ||||
if (locked) | if (locked) | ||||
PROC_UNLOCK(p->td->td_proc); | PROC_UNLOCK(p->td->td_proc); | ||||
#ifdef COMPRESS_USER_CORES | #ifdef GZIO | ||||
if (p->gzfile != Z_NULL) | if (p->gzs != NULL) | ||||
error = compress_core(p->gzfile, NULL, __DECONST(char *, data), | error = gzio_write(p->gzs, __DECONST(char *, data), len); | ||||
len, p->td); | |||||
else | else | ||||
#endif | #endif | ||||
error = vn_rdwr_inchunks(UIO_WRITE, p->vp, | error = core_write(p, __DECONST(void *, data), len, p->offset, | ||||
__DECONST(void *, data), len, p->offset, UIO_SYSSPACE, | UIO_SYSSPACE); | ||||
IO_UNIT | IO_DIRECT | IO_RANGELOCKED, p->active_cred, | |||||
p->file_cred, NULL, p->td); | |||||
if (locked) | if (locked) | ||||
PROC_LOCK(p->td->td_proc); | PROC_LOCK(p->td->td_proc); | ||||
if (error != 0) | if (error != 0) | ||||
return (-error); | return (-error); | ||||
p->offset += len; | p->offset += len; | ||||
return (len); | return (len); | ||||
} | } | ||||
Show All 12 Lines | |||||
int | int | ||||
__elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) | __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) | ||||
{ | { | ||||
struct ucred *cred = td->td_ucred; | struct ucred *cred = td->td_ucred; | ||||
int error = 0; | int error = 0; | ||||
struct sseg_closure seginfo; | struct sseg_closure seginfo; | ||||
struct note_info_list notelst; | struct note_info_list notelst; | ||||
struct coredump_params params; | |||||
struct note_info *ninfo; | struct note_info *ninfo; | ||||
void *hdr; | void *hdr, *tmpbuf; | ||||
size_t hdrsize, notesz, coresize; | size_t hdrsize, notesz, coresize; | ||||
boolean_t compress; | |||||
gzFile gzfile = Z_NULL; | compress = (flags & IMGACT_CORE_COMPRESS) != 0; | ||||
char *core_buf = NULL; | |||||
#ifdef COMPRESS_USER_CORES | |||||
char gzopen_flags[8]; | |||||
char *p; | |||||
int doing_compress = flags & IMGACT_CORE_COMPRESS; | |||||
#endif | |||||
hdr = NULL; | hdr = NULL; | ||||
TAILQ_INIT(¬elst); | TAILQ_INIT(¬elst); | ||||
#ifdef COMPRESS_USER_CORES | |||||
if (doing_compress) { | |||||
p = gzopen_flags; | |||||
*p++ = 'w'; | |||||
if (compress_user_cores_gzlevel >= 0 && | |||||
compress_user_cores_gzlevel <= 9) | |||||
*p++ = '0' + compress_user_cores_gzlevel; | |||||
*p = 0; | |||||
gzfile = gz_open("", gzopen_flags, vp); | |||||
if (gzfile == Z_NULL) { | |||||
error = EFAULT; | |||||
goto done; | |||||
} | |||||
core_buf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO); | |||||
if (!core_buf) { | |||||
error = ENOMEM; | |||||
goto done; | |||||
} | |||||
} | |||||
#endif | |||||
/* Size the program segments. */ | /* Size the program segments. */ | ||||
seginfo.count = 0; | seginfo.count = 0; | ||||
seginfo.size = 0; | seginfo.size = 0; | ||||
each_writable_segment(td, cb_size_segment, &seginfo); | each_writable_segment(td, cb_size_segment, &seginfo); | ||||
/* | /* | ||||
* Collect info about the core file header area. | * Collect info about the core file header area. | ||||
*/ | */ | ||||
Show All 10 Lines | if (error != 0) { | ||||
goto done; | goto done; | ||||
} | } | ||||
#endif | #endif | ||||
if (coresize >= limit) { | if (coresize >= limit) { | ||||
error = EFAULT; | error = EFAULT; | ||||
goto done; | goto done; | ||||
} | } | ||||
/* Set up core dump parameters. */ | |||||
params.offset = 0; | |||||
params.active_cred = cred; | |||||
params.file_cred = NOCRED; | |||||
params.td = td; | |||||
params.vp = vp; | |||||
params.gzs = NULL; | |||||
tmpbuf = NULL; | |||||
#ifdef GZIO | |||||
/* Create a compression stream if necessary. */ | |||||
if (compress) { | |||||
params.gzs = gzio_init(core_gz_write, GZIO_DEFLATE, | |||||
CORE_BUF_SIZE, compress_user_cores_gzlevel, ¶ms); | |||||
if (params.gzs == NULL) { | |||||
error = EFAULT; | |||||
goto done; | |||||
} | |||||
tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO); | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Allocate memory for building the header, fill it up, | * Allocate memory for building the header, fill it up, | ||||
* and write it out following the notes. | * and write it out following the notes. | ||||
*/ | */ | ||||
hdr = malloc(hdrsize, M_TEMP, M_WAITOK); | hdr = malloc(hdrsize, M_TEMP, M_WAITOK); | ||||
if (hdr == NULL) { | if (hdr == NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
error = __elfN(corehdr)(td, vp, cred, seginfo.count, hdr, hdrsize, | error = __elfN(corehdr)(¶ms, seginfo.count, hdr, hdrsize, ¬elst, | ||||
¬elst, notesz, gzfile); | notesz); | ||||
/* Write the contents of all of the writable segments. */ | /* Write the contents of all of the writable segments. */ | ||||
if (error == 0) { | if (error == 0) { | ||||
Elf_Phdr *php; | Elf_Phdr *php; | ||||
off_t offset; | off_t offset; | ||||
int i; | int i; | ||||
php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; | php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; | ||||
offset = round_page(hdrsize + notesz); | offset = round_page(hdrsize + notesz); | ||||
for (i = 0; i < seginfo.count; i++) { | for (i = 0; i < seginfo.count; i++) { | ||||
error = core_output(vp, (caddr_t)(uintptr_t)php->p_vaddr, | error = core_output((caddr_t)(uintptr_t)php->p_vaddr, | ||||
php->p_filesz, offset, cred, NOCRED, curthread, core_buf, gzfile); | php->p_filesz, offset, ¶ms, tmpbuf); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
offset += php->p_filesz; | offset += php->p_filesz; | ||||
php++; | php++; | ||||
} | } | ||||
#ifdef GZIO | |||||
if (error == 0 && compress) | |||||
error = gzio_flush(params.gzs); | |||||
#endif | |||||
} | } | ||||
if (error) { | if (error) { | ||||
log(LOG_WARNING, | log(LOG_WARNING, | ||||
"Failed to write core file for process %s (error %d)\n", | "Failed to write core file for process %s (error %d)\n", | ||||
curproc->p_comm, error); | curproc->p_comm, error); | ||||
} | } | ||||
done: | done: | ||||
#ifdef COMPRESS_USER_CORES | #ifdef GZIO | ||||
if (core_buf) | if (compress) { | ||||
free(core_buf, M_TEMP); | free(tmpbuf, M_TEMP); | ||||
if (gzfile) | gzio_fini(params.gzs); | ||||
gzclose(gzfile); | } | ||||
#endif | #endif | ||||
while ((ninfo = TAILQ_FIRST(¬elst)) != NULL) { | while ((ninfo = TAILQ_FIRST(¬elst)) != NULL) { | ||||
TAILQ_REMOVE(¬elst, ninfo, link); | TAILQ_REMOVE(¬elst, ninfo, link); | ||||
free(ninfo, M_TEMP); | free(ninfo, M_TEMP); | ||||
} | } | ||||
if (hdr != NULL) | if (hdr != NULL) | ||||
free(hdr, M_TEMP); | free(hdr, M_TEMP); | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | each_writable_segment(td, func, closure) | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
} | } | ||||
/* | /* | ||||
* Write the core file header to the file, including padding up to | * Write the core file header to the file, including padding up to | ||||
* the page boundary. | * the page boundary. | ||||
*/ | */ | ||||
static int | static int | ||||
__elfN(corehdr)(struct thread *td, struct vnode *vp, struct ucred *cred, | __elfN(corehdr)(struct coredump_params *p, int numsegs, void *hdr, | ||||
int numsegs, void *hdr, size_t hdrsize, struct note_info_list *notelst, | size_t hdrsize, struct note_info_list *notelst, size_t notesz) | ||||
size_t notesz, gzFile gzfile) | |||||
{ | { | ||||
struct sbuf_drain_core_params params; | |||||
struct note_info *ninfo; | struct note_info *ninfo; | ||||
struct sbuf *sb; | struct sbuf *sb; | ||||
int error; | int error; | ||||
/* Fill in the header. */ | /* Fill in the header. */ | ||||
bzero(hdr, hdrsize); | bzero(hdr, hdrsize); | ||||
__elfN(puthdr)(td, hdr, hdrsize, numsegs, notesz); | __elfN(puthdr)(p->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 | |||||
params.gzfile = gzfile; | |||||
#endif | |||||
sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN); | sb = sbuf_new(NULL, NULL, CORE_BUF_SIZE, SBUF_FIXEDLEN); | ||||
sbuf_set_drain(sb, sbuf_drain_core_output, ¶ms); | sbuf_set_drain(sb, sbuf_drain_core_output, p); | ||||
sbuf_start_section(sb, NULL); | sbuf_start_section(sb, NULL); | ||||
sbuf_bcat(sb, hdr, hdrsize); | sbuf_bcat(sb, hdr, hdrsize); | ||||
TAILQ_FOREACH(ninfo, notelst, link) | TAILQ_FOREACH(ninfo, notelst, link) | ||||
__elfN(putnote)(ninfo, sb); | __elfN(putnote)(ninfo, sb); | ||||
/* Align up to a page boundary for the program segments. */ | /* Align up to a page boundary for the program segments. */ | ||||
sbuf_end_section(sb, -1, PAGE_SIZE, 0); | sbuf_end_section(sb, -1, PAGE_SIZE, 0); | ||||
error = sbuf_finish(sb); | error = sbuf_finish(sb); | ||||
sbuf_delete(sb); | sbuf_delete(sb); | ||||
▲ Show 20 Lines • Show All 649 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Tell kern_execve.c about it, with a little help from the linker. | * Tell kern_execve.c about it, with a little help from the linker. | ||||
*/ | */ | ||||
static struct execsw __elfN(execsw) = { | static struct execsw __elfN(execsw) = { | ||||
__CONCAT(exec_, __elfN(imgact)), | __CONCAT(exec_, __elfN(imgact)), | ||||
__XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) | __XSTRING(__CONCAT(ELF, __ELF_WORD_SIZE)) | ||||
}; | }; | ||||
EXEC_SET(__CONCAT(elf, __ELF_WORD_SIZE), __elfN(execsw)); | EXEC_SET(__CONCAT(elf, __ELF_WORD_SIZE), __elfN(execsw)); | ||||
#ifdef COMPRESS_USER_CORES | |||||
/* | |||||
* Compress and write out a core segment for a user process. | |||||
* | |||||
* 'inbuf' is the starting address of a VM segment in the process' address | |||||
* space that is to be compressed and written out to the core file. 'dest_buf' | |||||
* is a buffer in the kernel's address space. The segment is copied from | |||||
* 'inbuf' to 'dest_buf' first before being processed by the compression | |||||
* 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, | |||||
struct thread *td) | |||||
{ | |||||
int len_compressed; | |||||
int error = 0; | |||||
unsigned int chunk_len; | |||||
while (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); | |||||
if ((unsigned int)len_compressed != chunk_len) { | |||||
log(LOG_WARNING, | |||||
"compress_core: length mismatch (0x%x returned, " | |||||
"0x%x expected)\n", len_compressed, chunk_len); | |||||
EVENTHANDLER_INVOKE(app_coredump_error, td, | |||||
"compress_core: length mismatch %x -> %x", | |||||
chunk_len, len_compressed); | |||||
error = EFAULT; | |||||
break; | |||||
} | |||||
len -= chunk_len; | |||||
maybe_yield(); | |||||
} | |||||
return (error); | |||||
} | |||||
#endif /* COMPRESS_USER_CORES */ | |||||
static vm_prot_t | static vm_prot_t | ||||
__elfN(trans_prot)(Elf_Word flags) | __elfN(trans_prot)(Elf_Word flags) | ||||
{ | { | ||||
vm_prot_t prot; | vm_prot_t prot; | ||||
prot = 0; | prot = 0; | ||||
if (flags & PF_X) | if (flags & PF_X) | ||||
Show All 28 Lines |