diff options
-rw-r--r-- | sys/arch/sparc/sparc/process_machdep.c | 6 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/process_machdep.c | 6 | ||||
-rw-r--r-- | sys/compat/aout/compat_aout.c | 4 | ||||
-rw-r--r-- | sys/compat/bsdos/bsdos_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/freebsd/freebsd_exec.c | 5 | ||||
-rw-r--r-- | sys/compat/hpux/hppa/hpux_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/hpux/m68k/hpux_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/ibcs2/ibcs2_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/linux/linux_exec.c | 5 | ||||
-rw-r--r-- | sys/compat/osf1/osf1_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/sunos/sunos_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/svr4/svr4_exec.c | 4 | ||||
-rw-r--r-- | sys/compat/ultrix/ultrix_misc.c | 4 | ||||
-rw-r--r-- | sys/kern/exec_elf.c | 476 | ||||
-rw-r--r-- | sys/kern/init_main.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 67 | ||||
-rw-r--r-- | sys/sys/core.h | 8 | ||||
-rw-r--r-- | sys/sys/exec_elf.h | 60 | ||||
-rw-r--r-- | sys/sys/proc.h | 3 | ||||
-rw-r--r-- | sys/uvm/uvm_extern.h | 20 | ||||
-rw-r--r-- | sys/uvm/uvm_unix.c | 75 |
21 files changed, 737 insertions, 34 deletions
diff --git a/sys/arch/sparc/sparc/process_machdep.c b/sys/arch/sparc/sparc/process_machdep.c index 6a42d97e2a4..93a5ff26dd5 100644 --- a/sys/arch/sparc/sparc/process_machdep.c +++ b/sys/arch/sparc/sparc/process_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process_machdep.c,v 1.12 2005/12/30 00:18:30 kettenis Exp $ */ +/* $OpenBSD: process_machdep.c,v 1.13 2009/03/05 19:52:23 kettenis Exp $ */ /* $NetBSD: process_machdep.c,v 1.6 1996/03/14 21:09:26 christos Exp $ */ /* @@ -162,11 +162,11 @@ process_write_fpregs(p, regs) return 0; } +#endif /* PTRACE */ + register_t process_get_wcookie(p) struct proc *p; { return p->p_addr->u_pcb.pcb_wcookie; } - -#endif /* PTRACE */ diff --git a/sys/arch/sparc64/sparc64/process_machdep.c b/sys/arch/sparc64/sparc64/process_machdep.c index d57c0887ebd..fb403b4513c 100644 --- a/sys/arch/sparc64/sparc64/process_machdep.c +++ b/sys/arch/sparc64/sparc64/process_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process_machdep.c,v 1.11 2007/10/31 22:46:52 kettenis Exp $ */ +/* $OpenBSD: process_machdep.c,v 1.12 2009/03/05 19:52:23 kettenis Exp $ */ /* $NetBSD: process_machdep.c,v 1.10 2000/09/26 22:05:50 eeh Exp $ */ /* @@ -231,10 +231,10 @@ process_write_fpregs(p, regs) return 0; } +#endif /* PTRACE */ + register_t process_get_wcookie(struct proc *p) { return p->p_addr->u_pcb.pcb_wcookie; } - -#endif /* PTRACE */ diff --git a/sys/compat/aout/compat_aout.c b/sys/compat/aout/compat_aout.c index ec86e0158f7..924d5d228d0 100644 --- a/sys/compat/aout/compat_aout.c +++ b/sys/compat/aout/compat_aout.c @@ -1,4 +1,4 @@ -/* $OpenBSD: compat_aout.c,v 1.2 2003/08/23 19:28:53 tedu Exp $ */ +/* $OpenBSD: compat_aout.c,v 1.3 2009/03/05 19:52:23 kettenis Exp $ */ /* * Copyright (c) 2003 Marc Espie @@ -30,6 +30,7 @@ #include <sys/mount.h> #include <sys/syscallargs.h> #include <sys/fcntl.h> +#include <sys/core.h> #include <compat/common/compat_util.h> void aout_compat_setup(struct exec_package *epp); @@ -54,6 +55,7 @@ struct emul emul_aout = { copyargs, setregs, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/compat/bsdos/bsdos_exec.c b/sys/compat/bsdos/bsdos_exec.c index 04e013c0435..f8011c9044f 100644 --- a/sys/compat/bsdos/bsdos_exec.c +++ b/sys/compat/bsdos/bsdos_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bsdos_exec.c,v 1.4 2001/11/06 19:53:17 miod Exp $ */ +/* $OpenBSD: bsdos_exec.c,v 1.5 2009/03/05 19:52:23 kettenis Exp $ */ /* * Copyright (c) 1993, 1994 Christopher G. Demetriou @@ -36,6 +36,7 @@ #include <sys/signalvar.h> #include <sys/malloc.h> #include <sys/vnode.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/resourcevar.h> #include <uvm/uvm_extern.h> @@ -70,6 +71,7 @@ struct emul emul_bsdos = { copyargs, setregs, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/compat/freebsd/freebsd_exec.c b/sys/compat/freebsd/freebsd_exec.c index 3a750dce41d..91beeeb0239 100644 --- a/sys/compat/freebsd/freebsd_exec.c +++ b/sys/compat/freebsd/freebsd_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: freebsd_exec.c,v 1.18 2008/06/12 04:32:57 miod Exp $ */ +/* $OpenBSD: freebsd_exec.c,v 1.19 2009/03/05 19:52:23 kettenis Exp $ */ /* $NetBSD: freebsd_exec.c,v 1.2 1996/05/18 16:02:08 christos Exp $ */ /* @@ -36,6 +36,7 @@ #include <sys/proc.h> #include <sys/malloc.h> #include <sys/vnode.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/resourcevar.h> #include <uvm/uvm_extern.h> @@ -71,6 +72,7 @@ struct emul emul_freebsd_aout = { copyargs, setregs, NULL, + coredump_trad, freebsd_sigcode, freebsd_esigcode, }; @@ -91,6 +93,7 @@ struct emul emul_freebsd_elf = { elf32_copyargs, setregs, exec_elf32_fixup, + coredump_trad, freebsd_sigcode, freebsd_esigcode, }; diff --git a/sys/compat/hpux/hppa/hpux_exec.c b/sys/compat/hpux/hppa/hpux_exec.c index 163ce3dbad8..8c7bd9114c3 100644 --- a/sys/compat/hpux/hppa/hpux_exec.c +++ b/sys/compat/hpux/hppa/hpux_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hpux_exec.c,v 1.3 2005/12/30 19:46:53 miod Exp $ */ +/* $OpenBSD: hpux_exec.c,v 1.4 2009/03/05 19:52:23 kettenis Exp $ */ /* * Copyright (c) 2004 Michael Shalayeff. All rights reserved. @@ -46,6 +46,7 @@ #include <sys/vnode.h> #include <sys/mman.h> #include <sys/stat.h> +#include <sys/core.h> #include <uvm/uvm_extern.h> @@ -89,6 +90,7 @@ struct emul emul_hpux = { copyargs, hpux_setregs, NULL, + coredump_trad, hpux_sigcode, hpux_esigcode, }; diff --git a/sys/compat/hpux/m68k/hpux_exec.c b/sys/compat/hpux/m68k/hpux_exec.c index ac83a6ff412..97653f9c56d 100644 --- a/sys/compat/hpux/m68k/hpux_exec.c +++ b/sys/compat/hpux/m68k/hpux_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hpux_exec.c,v 1.3 2007/11/02 19:18:54 martin Exp $ */ +/* $OpenBSD: hpux_exec.c,v 1.4 2009/03/05 19:52:23 kettenis Exp $ */ /* $NetBSD: hpux_exec.c,v 1.8 1997/03/16 10:14:44 thorpej Exp $ */ /* @@ -46,6 +46,7 @@ #include <sys/vnode.h> #include <sys/mman.h> #include <sys/stat.h> +#include <sys/core.h> #include <uvm/uvm_extern.h> @@ -89,6 +90,7 @@ struct emul emul_hpux = { copyargs, hpux_setregs, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/compat/ibcs2/ibcs2_exec.c b/sys/compat/ibcs2/ibcs2_exec.c index 1649bbb29b0..cedbc2bbf73 100644 --- a/sys/compat/ibcs2/ibcs2_exec.c +++ b/sys/compat/ibcs2/ibcs2_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ibcs2_exec.c,v 1.18 2006/12/29 13:04:37 pedro Exp $ */ +/* $OpenBSD: ibcs2_exec.c,v 1.19 2009/03/05 19:52:23 kettenis Exp $ */ /* $NetBSD: ibcs2_exec.c,v 1.12 1996/10/12 02:13:52 thorpej Exp $ */ /* @@ -38,6 +38,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/malloc.h> #include <sys/vnode.h> @@ -100,6 +101,7 @@ struct emul emul_ibcs2 = { copyargs, setregs, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/compat/linux/linux_exec.c b/sys/compat/linux/linux_exec.c index ae11761ae17..67d36895e2a 100644 --- a/sys/compat/linux/linux_exec.c +++ b/sys/compat/linux/linux_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_exec.c,v 1.30 2008/06/26 05:42:14 ray Exp $ */ +/* $OpenBSD: linux_exec.c,v 1.31 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: linux_exec.c,v 1.13 1996/04/05 00:01:10 christos Exp $ */ /*- @@ -39,6 +39,7 @@ #include <sys/namei.h> #include <sys/vnode.h> #include <sys/mount.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/exec_elf.h> #include <sys/exec_olf.h> @@ -101,6 +102,7 @@ struct emul emul_linux_aout = { linux_aout_copyargs, setregs, NULL, + coredump_trad, linux_sigcode, linux_esigcode, 0, @@ -126,6 +128,7 @@ struct emul emul_linux_elf = { elf32_copyargs, setregs, exec_elf32_fixup, + coredump_trad, linux_sigcode, linux_esigcode, 0, diff --git a/sys/compat/osf1/osf1_exec.c b/sys/compat/osf1/osf1_exec.c index 7e30538baa8..b9fcd97a7b6 100644 --- a/sys/compat/osf1/osf1_exec.c +++ b/sys/compat/osf1/osf1_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: osf1_exec.c,v 1.5 2004/06/22 23:52:18 jfb Exp $ */ +/* $OpenBSD: osf1_exec.c,v 1.6 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD$ */ /* @@ -39,6 +39,7 @@ #include <sys/namei.h> #include <sys/vnode.h> #include <sys/mount.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/exec_ecoff.h> #include <sys/signalvar.h> @@ -90,6 +91,7 @@ struct emul emul_osf1 = { osf1_copyargs, cpu_exec_ecoff_setregs, NULL, + coredump_trad, osf1_sigcode, osf1_esigcode, }; diff --git a/sys/compat/sunos/sunos_exec.c b/sys/compat/sunos/sunos_exec.c index ac79176802c..35dbc70bded 100644 --- a/sys/compat/sunos/sunos_exec.c +++ b/sys/compat/sunos/sunos_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sunos_exec.c,v 1.18 2005/12/30 19:46:55 miod Exp $ */ +/* $OpenBSD: sunos_exec.c,v 1.19 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: sunos_exec.c,v 1.11 1996/05/05 12:01:47 briggs Exp $ */ /* @@ -37,6 +37,7 @@ #include <sys/signalvar.h> #include <sys/vnode.h> #include <sys/file.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/resourcevar.h> #include <sys/wait.h> @@ -91,6 +92,7 @@ struct emul emul_sunos = { copyargs, setregs, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/compat/svr4/svr4_exec.c b/sys/compat/svr4/svr4_exec.c index d7b9cc55853..fd047282d39 100644 --- a/sys/compat/svr4/svr4_exec.c +++ b/sys/compat/svr4/svr4_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: svr4_exec.c,v 1.16 2008/06/12 04:32:59 miod Exp $ */ +/* $OpenBSD: svr4_exec.c,v 1.17 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: svr4_exec.c,v 1.16 1995/10/14 20:24:20 christos Exp $ */ /* @@ -35,6 +35,7 @@ #include <sys/malloc.h> #include <sys/namei.h> #include <sys/vnode.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/exec_elf.h> #include <sys/exec_olf.h> @@ -77,6 +78,7 @@ struct emul emul_svr4 = { svr4_copyargs, setregs, exec_elf32_fixup, + coredump_trad, svr4_sigcode, svr4_esigcode, }; diff --git a/sys/compat/ultrix/ultrix_misc.c b/sys/compat/ultrix/ultrix_misc.c index bfac657c5ac..ae56326ac42 100644 --- a/sys/compat/ultrix/ultrix_misc.c +++ b/sys/compat/ultrix/ultrix_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ultrix_misc.c,v 1.30 2007/06/06 17:15:13 deraadt Exp $ */ +/* $OpenBSD: ultrix_misc.c,v 1.31 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: ultrix_misc.c,v 1.23 1996/04/07 17:23:04 jonathan Exp $ */ /* @@ -89,6 +89,7 @@ /*#include <sys/stat.h>*/ /*#include <sys/ioctl.h>*/ #include <sys/kernel.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/malloc.h> #include <sys/mbuf.h> @@ -161,6 +162,7 @@ struct emul emul_ultrix = { copyargs, ULTRIX_EXEC_SETREGS, NULL, + coredump_trad, sigcode, esigcode, }; diff --git a/sys/kern/exec_elf.c b/sys/kern/exec_elf.c index 2a0083906db..59197aba4a9 100644 --- a/sys/kern/exec_elf.c +++ b/sys/kern/exec_elf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.c,v 1.67 2008/11/10 03:56:16 deraadt Exp $ */ +/* $OpenBSD: exec_elf.c,v 1.68 2009/03/05 19:52:24 kettenis Exp $ */ /* * Copyright (c) 1996 Per Fogelstrom @@ -31,6 +31,41 @@ * */ +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Jason R. Thorpe for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -40,10 +75,12 @@ #include <sys/mount.h> #include <sys/namei.h> #include <sys/vnode.h> +#include <sys/core.h> #include <sys/exec.h> #include <sys/exec_elf.h> #include <sys/exec_olf.h> #include <sys/file.h> +#include <sys/ptrace.h> #include <sys/syscall.h> #include <sys/signalvar.h> #include <sys/stat.h> @@ -90,6 +127,7 @@ int ELFNAME(check_header)(Elf_Ehdr *); int ELFNAME(read_from)(struct proc *, struct vnode *, u_long, caddr_t, int); void ELFNAME(load_psection)(struct exec_vmcmd_set *, struct vnode *, Elf_Phdr *, Elf_Addr *, Elf_Addr *, int *, int); +int ELFNAMEEND(coredump)(struct proc *, void *); extern char sigcode[], esigcode[]; #ifdef SYSCALL_DEBUG @@ -125,6 +163,7 @@ struct emul ELFNAMEEND(emul) = { ELFNAME(copyargs), setregs, ELFNAME2(exec,fixup), + ELFNAMEEND(coredump), sigcode, esigcode, EMUL_ENABLED | EMUL_NATIVE, @@ -881,3 +920,438 @@ out1: free(hph, M_TEMP); return error; } + +struct countsegs_state { + int npsections; +}; + +int ELFNAMEEND(coredump_countsegs)(struct proc *, void *, + struct uvm_coredump_state *); + +struct writesegs_state { + Elf_Phdr *psections; + off_t secoff; +}; + +int ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *, + struct uvm_coredump_state *); + +int ELFNAMEEND(coredump_notes)(struct proc *, void *, size_t *); +int ELFNAMEEND(coredump_note)(struct proc *, void *, size_t *); +int ELFNAMEEND(coredump_writenote)(struct proc *, void *, Elf_Note *, + const char *, void *); + +#define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ +#define elfround(x) roundup((x), ELFROUNDSIZE) + +int +ELFNAMEEND(coredump)(struct proc *p, void *cookie) +{ + Elf_Ehdr ehdr; + Elf_Phdr phdr, *psections; + struct countsegs_state cs; + struct writesegs_state ws; + off_t notestart, secstart, offset; + size_t notesize; + int error, i; + + psections = NULL; + /* + * We have to make a total of 3 passes across the map: + * + * 1. Count the number of map entries (the number of + * PT_LOAD sections). + * + * 2. Write the P-section headers. + * + * 3. Write the P-sections. + */ + + /* Pass 1: count the entries. */ + cs.npsections = 0; + error = uvm_coredump_walkmap(p, NULL, + ELFNAMEEND(coredump_countsegs), &cs); + if (error) + goto out; + + /* Count the PT_NOTE section. */ + cs.npsections++; + + /* Get the size of the notes. */ + error = ELFNAMEEND(coredump_notes)(p, NULL, ¬esize); + if (error) + goto out; + + memset(&ehdr, 0, sizeof(ehdr)); + memcpy(ehdr.e_ident, ELFMAG, SELFMAG); + ehdr.e_ident[EI_CLASS] = ELF_TARG_CLASS; + ehdr.e_ident[EI_DATA] = ELF_TARG_DATA; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + /* XXX Should be the OSABI/ABI version of the executable. */ + ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; + ehdr.e_ident[EI_ABIVERSION] = 0; + ehdr.e_type = ET_CORE; + /* XXX This should be the e_machine of the executable. */ + ehdr.e_machine = ELF_TARG_MACH; + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = 0; + ehdr.e_phoff = sizeof(ehdr); + ehdr.e_shoff = 0; + ehdr.e_flags = 0; + ehdr.e_ehsize = sizeof(ehdr); + ehdr.e_phentsize = sizeof(Elf_Phdr); + ehdr.e_phnum = cs.npsections; + ehdr.e_shentsize = 0; + ehdr.e_shnum = 0; + ehdr.e_shstrndx = 0; + + /* Write out the ELF header. */ + error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); + if (error) + goto out; + + offset = sizeof(ehdr); + + notestart = offset + sizeof(phdr) * cs.npsections; + secstart = notestart + notesize; + + psections = malloc(cs.npsections * sizeof(Elf_Phdr), + M_TEMP, M_WAITOK|M_ZERO); + + /* Pass 2: now write the P-section headers. */ + ws.secoff = secstart; + ws.psections = psections; + error = uvm_coredump_walkmap(p, cookie, + ELFNAMEEND(coredump_writeseghdrs), &ws); + if (error) + goto out; + + /* Write out the PT_NOTE header. */ + ws.psections->p_type = PT_NOTE; + ws.psections->p_offset = notestart; + ws.psections->p_vaddr = 0; + ws.psections->p_paddr = 0; + ws.psections->p_filesz = notesize; + ws.psections->p_memsz = 0; + ws.psections->p_flags = PF_R; + ws.psections->p_align = ELFROUNDSIZE; + + error = coredump_write(cookie, UIO_SYSSPACE, psections, + cs.npsections * sizeof(Elf_Phdr)); + if (error) + goto out; + +#ifdef DIAGNOSTIC + offset += cs.npsections * sizeof(Elf_Phdr); + if (offset != notestart) + panic("coredump: offset %lld != notestart %lld", + (long long) offset, (long long) notestart); +#endif + + /* Write out the notes. */ + error = ELFNAMEEND(coredump_notes)(p, cookie, ¬esize); + if (error) + goto out; + +#ifdef DIAGNOSTIC + offset += notesize; + if (offset != secstart) + panic("coredump: offset %lld != secstart %lld", + (long long) offset, (long long) secstart); +#endif + + /* Pass 3: finally, write the sections themselves. */ + for (i = 0; i < cs.npsections - 1; i++) { + if (psections[i].p_filesz == 0) + continue; + +#ifdef DIAGNOSTIC + if (offset != psections[i].p_offset) + panic("coredump: offset %lld != p_offset[%d] %lld", + (long long) offset, i, + (long long) psections[i].p_filesz); +#endif + + error = coredump_write(cookie, UIO_USERSPACE, + (void *)(vaddr_t)psections[i].p_vaddr, + psections[i].p_filesz); + if (error) + goto out; + +#ifdef DIAGNOSTIC + offset += psections[i].p_filesz; +#endif + } + +out: + return (error); +} + +int +ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie, + struct uvm_coredump_state *us) +{ + struct countsegs_state *cs = us->cookie; + + cs->npsections++; + return (0); +} + +int +ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie, + struct uvm_coredump_state *us) +{ + struct writesegs_state *ws = us->cookie; + Elf_Phdr phdr; + vsize_t size, realsize; + + size = us->end - us->start; + realsize = us->realend - us->start; + + phdr.p_type = PT_LOAD; + phdr.p_offset = ws->secoff; + phdr.p_vaddr = us->start; + phdr.p_paddr = 0; + phdr.p_filesz = realsize; + phdr.p_memsz = size; + phdr.p_flags = 0; + if (us->prot & VM_PROT_READ) + phdr.p_flags |= PF_R; + if (us->prot & VM_PROT_WRITE) + phdr.p_flags |= PF_W; + if (us->prot & VM_PROT_EXECUTE) + phdr.p_flags |= PF_X; + phdr.p_align = PAGE_SIZE; + + ws->secoff += phdr.p_filesz; + *ws->psections++ = phdr; + + return (0); +} + +int +ELFNAMEEND(coredump_notes)(struct proc *p, void *iocookie, size_t *sizep) +{ + struct ps_strings pss; + struct iovec iov; + struct uio uio; + struct elfcore_procinfo cpi; + Elf_Note nhdr; +#ifdef RTHREADS + struct proc *q; +#endif + size_t size, notesize; + int error; + + size = 0; + + /* First, write an elfcore_procinfo. */ + notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD")) + + elfround(sizeof(cpi)); + if (iocookie) { + bzero(&cpi, sizeof(cpi)); + + cpi.cpi_version = ELFCORE_PROCINFO_VERSION; + cpi.cpi_cpisize = sizeof(cpi); + cpi.cpi_signo = p->p_sigacts->ps_sig; + cpi.cpi_sigcode = p->p_sigacts->ps_code; + + cpi.cpi_sigpend = p->p_siglist; + cpi.cpi_sigmask = p->p_sigmask; + cpi.cpi_sigignore = p->p_sigignore; + cpi.cpi_sigcatch = p->p_sigcatch; + + cpi.cpi_pid = p->p_pid; + cpi.cpi_ppid = p->p_pptr->p_pid; + cpi.cpi_pgrp = p->p_pgid; + cpi.cpi_sid = p->p_session->s_leader->p_pid; + + cpi.cpi_ruid = p->p_cred->p_ruid; + cpi.cpi_euid = p->p_ucred->cr_uid; + cpi.cpi_svuid = p->p_cred->p_svuid; + + cpi.cpi_rgid = p->p_cred->p_rgid; + cpi.cpi_egid = p->p_ucred->cr_gid; + cpi.cpi_svgid = p->p_cred->p_svgid; + + (void)strlcpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); + + nhdr.namesz = sizeof("OpenBSD"); + nhdr.descsz = sizeof(cpi); + nhdr.type = NT_OPENBSD_PROCINFO; + + error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, + "OpenBSD", &cpi); + if (error) + return (error); + } + size += notesize; + + /* Second, write an NT_OPENBSD_AUXV note. */ + notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD")) + + elfround(p->p_emul->e_arglen * sizeof(char *)); + if (iocookie) { + iov.iov_base = &pss; + iov.iov_len = sizeof(pss); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)PS_STRINGS; + uio.uio_resid = sizeof(pss); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_procp = NULL; + + error = uvm_io(&p->p_vmspace->vm_map, &uio, 0); + if (error) + return (error); + + if (pss.ps_envstr == NULL) + return (EIO); + + nhdr.namesz = sizeof("OpenBSD"); + nhdr.descsz = p->p_emul->e_arglen * sizeof(char *); + nhdr.type = NT_OPENBSD_AUXV; + + error = coredump_write(iocookie, UIO_SYSSPACE, + &nhdr, sizeof(nhdr)); + if (error) + return (error); + + error = coredump_write(iocookie, UIO_SYSSPACE, + "OpenBSD", elfround(nhdr.namesz)); + if (error) + return (error); + + error = coredump_write(iocookie, UIO_USERSPACE, + pss.ps_envstr + pss.ps_nenvstr + 1, nhdr.descsz); + if (error) + return (error); + } + size += notesize; + +#ifdef PT_WCOOKIE + notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD")) + + elfround(sizeof(register_t)); + if (iocookie) { + register_t wcookie; + + nhdr.namesz = sizeof("OpenBSD"); + nhdr.descsz = sizeof(register_t); + nhdr.type = NT_OPENBSD_WCOOKIE; + + wcookie = process_get_wcookie(p); + error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, + "OpenBSD", &wcookie); + if (error) + return (error); + } + size += notesize; +#endif + + /* + * Now write the register info for the thread that caused the + * coredump. + */ + error = ELFNAMEEND(coredump_note)(p, iocookie, ¬esize); + if (error) + return (error); + size += notesize; + +#ifdef RTHREADS + /* + * Now, for each thread, write the register info and any other + * per-thread notes. Since we're dumping core, we don't bother + * locking. + */ + TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) { + if (q == p) /* we've taken care of this thread */ + continue; + error = ELFNAMEEND(coredump_note)(q, iocookie, ¬esize); + if (error) + return (error); + size += notesize; + } +#endif + + *sizep = size; + return (0); +} + +int +ELFNAMEEND(coredump_note)(struct proc *p, void *iocookie, size_t *sizep) +{ + Elf_Note nhdr; + int size, notesize, error; + int namesize; + char name[64+ELFROUNDSIZE]; + struct reg intreg; +#ifdef PT_GETFPREGS + struct fpreg freg; +#endif + + size = 0; + + snprintf(name, sizeof(name)-ELFROUNDSIZE, "%s@%d", + "OpenBSD", p->p_pid); + namesize = strlen(name) + 1; + memset(name + namesize, 0, elfround(namesize) - namesize); + + notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg)); + if (iocookie) { + error = process_read_regs(p, &intreg); + if (error) + return (error); + + nhdr.namesz = namesize; + nhdr.descsz = sizeof(intreg); + nhdr.type = NT_OPENBSD_REGS; + + error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, + name, &intreg); + if (error) + return (error); + + } + size += notesize; + +#ifdef PT_GETFPREGS + notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg)); + if (iocookie) { + error = process_read_fpregs(p, &freg); + if (error) + return (error); + + nhdr.namesz = namesize; + nhdr.descsz = sizeof(freg); + nhdr.type = NT_OPENBSD_FPREGS; + + error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, + name, &freg); + if (error) + return (error); + } + size += notesize; +#endif + + *sizep = size; + /* XXX Add hook for machdep per-LWP notes. */ + return (0); +} + +int +ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Note *nhdr, + const char *name, void *data) +{ + int error; + + error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr)); + if (error) + return error; + + error = coredump_write(cookie, UIO_SYSSPACE, name, + elfround(nhdr->namesz)); + if (error) + return error; + + return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->descsz); +} diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index b9b7010788f..b65ebbc9393 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.157 2009/02/13 19:58:27 deraadt Exp $ */ +/* $OpenBSD: init_main.c,v 1.158 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -39,6 +39,7 @@ */ #include <sys/param.h> +#include <sys/core.h> #include <sys/filedesc.h> #include <sys/file.h> #include <sys/errno.h> @@ -163,6 +164,7 @@ struct emul emul_native = { copyargs, setregs, NULL, + coredump_trad, sigcode, esigcode, EMUL_ENABLED | EMUL_NATIVE, diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index ed52c212eca..15053a45b20 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.102 2009/01/29 22:18:06 guenther Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.103 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1380,6 +1380,13 @@ sigexit(struct proc *p, int signum) int nosuidcoredump = 1; +struct coredump_iostate { + struct proc *io_proc; + struct vnode *io_vp; + struct ucred *io_cred; + off_t io_offset; +}; + /* * Dump core, into a file named "progname.core", unless the process was * setuid/setgid. @@ -1392,10 +1399,10 @@ coredump(struct proc *p) struct vmspace *vm = p->p_vmspace; struct nameidata nd; struct vattr vattr; + struct coredump_iostate io; int error, error1, len; char name[sizeof("/var/crash/") + MAXCOMLEN + sizeof(".core")]; char *dir = ""; - struct core core; /* * Don't dump if not root and the process has used set user or @@ -1455,6 +1462,31 @@ coredump(struct proc *p) bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc)); fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); + io.io_proc = p; + io.io_vp = vp; + io.io_cred = cred; + io.io_offset = 0; + + error = (*p->p_emul->e_coredump)(p, &io); +out: + VOP_UNLOCK(vp, 0, p); + error1 = vn_close(vp, FWRITE, cred, p); + crfree(cred); + if (error == 0) + error = error1; + return (error); +} + +int +coredump_trad(struct proc *p, void *cookie) +{ + struct coredump_iostate *io = cookie; + struct vmspace *vm = io->io_proc->p_vmspace; + struct vnode *vp = io->io_vp; + struct ucred *cred = io->io_cred; + struct core core; + int error; + core.c_midmag = 0; strlcpy(core.c_name, p->p_comm, sizeof(core.c_name)); core.c_nseg = 0; @@ -1466,26 +1498,41 @@ coredump(struct proc *p) core.c_ssize = (u_long)round_page(ptoa(vm->vm_ssize)); error = cpu_coredump(p, vp, cred, &core); if (error) - goto out; + return (error); /* * uvm_coredump() spits out all appropriate segments. * All that's left to do is to write the core header. */ error = uvm_coredump(p, vp, cred, &core); if (error) - goto out; + return (error); error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&core, (int)core.c_hdrsize, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); -out: - VOP_UNLOCK(vp, 0, p); - error1 = vn_close(vp, FWRITE, cred, p); - crfree(cred); - if (error == 0) - error = error1; return (error); } +int +coredump_write(void *cookie, enum uio_seg segflg, const void *data, size_t len) +{ + struct coredump_iostate *io = cookie; + int error; + + error = vn_rdwr(UIO_WRITE, io->io_vp, (void *)data, len, + io->io_offset, segflg, + IO_NODELOCKED|IO_UNIT, io->io_cred, NULL, io->io_proc); + if (error) { + printf("pid %d (%s): %s write of %zu@%p at %lld failed: %d\n", + io->io_proc->p_pid, io->io_proc->p_comm, + segflg == UIO_USERSPACE ? "user" : "system", + len, data, (long long) io->io_offset, error); + return (error); + } + + io->io_offset += len; + return (0); +} + /* * Nonexistent system call-- signal process (may want to handle it). * Flag error in case process won't see signal immediately (blocked or ignored). diff --git a/sys/sys/core.h b/sys/sys/core.h index 5aeb41b7dcc..941b63b32b0 100644 --- a/sys/sys/core.h +++ b/sys/sys/core.h @@ -1,4 +1,4 @@ -/* $OpenBSD: core.h,v 1.3 2003/10/30 21:38:09 jmc Exp $ */ +/* $OpenBSD: core.h,v 1.4 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: core.h,v 1.4 1994/10/29 08:20:14 cgd Exp $ */ /* @@ -86,3 +86,9 @@ struct coreseg { u_long c_addr; /* Virtual address of segment */ u_long c_size; /* Size of this segment */ }; + +#ifdef _KERNEL +int coredump_trad(struct proc *, void *); + +int coredump_write(void *, enum uio_seg, const void *, size_t); +#endif diff --git a/sys/sys/exec_elf.h b/sys/sys/exec_elf.h index 6b8fb1c0a2f..72c4a5b2568 100644 --- a/sys/sys/exec_elf.h +++ b/sys/sys/exec_elf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.h,v 1.43 2007/05/14 05:04:58 tedu Exp $ */ +/* $OpenBSD: exec_elf.h,v 1.44 2009/03/05 19:52:24 kettenis Exp $ */ /* * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. * @@ -481,6 +481,64 @@ typedef struct { } Elf64_Note; /* + * OpenBSD-specific core file information. + * + * OpenBSDBSD ELF core files use notes to provide information about + * the process's state. The note name is "OpenBSD" for information + * that is global to the process, and "OpenBSD@nn", where "nn" is the + * thread ID of the thread that the information belongs to (such as + * register state). + * + * We use the following note identifiers: + * + * NT_OPENBSD_PROCINFO + * Note is a "elfcore_procinfo" structure. + * NT_OPENBSD_AUXV + * Note is a a bunch of Auxilliary Vectors, terminted by + * an AT_NULL entry. + * NT_OPENBSD_REGS + * Note is a "reg" structure. + * NT_OPENBSD_FPREGS + * Note is a "fpreg" structure. + * + * Please try to keep the members of the "elfcore_procinfo" structure + * nicely aligned, and if you add elements, add them to the end and + * bump the version. + */ + +#define NT_OPENBSD_PROCINFO 10 +#define NT_OPENBSD_AUXV 11 + +#define NT_OPENBSD_REGS 20 +#define NT_OPENBSD_FPREGS 21 +#define NT_OPENBSD_XFPREGS 22 +#define NT_OPENBSD_WCOOKIE 23 + +struct elfcore_procinfo { + /* Version 1 fields start here. */ + uint32_t cpi_version; /* netbsd_elfcore_procinfo version */ +#define ELFCORE_PROCINFO_VERSION 1 + uint32_t cpi_cpisize; /* sizeof(netbsd_elfcore_procinfo) */ + uint32_t cpi_signo; /* killing signal */ + uint32_t cpi_sigcode; /* signal code */ + uint32_t cpi_sigpend; /* pending signals */ + uint32_t cpi_sigmask; /* blocked signals */ + uint32_t cpi_sigignore; /* ignored signals */ + uint32_t cpi_sigcatch; /* signals being caught by user */ + int32_t cpi_pid; /* process ID */ + int32_t cpi_ppid; /* parent process ID */ + int32_t cpi_pgrp; /* process group ID */ + int32_t cpi_sid; /* session ID */ + uint32_t cpi_ruid; /* real user ID */ + uint32_t cpi_euid; /* effective user ID */ + uint32_t cpi_svuid; /* saved user ID */ + uint32_t cpi_rgid; /* real group ID */ + uint32_t cpi_egid; /* effective group ID */ + uint32_t cpi_svgid; /* saved group ID */ + int8_t cpi_name[32]; /* copy of p->p_comm */ +}; + +/* * XXX - these _KERNEL items aren't part of the ABI! */ #if defined(_KERNEL) || defined(_DYN_LOADER) diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d50bcdfc9b7..aeec114cec4 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.111 2008/12/16 07:57:28 guenther Exp $ */ +/* $OpenBSD: proc.h,v 1.112 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -100,6 +100,7 @@ struct emul { void (*e_setregs)(struct proc *, struct exec_package *, u_long, register_t *); int (*e_fixup)(struct proc *, struct exec_package *); + int (*e_coredump)(struct proc *, void *cookie); char *e_sigcode; /* Start of sigcode */ char *e_esigcode; /* End of sigcode */ int e_flags; /* Flags, see below */ diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h index 2ec3f3431da..2e97ced5933 100644 --- a/sys/uvm/uvm_extern.h +++ b/sys/uvm/uvm_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_extern.h,v 1.73 2009/02/11 11:09:36 mikeb Exp $ */ +/* $OpenBSD: uvm_extern.h,v 1.74 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */ /* @@ -406,6 +406,20 @@ struct vmspace { #ifdef _KERNEL /* + * used to keep state while iterating over the map for a core dump. + */ +struct uvm_coredump_state { + void *cookie; /* opaque for the caller */ + vaddr_t start; /* start of region */ + vaddr_t realend; /* real end of region */ + vaddr_t end; /* virtual end of region */ + vm_prot_t prot; /* protection of region */ + int flags; /* flags; see below */ +}; + +#define UVM_COREDUMP_STACK 0x01 /* region is user stack */ + +/* * the various kernel maps, owned by MD code */ extern struct vm_map *exec_map; @@ -574,6 +588,10 @@ void uvm_swap_init(void); /* uvm_unix.c */ int uvm_coredump(struct proc *, struct vnode *, struct ucred *, struct core *); +int uvm_coredump_walkmap(struct proc *, + void *, + int (*)(struct proc *, void *, + struct uvm_coredump_state *), void *); void uvm_grow(struct proc *, vaddr_t); /* uvm_user.c */ diff --git a/sys/uvm/uvm_unix.c b/sys/uvm/uvm_unix.c index 88601d6a810..118072ea12e 100644 --- a/sys/uvm/uvm_unix.c +++ b/sys/uvm/uvm_unix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_unix.c,v 1.34 2008/03/02 20:29:20 kettenis Exp $ */ +/* $OpenBSD: uvm_unix.c,v 1.35 2009/03/05 19:52:24 kettenis Exp $ */ /* $NetBSD: uvm_unix.c,v 1.18 2000/09/13 15:00:25 thorpej Exp $ */ /* @@ -255,3 +255,76 @@ uvm_coredump(p, vp, cred, chdr) return (error); } +int +uvm_coredump_walkmap(struct proc *p, void *iocookie, + int (*func)(struct proc *, void *, struct uvm_coredump_state *), + void *cookie) +{ + struct uvm_coredump_state state; + struct vmspace *vm = p->p_vmspace; + struct vm_map *map = &vm->vm_map; + struct vm_map_entry *entry; + vaddr_t top; + int error; + + for (entry = map->header.next; entry != &map->header; + entry = entry->next) { + + state.cookie = cookie; + state.prot = entry->protection; + state.flags = 0; + + /* should never happen for a user process */ + if (UVM_ET_ISSUBMAP(entry)) { + panic("uvm_coredump: user process with submap?"); + } + + if (!(entry->protection & VM_PROT_WRITE) && + entry->start != p->p_sigcode) + continue; + + /* + * Don't dump mmaped devices. + */ + if (entry->object.uvm_obj != NULL && + UVM_OBJ_IS_DEVICE(entry->object.uvm_obj)) + continue; + + state.start = entry->start; + state.realend = entry->end; + state.end = entry->end; + + if (state.start >= VM_MAXUSER_ADDRESS) + continue; + + if (state.end > VM_MAXUSER_ADDRESS) + state.end = VM_MAXUSER_ADDRESS; + +#ifdef MACHINE_STACK_GROWS_UP + if (USRSTACK <= state.start && + state.start < (USRSTACK + MAXSSIZ)) { + top = round_page(USRSTACK + ptoa(vm->vm_ssize)); + if (state.end > top) + state.end = top; + + if (state.start >= state.end) + continue; +#else + if (state.start >= (vaddr_t)vm->vm_maxsaddr) { + top = trunc_page(USRSTACK - ptoa(vm->vm_ssize)); + if (state.start < top) + state.start = top; + + if (state.start >= state.end) + continue; +#endif + state.flags |= UVM_COREDUMP_STACK; + } + + error = (*func)(p, iocookie, &state); + if (error) + return (error); + } + + return (0); +} |