summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/exec
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/uts/common/exec
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/uts/common/exec')
-rw-r--r--usr/src/uts/common/exec/aout/aout.c350
-rw-r--r--usr/src/uts/common/exec/elf/elf.c1812
-rw-r--r--usr/src/uts/common/exec/elf/elf_impl.h131
-rw-r--r--usr/src/uts/common/exec/elf/elf_notes.c418
-rw-r--r--usr/src/uts/common/exec/elf/old_notes.c240
-rw-r--r--usr/src/uts/common/exec/intp/intp.c230
-rw-r--r--usr/src/uts/common/exec/java/java.c205
7 files changed, 3386 insertions, 0 deletions
diff --git a/usr/src/uts/common/exec/aout/aout.c b/usr/src/uts/common/exec/aout/aout.c
new file mode 100644
index 0000000000..dae94a9560
--- /dev/null
+++ b/usr/src/uts/common/exec/aout/aout.c
@@ -0,0 +1,350 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fpu/fpusystm.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/debug.h>
+#include <sys/exec.h>
+#include <sys/exechdr.h>
+#include <sys/auxv.h>
+#include <sys/core.h>
+#include <sys/vmparam.h>
+#include <sys/archsystm.h>
+#include <sys/fs/swapnode.h>
+#include <sys/modctl.h>
+#include <vm/anon.h>
+#include <vm/as.h>
+#include <vm/seg.h>
+
+static int aoutexec(vnode_t *vp, execa_t *uap, uarg_t *args,
+ intpdata_t *idatap, int level, long *execsz, int setid,
+ caddr_t exec_file, cred_t *cred);
+static int get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz,
+ int *isdyn);
+static int aoutcore(vnode_t *vp, proc_t *pp, cred_t *credp,
+ rlim64_t rlimit, int sig, core_content_t content);
+#ifdef _LP64
+extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
+ long *, int, caddr_t, cred_t *);
+extern int elf32core(vnode_t *, proc_t *, cred_t *, rlim64_t, int,
+ core_content_t);
+#else /* _LP64 */
+extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
+ long *, int, caddr_t, cred_t *);
+extern int elfcore(vnode_t *, proc_t *, cred_t *, rlim64_t, int,
+ core_content_t);
+#endif /* _LP64 */
+
+char _depends_on[] = "exec/elfexec";
+
+static struct execsw nesw = {
+ aout_nmagicstr,
+ 2,
+ 2,
+ aoutexec,
+ aoutcore
+};
+
+static struct execsw zesw = {
+ aout_zmagicstr,
+ 2,
+ 2,
+ aoutexec,
+ aoutcore
+};
+
+static struct execsw oesw = {
+ aout_omagicstr,
+ 2,
+ 2,
+ aoutexec,
+ aoutcore
+};
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modlexec nexec = {
+ &mod_execops, "exec for NMAGIC", &nesw
+};
+
+static struct modlexec zexec = {
+ &mod_execops, "exec for ZMAGIC", &zesw
+};
+
+static struct modlexec oexec = {
+ &mod_execops, "exec for OMAGIC", &oesw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, &nexec, &zexec, &oexec, 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));
+}
+
+
+/*ARGSUSED*/
+static int
+aoutexec(vnode_t *vp, struct execa *uap, struct uarg *args,
+ struct intpdata *idatap, int level, long *execsz, int setid,
+ caddr_t exec_file, cred_t *cred)
+{
+ int error;
+ struct exdata edp, edpout;
+ struct execenv exenv;
+ proc_t *pp = ttoproc(curthread);
+ struct vnode *nvp;
+ int pagetext, pagedata;
+ int dataprot = PROT_ALL;
+ int textprot = PROT_ALL & ~PROT_WRITE;
+ int isdyn;
+
+ args->to_model = DATAMODEL_ILP32;
+ *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1);
+
+ /*
+ * Read in and validate the file header.
+ */
+ if (error = get_aout_head(&vp, &edp, execsz, &isdyn))
+ return (error);
+
+ if (error = chkaout(&edp))
+ return (error);
+
+ /*
+ * Take a quick look to see if it looks like we will have
+ * enough swap space for the program to get started. This
+ * is not a guarantee that we will succeed, but it is definitely
+ * better than finding this out after we are committed to the
+ * new memory image. Maybe what is needed is a way to "prereserve"
+ * swap space for some segment mappings here.
+ *
+ * But with shared libraries the process can make it through
+ * the exec only to have ld.so fail to get the program going
+ * because its mmap's will not be able to succeed if the system
+ * is running low on swap space. In fact this is a far more
+ * common failure mode, but we cannot do much about this here
+ * other than add some slop to our anonymous memory resources
+ * requirements estimate based on some guess since we cannot know
+ * what else the program will really need to get to a useful state.
+ *
+ * XXX - The stack size (clrnd(SSIZE + btopr(nargc))) should also
+ * be used when checking for swap space. This requires some work
+ * since nargc is actually determined in exec_args() which is done
+ * after this check and hence we punt for now.
+ *
+ * nargc = SA(nc + (na + 4) * NBPW) + sizeof (struct rwindow);
+ */
+ if (CURRENT_TOTAL_AVAILABLE_SWAP < btopr(edp.ux_dsize) + btopr(SSIZE))
+ return (ENOMEM);
+
+ /*
+ * Load the trap 0 interpreter.
+ */
+ if (error = lookupname("/usr/4lib/sbcp", UIO_SYSSPACE, FOLLOW,
+ NULLVPP, &nvp)) {
+ goto done;
+ }
+#ifdef _LP64
+ if (error = elf32exec(nvp, uap, args, idatap, level, execsz,
+ setid, exec_file, cred))
+#else /* _LP64 */
+ if (error = elfexec(nvp, uap, args, idatap, level, execsz,
+ setid, exec_file, cred))
+#endif /* _LP64 */
+ {
+ VN_RELE(nvp);
+ return (error);
+ }
+ VN_RELE(nvp);
+
+ /*
+ * Determine the a.out's characteristics.
+ */
+ getexinfo(&edp, &edpout, &pagetext, &pagedata);
+
+ /*
+ * Load the a.out's text and data.
+ */
+ if (error = execmap(edp.vp, edp.ux_txtorg, edp.ux_tsize,
+ (size_t)0, edp.ux_toffset, textprot, pagetext, 0))
+ goto done;
+ if (error = execmap(edp.vp, edp.ux_datorg, edp.ux_dsize,
+ edp.ux_bsize, edp.ux_doffset, dataprot, pagedata, 0))
+ goto done;
+
+ exenv.ex_brkbase = (caddr_t)edp.ux_datorg;
+ exenv.ex_brksize = edp.ux_dsize + edp.ux_bsize;
+ exenv.ex_magic = edp.ux_mag;
+ exenv.ex_vp = edp.vp;
+ setexecenv(&exenv);
+
+done:
+ if (error != 0)
+ psignal(pp, SIGKILL);
+ else {
+ /*
+ * Ensure that the max fds do not exceed 256 (this is
+ * applicable to 4.x binaries, which is why we only
+ * do it on a.out files).
+ */
+ struct rlimit64 fdno_rlim;
+ rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1);
+
+ mutex_enter(&curproc->p_lock);
+ (void) rctl_rlimit_get(rctlproc_legacy[RLIMIT_NOFILE], curproc,
+ &fdno_rlim);
+ if (fdno_rlim.rlim_cur > 256) {
+ fdno_rlim.rlim_cur = fdno_rlim.rlim_max = 256;
+ (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE],
+ curproc, &fdno_rlim, gp,
+ rctlproc_flags[RLIMIT_NOFILE],
+ rctlproc_signals[RLIMIT_NOFILE], CRED());
+ } else if (fdno_rlim.rlim_max > 256) {
+ fdno_rlim.rlim_max = 256;
+ (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE],
+ curproc, &fdno_rlim, gp,
+ rctlproc_flags[RLIMIT_NOFILE],
+ rctlproc_signals[RLIMIT_NOFILE], CRED());
+ }
+ mutex_exit(&curproc->p_lock);
+
+ rctl_prealloc_destroy(gp);
+ }
+
+ return (error);
+}
+
+/*
+ * Read in and validate the file header.
+ */
+static int
+get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, int *isdyn)
+{
+ struct vnode *vp = *vpp;
+ struct exec filhdr;
+ int error;
+ ssize_t resid;
+ rlim64_t limit;
+ rlim64_t roundlimit;
+
+ if (error = vn_rdwr(UIO_READ, vp, (caddr_t)&filhdr,
+ (ssize_t)sizeof (filhdr), (offset_t)0, UIO_SYSSPACE, 0,
+ (rlim64_t)0, CRED(), &resid))
+ return (error);
+
+ if (resid != 0)
+ return (ENOEXEC);
+
+ switch (filhdr.a_magic) {
+ case OMAGIC:
+ filhdr.a_data += filhdr.a_text;
+ filhdr.a_text = 0;
+ break;
+ case ZMAGIC:
+ case NMAGIC:
+ break;
+ default:
+ return (ENOEXEC);
+ }
+
+ /*
+ * Check total memory requirements (in pages) for a new process
+ * against the available memory or upper limit of memory allowed.
+ *
+ * For the 64-bit kernel, the limit can be set large enough so that
+ * rounding it up to a page can overflow, so we check for btopr()
+ * overflowing here by comparing it with the unrounded limit in pages.
+ */
+ *execsz += btopr(filhdr.a_text + filhdr.a_data);
+ limit = btop(curproc->p_vmem_ctl);
+ roundlimit = btopr(curproc->p_vmem_ctl);
+ if ((roundlimit > limit && *execsz > roundlimit) ||
+ (roundlimit < limit && *execsz > limit)) {
+ mutex_enter(&curproc->p_lock);
+ (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM],
+ curproc->p_rctls, curproc, RCA_SAFE);
+ mutex_exit(&curproc->p_lock);
+ return (ENOMEM);
+ }
+
+ edp->ux_mach = filhdr.a_machtype;
+ edp->ux_tsize = filhdr.a_text;
+ edp->ux_dsize = filhdr.a_data;
+ edp->ux_bsize = filhdr.a_bss;
+ edp->ux_mag = filhdr.a_magic;
+ edp->ux_toffset = gettfile(&filhdr);
+ edp->ux_doffset = getdfile(&filhdr);
+ edp->ux_txtorg = gettmem(&filhdr);
+ edp->ux_datorg = getdmem(&filhdr);
+ edp->ux_entloc = (caddr_t)filhdr.a_entry;
+ edp->vp = vp;
+ *isdyn = filhdr.a_dynamic;
+
+ return (0);
+}
+
+static int
+aoutcore(vnode_t *vp, proc_t *pp, struct cred *credp, rlim64_t rlimit, int sig,
+ core_content_t content)
+{
+#ifdef _LP64
+ return (elf32core(vp, pp, credp, rlimit, sig, content));
+#else
+ return (elfcore(vp, pp, credp, rlimit, sig, content));
+#endif
+}
diff --git a/usr/src/uts/common/exec/elf/elf.c b/usr/src/uts/common/exec/elf/elf.c
new file mode 100644
index 0000000000..5d55bed432
--- /dev/null
+++ b/usr/src/uts/common/exec/elf/elf.c
@@ -0,0 +1,1812 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#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/auxv.h>
+#include <sys/exec.h>
+#include <sys/prsystm.h>
+#include <vm/as.h>
+#include <vm/rm.h>
+#include <vm/seg.h>
+#include <vm/seg_vn.h>
+#include <sys/modctl.h>
+#include <sys/systeminfo.h>
+#include <sys/vmparam.h>
+#include <sys/machelf.h>
+#include <sys/shm_impl.h>
+#include <sys/archsystm.h>
+#include <sys/fasttrap.h>
+#include "elf_impl.h"
+
+extern int at_flags;
+
+#define ORIGIN_STR "ORIGIN"
+#define ORIGIN_STR_SIZE 6
+
+static int getelfhead(vnode_t *, cred_t *, Ehdr *);
+static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *);
+static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *,
+ caddr_t *, ssize_t *);
+static size_t elfsize(Ehdr *, caddr_t, uintptr_t *);
+static int mapelfexec(vnode_t *, Ehdr *, caddr_t,
+ Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
+ caddr_t *, caddr_t *, intptr_t *, size_t, long *, size_t *);
+
+typedef enum {
+ STR_CTF,
+ STR_SYMTAB,
+ STR_DYNSYM,
+ STR_STRTAB,
+ STR_DYNSTR,
+ STR_SHSTRTAB,
+ STR_NUM
+} shstrtype_t;
+
+static const char *shstrtab_data[] = {
+ ".SUNW_ctf",
+ ".symtab",
+ ".dynsym",
+ ".strtab",
+ ".dynstr",
+ ".shstrtab"
+};
+
+typedef struct shstrtab {
+ int sst_ndx[STR_NUM];
+ int sst_cur;
+} shstrtab_t;
+
+static void
+shstrtab_init(shstrtab_t *s)
+{
+ bzero(&s->sst_ndx, sizeof (s->sst_ndx));
+ s->sst_cur = 1;
+}
+
+static int
+shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
+{
+ int ret;
+
+ if ((ret = s->sst_ndx[type]) != 0)
+ return (ret);
+
+ ret = s->sst_ndx[type] = s->sst_cur;
+ s->sst_cur += strlen(shstrtab_data[type]) + 1;
+
+ return (ret);
+}
+
+static size_t
+shstrtab_size(const shstrtab_t *s)
+{
+ return (s->sst_cur);
+}
+
+static void
+shstrtab_dump(const shstrtab_t *s, char *buf)
+{
+ int i, ndx;
+
+ *buf = '\0';
+ for (i = 0; i < STR_NUM; i++) {
+ if ((ndx = s->sst_ndx[i]) != 0)
+ (void) strcpy(buf + ndx, shstrtab_data[i]);
+ }
+}
+
+static int
+dtrace_safe_phdr(Phdr *phdrp, struct uarg *args, uintptr_t base)
+{
+ ASSERT(phdrp->p_type == PT_SUNWDTRACE);
+
+ /*
+ * See the comment in fasttrap.h for information on how to safely
+ * update this program header.
+ */
+ if (phdrp->p_memsz < PT_SUNWDTRACE_SIZE ||
+ (phdrp->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
+ return (-1);
+
+ args->thrptr = phdrp->p_vaddr + base;
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
+ int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred)
+{
+ caddr_t phdrbase = NULL;
+ caddr_t bssbase = 0;
+ caddr_t brkbase = 0;
+ size_t brksize = 0;
+ ssize_t dlnsize;
+ aux_entry_t *aux;
+ int error;
+ ssize_t resid;
+ int fd = -1;
+ intptr_t voffset;
+ Phdr *dyphdr = NULL;
+ Phdr *stphdr = NULL;
+ Phdr *uphdr = NULL;
+ Phdr *junk = NULL;
+ size_t len;
+ ssize_t phdrsize;
+ int postfixsize = 0;
+ int i, hsize;
+ Phdr *phdrp;
+ Phdr *dataphdrp = NULL;
+ Phdr *dtrphdr;
+ int hasu = 0;
+ int hasauxv = 0;
+ int hasdy = 0;
+
+ struct proc *p = ttoproc(curthread);
+ struct user *up = PTOU(p);
+ struct bigwad {
+ Ehdr ehdr;
+ aux_entry_t elfargs[__KERN_NAUXV_IMPL];
+ char dl_name[MAXPATHLEN];
+ char pathbuf[MAXPATHLEN];
+ struct vattr vattr;
+ struct execenv exenv;
+ } *bigwad; /* kmem_alloc this behemoth so we don't blow stack */
+ Ehdr *ehdrp;
+ char *dlnp;
+ char *pathbufp;
+ rlim64_t limit;
+ rlim64_t roundlimit;
+
+ ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64);
+
+ bigwad = kmem_alloc(sizeof (struct bigwad), KM_SLEEP);
+ ehdrp = &bigwad->ehdr;
+ dlnp = bigwad->dl_name;
+ pathbufp = bigwad->pathbuf;
+
+ /*
+ * Obtain ELF and program header information.
+ */
+ if ((error = getelfhead(vp, CRED(), ehdrp)) != 0 ||
+ (error = getelfphdr(vp, CRED(), ehdrp, &phdrbase, &phdrsize)) != 0)
+ goto out;
+
+ /*
+ * Put data model that we're exec-ing to into the args passed to
+ * exec_args(), so it will know what it is copying to on new stack.
+ * Now that we know whether we are exec-ing a 32-bit or 64-bit
+ * executable, we can set execsz with the appropriate NCARGS.
+ */
+#ifdef _LP64
+ if (ehdrp->e_ident[EI_CLASS] == ELFCLASS32) {
+ args->to_model = DATAMODEL_ILP32;
+ *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1);
+ } else {
+ args->to_model = DATAMODEL_LP64;
+ args->stk_prot &= ~PROT_EXEC;
+#if defined(__i386) || defined(__amd64)
+ args->dat_prot &= ~PROT_EXEC;
+#endif
+ *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS64-1);
+ }
+#else /* _LP64 */
+ args->to_model = DATAMODEL_ILP32;
+ *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS-1);
+#endif /* _LP64 */
+
+ /*
+ * Determine aux size now so that stack can be built
+ * in one shot (except actual copyout of aux image),
+ * determine any non-default stack protections,
+ * and still have this code be machine independent.
+ */
+ hsize = ehdrp->e_phentsize;
+ phdrp = (Phdr *)phdrbase;
+ for (i = ehdrp->e_phnum; i > 0; i--) {
+ switch (phdrp->p_type) {
+ case PT_INTERP:
+ hasauxv = hasdy = 1;
+ break;
+ case PT_PHDR:
+ hasu = 1;
+ break;
+ case PT_SUNWSTACK:
+ args->stk_prot = PROT_USER;
+ if (phdrp->p_flags & PF_R)
+ args->stk_prot |= PROT_READ;
+ if (phdrp->p_flags & PF_W)
+ args->stk_prot |= PROT_WRITE;
+ if (phdrp->p_flags & PF_X)
+ args->stk_prot |= PROT_EXEC;
+ break;
+ case PT_LOAD:
+ dataphdrp = phdrp;
+ break;
+ }
+ phdrp = (Phdr *)((caddr_t)phdrp + hsize);
+ }
+
+ if (ehdrp->e_type != ET_EXEC) {
+ dataphdrp = NULL;
+ hasauxv = 1;
+ }
+
+ /* Copy BSS permissions to args->dat_prot */
+ if (dataphdrp != NULL) {
+ args->dat_prot = PROT_USER;
+ if (dataphdrp->p_flags & PF_R)
+ args->dat_prot |= PROT_READ;
+ if (dataphdrp->p_flags & PF_W)
+ args->dat_prot |= PROT_WRITE;
+ if (dataphdrp->p_flags & PF_X)
+ args->dat_prot |= PROT_EXEC;
+ }
+
+ /*
+ * If a auxvector will be required - reserve the space for
+ * it now. This may be increased by exec_args if there are
+ * ISA-specific types (included in __KERN_NAUXV_IMPL).
+ */
+ if (hasauxv) {
+ /*
+ * If a AUX vector is being built - the base AUX
+ * entries are:
+ *
+ * AT_BASE
+ * AT_FLAGS
+ * AT_PAGESZ
+ * AT_SUN_LDSECURE
+ * AT_SUN_HWCAP
+ * AT_SUN_PLATFORM
+ * AT_SUN_EXECNAME
+ * AT_NULL
+ *
+ * total == 8
+ */
+ if (hasdy && hasu) {
+ /*
+ * Has PT_INTERP & PT_PHDR - the auxvectors that
+ * will be built are:
+ *
+ * AT_PHDR
+ * AT_PHENT
+ * AT_PHNUM
+ * AT_ENTRY
+ * AT_LDDATA
+ *
+ * total = 5
+ */
+ args->auxsize = (8 + 5) * sizeof (aux_entry_t);
+ } else if (hasdy) {
+ /*
+ * Has PT_INTERP but no PT_PHDR
+ *
+ * AT_EXECFD
+ * AT_LDDATA
+ *
+ * total = 2
+ */
+ args->auxsize = (8 + 2) * sizeof (aux_entry_t);
+ } else {
+ args->auxsize = 8 * sizeof (aux_entry_t);
+ }
+ } else
+ args->auxsize = 0;
+
+ aux = bigwad->elfargs;
+ /*
+ * Move args to the user's stack.
+ */
+ if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) {
+ if (error == -1) {
+ error = ENOEXEC;
+ goto bad;
+ }
+ goto out;
+ }
+
+ /*
+ * If this is an ET_DYN executable (shared object),
+ * determine its memory size so that mapelfexec() can load it.
+ */
+ if (ehdrp->e_type == ET_DYN)
+ len = elfsize(ehdrp, phdrbase, NULL);
+ else
+ len = 0;
+
+ dtrphdr = NULL;
+
+ if ((error = mapelfexec(vp, ehdrp, phdrbase, &uphdr, &dyphdr, &stphdr,
+ &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, len, execsz,
+ &brksize)) != 0)
+ goto bad;
+
+ if (uphdr != NULL && dyphdr == NULL)
+ goto bad;
+
+ if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
+ uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
+ goto bad;
+ }
+
+ if (dyphdr != NULL) {
+ size_t len;
+ uintptr_t lddata;
+ char *p;
+ struct vnode *nvp;
+
+ 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,
+ (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
+ CRED(), &resid)) != 0) {
+ uprintf("%s: Cannot obtain interpreter pathname\n",
+ exec_file);
+ goto bad;
+ }
+
+ if (resid != 0 || dlnp[dlnsize - 1] != '\0')
+ goto bad;
+
+ /*
+ * Search for '$ORIGIN' token in interpreter path.
+ * If found, expand it.
+ */
+ for (p = dlnp; p = strchr(p, '$'); ) {
+ uint_t len, curlen;
+ char *_ptr;
+
+ if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE))
+ continue;
+
+ curlen = 0;
+ len = p - dlnp - 1;
+ if (len) {
+ bcopy(dlnp, pathbufp, len);
+ curlen += len;
+ }
+ if (_ptr = strrchr(args->pathname, '/')) {
+ len = _ptr - args->pathname;
+ if ((curlen + len) > MAXPATHLEN)
+ break;
+
+ bcopy(args->pathname, &pathbufp[curlen], len);
+ curlen += len;
+ } else {
+ /*
+ * executable is a basename found in the
+ * current directory. So - just substitue
+ * '.' for ORIGIN.
+ */
+ pathbufp[curlen] = '.';
+ curlen++;
+ }
+ p += ORIGIN_STR_SIZE;
+ len = strlen(p);
+
+ if ((curlen + len) > MAXPATHLEN)
+ break;
+ bcopy(p, &pathbufp[curlen], len);
+ curlen += len;
+ pathbufp[curlen++] = '\0';
+ bcopy(pathbufp, dlnp, curlen);
+ }
+
+ /*
+ * /usr/lib/ld.so.1 is known to be a symlink to /lib/ld.so.1
+ * (and /usr/lib/64/ld.so.1 is a symlink to /lib/64/ld.so.1).
+ * Just in case /usr is not mounted, change it now.
+ */
+ if (strcmp(dlnp, USR_LIB_RTLD) == 0)
+ dlnp += 4;
+ error = lookupname(dlnp, UIO_SYSSPACE, FOLLOW, NULLVPP, &nvp);
+ if (error && dlnp != bigwad->dl_name) {
+ /* new kernel, old user-level */
+ error = lookupname(dlnp -= 4, UIO_SYSSPACE, FOLLOW,
+ NULLVPP, &nvp);
+ }
+ if (error) {
+ 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;
+ bigwad->exenv.ex_bssbase = (caddr_t)PAGESIZE;
+ } else {
+ bigwad->exenv.ex_bssbase = bssbase;
+ bigwad->exenv.ex_brkbase = brkbase;
+ }
+ bigwad->exenv.ex_brksize = brksize;
+ bigwad->exenv.ex_magic = elfmagic;
+ bigwad->exenv.ex_vp = vp;
+ setexecenv(&bigwad->exenv);
+
+ ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset)
+ ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize)
+ ADDAUX(aux, AT_PHNUM, ehdrp->e_phnum)
+ ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset)
+ } else {
+ if ((error = execopen(&vp, &fd)) != 0) {
+ VN_RELE(nvp);
+ goto bad;
+ }
+
+ ADDAUX(aux, AT_EXECFD, fd)
+ }
+
+ 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, CRED(), ehdrp)) != 0 ||
+ (error = getelfphdr(nvp, CRED(), 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".
+ */
+ if ((len = elfsize(ehdrp, phdrbase, &lddata)) == 0) {
+ VN_RELE(nvp);
+ uprintf("%s: Nothing to load in %s\n", exec_file, dlnp);
+ goto bad;
+ }
+
+ dtrphdr = NULL;
+
+ error = mapelfexec(nvp, ehdrp, phdrbase, &junk, &junk, &junk,
+ &dtrphdr, NULL, NULL, NULL, &voffset, len, execsz, NULL);
+ if (error || junk != NULL) {
+ VN_RELE(nvp);
+ uprintf("%s: Cannot map %s\n", exec_file, dlnp);
+ goto bad;
+ }
+
+ /*
+ * We use the DTrace program header to initialize the
+ * architecture-specific user per-LWP location. The dtrace
+ * fasttrap provider requires ready access to per-LWP scratch
+ * space. We assume that there is only one such program header
+ * in the interpreter.
+ */
+ if (dtrphdr != NULL &&
+ dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
+ VN_RELE(nvp);
+ uprintf("%s: Bad DTrace phdr in %s\n", exec_file, dlnp);
+ goto bad;
+ }
+
+ VN_RELE(nvp);
+ ADDAUX(aux, AT_SUN_LDDATA, voffset + lddata)
+ }
+
+ if (hasauxv) {
+ int auxf = AF_SUN_HWCAPVERIFY;
+ /*
+ * Note: AT_SUN_PLATFORM was filled in via exec_args()
+ */
+ ADDAUX(aux, AT_BASE, voffset)
+ ADDAUX(aux, AT_FLAGS, at_flags)
+ ADDAUX(aux, AT_PAGESZ, PAGESIZE)
+ /*
+ * Linker flags. (security)
+ * p_flag not yet set at this time.
+ * We rely on gexec() to provide us with the information.
+ */
+ ADDAUX(aux, AT_SUN_AUXFLAGS,
+ setid ? AF_SUN_SETUGID | auxf : auxf);
+ /*
+ * Hardware capability flag word (performance hints)
+ * Used for choosing faster library routines.
+ * (Potentially different between 32-bit and 64-bit ABIs)
+ */
+#if defined(_LP64)
+ if (args->to_model == DATAMODEL_NATIVE)
+ ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
+ else
+ ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
+#else
+ ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
+#endif
+ ADDAUX(aux, AT_NULL, 0)
+ postfixsize = (char *)aux - (char *)bigwad->elfargs;
+ ASSERT(postfixsize == args->auxsize);
+ ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t));
+ }
+
+ /*
+ * For the 64-bit kernel, the limit is big enough that rounding it up
+ * to a page can overflow the 64-bit limit, so we check for btopr()
+ * overflowing here by comparing it with the unrounded limit in pages.
+ * If it hasn't overflowed, compare the exec size with the rounded up
+ * limit in pages. Otherwise, just compare with the unrounded limit.
+ */
+ limit = btop(p->p_vmem_ctl);
+ roundlimit = btopr(p->p_vmem_ctl);
+ if ((roundlimit > limit && *execsz > roundlimit) ||
+ (roundlimit < limit && *execsz > limit)) {
+ mutex_enter(&p->p_lock);
+ (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], p->p_rctls, p,
+ RCA_SAFE);
+ mutex_exit(&p->p_lock);
+ error = ENOMEM;
+ goto bad;
+ }
+
+ bzero(up->u_auxv, sizeof (up->u_auxv));
+ if (postfixsize) {
+ int num_auxv;
+
+ /*
+ * Copy the aux vector to the user stack.
+ */
+ error = execpoststack(args, bigwad->elfargs, postfixsize);
+ if (error)
+ goto bad;
+
+ /*
+ * Copy auxv to the process's user structure for use by /proc.
+ */
+ num_auxv = postfixsize / sizeof (aux_entry_t);
+ ASSERT(num_auxv <= sizeof (up->u_auxv) / sizeof (auxv_t));
+ aux = bigwad->elfargs;
+ for (i = 0; i < num_auxv; i++) {
+ up->u_auxv[i].a_type = aux[i].a_type;
+ up->u_auxv[i].a_un.a_val = (aux_val_t)aux[i].a_un.a_val;
+ }
+ }
+
+ /*
+ * Pass back the starting address so we can set the program counter.
+ */
+ args->entry = (uintptr_t)(ehdrp->e_entry + voffset);
+
+ if (!uphdr) {
+ if (ehdrp->e_type == ET_DYN) {
+ /*
+ * If we are executing a shared library which doesn't
+ * have a interpreter (probably ld.so.1) then
+ * we don't set the brkbase now. Instead we
+ * delay it's setting until the first call
+ * via grow.c::brk(). This permits ld.so.1 to
+ * initialize brkbase to the tail of the executable it
+ * loads (which is where it needs to be).
+ */
+ bigwad->exenv.ex_brkbase = (caddr_t)0;
+ bigwad->exenv.ex_bssbase = (caddr_t)0;
+ bigwad->exenv.ex_brksize = 0;
+ } else {
+ bigwad->exenv.ex_brkbase = brkbase;
+ bigwad->exenv.ex_bssbase = bssbase;
+ bigwad->exenv.ex_brksize = brksize;
+ }
+ 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(p, SIGKILL);
+
+ if (error == 0)
+ error = ENOEXEC;
+out:
+ if (phdrbase != NULL)
+ kmem_free(phdrbase, phdrsize);
+ kmem_free(bigwad, sizeof (struct bigwad));
+ return (error);
+}
+
+/*
+ * Compute the memory size requirement for the ELF file.
+ */
+static size_t
+elfsize(Ehdr *ehdrp, caddr_t phdrbase, uintptr_t *lddata)
+{
+ size_t len;
+ Phdr *phdrp = (Phdr *)phdrbase;
+ int hsize = ehdrp->e_phentsize;
+ int first = 1;
+ int dfirst = 1; /* first data segment */
+ uintptr_t loaddr = 0;
+ uintptr_t hiaddr = 0;
+ uintptr_t lo, hi;
+ int i;
+
+ for (i = ehdrp->e_phnum; i > 0; i--) {
+ if (phdrp->p_type == PT_LOAD) {
+ lo = phdrp->p_vaddr;
+ hi = lo + phdrp->p_memsz;
+ if (first) {
+ loaddr = lo;
+ hiaddr = hi;
+ first = 0;
+ } else {
+ if (loaddr > lo)
+ loaddr = lo;
+ if (hiaddr < hi)
+ hiaddr = hi;
+ }
+
+ /*
+ * save the address of the first data segment
+ * of a object - used for the AT_SUNW_LDDATA
+ * aux entry.
+ */
+ if ((lddata != NULL) && dfirst &&
+ (phdrp->p_flags & PF_W)) {
+ *lddata = lo;
+ dfirst = 0;
+ }
+ }
+ phdrp = (Phdr *)((caddr_t)phdrp + hsize);
+ }
+
+ len = hiaddr - (loaddr & PAGEMASK);
+ len = roundup(len, PAGESIZE);
+
+ return (len);
+}
+
+/*
+ * Read in the ELF header and program header table.
+ * SUSV3 requires:
+ * ENOEXEC File format is not recognized
+ * EINVAL Format recognized but execution not supported
+ */
+static int
+getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr)
+{
+ int error;
+ ssize_t resid;
+
+ /*
+ * 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 (Ehdr), (offset_t)0, UIO_SYSSPACE, 0,
+ (rlim64_t)0, credp, &resid)) != 0)
+ return (error);
+
+ /*
+ * Since a separate version is compiled for handling 32-bit and
+ * 64-bit ELF executables on a 64-bit kernel, the 64-bit version
+ * doesn't need to be able to deal with 32-bit ELF files.
+ */
+ if (resid != 0 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3)
+ return (ENOEXEC);
+ if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
+#if defined(_ILP32) || defined(_ELF32_COMPAT)
+ ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+#else
+ ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
+#endif
+ !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
+ ehdr->e_flags))
+ return (EINVAL);
+
+ return (0);
+}
+
+#ifdef _ELF32_COMPAT
+extern size_t elf_nphdr_max;
+#else
+size_t elf_nphdr_max = 1000;
+#endif
+
+static int
+getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
+ caddr_t *phbasep, ssize_t *phsizep)
+{
+ ssize_t resid, minsize;
+ int err;
+
+ /*
+ * Since we're going to be using e_phentsize to iterate down the
+ * array of program headers, it must be 8-byte aligned or else
+ * a we might cause a misaligned access. We use all members through
+ * p_flags on 32-bit ELF files and p_memsz on 64-bit ELF files so
+ * e_phentsize must be at least large enough to include those
+ * members.
+ */
+#if !defined(_LP64) || defined(_ELF32_COMPAT)
+ minsize = offsetof(Phdr, p_flags) + sizeof (((Phdr *)NULL)->p_flags);
+#else
+ minsize = offsetof(Phdr, p_memsz) + sizeof (((Phdr *)NULL)->p_memsz);
+#endif
+ if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3))
+ return (EINVAL);
+
+ *phsizep = ehdr->e_phnum * ehdr->e_phentsize;
+
+ if (*phsizep > sizeof (Phdr) * elf_nphdr_max) {
+ if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL)
+ return (ENOMEM);
+ } else {
+ *phbasep = kmem_alloc(*phsizep, KM_SLEEP);
+ }
+
+ if ((err = vn_rdwr(UIO_READ, vp, *phbasep, *phsizep,
+ (offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0,
+ credp, &resid)) != 0) {
+ kmem_free(*phbasep, *phsizep);
+ *phbasep = NULL;
+ return (err);
+ }
+
+ return (0);
+}
+
+#ifdef _ELF32_COMPAT
+extern size_t elf_nshdr_max;
+extern size_t elf_shstrtab_max;
+#else
+size_t elf_nshdr_max = 10000;
+size_t elf_shstrtab_max = 100 * 1024;
+#endif
+
+
+static int
+getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
+ caddr_t *shbasep, ssize_t *shsizep,
+ char **shstrbasep, ssize_t *shstrsizep)
+{
+ ssize_t resid, minsize;
+ int err;
+ Shdr *shdr;
+
+ /*
+ * Since we're going to be using e_shentsize to iterate down the
+ * array of section headers, it must be 8-byte aligned or else
+ * a we might cause a misaligned access. We use all members through
+ * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize
+ * must be at least large enough to include that member. The
+ * index of the string table section must be valid.
+ */
+ minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize);
+ if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) ||
+ ehdr->e_shstrndx >= ehdr->e_shnum)
+ return (EINVAL);
+
+ *shsizep = ehdr->e_shnum * ehdr->e_shentsize;
+
+ if (*shsizep > sizeof (Shdr) * elf_nshdr_max) {
+ if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL)
+ return (ENOMEM);
+ } else {
+ *shbasep = kmem_alloc(*shsizep, KM_SLEEP);
+ }
+
+ if ((err = vn_rdwr(UIO_READ, vp, *shbasep, *shsizep,
+ (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0,
+ credp, &resid)) != 0) {
+ kmem_free(*shbasep, *shsizep);
+ return (err);
+ }
+
+ /*
+ * Pull the section string table out of the vnode; fail if the size
+ * is zero.
+ */
+ shdr = (Shdr *)(*shbasep + ehdr->e_shstrndx * ehdr->e_shentsize);
+ if ((*shstrsizep = shdr->sh_size) == 0) {
+ kmem_free(*shbasep, *shsizep);
+ return (EINVAL);
+ }
+
+ if (*shstrsizep > elf_shstrtab_max) {
+ if ((*shstrbasep = kmem_alloc(*shstrsizep,
+ KM_NOSLEEP)) == NULL) {
+ kmem_free(*shbasep, *shsizep);
+ return (ENOMEM);
+ }
+ } else {
+ *shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP);
+ }
+
+ if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, *shstrsizep,
+ (offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
+ credp, &resid)) != 0) {
+ kmem_free(*shbasep, *shsizep);
+ kmem_free(*shstrbasep, *shstrsizep);
+ return (err);
+ }
+
+ /*
+ * Make sure the strtab is null-terminated to make sure we
+ * don't run off the end of the table.
+ */
+ (*shstrbasep)[*shstrsizep - 1] = '\0';
+
+ return (0);
+}
+
+static int
+mapelfexec(
+ vnode_t *vp,
+ Ehdr *ehdr,
+ caddr_t phdrbase,
+ Phdr **uphdr,
+ Phdr **dyphdr,
+ Phdr **stphdr,
+ Phdr **dtphdr,
+ Phdr *dataphdrp,
+ caddr_t *bssbase,
+ caddr_t *brkbase,
+ intptr_t *voffset,
+ size_t len,
+ long *execsz,
+ size_t *brksize)
+{
+ 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, (offset_t)0, 1, 0);
+ if (addr == NULL)
+ return (ENOMEM);
+ *voffset = (intptr_t)addr;
+ } else {
+ *voffset = 0;
+ }
+ phdr = (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)((uintptr_t)phdr->p_vaddr + *voffset);
+ zfodsz = (size_t)phdr->p_memsz - phdr->p_filesz;
+
+ offset = phdr->p_offset;
+ if (((uintptr_t)offset & PAGEOFFSET) ==
+ ((uintptr_t)addr & PAGEOFFSET) &&
+ (!(vp->v_flag & VNOMAP))) {
+ page = 1;
+ } else {
+ page = 0;
+ }
+
+ if (curproc->p_brkpageszc != 0 && phdr == dataphdrp) {
+ /*
+ * segvn only uses large pages for segments
+ * that have the requested large page size
+ * aligned base and size. To insure the part
+ * of bss that starts at heap large page size
+ * boundary gets mapped by large pages create
+ * 2 bss segvn segments which is accomplished
+ * by calling execmap twice. First execmap
+ * will create the bss segvn segment that is
+ * before the large page boundary and it will
+ * be mapped with base pages. If bss start is
+ * already large page aligned only 1 bss
+ * segment will be created. The second bss
+ * segment's size is large page size aligned
+ * so that segvn uses large pages for that
+ * segment and it also makes the heap that
+ * starts right after bss to start at large
+ * page boundary.
+ */
+ uint_t szc = curproc->p_brkpageszc;
+ size_t pgsz = page_get_pagesize(szc);
+ caddr_t zaddr = addr + phdr->p_filesz;
+ size_t zlen = P2NPHASE((uintptr_t)zaddr, pgsz);
+
+ ASSERT(pgsz > PAGESIZE);
+
+ if (error = execmap(vp, addr, phdr->p_filesz,
+ zlen, phdr->p_offset, prot, page, szc))
+ goto bad;
+ if (zfodsz > zlen) {
+ zfodsz -= zlen;
+ zaddr += zlen;
+ zlen = P2ROUNDUP(zfodsz, pgsz);
+ if (error = execmap(vp, zaddr, 0, zlen,
+ phdr->p_offset, prot, page, szc))
+ goto bad;
+ }
+ if (brksize != NULL)
+ *brksize = zlen - zfodsz;
+ } else {
+ if (error = execmap(vp, addr, phdr->p_filesz,
+ zfodsz, phdr->p_offset, prot, page, 0))
+ goto bad;
+ }
+
+ if (bssbase != NULL && addr >= *bssbase &&
+ phdr == dataphdrp) {
+ *bssbase = addr + phdr->p_filesz;
+ }
+ if (brkbase != NULL && addr >= *brkbase) {
+ *brkbase = addr + phdr->p_memsz;
+ }
+
+ *execsz += btopr(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;
+
+ case PT_SUNWDTRACE:
+ if (dtphdr != NULL)
+ *dtphdr = phdr;
+ break;
+
+ default:
+ break;
+ }
+ phdr = (Phdr *)((caddr_t)phdr + hsize);
+ }
+ return (0);
+bad:
+ if (error == 0)
+ error = EINVAL;
+ return (error);
+}
+
+int
+elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
+ rlim64_t rlimit, cred_t *credp)
+{
+ Note note;
+ int error;
+
+ bzero(&note, sizeof (note));
+ bcopy("CORE", note.name, 4);
+ note.nhdr.n_type = type;
+ /*
+ * The System V ABI states that n_namesz must be the length of the
+ * string that follows the Nhdr structure including the terminating
+ * null. The ABI also specifies that sufficient padding should be
+ * included so that the description that follows the name string
+ * begins on a 4- or 8-byte boundary for 32- and 64-bit binaries
+ * respectively. However, since this change was not made correctly
+ * at the time of the 64-bit port, both 32- and 64-bit binaries
+ * descriptions are only guaranteed to begin on a 4-byte boundary.
+ */
+ note.nhdr.n_namesz = 5;
+ note.nhdr.n_descsz = roundup(descsz, sizeof (Word));
+
+ if (error = core_write(vp, UIO_SYSSPACE, *offsetp, &note,
+ sizeof (note), rlimit, credp))
+ return (error);
+
+ *offsetp += sizeof (note);
+
+ if (error = core_write(vp, UIO_SYSSPACE, *offsetp, desc,
+ note.nhdr.n_descsz, rlimit, credp))
+ return (error);
+
+ *offsetp += note.nhdr.n_descsz;
+ return (0);
+}
+
+/*
+ * Copy the section data from one vnode to the section of another vnode.
+ */
+static void
+copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
+ void *buf, size_t size, cred_t *credp, rlim64_t rlimit)
+{
+ ssize_t resid;
+ size_t len, n = src->sh_size;
+ offset_t off = 0;
+
+ while (n != 0) {
+ len = MIN(size, n);
+ if (vn_rdwr(UIO_READ, src_vp, buf, len, src->sh_offset + off,
+ UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 ||
+ resid >= len ||
+ core_write(dst_vp, UIO_SYSSPACE, *doffset + off,
+ buf, len - resid, rlimit, credp) != 0) {
+ dst->sh_size = 0;
+ dst->sh_offset = 0;
+ return;
+ }
+
+ ASSERT(n >= len - resid);
+
+ n -= len - resid;
+ off += len - resid;
+ }
+
+ *doffset += src->sh_size;
+}
+
+#ifdef _ELF32_COMPAT
+extern size_t elf_datasz_max;
+#else
+size_t elf_datasz_max = 1 * 1024 * 1024;
+#endif
+
+/*
+ * This function processes mappings that correspond to load objects to
+ * examine their respective sections for elfcore(). It's called once with
+ * v set to NULL to count the number of sections that we're going to need
+ * and then again with v set to some allocated buffer that we fill in with
+ * all the section data.
+ */
+static int
+process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
+ Shdr *v, int nshdrs, rlim64_t rlimit, Off *doffsetp, int *nshdrsp)
+{
+ vnode_t *lastvp = NULL;
+ struct seg *seg;
+ int i, j;
+ void *data = NULL;
+ size_t datasz = 0;
+ shstrtab_t shstrtab;
+ struct as *as = p->p_as;
+ int error = 0;
+
+ if (v != NULL)
+ shstrtab_init(&shstrtab);
+
+ i = 1;
+ for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
+ uint_t prot;
+ vnode_t *mvp;
+ void *tmp = NULL;
+ caddr_t saddr = seg->s_base;
+ caddr_t naddr;
+ caddr_t eaddr;
+ size_t segsize;
+
+ Ehdr ehdr;
+ caddr_t shbase;
+ ssize_t shsize;
+ char *shstrbase;
+ ssize_t shstrsize;
+
+ Shdr *shdr;
+ const char *name;
+ size_t sz;
+ uintptr_t off;
+
+ int ctf_ndx = 0;
+ int symtab_ndx = 0;
+
+ /*
+ * Since we're just looking for text segments of load
+ * objects, we only care about the protection bits; we don't
+ * care about the actual size of the segment so we use the
+ * reserved size. If the segment's size is zero, there's
+ * something fishy going on so we ignore this segment.
+ */
+ if (seg->s_ops != &segvn_ops ||
+ SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
+ mvp == lastvp || mvp == NULL || mvp->v_type != VREG ||
+ (segsize = pr_getsegsize(seg, 1)) == 0)
+ continue;
+
+ eaddr = saddr + segsize;
+ prot = pr_getprot(seg, 1, &tmp, &saddr, &naddr, eaddr);
+ pr_getprot_done(&tmp);
+
+ /*
+ * Skip this segment unless the protection bits look like
+ * what we'd expect for a text segment.
+ */
+ if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
+ continue;
+
+ if (getelfhead(mvp, credp, &ehdr) != 0 ||
+ getelfshdr(mvp, credp, &ehdr, &shbase, &shsize,
+ &shstrbase, &shstrsize) != 0)
+ continue;
+
+ off = ehdr.e_shentsize;
+ for (j = 1; j < ehdr.e_shnum; j++, off += ehdr.e_shentsize) {
+ Shdr *symtab = NULL, *strtab;
+
+ shdr = (Shdr *)(shbase + off);
+
+ if (shdr->sh_name >= shstrsize)
+ continue;
+
+ name = shstrbase + shdr->sh_name;
+
+ if (strcmp(name, shstrtab_data[STR_CTF]) == 0) {
+ if ((content & CC_CONTENT_CTF) == 0 ||
+ ctf_ndx != 0)
+ continue;
+
+ if (shdr->sh_link > 0 &&
+ shdr->sh_link < ehdr.e_shnum) {
+ symtab = (Shdr *)(shbase +
+ shdr->sh_link * ehdr.e_shentsize);
+ }
+
+ if (v != NULL && i < nshdrs - 1) {
+ if (shdr->sh_size > datasz &&
+ shdr->sh_size <= elf_datasz_max) {
+ if (data != NULL)
+ kmem_free(data, datasz);
+
+ datasz = shdr->sh_size;
+ data = kmem_alloc(datasz,
+ KM_SLEEP);
+ }
+
+ v[i].sh_name = shstrtab_ndx(&shstrtab,
+ STR_CTF);
+ v[i].sh_addr = (Addr)(uintptr_t)saddr;
+ v[i].sh_type = SHT_PROGBITS;
+ v[i].sh_addralign = 4;
+ *doffsetp = roundup(*doffsetp,
+ v[i].sh_addralign);
+ v[i].sh_offset = *doffsetp;
+ v[i].sh_size = shdr->sh_size;
+ if (symtab == NULL) {
+ v[i].sh_link = 0;
+ } else if (symtab->sh_type ==
+ SHT_SYMTAB &&
+ symtab_ndx != 0) {
+ v[i].sh_link =
+ symtab_ndx;
+ } else {
+ v[i].sh_link = i + 1;
+ }
+
+ copy_scn(shdr, mvp, &v[i], vp,
+ doffsetp, data, datasz, credp,
+ rlimit);
+ }
+
+ ctf_ndx = i++;
+
+ /*
+ * We've already dumped the symtab.
+ */
+ if (symtab != NULL &&
+ symtab->sh_type == SHT_SYMTAB &&
+ symtab_ndx != 0)
+ continue;
+
+ } else if (strcmp(name,
+ shstrtab_data[STR_SYMTAB]) == 0) {
+ if ((content & CC_CONTENT_SYMTAB) == 0 ||
+ symtab != 0)
+ continue;
+
+ symtab = shdr;
+ }
+
+ if (symtab != NULL) {
+ if ((symtab->sh_type != SHT_DYNSYM &&
+ symtab->sh_type != SHT_SYMTAB) ||
+ symtab->sh_link == 0 ||
+ symtab->sh_link >= ehdr.e_shnum)
+ continue;
+
+ strtab = (Shdr *)(shbase +
+ symtab->sh_link * ehdr.e_shentsize);
+
+ if (strtab->sh_type != SHT_STRTAB)
+ continue;
+
+ if (v != NULL && i < nshdrs - 2) {
+ sz = MAX(symtab->sh_size,
+ strtab->sh_size);
+ if (sz > datasz &&
+ sz <= elf_datasz_max) {
+ if (data != NULL)
+ kmem_free(data, datasz);
+
+ datasz = sz;
+ data = kmem_alloc(datasz,
+ KM_SLEEP);
+ }
+
+ if (symtab->sh_type == SHT_DYNSYM) {
+ v[i].sh_name = shstrtab_ndx(
+ &shstrtab, STR_DYNSYM);
+ v[i + 1].sh_name = shstrtab_ndx(
+ &shstrtab, STR_DYNSTR);
+ } else {
+ v[i].sh_name = shstrtab_ndx(
+ &shstrtab, STR_SYMTAB);
+ v[i + 1].sh_name = shstrtab_ndx(
+ &shstrtab, STR_STRTAB);
+ }
+
+ v[i].sh_type = symtab->sh_type;
+ v[i].sh_addr = symtab->sh_addr;
+ if (ehdr.e_type == ET_DYN ||
+ v[i].sh_addr == 0)
+ v[i].sh_addr +=
+ (Addr)(uintptr_t)saddr;
+ v[i].sh_addralign =
+ symtab->sh_addralign;
+ *doffsetp = roundup(*doffsetp,
+ v[i].sh_addralign);
+ v[i].sh_offset = *doffsetp;
+ v[i].sh_size = symtab->sh_size;
+ v[i].sh_link = i + 1;
+ v[i].sh_entsize = symtab->sh_entsize;
+ v[i].sh_info = symtab->sh_info;
+
+ copy_scn(symtab, mvp, &v[i], vp,
+ doffsetp, data, datasz, credp,
+ rlimit);
+
+ v[i + 1].sh_type = SHT_STRTAB;
+ v[i + 1].sh_flags = SHF_STRINGS;
+ v[i + 1].sh_addr = symtab->sh_addr;
+ if (ehdr.e_type == ET_DYN ||
+ v[i + 1].sh_addr == 0)
+ v[i + 1].sh_addr +=
+ (Addr)(uintptr_t)saddr;
+ v[i + 1].sh_addralign =
+ strtab->sh_addralign;
+ *doffsetp = roundup(*doffsetp,
+ v[i + 1].sh_addralign);
+ v[i + 1].sh_offset = *doffsetp;
+ v[i + 1].sh_size = strtab->sh_size;
+
+ copy_scn(strtab, mvp, &v[i + 1], vp,
+ doffsetp, data, datasz, credp,
+ rlimit);
+ }
+
+ if (symtab->sh_type == SHT_SYMTAB)
+ symtab_ndx = i;
+ i += 2;
+ }
+ }
+
+ kmem_free(shstrbase, shstrsize);
+ kmem_free(shbase, shsize);
+
+ lastvp = mvp;
+ }
+
+ if (v == NULL) {
+ if (i == 1)
+ *nshdrsp = 0;
+ else
+ *nshdrsp = i + 1;
+ goto done;
+ }
+
+ if (i != nshdrs - 1) {
+ cmn_err(CE_WARN, "elfcore: core dump failed for "
+ "process %d; address space is changing", p->p_pid);
+ error = EIO;
+ goto done;
+ }
+
+ v[i].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
+ v[i].sh_size = shstrtab_size(&shstrtab);
+ v[i].sh_addralign = 1;
+ *doffsetp = roundup(*doffsetp, v[i].sh_addralign);
+ v[i].sh_offset = *doffsetp;
+ v[i].sh_flags = SHF_STRINGS;
+ v[i].sh_type = SHT_STRTAB;
+
+ if (v[i].sh_size > datasz) {
+ if (data != NULL)
+ kmem_free(data, datasz);
+
+ datasz = v[i].sh_size;
+ data = kmem_alloc(datasz,
+ KM_SLEEP);
+ }
+
+ shstrtab_dump(&shstrtab, data);
+
+ if ((error = core_write(vp, UIO_SYSSPACE, *doffsetp,
+ data, v[i].sh_size, rlimit, credp)) != 0)
+ goto done;
+
+ *doffsetp += v[i].sh_size;
+
+done:
+ if (data != NULL)
+ kmem_free(data, datasz);
+
+ return (error);
+}
+
+int
+elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
+ core_content_t content)
+{
+ offset_t poffset, soffset;
+ Off doffset;
+ int error, i, nphdrs, nshdrs;
+ int overflow = 0;
+ struct seg *seg;
+ struct as *as = p->p_as;
+ union {
+ Ehdr ehdr;
+ Phdr phdr[1];
+ Shdr shdr[1];
+ } *bigwad;
+ size_t bigsize;
+ size_t phdrsz, shdrsz;
+ Ehdr *ehdr;
+ Phdr *v;
+ caddr_t brkbase;
+ size_t brksize;
+ caddr_t stkbase;
+ size_t stksize;
+ int ntries = 0;
+
+top:
+ /*
+ * Make sure we have everything we need (registers, etc.).
+ * All other lwps have already stopped and are in an orderly state.
+ */
+ ASSERT(p == ttoproc(curthread));
+ prstop(0, 0);
+
+ AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
+ nphdrs = prnsegs(as, 0) + 2; /* two CORE note sections */
+
+ /*
+ * Count the number of section headers we're going to need.
+ */
+ nshdrs = 0;
+ if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
+ (void) process_scns(content, p, credp, NULL, NULL, NULL, 0,
+ NULL, &nshdrs);
+ }
+ AS_LOCK_EXIT(as, &as->a_lock);
+
+ phdrsz = nphdrs * sizeof (Phdr);
+ shdrsz = nshdrs * sizeof (Shdr);
+
+ bigsize = MAX(sizeof (*bigwad), MAX(phdrsz, shdrsz));
+ bigwad = kmem_alloc(bigsize, KM_SLEEP);
+
+ ehdr = &bigwad->ehdr;
+ bzero(ehdr, sizeof (*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] = ELFCLASS;
+ ehdr->e_type = ET_CORE;
+
+#if !defined(_LP64) || defined(_ELF32_COMPAT)
+
+#if defined(__sparc)
+ ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
+ ehdr->e_machine = EM_SPARC;
+#elif defined(__i386) || defined(__i386_COMPAT)
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_machine = EM_386;
+#else
+#error "no recognized machine type is defined"
+#endif
+
+#else /* !defined(_LP64) || defined(_ELF32_COMPAT) */
+
+#if defined(__sparc)
+ ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
+ ehdr->e_machine = EM_SPARCV9;
+#elif defined(__ia64)
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_machine = EM_IA_64;
+#elif defined(__amd64)
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_machine = EM_AMD64;
+#else
+#error "no recognized 64-bit machine type is defined"
+#endif
+
+#endif /* !defined(_LP64) || defined(_ELF32_COMPAT) */
+
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_phoff = sizeof (Ehdr);
+ ehdr->e_ehsize = sizeof (Ehdr);
+ ehdr->e_phentsize = sizeof (Phdr);
+ ehdr->e_phnum = (unsigned short)nphdrs;
+
+ if (nshdrs > 0) {
+ ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
+ ehdr->e_shentsize = sizeof (Shdr);
+ ehdr->e_shnum = (unsigned short)nshdrs;
+ ehdr->e_shoff = ehdr->e_phoff +
+ ehdr->e_phentsize * ehdr->e_phnum;
+ }
+
+ if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
+ sizeof (Ehdr), rlimit, credp))
+ goto done;
+
+ poffset = sizeof (Ehdr);
+ soffset = sizeof (Ehdr) + phdrsz;
+ doffset = sizeof (Ehdr) + phdrsz + shdrsz;
+
+ v = &bigwad->phdr[0];
+ bzero(v, phdrsz);
+
+ setup_old_note_header(&v[0], p);
+ v[0].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += v[0].p_filesz;
+
+ setup_note_header(&v[1], p);
+ v[1].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += v[1].p_filesz;
+
+ mutex_enter(&p->p_lock);
+
+ brkbase = p->p_brkbase;
+ brksize = p->p_brksize;
+
+ stkbase = p->p_usrstack - p->p_stksize;
+ stksize = p->p_stksize;
+
+ mutex_exit(&p->p_lock);
+
+ AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
+ i = 2;
+ for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
+ caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
+ caddr_t saddr, naddr;
+ void *tmp = NULL;
+ extern struct seg_ops segspt_shmops;
+
+ for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
+ uint_t prot;
+ size_t size;
+ int type;
+ vnode_t *mvp;
+
+ prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
+ prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
+ if ((size = (size_t)(naddr - saddr)) == 0)
+ continue;
+ if (i == nphdrs) {
+ overflow++;
+ continue;
+ }
+ v[i].p_type = PT_LOAD;
+ v[i].p_vaddr = (Addr)(uintptr_t)saddr;
+ v[i].p_memsz = size;
+ if (prot & PROT_READ)
+ v[i].p_flags |= PF_R;
+ if (prot & PROT_WRITE)
+ v[i].p_flags |= PF_W;
+ if (prot & PROT_EXEC)
+ v[i].p_flags |= PF_X;
+
+ /*
+ * Figure out which mappings to include in the core.
+ */
+ type = SEGOP_GETTYPE(seg, saddr);
+
+ if (saddr == stkbase && size == stksize) {
+ if (!(content & CC_CONTENT_STACK))
+ goto exclude;
+
+ } else if (saddr == brkbase && size == brksize) {
+ if (!(content & CC_CONTENT_HEAP))
+ goto exclude;
+
+ } else if (seg->s_ops == &segspt_shmops) {
+ if (type & MAP_NORESERVE) {
+ if (!(content & CC_CONTENT_DISM))
+ goto exclude;
+ } else {
+ if (!(content & CC_CONTENT_ISM))
+ goto exclude;
+ }
+
+ } else if (seg->s_ops != &segvn_ops) {
+ goto exclude;
+
+ } else if (type & MAP_SHARED) {
+ if (shmgetid(p, saddr) != SHMID_NONE) {
+ if (!(content & CC_CONTENT_SHM))
+ goto exclude;
+
+ } else if (SEGOP_GETVP(seg, seg->s_base,
+ &mvp) != 0 || mvp == NULL ||
+ mvp->v_type != VREG) {
+ if (!(content & CC_CONTENT_SHANON))
+ goto exclude;
+
+ } else {
+ if (!(content & CC_CONTENT_SHFILE))
+ goto exclude;
+ }
+
+ } else if (SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
+ mvp == NULL || mvp->v_type != VREG) {
+ if (!(content & CC_CONTENT_ANON))
+ goto exclude;
+
+ } else if (prot == (PROT_READ | PROT_EXEC)) {
+ if (!(content & CC_CONTENT_TEXT))
+ goto exclude;
+
+ } else if (prot == PROT_READ) {
+ if (!(content & CC_CONTENT_RODATA))
+ goto exclude;
+
+ } else {
+ if (!(content & CC_CONTENT_DATA))
+ goto exclude;
+ }
+
+ doffset = roundup(doffset, sizeof (Word));
+ v[i].p_offset = doffset;
+ v[i].p_filesz = size;
+ doffset += size;
+exclude:
+ i++;
+ }
+ ASSERT(tmp == NULL);
+ }
+ AS_LOCK_EXIT(as, &as->a_lock);
+
+ if (overflow || i != nphdrs) {
+ if (ntries++ == 0) {
+ kmem_free(bigwad, bigsize);
+ goto top;
+ }
+ cmn_err(CE_WARN, "elfcore: core dump failed for "
+ "process %d; address space is changing", p->p_pid);
+ error = EIO;
+ goto done;
+ }
+
+ if ((error = core_write(vp, UIO_SYSSPACE, poffset,
+ v, phdrsz, rlimit, credp)) != 0)
+ goto done;
+
+ if ((error = write_old_elfnotes(p, sig, vp, v[0].p_offset, rlimit,
+ credp)) != 0)
+ goto done;
+
+ if ((error = write_elfnotes(p, sig, vp, v[1].p_offset, rlimit,
+ credp, content)) != 0)
+ goto done;
+
+ for (i = 2; i < nphdrs; i++) {
+ if (v[i].p_filesz == 0)
+ continue;
+
+ /*
+ * If dumping out this segment fails, rather than failing
+ * the core dump entirely, we reset the size of the mapping
+ * to zero to indicate that the data is absent from the core
+ * file and or in the PF_SUNW_FAILURE flag to differentiate
+ * this from mappings that were excluded due to the core file
+ * content settings.
+ */
+ if ((error = core_seg(p, vp, v[i].p_offset,
+ (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz,
+ rlimit, credp)) != 0) {
+
+ /*
+ * Since the space reserved for the segment is now
+ * unused, we stash the errno in the first four
+ * bytes. This undocumented interface will let us
+ * understand the nature of the failure.
+ */
+ (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+ &error, sizeof (error), rlimit, credp);
+
+ v[i].p_filesz = 0;
+ v[i].p_flags |= PF_SUNW_FAILURE;
+ if ((error = core_write(vp, UIO_SYSSPACE,
+ poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]),
+ rlimit, credp)) != 0)
+ goto done;
+ }
+ }
+
+ if (nshdrs > 0) {
+ bzero(&bigwad->shdr[0], shdrsz);
+
+ AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
+ if ((error = process_scns(content, p, credp, vp,
+ &bigwad->shdr[0], nshdrs, rlimit, &doffset, NULL)) != 0) {
+ AS_LOCK_EXIT(as, &as->a_lock);
+ goto done;
+ }
+ AS_LOCK_EXIT(as, &as->a_lock);
+
+
+ if ((error = core_write(vp, UIO_SYSSPACE, soffset,
+ &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
+ goto done;
+ }
+
+done:
+ kmem_free(bigwad, bigsize);
+ return (error);
+}
+
+#ifndef _ELF32_COMPAT
+
+static struct execsw esw = {
+#ifdef _LP64
+ elf64magicstr,
+#else /* _LP64 */
+ elf32magicstr,
+#endif /* _LP64 */
+ 0,
+ 5,
+ elfexec,
+ elfcore
+};
+
+static struct modlexec modlexec = {
+ &mod_execops, "exec module for elf", &esw
+};
+
+#ifdef _LP64
+extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args,
+ intpdata_t *idatap, int level, long *execsz,
+ int setid, caddr_t exec_file, cred_t *cred);
+extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp,
+ rlim64_t rlimit, int sig, core_content_t content);
+
+static struct execsw esw32 = {
+ elf32magicstr,
+ 0,
+ 5,
+ elf32exec,
+ elf32core
+};
+
+static struct modlexec modlexec32 = {
+ &mod_execops, "32-bit exec module for elf", &esw32
+};
+#endif /* _LP64 */
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *)&modlexec,
+#ifdef _LP64
+ (void *)&modlexec32,
+#endif /* _LP64 */
+ 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));
+}
+
+#endif /* !_ELF32_COMPAT */
diff --git a/usr/src/uts/common/exec/elf/elf_impl.h b/usr/src/uts/common/exec/elf/elf_impl.h
new file mode 100644
index 0000000000..52094e3794
--- /dev/null
+++ b/usr/src/uts/common/exec/elf/elf_impl.h
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ELF_ELF_IMPL_H
+#define _ELF_ELF_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_LP64) || defined(_ELF32_COMPAT)
+
+/*
+ * Definitions for ELF32, native 32-bit or 32-bit compatibility mode.
+ */
+#define ELFCLASS ELFCLASS32
+typedef unsigned int aux_val_t;
+typedef auxv32_t aux_entry_t;
+
+#define USR_LIB_RTLD "/usr/lib/ld.so.1"
+
+#else /* !_LP64 || _ELF32_COMPAT */
+
+/*
+ * Definitions for native 64-bit ELF
+ */
+#define ELFCLASS ELFCLASS64
+typedef unsigned long aux_val_t;
+typedef auxv_t aux_entry_t;
+
+/* put defines for 64-bit architectures here */
+#if defined(__sparcv9)
+#define USR_LIB_RTLD "/usr/lib/sparcv9/ld.so.1"
+#endif
+
+#if defined(__amd64)
+#define USR_LIB_RTLD "/usr/lib/amd64/ld.so.1"
+#endif
+
+#endif /* !_LP64 || _ELF32_COMPAT */
+
+/*
+ * Start of an ELF Note.
+ */
+typedef struct {
+ Nhdr nhdr;
+ char name[8];
+} Note;
+
+#ifdef _ELF32_COMPAT
+/*
+ * These are defined only for the 32-bit compatibility
+ * compilation mode of the 64-bit kernel.
+ */
+#define elfexec elf32exec
+#define elfnote elf32note
+#define elfcore elf32core
+#define setup_note_header setup_note_header32
+#define write_elfnotes write_elfnotes32
+#define setup_old_note_header setup_old_note_header32
+#define write_old_elfnotes write_old_elfnotes32
+
+#if defined(__sparc)
+#define gwindows_t gwindows32_t
+#define rwindow rwindow32
+#endif
+
+#define psinfo_t psinfo32_t
+#define pstatus_t pstatus32_t
+#define lwpsinfo_t lwpsinfo32_t
+#define lwpstatus_t lwpstatus32_t
+
+#define prgetpsinfo prgetpsinfo32
+#define prgetstatus prgetstatus32
+#define prgetlwpsinfo prgetlwpsinfo32
+#define prgetlwpstatus prgetlwpstatus32
+#define prgetwindows prgetwindows32
+
+#define prpsinfo_t prpsinfo32_t
+#define prstatus_t prstatus32_t
+#if defined(prfpregset_t)
+#undef prfpregset_t
+#endif
+#define prfpregset_t prfpregset32_t
+
+#define oprgetstatus oprgetstatus32
+#define oprgetpsinfo oprgetpsinfo32
+#define prgetprfpregs prgetprfpregs32
+
+#endif /* _ELF32_COMPAT */
+
+extern int elfnote(vnode_t *, offset_t *, int, int, void *, rlim64_t, cred_t *);
+extern void setup_old_note_header(Phdr *, proc_t *);
+extern void setup_note_header(Phdr *, proc_t *);
+
+extern int write_old_elfnotes(proc_t *, int, vnode_t *, offset_t,
+ rlim64_t, cred_t *);
+
+extern int write_elfnotes(proc_t *, int, vnode_t *, offset_t,
+ rlim64_t, cred_t *, core_content_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ELF_ELF_IMPL_H */
diff --git a/usr/src/uts/common/exec/elf/elf_notes.c b/usr/src/uts/common/exec/elf/elf_notes.c
new file mode 100644
index 0000000000..8649e64d48
--- /dev/null
+++ b/usr/src/uts/common/exec/elf/elf_notes.c
@@ -0,0 +1,418 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#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/priv.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>
+#include <sys/regset.h>
+#include <sys/auxv.h>
+#include <sys/exec.h>
+#include <sys/prsystm.h>
+#include <sys/utsname.h>
+#include <sys/zone.h>
+#include <vm/as.h>
+#include <vm/rm.h>
+#include <sys/modctl.h>
+#include <sys/systeminfo.h>
+#include <sys/machelf.h>
+#include "elf_impl.h"
+#if defined(__i386) || defined(__i386_COMPAT)
+#include <sys/sysi86.h>
+#endif
+
+void
+setup_note_header(Phdr *v, proc_t *p)
+{
+ int nlwp = p->p_lwpcnt;
+ int nzomb = p->p_zombcnt;
+ size_t size;
+ prcred_t *pcrp;
+
+ v[0].p_type = PT_NOTE;
+ v[0].p_flags = PF_R;
+ v[0].p_filesz = (sizeof (Note) * (9 + 2 * nlwp + nzomb))
+ + roundup(sizeof (psinfo_t), sizeof (Word))
+ + roundup(sizeof (pstatus_t), sizeof (Word))
+ + roundup(prgetprivsize(), sizeof (Word))
+ + roundup(priv_get_implinfo_size(), sizeof (Word))
+ + roundup(strlen(platform) + 1, sizeof (Word))
+ + roundup(strlen(p->p_zone->zone_name) + 1, sizeof (Word))
+ + roundup(__KERN_NAUXV_IMPL * sizeof (aux_entry_t), sizeof (Word))
+ + roundup(sizeof (utsname), sizeof (Word))
+ + roundup(sizeof (core_content_t), sizeof (Word))
+ + (nlwp + nzomb) * roundup(sizeof (lwpsinfo_t), sizeof (Word))
+ + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word));
+
+ size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1);
+ pcrp = kmem_alloc(size, KM_SLEEP);
+ prgetcred(p, pcrp);
+ if (pcrp->pr_ngroups != 0) {
+ v[0].p_filesz += sizeof (Note) + roundup(sizeof (prcred_t) +
+ sizeof (gid_t) * (pcrp->pr_ngroups - 1), sizeof (Word));
+ } else {
+ v[0].p_filesz += sizeof (Note) +
+ roundup(sizeof (prcred_t), sizeof (Word));
+ }
+ kmem_free(pcrp, size);
+
+#if defined(__i386) || defined(__i386_COMPAT)
+ mutex_enter(&p->p_ldtlock);
+ size = prnldt(p) * sizeof (struct ssd);
+ mutex_exit(&p->p_ldtlock);
+ if (size != 0)
+ v[0].p_filesz += sizeof (Note) + roundup(size, sizeof (Word));
+#endif /* __i386 || __i386_COMPAT */
+
+ if ((size = prhasx(p)? prgetprxregsize(p) : 0) != 0)
+ v[0].p_filesz += nlwp * sizeof (Note)
+ + nlwp * roundup(size, sizeof (Word));
+
+#if defined(__sparc)
+ /*
+ * Figure out the number and sizes of register windows.
+ */
+ {
+ kthread_t *t = p->p_tlist;
+ do {
+ if ((size = prnwindows(ttolwp(t))) != 0) {
+ size = sizeof (gwindows_t) -
+ (SPARC_MAXREGWINDOW - size) *
+ sizeof (struct rwindow);
+ v[0].p_filesz += sizeof (Note) +
+ roundup(size, sizeof (Word));
+ }
+ } while ((t = t->t_forw) != p->p_tlist);
+ }
+ /*
+ * Space for the Ancillary State Registers.
+ */
+ if (p->p_model == DATAMODEL_LP64)
+ v[0].p_filesz += nlwp * sizeof (Note)
+ + nlwp * roundup(sizeof (asrset_t), sizeof (Word));
+#endif /* __sparc */
+}
+
+int
+write_elfnotes(proc_t *p, int sig, vnode_t *vp, offset_t offset,
+ rlim64_t rlimit, cred_t *credp, core_content_t content)
+{
+ union {
+ psinfo_t psinfo;
+ pstatus_t pstatus;
+ lwpsinfo_t lwpsinfo;
+ lwpstatus_t lwpstatus;
+#if defined(__sparc)
+ gwindows_t gwindows;
+ asrset_t asrset;
+#endif /* __sparc */
+ char xregs[1];
+ aux_entry_t auxv[__KERN_NAUXV_IMPL];
+ prcred_t pcred;
+ prpriv_t ppriv;
+ priv_impl_info_t prinfo;
+ struct utsname uts;
+ } *bigwad;
+
+ size_t xregsize = prhasx(p)? prgetprxregsize(p) : 0;
+ size_t crsize = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1);
+ size_t psize = prgetprivsize();
+ size_t bigsize = MAX(psize, MAX(sizeof (*bigwad),
+ MAX(xregsize, crsize)));
+
+ priv_impl_info_t *prii;
+
+ lwpdir_t *ldp;
+ lwpent_t *lep;
+ kthread_t *t;
+ klwp_t *lwp;
+ user_t *up;
+ int i;
+ int nlwp;
+ int nzomb;
+ int error;
+ uchar_t oldsig;
+#if defined(__i386) || defined(__i386_COMPAT)
+ struct ssd *ssd;
+ size_t ssdsize;
+#endif /* __i386 || __i386_COMPAT */
+
+ bigsize = MAX(bigsize, priv_get_implinfo_size());
+
+ bigwad = kmem_alloc(bigsize, KM_SLEEP);
+
+ /*
+ * 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).
+ */
+
+ /*
+ * Get the psinfo, and set the wait status to indicate that a core was
+ * dumped. We have to forge this since p->p_wcode is not set yet.
+ */
+ mutex_enter(&p->p_lock);
+ prgetpsinfo(p, &bigwad->psinfo);
+ mutex_exit(&p->p_lock);
+ bigwad->psinfo.pr_wstat = wstat(CLD_DUMPED, sig);
+
+ error = elfnote(vp, &offset, NT_PSINFO, sizeof (bigwad->psinfo),
+ (caddr_t)&bigwad->psinfo, rlimit, credp);
+ if (error)
+ goto done;
+
+ /*
+ * Modify t_whystop and lwp_cursig so it appears that the current LWP
+ * is stopped after faulting on the signal that caused the core dump.
+ * As a result, prgetstatus() will record that signal, the saved
+ * lwp_siginfo, and its signal handler in the core file status. We
+ * restore lwp_cursig in case a subsequent signal was received while
+ * dumping core.
+ */
+ mutex_enter(&p->p_lock);
+ lwp = ttolwp(curthread);
+
+ oldsig = lwp->lwp_cursig;
+ lwp->lwp_cursig = (uchar_t)sig;
+ curthread->t_whystop = PR_FAULTED;
+
+ prgetstatus(p, &bigwad->pstatus, p->p_zone);
+ bigwad->pstatus.pr_lwp.pr_why = 0;
+
+ curthread->t_whystop = 0;
+ lwp->lwp_cursig = oldsig;
+ mutex_exit(&p->p_lock);
+
+ error = elfnote(vp, &offset, NT_PSTATUS, sizeof (bigwad->pstatus),
+ (caddr_t)&bigwad->pstatus, rlimit, credp);
+ if (error)
+ goto done;
+
+ error = elfnote(vp, &offset, NT_PLATFORM, strlen(platform) + 1,
+ platform, rlimit, credp);
+ if (error)
+ goto done;
+
+ up = PTOU(p);
+ for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
+ bigwad->auxv[i].a_type = up->u_auxv[i].a_type;
+ bigwad->auxv[i].a_un.a_val = up->u_auxv[i].a_un.a_val;
+ }
+ error = elfnote(vp, &offset, NT_AUXV, sizeof (bigwad->auxv),
+ (caddr_t)bigwad->auxv, rlimit, credp);
+ if (error)
+ goto done;
+
+ bcopy(&utsname, &bigwad->uts, sizeof (struct utsname));
+ if (!INGLOBALZONE(p)) {
+ bcopy(p->p_zone->zone_nodename, &bigwad->uts.nodename,
+ _SYS_NMLN);
+ }
+ error = elfnote(vp, &offset, NT_UTSNAME, sizeof (struct utsname),
+ (caddr_t)&bigwad->uts, rlimit, credp);
+ if (error)
+ goto done;
+
+ prgetcred(p, &bigwad->pcred);
+
+ if (bigwad->pcred.pr_ngroups != 0) {
+ crsize = sizeof (prcred_t) +
+ sizeof (gid_t) * (bigwad->pcred.pr_ngroups - 1);
+ } else
+ crsize = sizeof (prcred_t);
+
+ error = elfnote(vp, &offset, NT_PRCRED, crsize,
+ (caddr_t)&bigwad->pcred, rlimit, credp);
+ if (error)
+ goto done;
+
+ error = elfnote(vp, &offset, NT_CONTENT, sizeof (core_content_t),
+ (caddr_t)&content, rlimit, credp);
+ if (error)
+ goto done;
+
+ prgetpriv(p, &bigwad->ppriv);
+
+ error = elfnote(vp, &offset, NT_PRPRIV, psize,
+ (caddr_t)&bigwad->ppriv, rlimit, credp);
+ if (error)
+ goto done;
+
+ prii = priv_hold_implinfo();
+ error = elfnote(vp, &offset, NT_PRPRIVINFO, priv_get_implinfo_size(),
+ (caddr_t)prii, rlimit, credp);
+ priv_release_implinfo();
+ if (error)
+ goto done;
+
+ /* zone can't go away as long as process exists */
+ error = elfnote(vp, &offset, NT_ZONENAME,
+ strlen(p->p_zone->zone_name) + 1, p->p_zone->zone_name,
+ rlimit, credp);
+ if (error)
+ goto done;
+
+#if defined(__i386) || defined(__i386_COMPAT)
+ mutex_enter(&p->p_ldtlock);
+ ssdsize = prnldt(p) * sizeof (struct ssd);
+ if (ssdsize != 0) {
+ ssd = kmem_alloc(ssdsize, KM_SLEEP);
+ prgetldt(p, ssd);
+ error = elfnote(vp, &offset, NT_LDT, ssdsize,
+ (caddr_t)ssd, rlimit, credp);
+ kmem_free(ssd, ssdsize);
+ }
+ mutex_exit(&p->p_ldtlock);
+ if (error)
+ goto done;
+#endif /* __i386 || defined(__i386_COMPAT) */
+
+ nlwp = p->p_lwpcnt;
+ nzomb = p->p_zombcnt;
+ /* for each entry in the lwp directory ... */
+ for (ldp = p->p_lwpdir; nlwp + nzomb != 0; ldp++) {
+
+ if ((lep = ldp->ld_entry) == NULL) /* empty slot */
+ continue;
+
+ if ((t = lep->le_thread) != NULL) { /* active lwp */
+ ASSERT(nlwp != 0);
+ nlwp--;
+ lwp = ttolwp(t);
+ mutex_enter(&p->p_lock);
+ prgetlwpsinfo(t, &bigwad->lwpsinfo);
+ mutex_exit(&p->p_lock);
+ } else { /* zombie lwp */
+ ASSERT(nzomb != 0);
+ nzomb--;
+ bzero(&bigwad->lwpsinfo, sizeof (bigwad->lwpsinfo));
+ bigwad->lwpsinfo.pr_lwpid = lep->le_lwpid;
+ bigwad->lwpsinfo.pr_state = SZOMB;
+ bigwad->lwpsinfo.pr_sname = 'Z';
+ bigwad->lwpsinfo.pr_start.tv_sec = lep->le_start;
+ }
+ error = elfnote(vp, &offset, NT_LWPSINFO,
+ sizeof (bigwad->lwpsinfo), (caddr_t)&bigwad->lwpsinfo,
+ rlimit, credp);
+ if (error)
+ goto done;
+ if (t == NULL) /* nothing more to do for a zombie */
+ continue;
+
+ mutex_enter(&p->p_lock);
+ if (t == curthread) {
+ /*
+ * Modify t_whystop and lwp_cursig so it appears that
+ * the current LWP is stopped after faulting on the
+ * signal that caused the core dump. As a result,
+ * prgetlwpstatus() will record that signal, the saved
+ * lwp_siginfo, and its signal handler in the core file
+ * status. We restore lwp_cursig in case a subsequent
+ * signal was received while dumping core.
+ */
+ oldsig = lwp->lwp_cursig;
+ lwp->lwp_cursig = (uchar_t)sig;
+ t->t_whystop = PR_FAULTED;
+
+ prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone);
+ bigwad->lwpstatus.pr_why = 0;
+
+ t->t_whystop = 0;
+ lwp->lwp_cursig = oldsig;
+ } else {
+ prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone);
+ }
+ mutex_exit(&p->p_lock);
+ error = elfnote(vp, &offset, NT_LWPSTATUS,
+ sizeof (bigwad->lwpstatus), (caddr_t)&bigwad->lwpstatus,
+ rlimit, credp);
+ if (error)
+ goto done;
+
+#if defined(__sparc)
+ /*
+ * Unspilled SPARC register windows.
+ */
+ {
+ size_t size = prnwindows(lwp);
+
+ if (size != 0) {
+ size = sizeof (gwindows_t) -
+ (SPARC_MAXREGWINDOW - size) *
+ sizeof (struct rwindow);
+ prgetwindows(lwp, &bigwad->gwindows);
+ error = elfnote(vp, &offset, NT_GWINDOWS,
+ size, (caddr_t)&bigwad->gwindows,
+ rlimit, credp);
+ if (error)
+ goto done;
+ }
+ }
+ /*
+ * Ancillary State Registers.
+ */
+ if (p->p_model == DATAMODEL_LP64) {
+ prgetasregs(lwp, bigwad->asrset);
+ error = elfnote(vp, &offset, NT_ASRS,
+ sizeof (asrset_t), (caddr_t)bigwad->asrset,
+ rlimit, credp);
+ if (error)
+ goto done;
+ }
+#endif /* __sparc */
+
+ if (xregsize) {
+ prgetprxregs(lwp, bigwad->xregs);
+ error = elfnote(vp, &offset, NT_PRXREG,
+ xregsize, bigwad->xregs, rlimit, credp);
+ if (error)
+ goto done;
+ }
+ }
+ ASSERT(nlwp == 0);
+
+done:
+ kmem_free(bigwad, bigsize);
+ return (error);
+}
diff --git a/usr/src/uts/common/exec/elf/old_notes.c b/usr/src/uts/common/exec/elf/old_notes.c
new file mode 100644
index 0000000000..16cf8a5302
--- /dev/null
+++ b/usr/src/uts/common/exec/elf/old_notes.c
@@ -0,0 +1,240 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#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/old_procfs.h>
+#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>
+#include <sys/machelf.h>
+#include <sys/zone.h>
+#include "elf_impl.h"
+
+extern void oprgetstatus(kthread_t *, prstatus_t *, zone_t *);
+extern void oprgetpsinfo(proc_t *, prpsinfo_t *, kthread_t *);
+
+void
+setup_old_note_header(Phdr *v, proc_t *p)
+{
+ int nlwp = p->p_lwpcnt;
+ size_t size;
+
+ v[0].p_type = PT_NOTE;
+ v[0].p_flags = PF_R;
+ v[0].p_filesz = (sizeof (Note) * (3 + nlwp))
+ + roundup(sizeof (prpsinfo_t), sizeof (Word))
+ + roundup(strlen(platform) + 1, sizeof (Word))
+ + roundup(__KERN_NAUXV_IMPL * sizeof (aux_entry_t),
+ sizeof (Word))
+ + nlwp * roundup(sizeof (prstatus_t), sizeof (Word));
+ if (prhasfp())
+ v[0].p_filesz += nlwp * sizeof (Note)
+ + nlwp*roundup(sizeof (prfpregset_t), sizeof (Word));
+ if ((size = prhasx(p)? prgetprxregsize(p) : 0) != 0)
+ v[0].p_filesz += nlwp * sizeof (Note)
+ + nlwp * roundup(size, sizeof (Word));
+
+#if defined(__sparc)
+ /*
+ * Figure out the number and sizes of register windows.
+ */
+ {
+ kthread_t *t = p->p_tlist;
+ do {
+ if ((size = prnwindows(ttolwp(t))) != 0) {
+ size = sizeof (gwindows_t) -
+ (SPARC_MAXREGWINDOW - size) *
+ sizeof (struct rwindow);
+ v[0].p_filesz += sizeof (Note) +
+ roundup(size, sizeof (Word));
+ }
+ } while ((t = t->t_forw) != p->p_tlist);
+ }
+#endif /* __sparc */
+}
+
+int
+write_old_elfnotes(proc_t *p, int sig, vnode_t *vp, offset_t offset,
+ rlim64_t rlimit, cred_t *credp)
+{
+ union {
+ prpsinfo_t psinfo;
+ prstatus_t prstat;
+ prfpregset_t fpregs;
+#if defined(__sparc)
+ gwindows_t gwindows;
+#endif /* __sparc */
+ char xregs[1];
+ aux_entry_t auxv[__KERN_NAUXV_IMPL];
+ } *bigwad;
+ int xregsize = prhasx(p)? prgetprxregsize(p) : 0;
+ size_t bigsize = MAX(sizeof (*bigwad), (size_t)xregsize);
+ kthread_t *t;
+ klwp_t *lwp;
+ user_t *up;
+ int i;
+ int nlwp;
+ int error;
+
+ bigwad = kmem_alloc(bigsize, KM_SLEEP);
+
+ /*
+ * The order of the elfnote entries should be same here and in
+ * the gcore(1) command. Synchronization is needed between the
+ * kernel and libproc's Pfgcore() function where the meat of
+ * the gcore(1) command lives.
+ */
+
+ mutex_enter(&p->p_lock);
+ oprgetpsinfo(p, &bigwad->psinfo, NULL);
+ mutex_exit(&p->p_lock);
+ 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;
+
+ up = PTOU(p);
+ for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
+ bigwad->auxv[i].a_type = up->u_auxv[i].a_type;
+ bigwad->auxv[i].a_un.a_val = up->u_auxv[i].a_un.a_val;
+ }
+ error = elfnote(vp, &offset, NT_AUXV, sizeof (bigwad->auxv),
+ (caddr_t)bigwad->auxv, rlimit, credp);
+ if (error)
+ goto done;
+
+ t = curthread;
+ nlwp = p->p_lwpcnt;
+ do {
+ ASSERT(nlwp != 0);
+ nlwp--;
+ lwp = ttolwp(t);
+
+ mutex_enter(&p->p_lock);
+ if (t == curthread) {
+ uchar_t oldsig;
+
+ /*
+ * Modify t_whystop and lwp_cursig so it appears that
+ * the current LWP is stopped after faulting on the
+ * signal that caused the core dump. As a result,
+ * oprgetstatus() will record that signal, the saved
+ * lwp_siginfo, and its signal handler in the core file
+ * status. We restore lwp_cursig in case a subsequent
+ * signal was received while dumping core.
+ */
+ oldsig = lwp->lwp_cursig;
+ lwp->lwp_cursig = (uchar_t)sig;
+ t->t_whystop = PR_FAULTED;
+
+ oprgetstatus(t, &bigwad->prstat, p->p_zone);
+ bigwad->prstat.pr_why = 0;
+
+ t->t_whystop = 0;
+ lwp->lwp_cursig = oldsig;
+
+ } else {
+ oprgetstatus(t, &bigwad->prstat, p->p_zone);
+ }
+ mutex_exit(&p->p_lock);
+ error = elfnote(vp, &offset, NT_PRSTATUS,
+ sizeof (bigwad->prstat), (caddr_t)&bigwad->prstat,
+ rlimit, credp);
+ if (error)
+ goto done;
+
+ if (prhasfp()) {
+ prgetprfpregs(lwp, &bigwad->fpregs);
+ error = elfnote(vp, &offset, NT_PRFPREG,
+ sizeof (bigwad->fpregs), (caddr_t)&bigwad->fpregs,
+ rlimit, credp);
+ if (error)
+ goto done;
+ }
+
+#if defined(__sparc)
+ /*
+ * Unspilled SPARC register windows.
+ */
+ {
+ size_t size = prnwindows(lwp);
+
+ if (size != 0) {
+ size = sizeof (gwindows_t) -
+ (SPARC_MAXREGWINDOW - size) *
+ sizeof (struct rwindow);
+ prgetwindows(lwp, &bigwad->gwindows);
+ error = elfnote(vp, &offset, NT_GWINDOWS,
+ size, (caddr_t)&bigwad->gwindows,
+ rlimit, credp);
+ if (error)
+ goto done;
+ }
+ }
+#endif /* __sparc */
+
+ if (xregsize) {
+ prgetprxregs(lwp, bigwad->xregs);
+ error = elfnote(vp, &offset, NT_PRXREG,
+ xregsize, bigwad->xregs, rlimit, credp);
+ if (error)
+ goto done;
+ }
+ } while ((t = t->t_forw) != curthread);
+ ASSERT(nlwp == 0);
+
+done:
+ kmem_free(bigwad, bigsize);
+ return (error);
+}
diff --git a/usr/src/uts/common/exec/intp/intp.c b/usr/src/uts/common/exec/intp/intp.c
new file mode 100644
index 0000000000..ec1a2a6dfd
--- /dev/null
+++ b/usr/src/uts/common/exec/intp/intp.c
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.6 */
+
+#include <sys/types.h>
+#include <sys/param.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/proc.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/pathname.h>
+#include <sys/disp.h>
+#include <sys/exec.h>
+#include <sys/kmem.h>
+
+/*
+ * This is the loadable module wrapper.
+ */
+#include <sys/modctl.h>
+
+extern int intpexec();
+
+static struct execsw esw = {
+ intpmagicstr,
+ 0,
+ 2,
+ intpexec,
+ NULL
+};
+
+/*
+ * Module linkage information for the kernel.
+ */
+extern struct mod_ops mod_execops;
+
+static struct modlexec modlexec = {
+ &mod_execops, "exec mod for interp", &esw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modlexec, NULL
+};
+
+int
+_init()
+{
+ return (mod_install(&modlinkage));
+}
+
+int
+_fini()
+{
+ return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/*
+ * Crack open a '#!' line.
+ */
+static int
+getintphead(struct vnode *vp, struct intpdata *idatap)
+{
+ int error;
+ char *cp, *linep = idatap->intp;
+ ssize_t resid;
+
+ /*
+ * Read the entire line and confirm that it starts with '#!'.
+ */
+ if (error = vn_rdwr(UIO_READ, vp, linep, INTPSZ, (offset_t)0,
+ UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
+ return (error);
+ if (resid > INTPSZ-2 || linep[0] != '#' || linep[1] != '!')
+ return (ENOEXEC);
+ /*
+ * Blank all white space and find the newline.
+ */
+ for (cp = &linep[2]; cp < &linep[INTPSZ] && *cp != '\n'; cp++)
+ if (*cp == '\t')
+ *cp = ' ';
+ if (cp >= &linep[INTPSZ])
+ return (ENOEXEC);
+ ASSERT(*cp == '\n');
+ *cp = '\0';
+
+ /*
+ * Locate the beginning and end of the interpreter name.
+ * In addition to the name, one additional argument may
+ * optionally be included here, to be prepended to the
+ * arguments provided on the command line. Thus, for
+ * example, you can say
+ *
+ * #! /usr/bin/awk -f
+ */
+ for (cp = &linep[2]; *cp == ' '; cp++)
+ ;
+ if (*cp == '\0')
+ return (ENOEXEC);
+ idatap->intp_name = cp;
+ while (*cp && *cp != ' ')
+ cp++;
+ if (*cp == '\0')
+ idatap->intp_arg = NULL;
+ else {
+ *cp++ = '\0';
+ while (*cp == ' ')
+ cp++;
+ if (*cp == '\0')
+ idatap->intp_arg = NULL;
+ else {
+ idatap->intp_arg = cp;
+ while (*cp && *cp != ' ')
+ cp++;
+ *cp = '\0';
+ }
+ }
+ return (0);
+}
+
+int
+intpexec(
+ 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)
+{
+ vnode_t *nvp;
+ int error = 0;
+ struct intpdata idata;
+ struct pathname intppn;
+ struct pathname resolvepn;
+ char *opath;
+ char devfd[14];
+ int fd = -1;
+
+ if (level) { /* Can't recurse */
+ error = ENOEXEC;
+ goto bad;
+ }
+
+ ASSERT(idatap == (struct intpdata *)NULL);
+
+ /*
+ * Allocate a buffer to read in the interpreter pathname.
+ */
+ idata.intp = kmem_alloc(INTPSZ, KM_SLEEP);
+ if (error = getintphead(vp, &idata))
+ goto fail;
+
+ /*
+ * Look the new vnode up.
+ */
+ if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &intppn))
+ goto fail;
+ pn_alloc(&resolvepn);
+ if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) {
+ pn_free(&resolvepn);
+ pn_free(&intppn);
+ goto fail;
+ }
+ opath = args->pathname;
+ args->pathname = resolvepn.pn_path;
+ /* don't free resolvepn until we are done with args */
+ pn_free(&intppn);
+
+ if (setid) { /* close security hole */
+ (void) strcpy(devfd, "/dev/fd/");
+ if (error = execopen(&vp, &fd))
+ goto done;
+ numtos(fd, &devfd[8]);
+ args->fname = devfd;
+ }
+
+ error = gexec(&nvp, uap, args, &idata, ++level,
+ execsz, exec_file, cred);
+done:
+ VN_RELE(nvp);
+ args->pathname = opath;
+ pn_free(&resolvepn);
+fail:
+ kmem_free(idata.intp, INTPSZ);
+ if (error && fd != -1)
+ (void) execclose(fd);
+bad:
+ return (error);
+}
diff --git a/usr/src/uts/common/exec/java/java.c b/usr/src/uts/common/exec/java/java.c
new file mode 100644
index 0000000000..0e8c3996e7
--- /dev/null
+++ b/usr/src/uts/common/exec/java/java.c
@@ -0,0 +1,205 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Launch Java executables via exec(2).
+ *
+ * Java executables are platform-independent executable files
+ * based on the JAR file format. Executable JAR files contain a
+ * special 'extra field' header in the first file of the archive
+ * that marks the file as a true executable. The data in that field
+ * is used to pass additional run-time information to the Java VM.
+ *
+ * This handler looks for the appropriate magic number on the
+ * front of the file, checks that the JAR file is executable, then
+ * invokes the Java runtime environment to do the rest of the work.
+ */
+
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/exec.h>
+#include <sys/modctl.h>
+#include <sys/cmn_err.h>
+#include <sys/pathname.h>
+
+/*
+ * These variables can be tweaked via /etc/system to allow prototyping
+ * and debugging. See PSARC/1997/123.
+ *
+ * Modified by PSARC/1999/012 to be Contract Private between Solaris and
+ * the Java Technology Group. It is expected that any future change to
+ * these variables be coordinated between the consolidations.
+ */
+#if defined(__sparc)
+char *jexec = "/usr/java/jre/lib/sparc/jexec";
+#elif defined(__i386) || defined(__i386_COMPAT)
+char *jexec = "/usr/java/jre/lib/i386/jexec";
+#else
+#error "Unknown ISA"
+#endif
+char *jexec_arg = "-jar";
+
+/*
+ * ZIP/JAR file header information
+ */
+#define SIGSIZ 4
+#define LOCSIG "PK\003\004"
+#define LOCHDRSIZ 30
+
+#define CH(b, n) (((unsigned char *)(b))[n])
+#define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8))
+#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16))
+
+#define LOCNAM(b) (SH(b, 26)) /* filename size */
+#define LOCEXT(b) (SH(b, 28)) /* extra field size */
+
+#define XFHSIZ 4 /* header id, data size */
+#define XFHID(b) (SH(b, 0)) /* extract field header id */
+#define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */
+#define XFJAVASIG 0xcafe /* java executables */
+
+/*ARGSUSED3*/
+static int
+javaexec(vnode_t *vp, struct execa *uap, struct uarg *args,
+ struct intpdata *idatap, int level, long *execsz, int setid,
+ caddr_t execfile, cred_t *cred)
+{
+ struct intpdata idata;
+ int error;
+ ssize_t resid;
+ vnode_t *nvp;
+ off_t xoff, xoff_end;
+ char lochdr[LOCHDRSIZ];
+ struct pathname lookpn;
+ struct pathname resolvepn;
+ char *opath;
+
+ if (level)
+ return (ENOEXEC); /* no recursion */
+
+ /*
+ * Read in the full local file header, and validate
+ * the initial signature.
+ */
+ if ((error = vn_rdwr(UIO_READ, vp, lochdr, sizeof (lochdr),
+ 0, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0)
+ return (error);
+ if (resid != 0 || strncmp(lochdr, LOCSIG, SIGSIZ) != 0)
+ return (ENOEXEC);
+
+ /*
+ * Ok, so this -is- a ZIP file, and might even be a JAR file.
+ * Is it a Java executable?
+ */
+ xoff = sizeof (lochdr) + LOCNAM(lochdr);
+ xoff_end = xoff + LOCEXT(lochdr);
+
+ while (xoff < xoff_end) {
+ char xfhdr[XFHSIZ];
+
+ if ((error = vn_rdwr(UIO_READ, vp, xfhdr, sizeof (xfhdr),
+ xoff, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0)
+ return (error);
+ if (resid != 0)
+ return (ENOEXEC);
+ if (XFHID(xfhdr) == XFJAVASIG)
+ break;
+ xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr);
+ }
+
+ if (xoff >= xoff_end)
+ return (ENOEXEC);
+
+ /*
+ * Note: If we ever make setid execution work, we need to ensure
+ * that we use /dev/fd to avoid the classic setuid shell script
+ * security hole.
+ */
+ if (setid)
+ return (EACCES);
+
+ /*
+ * Find and invoke the Java runtime environment on the file
+ */
+ idata.intp = NULL;
+ idata.intp_name = jexec;
+ idata.intp_arg = jexec_arg;
+ if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &lookpn))
+ return (error);
+ pn_alloc(&resolvepn);
+ if (error = lookuppn(&lookpn, &resolvepn, FOLLOW, NULLVPP, &nvp)) {
+ pn_free(&resolvepn);
+ pn_free(&lookpn);
+ return (ENOEXEC);
+ }
+ opath = args->pathname;
+ args->pathname = resolvepn.pn_path;
+ /* don't free resolvepn until we are done with args */
+ pn_free(&lookpn);
+ error = gexec(&nvp,
+ uap, args, &idata, level + 1, execsz, execfile, cred);
+ VN_RELE(nvp);
+ args->pathname = opath;
+ pn_free(&resolvepn);
+ return (error);
+}
+
+static struct execsw jexecsw = {
+ javamagicstr,
+ 0,
+ 4,
+ javaexec,
+ NULL
+};
+
+static struct modlexec jmodlexec = {
+ &mod_execops, "exec for Java", &jexecsw
+};
+
+static struct modlinkage jmodlinkage = {
+ MODREV_1, &jmodlexec, NULL
+};
+
+int
+_init(void)
+{
+ return (mod_install(&jmodlinkage));
+}
+
+int
+_fini(void)
+{
+ return (mod_remove(&jmodlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&jmodlinkage, modinfop));
+}