Viola! The kernel now generates standard ELF core dumps for ELF

executables.

Currently only data and stack are included in the core dumps.  I am
looking into adding the other (mmapped) writable segments as well.
This commit is contained in:
John Polstra 1998-09-14 22:46:08 +00:00
parent 1a291e0cd4
commit 8c64af4f75
2 changed files with 361 additions and 16 deletions

View File

@ -26,25 +26,31 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: imgact_elf.c,v 1.29 1998/07/29 18:39:35 dfr Exp $
* $Id: imgact_elf.c,v 1.30 1998/09/14 05:36:49 jdp Exp $
*/
#include "opt_rlimit.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/acct.h>
#include <sys/exec.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/kernel.h>
#include <sys/sysent.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/namei.h>
#include <sys/pioctl.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <vm/vm.h>
@ -78,9 +84,13 @@
static int elf_check_header __P((const Elf_Ehdr *hdr, int type));
static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot));
static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry));
static int elf_freebsd_fixup __P((long **stack_base, struct image_params *imgp));
static int elf_freebsd_fixup __P((long **stack_base,
struct image_params *imgp));
static int elf_load_file __P((struct proc *p, char *file, u_long *addr,
u_long *entry));
static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp,
vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
vm_prot_t prot));
static int exec_elf_imgact __P((struct image_params *imgp));
static int elf_trace = 0;
@ -639,14 +649,6 @@ exec_elf_imgact(struct image_params *imgp)
return error;
}
int
elf_coredump (p)
register struct proc *p;
{
/* Not implemented yet. */
return EFAULT;
}
static int
elf_freebsd_fixup(long **stack_base, struct image_params *imgp)
{
@ -678,6 +680,268 @@ elf_freebsd_fixup(long **stack_base, struct image_params *imgp)
return 0;
}
/*
* Code for generating ELF core dumps.
*/
static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *));
static size_t elf_hdrsize(void);
static void elf_puthdr(void *, size_t *, const prstatus_t *,
const prfpregset_t *, const prpsinfo_t *, const void *, size_t,
const void *, size_t);
static void elf_putnote(void *, size_t *, const char *, int, const void *,
size_t);
extern int osreldate;
int
elf_coredump(p)
register struct proc *p;
{
register struct vnode *vp;
register struct ucred *cred = p->p_cred->pc_ucred;
register struct vmspace *vm = p->p_vmspace;
struct nameidata nd;
struct vattr vattr;
int error, error1;
char *name; /* name of corefile */
size_t hdrsize;
STOPEVENT(p, S_CORE, 0);
if (sugid_coredump == 0 && p->p_flag & P_SUGID)
return (EFAULT);
hdrsize = elf_hdrsize();
if (hdrsize + ctob(vm->vm_dsize + vm->vm_ssize) >=
p->p_rlimit[RLIMIT_CORE].rlim_cur)
return (EFAULT);
name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
if (name == NULL)
return (EFAULT); /* XXX -- not the best error */
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p);
error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR);
free(name, M_TEMP);
if (error)
return (error);
vp = nd.ni_vp;
/* Don't dump to non-regular files or files with links. */
if (vp->v_type != VREG ||
VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) {
error = EFAULT;
goto out;
}
VATTR_NULL(&vattr);
vattr.va_size = 0;
VOP_LEASE(vp, p, cred, LEASE_WRITE);
VOP_SETATTR(vp, &vattr, cred, p);
p->p_acflag |= ACORE;
error = elf_corehdr(p, vp, cred);
if (error == 0)
error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
(int)ctob(vm->vm_dsize), (off_t)hdrsize, UIO_USERSPACE,
IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
if (error == 0)
error = vn_rdwr(UIO_WRITE, vp,
(caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
round_page(ctob(vm->vm_ssize)),
(off_t)hdrsize + ctob(vm->vm_dsize), UIO_USERSPACE,
IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);
out:
VOP_UNLOCK(vp, 0, p);
error1 = vn_close(vp, FWRITE, cred, p);
if (error == 0)
error = error1;
return (error);
}
static int
elf_corehdr(p, vp, cred)
struct proc *p;
struct vnode *vp;
struct ucred *cred;
{
struct vmspace *vm = p->p_vmspace;
size_t off;
size_t hdrsize;
prstatus_t status;
prfpregset_t fpregset;
prpsinfo_t psinfo;
void *hdr;
int error;
/* Gather the information for the header. */
bzero(&status, sizeof status);
status.pr_version = PRSTATUS_VERSION;
status.pr_statussz = sizeof(prstatus_t);
status.pr_gregsetsz = sizeof(gregset_t);
status.pr_fpregsetsz = sizeof(fpregset_t);
status.pr_osreldate = osreldate;
status.pr_cursig = p->p_sigacts->ps_sig;
status.pr_pid = p->p_pid;
fill_regs(p, &status.pr_reg);
fill_fpregs(p, &fpregset);
bzero(&psinfo, sizeof psinfo);
psinfo.pr_version = PRPSINFO_VERSION;
psinfo.pr_psinfosz = sizeof(prpsinfo_t);
strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN);
psinfo.pr_psargs[0] = '\0'; /* XXX - args not implemented yet */
/* Allocate memory for building the header. */
hdrsize = elf_hdrsize();
hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
if (hdr == NULL)
return EINVAL;
bzero(hdr, hdrsize);
/* Fill in the header. */
off = 0;
elf_puthdr(hdr, &off, &status, &fpregset, &psinfo,
vm->vm_daddr, ctob(vm->vm_dsize),
(void *)trunc_page(USRSTACK - ctob(vm->vm_ssize)),
ctob(vm->vm_ssize));
/* Write it to the core file. */
error = vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p);
free(hdr, M_TEMP);
return error;
}
static size_t
elf_hdrsize(void)
{
size_t off;
off = 0;
elf_puthdr(NULL, &off, NULL, NULL, NULL, NULL, 0, NULL, 0);
return off;
}
static void
elf_puthdr(void *dst, size_t *off, const prstatus_t *status,
const prfpregset_t *fpregset, const prpsinfo_t *psinfo,
const void *data, size_t datasz, const void *stack, size_t stacksz)
{
size_t ehoff;
size_t phoff;
size_t noteoff;
size_t notesz;
size_t dataoff;
size_t stackoff;
int numsegs = 3;
ehoff = *off;
*off += sizeof(Elf_Ehdr);
phoff = *off;
*off += numsegs * sizeof(Elf_Phdr);
noteoff = *off;
elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status,
sizeof *status);
elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
sizeof *fpregset);
elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo,
sizeof *psinfo);
notesz = *off - noteoff;
/* Align up to a page boundary for the data segment. */
*off = round_page(*off);
if (dst != NULL) {
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
/*
* 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_PAD] = 0;
strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD",
EI_NIDENT - EI_BRAND);
ehdr->e_type = ET_CORE;
ehdr->e_machine = ELF_ARCH;
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;
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 = 0;
phdr->p_align = 0;
phdr++;
/* The data segment. */
phdr->p_type = PT_LOAD;
phdr->p_offset = *off;
phdr->p_vaddr = (Elf_Addr)data;
phdr->p_paddr = 0;
phdr->p_filesz = phdr->p_memsz = datasz;
phdr->p_align = PAGE_SIZE;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr++;
/* The stack segment. */
phdr->p_type = PT_LOAD;
phdr->p_offset = *off + datasz;
phdr->p_vaddr = (Elf_Addr)stack;
phdr->p_paddr = 0;
phdr->p_filesz = phdr->p_memsz = stacksz;
phdr->p_align = PAGE_SIZE;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr++;
}
}
static void
elf_putnote(void *dst, size_t *off, const char *name, int type,
const void *desc, size_t descsz)
{
Elf_Note note;
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(Elf_Size));
if (dst != NULL)
bcopy(desc, (char *)dst + *off, note.n_descsz);
*off += roundup2(note.n_descsz, sizeof(Elf_Size));
}
/*
* Tell kern_execve.c about it, with a little help from the linker.
* Since `const' objects end up in the text segment, TEXT_SET is the

81
sys/sys/procfs.h Normal file
View File

@ -0,0 +1,81 @@
/*-
* Copyright (c) 1998 John D. Polstra.
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
*
* $Id$
*/
#ifndef _SYS_PROCFS_H_
#define _SYS_PROCFS_H_
#include <sys/param.h>
#include <machine/reg.h>
typedef struct reg gregset_t;
typedef struct fpreg fpregset_t;
/*
* These structures define an interface between core files and the debugger.
* Never change or delete any elements. If you add elements, add them to
* the end of the structure, and increment the value of its version field.
* This will help to ensure that today's core dump will still be usable
* with next year's debugger.
*
* A lot more things should be added to these structures. At present,
* they contain the absolute bare minimum required to allow GDB to work
* with ELF core dumps.
*/
/*
* The parenthsized numbers like (1) indicate the minimum version number
* for which each element exists in the structure.
*/
#define PRSTATUS_VERSION 1 /* Current version of prstatus_t */
typedef struct prstatus {
int pr_version; /* Version number of struct (1) */
size_t pr_statussz; /* sizeof(prstatus_t) (1) */
size_t pr_gregsetsz; /* sizeof(gregset_t) (1) */
size_t pr_fpregsetsz; /* sizeof(fpregset_t) (1) */
int pr_osreldate; /* Kernel version (1) */
int pr_cursig; /* Current signal (1) */
pid_t pr_pid; /* Process ID (1) */
gregset_t pr_reg; /* General purpose registers (1) */
} prstatus_t;
typedef fpregset_t prfpregset_t;
#define PRARGSZ 80 /* Maximum argument bytes saved */
#define PRPSINFO_VERSION 1 /* Current version of prpsinfo_t */
typedef struct prpsinfo {
int pr_version; /* Version number of struct (1) */
size_t pr_psinfosz; /* sizeof(prpsinfo_t) (1) */
char pr_fname[MAXCOMLEN+1]; /* Command name, null terminated (1) */
char pr_psargs[PRARGSZ+1]; /* Arguments, null terminated (1) */
} prpsinfo_t;
#endif /* _SYS_PROCFS_H_ */