816 lines
19 KiB
C
Executable File
816 lines
19 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)elf.c 1.57 95/06/26 SMI" /* from S5R4 1.31 */
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/thread.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/cred.h>
|
|
#include <sys/user.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/kmem.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/pathname.h>
|
|
#include <sys/cmn_err.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/elf.h>
|
|
#include <sys/vmsystm.h>
|
|
#include <sys/debug.h>
|
|
#include <sys/procfs.h>
|
|
#ifdef sparc
|
|
#include <sys/elf_SPARC.h>
|
|
#endif /* sparc */
|
|
#ifdef i386
|
|
#include <sys/elf_386.h>
|
|
#endif /* i386 */
|
|
#include <sys/auxv.h>
|
|
#include <sys/exec.h>
|
|
#include <sys/prsystm.h>
|
|
#include <vm/as.h>
|
|
#include <vm/rm.h>
|
|
#include <sys/modctl.h>
|
|
#include <sys/systeminfo.h>
|
|
|
|
extern short elfmagic;
|
|
extern int at_flags;
|
|
|
|
static int getelfhead(struct vnode *, Elf32_Ehdr *, caddr_t *, long *);
|
|
static int mapelfexec(struct vnode *, Elf32_Ehdr *, caddr_t,
|
|
Elf32_Phdr **, Elf32_Phdr **, Elf32_Phdr **,
|
|
caddr_t *, long *, u_int, long *);
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
elfexec(
|
|
struct vnode *vp,
|
|
struct execa *uap,
|
|
struct uarg *args,
|
|
struct intpdata *idatap,
|
|
int level,
|
|
long *execsz,
|
|
int setid,
|
|
caddr_t exec_file,
|
|
struct cred *cred)
|
|
{
|
|
caddr_t phdrbase = NULL;
|
|
caddr_t base = 0;
|
|
int dlnsize, *aux, resid, error;
|
|
int fd = -1;
|
|
long voffset;
|
|
struct vnode *nvp;
|
|
Elf32_Phdr *dyphdr = NULL;
|
|
Elf32_Phdr *stphdr = NULL;
|
|
Elf32_Phdr *uphdr = NULL;
|
|
Elf32_Phdr *junk = NULL;
|
|
long phdrsize;
|
|
int postfixsize = 0;
|
|
int i, hsize;
|
|
Elf32_Phdr *phdrp;
|
|
int hasu = 0;
|
|
int hasdy = 0;
|
|
int auxsize = 0;
|
|
struct proc *pp = ttoproc(curthread);
|
|
struct user *up = PTOU(pp);
|
|
struct bigwad {
|
|
Elf32_Ehdr ehdr;
|
|
int elfargs[NUM_AUX_VECTORS * 2];
|
|
char dl_name[MAXPATHLEN];
|
|
struct vattr vattr;
|
|
struct execenv exenv;
|
|
} *bigwad; /* kmem_alloc this behemoth so we don't blow stack */
|
|
Elf32_Ehdr *ehdrp;
|
|
char *dlnp;
|
|
|
|
bigwad = kmem_alloc(sizeof (struct bigwad), KM_SLEEP);
|
|
ehdrp = &bigwad->ehdr;
|
|
dlnp = bigwad->dl_name;
|
|
|
|
/*
|
|
* Obtain ELF and program header information.
|
|
*/
|
|
if ((error = getelfhead(vp, ehdrp, &phdrbase, &phdrsize)) != 0)
|
|
goto out;
|
|
|
|
/*
|
|
* Determine aux size now so that stack can be built
|
|
* in one shot (except actual copyout of aux image)
|
|
* and still have this code be machine independent.
|
|
*/
|
|
hsize = ehdrp->e_phentsize;
|
|
phdrp = (Elf32_Phdr *)phdrbase;
|
|
for (i = ehdrp->e_phnum; i > 0; i--) {
|
|
switch (phdrp->p_type) {
|
|
case PT_INTERP:
|
|
hasdy = 1;
|
|
break;
|
|
case PT_PHDR:
|
|
hasu = 1;
|
|
}
|
|
phdrp = (Elf32_Phdr *)((caddr_t)phdrp + hsize);
|
|
}
|
|
|
|
if (hasdy)
|
|
auxsize = (20 + (hasu ? 8 : 2)) * NBPW;
|
|
|
|
args->auxsize = auxsize;
|
|
aux = bigwad->elfargs;
|
|
/*
|
|
* Move args to the user's stack.
|
|
*/
|
|
if ((error = exec_args(uap, args, idatap, &aux)) != 0) {
|
|
if (error == -1) {
|
|
error = ENOEXEC;
|
|
goto bad;
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
if ((error = mapelfexec(vp, ehdrp, phdrbase, &uphdr, &dyphdr,
|
|
&stphdr, &base, &voffset, 0, execsz)) != 0)
|
|
goto bad;
|
|
|
|
#ifdef COFF_SUPPORT /* XXX - May be required */
|
|
if (stphdr != NULL) {
|
|
/* call coff stuff. */
|
|
if ((error = elf_coffshlib(vp, stphdr, execsz, ehdp)) != 0)
|
|
goto bad;
|
|
}
|
|
#endif
|
|
|
|
if (uphdr != NULL && dyphdr == NULL)
|
|
goto bad;
|
|
|
|
if (dyphdr != NULL) {
|
|
u_int len;
|
|
register Elf32_Phdr *fph = NULL, *lph;
|
|
|
|
dlnsize = dyphdr->p_filesz;
|
|
|
|
if (dlnsize > MAXPATHLEN || dlnsize <= 0)
|
|
goto bad;
|
|
|
|
/*
|
|
* Read in "interpreter" pathname.
|
|
*/
|
|
if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
|
|
dyphdr->p_offset, UIO_SYSSPACE, 0, (long) 0,
|
|
CRED(), &resid)) != 0) {
|
|
uprintf("%s: Cannot obtain interpreter pathname\n",
|
|
exec_file);
|
|
goto bad;
|
|
}
|
|
|
|
if (resid != 0 || dlnp[dlnsize - 1] != '\0')
|
|
goto bad;
|
|
|
|
if ((error = lookupname(dlnp, UIO_SYSSPACE, FOLLOW,
|
|
NULLVPP, &nvp)) != 0) {
|
|
uprintf("%s: Cannot find %s\n", exec_file, dlnp);
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* Setup the "aux" vector.
|
|
*/
|
|
if (uphdr) {
|
|
if (ehdrp->e_type == ET_DYN)
|
|
/* don't use the first page */
|
|
bigwad->exenv.ex_brkbase = (caddr_t)PAGESIZE;
|
|
else
|
|
bigwad->exenv.ex_brkbase = base;
|
|
bigwad->exenv.ex_brksize = 0;
|
|
bigwad->exenv.ex_magic = elfmagic;
|
|
bigwad->exenv.ex_vp = vp;
|
|
setexecenv(&bigwad->exenv);
|
|
|
|
*aux++ = AT_PHDR;
|
|
*aux++ = (int)uphdr->p_vaddr + voffset;
|
|
*aux++ = AT_PHENT;
|
|
*aux++ = ehdrp->e_phentsize;
|
|
*aux++ = AT_PHNUM;
|
|
*aux++ = ehdrp->e_phnum;
|
|
*aux++ = AT_ENTRY;
|
|
*aux++ = ehdrp->e_entry + voffset;
|
|
postfixsize += (8 * NBPW);
|
|
} else {
|
|
if ((error = execopen(&vp, &fd)) != 0) {
|
|
VN_RELE(nvp);
|
|
goto bad;
|
|
}
|
|
|
|
*aux++ = AT_EXECFD;
|
|
*aux++ = fd;
|
|
postfixsize += (2 * NBPW);
|
|
}
|
|
|
|
if ((error = execpermissions(nvp, &bigwad->vattr, args)) != 0) {
|
|
VN_RELE(nvp);
|
|
uprintf("%s: Cannot execute %s\n", exec_file, dlnp);
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* Now obtain the ELF header along with the entire program
|
|
* header contained in "nvp".
|
|
*/
|
|
kmem_free(phdrbase, phdrsize);
|
|
phdrbase = NULL;
|
|
if ((error = getelfhead(nvp, ehdrp, &phdrbase,
|
|
&phdrsize)) != 0) {
|
|
VN_RELE(nvp);
|
|
uprintf("%s: Cannot read %s\n", exec_file, dlnp);
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* Determine memory size of the "interpreter's" loadable
|
|
* sections. This size is then used to obtain the virtual
|
|
* address of a hole, in the user's address space, large
|
|
* enough to map the "interpreter".
|
|
*/
|
|
hsize = ehdrp->e_phentsize;
|
|
phdrp = (Elf32_Phdr *)phdrbase;
|
|
for (i = ehdrp->e_phnum; i > 0; i--) {
|
|
if (phdrp->p_type == PT_LOAD) {
|
|
if (fph == NULL)
|
|
fph = phdrp;
|
|
lph = phdrp;
|
|
}
|
|
phdrp = (Elf32_Phdr *)((caddr_t)phdrp + hsize);
|
|
}
|
|
if (fph == NULL) {
|
|
VN_RELE(nvp);
|
|
uprintf("%s: Nothing to load in %s\n", exec_file, dlnp);
|
|
goto bad;
|
|
}
|
|
len = roundup((lph->p_vaddr + lph->p_memsz) -
|
|
(fph->p_vaddr & PAGEMASK), PAGESIZE);
|
|
|
|
error = mapelfexec(nvp, ehdrp, phdrbase, &junk, &junk,
|
|
&junk, NULL, &voffset, len, execsz);
|
|
|
|
VN_RELE(nvp);
|
|
if (error || junk != NULL) {
|
|
uprintf("%s: Cannot map %s\n", exec_file, dlnp);
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* Note: AT_SUN_PLATFORM was filled in via exec_args()
|
|
*/
|
|
*aux++ = AT_BASE;
|
|
*aux++ = voffset;
|
|
*aux++ = AT_FLAGS;
|
|
*aux++ = at_flags;
|
|
*aux++ = AT_PAGESZ;
|
|
*aux++ = PAGESIZE;
|
|
|
|
/*
|
|
* Save uid, ruid, gid and rgid information
|
|
* for the linker.
|
|
*/
|
|
*aux++ = AT_SUN_UID;
|
|
*aux++ = cred->cr_uid;
|
|
*aux++ = AT_SUN_RUID;
|
|
*aux++ = cred->cr_ruid;
|
|
*aux++ = AT_SUN_GID;
|
|
*aux++ = cred->cr_gid;
|
|
*aux++ = AT_SUN_RGID;
|
|
*aux++ = cred->cr_rgid;
|
|
/*
|
|
* Hardware capability flag word (performance hints)
|
|
*/
|
|
*aux++ = AT_SUN_HWCAP;
|
|
*aux++ = auxv_hwcap;
|
|
|
|
*aux++ = AT_NULL;
|
|
*aux = 0;
|
|
postfixsize += (20 * NBPW);
|
|
ASSERT(postfixsize == args->auxsize);
|
|
}
|
|
|
|
if (*execsz > btoc(up->u_rlimit[RLIMIT_VMEM].rlim_cur)) {
|
|
error = ENOMEM;
|
|
goto bad;
|
|
}
|
|
|
|
bzero((caddr_t)up->u_auxv, sizeof (up->u_auxv));
|
|
if (postfixsize) {
|
|
error = execpoststack(args, bigwad->elfargs, postfixsize);
|
|
if (error)
|
|
goto bad;
|
|
ASSERT(postfixsize <= sizeof (up->u_auxv));
|
|
bcopy((caddr_t)bigwad->elfargs, (caddr_t)up->u_auxv,
|
|
postfixsize);
|
|
}
|
|
|
|
/*
|
|
* XXX -- should get rid of this stuff.
|
|
*/
|
|
up->u_exdata.ux_mag = 0413;
|
|
up->u_exdata.ux_entloc = (caddr_t)(ehdrp->e_entry + voffset);
|
|
|
|
if (!uphdr) {
|
|
bigwad->exenv.ex_brkbase = base;
|
|
bigwad->exenv.ex_brksize = 0;
|
|
bigwad->exenv.ex_magic = elfmagic;
|
|
bigwad->exenv.ex_vp = vp;
|
|
setexecenv(&bigwad->exenv);
|
|
}
|
|
ASSERT(error == 0);
|
|
goto out;
|
|
|
|
bad:
|
|
if (fd != -1) /* did we open the a.out yet */
|
|
(void) execclose(fd);
|
|
|
|
psignal(pp, SIGKILL);
|
|
|
|
if (error == 0)
|
|
error = ENOEXEC;
|
|
out:
|
|
if (phdrbase != NULL)
|
|
kmem_free(phdrbase, phdrsize);
|
|
kmem_free(bigwad, sizeof (struct bigwad));
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Read in the ELF header and program header table.
|
|
*/
|
|
static int
|
|
getelfhead(
|
|
struct vnode *vp,
|
|
Elf32_Ehdr *ehdr,
|
|
caddr_t *phdrbase,
|
|
long *phdrsizep)
|
|
{
|
|
int resid, error;
|
|
long phdrsize;
|
|
|
|
/*
|
|
* We got here by the first two bytes in ident,
|
|
* now read the entire ELF header.
|
|
*/
|
|
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t) ehdr,
|
|
sizeof (Elf32_Ehdr), (off_t) 0, UIO_SYSSPACE, 0,
|
|
(long) 0, CRED(), &resid)) != 0)
|
|
return (error);
|
|
|
|
if (resid != 0 ||
|
|
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
|
|
ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
|
|
ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
|
|
(ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
|
|
!elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
|
|
ehdr->e_flags) ||
|
|
ehdr->e_phentsize == 0 || (ehdr->e_phentsize & 3))
|
|
return (ENOEXEC);
|
|
|
|
/*
|
|
* Determine the size of the program header table
|
|
* and read it in.
|
|
*/
|
|
*phdrsizep = phdrsize = ehdr->e_phnum * ehdr->e_phentsize;
|
|
*phdrbase = (caddr_t)kmem_alloc(phdrsize, KM_SLEEP);
|
|
return (vn_rdwr(UIO_READ, vp, *phdrbase, phdrsize,
|
|
(off_t) ehdr->e_phoff, UIO_SYSSPACE, 0, (long) 0,
|
|
CRED(), &resid));
|
|
}
|
|
|
|
static int
|
|
mapelfexec(
|
|
struct vnode *vp,
|
|
Elf32_Ehdr *ehdr,
|
|
caddr_t phdrbase,
|
|
Elf32_Phdr **uphdr,
|
|
Elf32_Phdr **dyphdr,
|
|
Elf32_Phdr **stphdr,
|
|
caddr_t *base,
|
|
long *voffset,
|
|
u_int len,
|
|
long *execsz)
|
|
{
|
|
Elf32_Phdr *phdr;
|
|
int i, prot, error;
|
|
caddr_t addr;
|
|
size_t zfodsz;
|
|
int ptload = 0;
|
|
int page;
|
|
off_t offset;
|
|
int hsize = ehdr->e_phentsize;
|
|
|
|
if (ehdr->e_type == ET_DYN) {
|
|
/*
|
|
* Obtain the virtual address of a hole in the
|
|
* address space to map the "interpreter".
|
|
*/
|
|
map_addr(&addr, len, 0, 1);
|
|
if (addr == NULL)
|
|
return (ENOMEM);
|
|
*voffset = (long)addr;
|
|
} else
|
|
*voffset = 0;
|
|
|
|
phdr = (Elf32_Phdr *)phdrbase;
|
|
for (i = (int)ehdr->e_phnum; i > 0; i--) {
|
|
switch (phdr->p_type) {
|
|
case PT_LOAD:
|
|
if ((*dyphdr != NULL) && (*uphdr == NULL))
|
|
return (0);
|
|
|
|
ptload = 1;
|
|
prot = PROT_USER;
|
|
if (phdr->p_flags & PF_R)
|
|
prot |= PROT_READ;
|
|
if (phdr->p_flags & PF_W)
|
|
prot |= PROT_WRITE;
|
|
if (phdr->p_flags & PF_X)
|
|
prot |= PROT_EXEC;
|
|
|
|
addr = (caddr_t) phdr->p_vaddr + *voffset;
|
|
zfodsz = (size_t) phdr->p_memsz - phdr->p_filesz;
|
|
|
|
offset = phdr->p_offset;
|
|
if (((long)offset & PAGEOFFSET) ==
|
|
((long)addr & PAGEOFFSET) &&
|
|
(!(vp->v_flag & VNOMAP)))
|
|
page = 1;
|
|
else
|
|
page = 0;
|
|
|
|
if (error = execmap(vp, addr, phdr->p_filesz,
|
|
zfodsz, phdr->p_offset, prot, page))
|
|
goto bad;
|
|
|
|
if (base != NULL && addr >= *base)
|
|
*base = addr + phdr->p_memsz;
|
|
|
|
*execsz += btoc(phdr->p_memsz);
|
|
break;
|
|
|
|
case PT_INTERP:
|
|
if (ptload)
|
|
goto bad;
|
|
*dyphdr = phdr;
|
|
break;
|
|
|
|
case PT_SHLIB:
|
|
*stphdr = phdr;
|
|
break;
|
|
|
|
case PT_PHDR:
|
|
if (ptload)
|
|
goto bad;
|
|
*uphdr = phdr;
|
|
break;
|
|
|
|
case PT_NULL:
|
|
case PT_DYNAMIC:
|
|
case PT_NOTE:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
phdr = (Elf32_Phdr *)((caddr_t)phdr + hsize);
|
|
}
|
|
return (0);
|
|
bad:
|
|
if (error == 0)
|
|
error = ENOEXEC;
|
|
return (error);
|
|
}
|
|
|
|
#define WRT(vp, base, count, offset, rlimit, credp) \
|
|
vn_rdwr(UIO_WRITE, vp, (caddr_t)base, count, offset, UIO_SYSSPACE, \
|
|
0, rlimit, credp, (int *)NULL)
|
|
typedef struct {
|
|
Elf32_Nhdr Nhdr;
|
|
char name[8];
|
|
} Elf32_Note;
|
|
|
|
static int
|
|
elfnote(
|
|
vnode_t *vp,
|
|
off_t *offsetp,
|
|
int type,
|
|
int descsz,
|
|
caddr_t desc,
|
|
rlim_t rlimit,
|
|
struct cred *credp)
|
|
{
|
|
Elf32_Note note;
|
|
int error;
|
|
|
|
bzero((caddr_t)¬e, sizeof (note));
|
|
bcopy("CORE", note.name, 4);
|
|
note.Nhdr.n_type = type;
|
|
note.Nhdr.n_namesz = 5; /* ABI says this is strlen(note.name)+1 */
|
|
note.Nhdr.n_descsz = roundup(descsz, sizeof (Elf32_Word));
|
|
if (error = WRT(vp, ¬e, sizeof (note), *offsetp, rlimit, credp))
|
|
return (error);
|
|
*offsetp += sizeof (note);
|
|
if (error = WRT(vp, desc, note.Nhdr.n_descsz, *offsetp, rlimit, credp))
|
|
return (error);
|
|
*offsetp += note.Nhdr.n_descsz;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
elfcore(vnode_t *vp, proc_t *pp, struct cred *credp, rlim_t rlimit, int sig)
|
|
{
|
|
u_long hdrsz;
|
|
off_t offset, poffset;
|
|
int error, i, nhdrs;
|
|
u_int nlwp;
|
|
struct seg *seg;
|
|
struct as *as = pp->p_as;
|
|
kthread_t *t;
|
|
klwp_t *lwp = ttolwp(curthread);
|
|
struct user *up = PTOU(ttoproc(curthread));
|
|
int xregsize = 0; /* used for NT_PRXREG */
|
|
caddr_t xregs = (caddr_t)NULL; /* used for NT_PRXREG */
|
|
struct bigwad {
|
|
Elf32_Ehdr ehdr;
|
|
prpsinfo_t psinfo;
|
|
prstatus_t prstat;
|
|
prfpregset_t fpregs;
|
|
} *bigwad;
|
|
prpsinfo_t *psp;
|
|
Elf32_Ehdr *ehdr;
|
|
Elf32_Phdr *v;
|
|
|
|
/*
|
|
* Make sure we have everything we need (registers, etc.).
|
|
* All other lwps have already stopped and are in an orderly state.
|
|
*/
|
|
ASSERT(pp == ttoproc(curthread));
|
|
prstop(lwp, 0, 0);
|
|
|
|
AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
|
|
nhdrs = (prnsegs(as) + 1);
|
|
AS_LOCK_EXIT(as, &as->a_lock);
|
|
hdrsz = nhdrs * sizeof (Elf32_Phdr);
|
|
|
|
bigwad = kmem_zalloc(sizeof (struct bigwad) + hdrsz, KM_SLEEP);
|
|
|
|
ehdr = &bigwad->ehdr;
|
|
v = (Elf32_Phdr *)((char *)bigwad + sizeof (struct bigwad));
|
|
|
|
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] = ELFCLASS32;
|
|
ehdr->e_type = ET_CORE;
|
|
elfheadset(&ehdr->e_ident[EI_DATA], &ehdr->e_machine, &ehdr->e_flags);
|
|
ehdr->e_version = EV_CURRENT;
|
|
ehdr->e_phoff = sizeof (Elf32_Ehdr);
|
|
ehdr->e_ehsize = sizeof (Elf32_Ehdr);
|
|
ehdr->e_phentsize = sizeof (Elf32_Phdr);
|
|
ehdr->e_phnum = (unsigned short)nhdrs;
|
|
if (error = WRT(vp, ehdr, sizeof (Elf32_Ehdr), 0, rlimit, credp))
|
|
goto done;
|
|
|
|
offset = sizeof (Elf32_Ehdr);
|
|
poffset = sizeof (Elf32_Ehdr) + hdrsz;
|
|
|
|
nlwp = pp->p_lwpcnt + pp->p_zombcnt;
|
|
|
|
v[0].p_type = PT_NOTE;
|
|
v[0].p_flags = PF_R;
|
|
v[0].p_offset = poffset;
|
|
v[0].p_filesz = (sizeof (Elf32_Note) * (3 + nlwp))
|
|
+ roundup(sizeof (prpsinfo_t), sizeof (Elf32_Word))
|
|
+ nlwp * roundup(sizeof (prstatus_t), sizeof (Elf32_Word))
|
|
+ roundup(strlen(platform) + 1, sizeof (Elf32_Word))
|
|
+ roundup(sizeof (up->u_auxv), sizeof (Elf32_Word));
|
|
if (prhasfp())
|
|
v[0].p_filesz += nlwp * sizeof (Elf32_Note)
|
|
+ nlwp*roundup(sizeof (prfpregset_t), sizeof (Elf32_Word));
|
|
xregsize = prgetprxregsize();
|
|
if (xregsize && prhasx()) {
|
|
xregs = kmem_zalloc(xregsize, KM_SLEEP);
|
|
v[0].p_filesz += nlwp * sizeof (Elf32_Note)
|
|
+ nlwp * roundup(xregsize, sizeof (Elf32_Word));
|
|
}
|
|
poffset += v[0].p_filesz;
|
|
|
|
AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
|
|
for (i = 1, seg = AS_SEGP(as, as->a_segs); i < nhdrs && seg != NULL;
|
|
seg = AS_SEGP(as, seg->s_next)) {
|
|
caddr_t naddr;
|
|
caddr_t saddr = seg->s_base;
|
|
caddr_t eaddr = seg->s_base + seg->s_size;
|
|
|
|
do {
|
|
u_int prot, size;
|
|
prot = as_getprot(as, &saddr, &naddr);
|
|
if ((size = naddr - saddr) == 0)
|
|
continue;
|
|
v[i].p_type = PT_LOAD;
|
|
v[i].p_vaddr = (Elf32_Word)saddr;
|
|
v[i].p_memsz = size;
|
|
if (prot & PROT_WRITE)
|
|
v[i].p_flags |= PF_W;
|
|
if (prot & PROT_READ)
|
|
v[i].p_flags |= PF_R;
|
|
if (prot & PROT_EXEC)
|
|
v[i].p_flags |= PF_X;
|
|
if ((prot & PROT_READ) &&
|
|
(prot & (PROT_WRITE|PROT_EXEC)) != PROT_EXEC &&
|
|
SEGOP_GETTYPE(seg, saddr) != MAP_SHARED) {
|
|
v[i].p_offset = poffset;
|
|
v[i].p_filesz = size;
|
|
poffset += size;
|
|
}
|
|
i++;
|
|
} while ((saddr = naddr) < eaddr);
|
|
}
|
|
AS_LOCK_EXIT(as, &as->a_lock);
|
|
|
|
error = WRT(vp, v, hdrsz, offset, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
offset += hdrsz;
|
|
|
|
/*
|
|
* The order of the elfnote entries should be same here
|
|
* and in the gcore(1) command. Synchronization is
|
|
* needed between the kernel and gcore(1).
|
|
*/
|
|
|
|
mutex_enter(&pp->p_lock);
|
|
psp = &bigwad->psinfo;
|
|
prgetpsinfo(pp, psp, NULL);
|
|
/*
|
|
* prgetpsinfo() does not give us the process size.
|
|
* We have to do this ourself because we have to grab
|
|
* the address space lock and drop p_lock to do it.
|
|
*/
|
|
if (psp->pr_state == SZOMB || (pp->p_flag & SSYS) || as == &kas) {
|
|
mutex_exit(&pp->p_lock);
|
|
psp->pr_size = 0;
|
|
psp->pr_rssize = 0;
|
|
psp->pr_pctmem = 0;
|
|
} else {
|
|
AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
|
|
mutex_exit(&pp->p_lock);
|
|
psp->pr_size = btoc(rm_assize(as));
|
|
psp->pr_rssize = rm_asrss(as);
|
|
psp->pr_pctmem = rm_pctmemory(as);
|
|
AS_LOCK_EXIT(as, &as->a_lock);
|
|
}
|
|
psp->pr_bysize = ctob(psp->pr_size);
|
|
psp->pr_byrssize = ctob(psp->pr_rssize);
|
|
|
|
error = elfnote(vp, &offset, NT_PRPSINFO, sizeof (bigwad->psinfo),
|
|
(caddr_t)&bigwad->psinfo, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
|
|
error = elfnote(vp, &offset, NT_PLATFORM, strlen(platform) + 1,
|
|
platform, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
|
|
error = elfnote(vp, &offset, NT_AUXV, sizeof (up->u_auxv),
|
|
(caddr_t)up->u_auxv, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
|
|
t = curthread;
|
|
nlwp = pp->p_lwpcnt;
|
|
do {
|
|
ASSERT(nlwp != 0);
|
|
nlwp--;
|
|
|
|
mutex_enter(&pp->p_lock);
|
|
if (t == curthread && lwp->lwp_cursig == 0) {
|
|
/*
|
|
* Restore current signal information
|
|
* in order to get a correct prstatus.
|
|
*/
|
|
lwp->lwp_cursig = (u_char)sig;
|
|
t->t_whystop = PR_FAULTED; /* filthy */
|
|
prgetstatus(t, &bigwad->prstat);
|
|
bigwad->prstat.pr_why = 0;
|
|
t->t_whystop = 0;
|
|
lwp->lwp_cursig = 0;
|
|
} else {
|
|
prgetstatus(t, &bigwad->prstat);
|
|
}
|
|
mutex_exit(&pp->p_lock);
|
|
error = elfnote(vp, &offset, NT_PRSTATUS,
|
|
sizeof (bigwad->prstat), (caddr_t)&bigwad->prstat,
|
|
rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
|
|
if (prhasfp()) {
|
|
prgetprfpregs(ttolwp(t), &bigwad->fpregs);
|
|
error = elfnote(vp, &offset, NT_PRFPREG,
|
|
sizeof (bigwad->fpregs), (caddr_t)&bigwad->fpregs,
|
|
rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
}
|
|
if (xregsize && prhasx()) {
|
|
prgetprxregs(ttolwp(t), xregs);
|
|
error = elfnote(vp, &offset, NT_PRXREG,
|
|
xregsize, xregs, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
}
|
|
} while ((t = t->t_forw) != curthread);
|
|
ASSERT(nlwp == 0);
|
|
|
|
/* dump out zombied LWPs */
|
|
if ((nlwp = pp->p_zombcnt) != NULL) {
|
|
t = pp->p_zomblist;
|
|
while (nlwp-- > 0) {
|
|
mutex_enter(&pp->p_lock);
|
|
prgetstatus(t, &bigwad->prstat);
|
|
mutex_exit(&pp->p_lock);
|
|
error = elfnote(vp, &offset, NT_PRSTATUS,
|
|
sizeof (bigwad->prstat), (caddr_t)&bigwad->prstat,
|
|
rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
if (prhasfp()) {
|
|
prgetprfpregs(ttolwp(t), &bigwad->fpregs);
|
|
error = elfnote(vp, &offset, NT_PRFPREG,
|
|
sizeof (bigwad->fpregs),
|
|
(caddr_t)&bigwad->fpregs,
|
|
rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
}
|
|
if (xregsize && prhasx()) {
|
|
prgetprxregs(ttolwp(t), xregs);
|
|
error = elfnote(vp, &offset, NT_PRXREG,
|
|
xregsize, xregs, rlimit, credp);
|
|
if (error)
|
|
goto done;
|
|
}
|
|
t = t->t_forw;
|
|
}
|
|
ASSERT(t == pp->p_zomblist);
|
|
}
|
|
|
|
for (i = 1; !error && i < nhdrs; i++) {
|
|
if (v[i].p_filesz == 0)
|
|
continue;
|
|
error = core_seg(pp, vp, v[i].p_offset, (caddr_t)v[i].p_vaddr,
|
|
v[i].p_filesz, rlimit, credp);
|
|
}
|
|
|
|
done:
|
|
kmem_free(bigwad, sizeof (struct bigwad) + hdrsz);
|
|
if (xregs)
|
|
kmem_free(xregs, xregsize);
|
|
return (error);
|
|
}
|
|
|
|
static struct execsw esw = {
|
|
&elfmagic,
|
|
elfexec,
|
|
elfcore
|
|
};
|
|
|
|
static struct modlexec modlexec = {
|
|
&mod_execops, "exec module for elf", &esw
|
|
};
|
|
|
|
static struct modlinkage modlinkage = {
|
|
MODREV_1, (void *)&modlexec, NULL
|
|
};
|
|
|
|
int
|
|
_init(void)
|
|
{
|
|
return (mod_install(&modlinkage));
|
|
}
|
|
|
|
int
|
|
_fini(void)
|
|
{
|
|
return (mod_remove(&modlinkage));
|
|
}
|
|
|
|
int
|
|
_info(struct modinfo *modinfop)
|
|
{
|
|
return (mod_info(&modlinkage, modinfop));
|
|
}
|