xref: /titanic_52/usr/src/uts/common/exec/elf/elf.c (revision 263f549e5da8b32c4922f586afb365b8ae388a6c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ab9a77c7Sahl  * Common Development and Distribution License (the "License").
6ab9a77c7Sahl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21ab9a77c7Sahl 
227c478bd9Sstevel@tonic-gate /*
231022fd2aS  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
28ebb8ac07SRobert Mustacchi /*
29*263f549eSPatrick Mooney  * Copyright 2016 Joyent, Inc.
30ebb8ac07SRobert Mustacchi  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/thread.h>
357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
367c478bd9Sstevel@tonic-gate #include <sys/signal.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/user.h>
397c478bd9Sstevel@tonic-gate #include <sys/errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
417c478bd9Sstevel@tonic-gate #include <sys/mman.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/proc.h>
447c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
467c478bd9Sstevel@tonic-gate #include <sys/systm.h>
477c478bd9Sstevel@tonic-gate #include <sys/elf.h>
487c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
497c478bd9Sstevel@tonic-gate #include <sys/debug.h>
507c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
517c478bd9Sstevel@tonic-gate #include <sys/exec.h>
527c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
537c478bd9Sstevel@tonic-gate #include <vm/as.h>
547c478bd9Sstevel@tonic-gate #include <vm/rm.h>
557c478bd9Sstevel@tonic-gate #include <vm/seg.h>
567c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
577c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
587c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
597c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
607c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
617c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h>
627c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
637c478bd9Sstevel@tonic-gate #include <sys/fasttrap.h>
649acbbeafSnn35248 #include <sys/brand.h>
657c478bd9Sstevel@tonic-gate #include "elf_impl.h"
669acbbeafSnn35248 #include <sys/sdt.h>
67f971a346SBryan Cantrill #include <sys/siginfo.h>
689acbbeafSnn35248 
69*263f549eSPatrick Mooney #if defined(__x86)
70*263f549eSPatrick Mooney #include <sys/comm_page_util.h>
71*263f549eSPatrick Mooney #endif /* defined(__x86) */
72*263f549eSPatrick Mooney 
73*263f549eSPatrick Mooney 
747c478bd9Sstevel@tonic-gate extern int at_flags;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define	ORIGIN_STR	"ORIGIN"
777c478bd9Sstevel@tonic-gate #define	ORIGIN_STR_SIZE	6
787c478bd9Sstevel@tonic-gate 
7930da1432Sahl static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
8030da1432Sahl static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
8130da1432Sahl     ssize_t *);
8230da1432Sahl static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
8330da1432Sahl     ssize_t *, caddr_t *, ssize_t *);
8430da1432Sahl static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
8530da1432Sahl static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
867c478bd9Sstevel@tonic-gate     Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
879acbbeafSnn35248     caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate typedef enum {
907c478bd9Sstevel@tonic-gate 	STR_CTF,
917c478bd9Sstevel@tonic-gate 	STR_SYMTAB,
927c478bd9Sstevel@tonic-gate 	STR_DYNSYM,
937c478bd9Sstevel@tonic-gate 	STR_STRTAB,
947c478bd9Sstevel@tonic-gate 	STR_DYNSTR,
957c478bd9Sstevel@tonic-gate 	STR_SHSTRTAB,
967c478bd9Sstevel@tonic-gate 	STR_NUM
977c478bd9Sstevel@tonic-gate } shstrtype_t;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate static const char *shstrtab_data[] = {
1007c478bd9Sstevel@tonic-gate 	".SUNW_ctf",
1017c478bd9Sstevel@tonic-gate 	".symtab",
1027c478bd9Sstevel@tonic-gate 	".dynsym",
1037c478bd9Sstevel@tonic-gate 	".strtab",
1047c478bd9Sstevel@tonic-gate 	".dynstr",
1057c478bd9Sstevel@tonic-gate 	".shstrtab"
1067c478bd9Sstevel@tonic-gate };
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate typedef struct shstrtab {
1097c478bd9Sstevel@tonic-gate 	int	sst_ndx[STR_NUM];
1107c478bd9Sstevel@tonic-gate 	int	sst_cur;
1117c478bd9Sstevel@tonic-gate } shstrtab_t;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static void
1147c478bd9Sstevel@tonic-gate shstrtab_init(shstrtab_t *s)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	bzero(&s->sst_ndx, sizeof (s->sst_ndx));
1177c478bd9Sstevel@tonic-gate 	s->sst_cur = 1;
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int
1217c478bd9Sstevel@tonic-gate shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	int ret;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if ((ret = s->sst_ndx[type]) != 0)
1267c478bd9Sstevel@tonic-gate 		return (ret);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	ret = s->sst_ndx[type] = s->sst_cur;
1297c478bd9Sstevel@tonic-gate 	s->sst_cur += strlen(shstrtab_data[type]) + 1;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	return (ret);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static size_t
1357c478bd9Sstevel@tonic-gate shstrtab_size(const shstrtab_t *s)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	return (s->sst_cur);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static void
1417c478bd9Sstevel@tonic-gate shstrtab_dump(const shstrtab_t *s, char *buf)
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	int i, ndx;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	*buf = '\0';
1467c478bd9Sstevel@tonic-gate 	for (i = 0; i < STR_NUM; i++) {
1477c478bd9Sstevel@tonic-gate 		if ((ndx = s->sst_ndx[i]) != 0)
1487c478bd9Sstevel@tonic-gate 			(void) strcpy(buf + ndx, shstrtab_data[i]);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static int
1537c478bd9Sstevel@tonic-gate dtrace_safe_phdr(Phdr *phdrp, struct uarg *args, uintptr_t base)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	ASSERT(phdrp->p_type == PT_SUNWDTRACE);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * See the comment in fasttrap.h for information on how to safely
1597c478bd9Sstevel@tonic-gate 	 * update this program header.
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	if (phdrp->p_memsz < PT_SUNWDTRACE_SIZE ||
1627c478bd9Sstevel@tonic-gate 	    (phdrp->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
1637c478bd9Sstevel@tonic-gate 		return (-1);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	args->thrptr = phdrp->p_vaddr + base;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	return (0);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1709acbbeafSnn35248 /*
1719acbbeafSnn35248  * Map in the executable pointed to by vp. Returns 0 on success.
1729acbbeafSnn35248  */
1739acbbeafSnn35248 int
174396a100bSedp mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
1759acbbeafSnn35248     intptr_t *voffset, caddr_t exec_file, int *interp, caddr_t *bssbase,
17607678296Ssl108498     caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap)
1779acbbeafSnn35248 {
1789acbbeafSnn35248 	size_t		len;
1799acbbeafSnn35248 	struct vattr	vat;
1809acbbeafSnn35248 	caddr_t		phdrbase = NULL;
1819acbbeafSnn35248 	ssize_t		phdrsize;
1829acbbeafSnn35248 	int		nshdrs, shstrndx, nphdrs;
1839acbbeafSnn35248 	int		error = 0;
1849acbbeafSnn35248 	Phdr		*uphdr = NULL;
1859acbbeafSnn35248 	Phdr		*junk = NULL;
1869acbbeafSnn35248 	Phdr		*dynphdr = NULL;
1879acbbeafSnn35248 	Phdr		*dtrphdr = NULL;
1889acbbeafSnn35248 	uintptr_t	lddata;
1899acbbeafSnn35248 	long		execsz;
1909acbbeafSnn35248 	intptr_t	minaddr;
1919acbbeafSnn35248 
19207678296Ssl108498 	if (lddatap != NULL)
19307678296Ssl108498 		*lddatap = NULL;
19407678296Ssl108498 
1959acbbeafSnn35248 	if (error = execpermissions(vp, &vat, args)) {
1969acbbeafSnn35248 		uprintf("%s: Cannot execute %s\n", exec_file, args->pathname);
1979acbbeafSnn35248 		return (error);
1989acbbeafSnn35248 	}
1999acbbeafSnn35248 
2009acbbeafSnn35248 	if ((error = getelfhead(vp, CRED(), ehdr, &nshdrs, &shstrndx,
2019acbbeafSnn35248 	    &nphdrs)) != 0 ||
2029acbbeafSnn35248 	    (error = getelfphdr(vp, CRED(), ehdr, nphdrs, &phdrbase,
2039acbbeafSnn35248 	    &phdrsize)) != 0) {
2049acbbeafSnn35248 		uprintf("%s: Cannot read %s\n", exec_file, args->pathname);
2059acbbeafSnn35248 		return (error);
2069acbbeafSnn35248 	}
2079acbbeafSnn35248 
2089acbbeafSnn35248 	if ((len = elfsize(ehdr, nphdrs, phdrbase, &lddata)) == 0) {
2099acbbeafSnn35248 		uprintf("%s: Nothing to load in %s", exec_file, args->pathname);
2109acbbeafSnn35248 		kmem_free(phdrbase, phdrsize);
2119acbbeafSnn35248 		return (ENOEXEC);
2129acbbeafSnn35248 	}
21307678296Ssl108498 	if (lddatap != NULL)
21407678296Ssl108498 		*lddatap = lddata;
2159acbbeafSnn35248 
2169acbbeafSnn35248 	if (error = mapelfexec(vp, ehdr, nphdrs, phdrbase, &uphdr, &dynphdr,
2179acbbeafSnn35248 	    &junk, &dtrphdr, NULL, bssbase, brkbase, voffset, &minaddr,
2189acbbeafSnn35248 	    len, &execsz, brksize)) {
2199acbbeafSnn35248 		uprintf("%s: Cannot map %s\n", exec_file, args->pathname);
2209acbbeafSnn35248 		kmem_free(phdrbase, phdrsize);
2219acbbeafSnn35248 		return (error);
2229acbbeafSnn35248 	}
2239acbbeafSnn35248 
2249acbbeafSnn35248 	/*
2259acbbeafSnn35248 	 * Inform our caller if the executable needs an interpreter.
2269acbbeafSnn35248 	 */
2279acbbeafSnn35248 	*interp = (dynphdr == NULL) ? 0 : 1;
2289acbbeafSnn35248 
2299acbbeafSnn35248 	/*
2309acbbeafSnn35248 	 * If this is a statically linked executable, voffset should indicate
2319acbbeafSnn35248 	 * the address of the executable itself (it normally holds the address
2329acbbeafSnn35248 	 * of the interpreter).
2339acbbeafSnn35248 	 */
2349acbbeafSnn35248 	if (ehdr->e_type == ET_EXEC && *interp == 0)
2359acbbeafSnn35248 		*voffset = minaddr;
2369acbbeafSnn35248 
2379acbbeafSnn35248 	if (uphdr != NULL) {
2389acbbeafSnn35248 		*uphdr_vaddr = uphdr->p_vaddr;
2399acbbeafSnn35248 	} else {
240396a100bSedp 		*uphdr_vaddr = (Addr)-1;
2419acbbeafSnn35248 	}
2429acbbeafSnn35248 
2439acbbeafSnn35248 	kmem_free(phdrbase, phdrsize);
2449acbbeafSnn35248 	return (error);
2459acbbeafSnn35248 }
2469acbbeafSnn35248 
2477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2487c478bd9Sstevel@tonic-gate int
2497c478bd9Sstevel@tonic-gate elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
2509acbbeafSnn35248     int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
2519acbbeafSnn35248     int brand_action)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	caddr_t		phdrbase = NULL;
2547c478bd9Sstevel@tonic-gate 	caddr_t 	bssbase = 0;
2557c478bd9Sstevel@tonic-gate 	caddr_t 	brkbase = 0;
2567c478bd9Sstevel@tonic-gate 	size_t		brksize = 0;
2577c478bd9Sstevel@tonic-gate 	ssize_t		dlnsize;
2587c478bd9Sstevel@tonic-gate 	aux_entry_t	*aux;
2597c478bd9Sstevel@tonic-gate 	int		error;
2607c478bd9Sstevel@tonic-gate 	ssize_t		resid;
2617c478bd9Sstevel@tonic-gate 	int		fd = -1;
2627c478bd9Sstevel@tonic-gate 	intptr_t	voffset;
2637c478bd9Sstevel@tonic-gate 	Phdr		*dyphdr = NULL;
2647c478bd9Sstevel@tonic-gate 	Phdr		*stphdr = NULL;
2657c478bd9Sstevel@tonic-gate 	Phdr		*uphdr = NULL;
2667c478bd9Sstevel@tonic-gate 	Phdr		*junk = NULL;
2677c478bd9Sstevel@tonic-gate 	size_t		len;
2687c478bd9Sstevel@tonic-gate 	ssize_t		phdrsize;
2697c478bd9Sstevel@tonic-gate 	int		postfixsize = 0;
2707c478bd9Sstevel@tonic-gate 	int		i, hsize;
2717c478bd9Sstevel@tonic-gate 	Phdr		*phdrp;
2727c478bd9Sstevel@tonic-gate 	Phdr		*dataphdrp = NULL;
2737c478bd9Sstevel@tonic-gate 	Phdr		*dtrphdr;
274a0de58d6SRoger A. Faulkner 	Phdr		*capphdr = NULL;
275a0de58d6SRoger A. Faulkner 	Cap		*cap = NULL;
276a0de58d6SRoger A. Faulkner 	ssize_t		capsize;
2777c478bd9Sstevel@tonic-gate 	int		hasu = 0;
2787c478bd9Sstevel@tonic-gate 	int		hasauxv = 0;
2797c478bd9Sstevel@tonic-gate 	int		hasdy = 0;
2809acbbeafSnn35248 	int		branded = 0;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	struct proc *p = ttoproc(curthread);
2837c478bd9Sstevel@tonic-gate 	struct user *up = PTOU(p);
2847c478bd9Sstevel@tonic-gate 	struct bigwad {
2857c478bd9Sstevel@tonic-gate 		Ehdr	ehdr;
2867c478bd9Sstevel@tonic-gate 		aux_entry_t	elfargs[__KERN_NAUXV_IMPL];
2877c478bd9Sstevel@tonic-gate 		char		dl_name[MAXPATHLEN];
2887c478bd9Sstevel@tonic-gate 		char		pathbuf[MAXPATHLEN];
2897c478bd9Sstevel@tonic-gate 		struct vattr	vattr;
2907c478bd9Sstevel@tonic-gate 		struct execenv	exenv;
2917c478bd9Sstevel@tonic-gate 	} *bigwad;	/* kmem_alloc this behemoth so we don't blow stack */
2927c478bd9Sstevel@tonic-gate 	Ehdr		*ehdrp;
29330da1432Sahl 	int		nshdrs, shstrndx, nphdrs;
2947c478bd9Sstevel@tonic-gate 	char		*dlnp;
2957c478bd9Sstevel@tonic-gate 	char		*pathbufp;
2967c478bd9Sstevel@tonic-gate 	rlim64_t	limit;
2977c478bd9Sstevel@tonic-gate 	rlim64_t	roundlimit;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	ASSERT(p->p_model == DATAMODEL_ILP32 || p->p_model == DATAMODEL_LP64);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	bigwad = kmem_alloc(sizeof (struct bigwad), KM_SLEEP);
3027c478bd9Sstevel@tonic-gate 	ehdrp = &bigwad->ehdr;
3037c478bd9Sstevel@tonic-gate 	dlnp = bigwad->dl_name;
3047c478bd9Sstevel@tonic-gate 	pathbufp = bigwad->pathbuf;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * Obtain ELF and program header information.
3087c478bd9Sstevel@tonic-gate 	 */
30930da1432Sahl 	if ((error = getelfhead(vp, CRED(), ehdrp, &nshdrs, &shstrndx,
31030da1432Sahl 	    &nphdrs)) != 0 ||
31130da1432Sahl 	    (error = getelfphdr(vp, CRED(), ehdrp, nphdrs, &phdrbase,
31230da1432Sahl 	    &phdrsize)) != 0)
3137c478bd9Sstevel@tonic-gate 		goto out;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
316161d9479Srie 	 * Prevent executing an ELF file that has no entry point.
317161d9479Srie 	 */
318161d9479Srie 	if (ehdrp->e_entry == 0) {
319161d9479Srie 		uprintf("%s: Bad entry point\n", exec_file);
320161d9479Srie 		goto bad;
321161d9479Srie 	}
322161d9479Srie 
323161d9479Srie 	/*
3247c478bd9Sstevel@tonic-gate 	 * Put data model that we're exec-ing to into the args passed to
3257c478bd9Sstevel@tonic-gate 	 * exec_args(), so it will know what it is copying to on new stack.
3267c478bd9Sstevel@tonic-gate 	 * Now that we know whether we are exec-ing a 32-bit or 64-bit
3277c478bd9Sstevel@tonic-gate 	 * executable, we can set execsz with the appropriate NCARGS.
3287c478bd9Sstevel@tonic-gate 	 */
3297c478bd9Sstevel@tonic-gate #ifdef	_LP64
3307c478bd9Sstevel@tonic-gate 	if (ehdrp->e_ident[EI_CLASS] == ELFCLASS32) {
3317c478bd9Sstevel@tonic-gate 		args->to_model = DATAMODEL_ILP32;
3327c478bd9Sstevel@tonic-gate 		*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1);
3337c478bd9Sstevel@tonic-gate 	} else {
3347c478bd9Sstevel@tonic-gate 		args->to_model = DATAMODEL_LP64;
3357c478bd9Sstevel@tonic-gate 		args->stk_prot &= ~PROT_EXEC;
3367c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
3377c478bd9Sstevel@tonic-gate 		args->dat_prot &= ~PROT_EXEC;
3387c478bd9Sstevel@tonic-gate #endif
3397c478bd9Sstevel@tonic-gate 		*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS64-1);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate #else	/* _LP64 */
3427c478bd9Sstevel@tonic-gate 	args->to_model = DATAMODEL_ILP32;
3437c478bd9Sstevel@tonic-gate 	*execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS-1);
3447c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/*
347396a100bSedp 	 * We delay invoking the brand callback until we've figured out
348396a100bSedp 	 * what kind of elf binary we're trying to run, 32-bit or 64-bit.
349396a100bSedp 	 * We do this because now the brand library can just check
350396a100bSedp 	 * args->to_model to see if the target is 32-bit or 64-bit without
351396a100bSedp 	 * having do duplicate all the code above.
352396a100bSedp 	 */
353396a100bSedp 	if ((level < 2) &&
354396a100bSedp 	    (brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
355ec77975fSedp 		error = BROP(p)->b_elfexec(vp, uap, args,
356396a100bSedp 		    idatap, level + 1, execsz, setid, exec_file, cred,
357ec77975fSedp 		    brand_action);
358ec77975fSedp 		goto out;
359396a100bSedp 	}
360396a100bSedp 
361396a100bSedp 	/*
3627c478bd9Sstevel@tonic-gate 	 * Determine aux size now so that stack can be built
3637c478bd9Sstevel@tonic-gate 	 * in one shot (except actual copyout of aux image),
3647c478bd9Sstevel@tonic-gate 	 * determine any non-default stack protections,
3657c478bd9Sstevel@tonic-gate 	 * and still have this code be machine independent.
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	hsize = ehdrp->e_phentsize;
3687c478bd9Sstevel@tonic-gate 	phdrp = (Phdr *)phdrbase;
36930da1432Sahl 	for (i = nphdrs; i > 0; i--) {
3707c478bd9Sstevel@tonic-gate 		switch (phdrp->p_type) {
3717c478bd9Sstevel@tonic-gate 		case PT_INTERP:
3727c478bd9Sstevel@tonic-gate 			hasauxv = hasdy = 1;
3737c478bd9Sstevel@tonic-gate 			break;
3747c478bd9Sstevel@tonic-gate 		case PT_PHDR:
3757c478bd9Sstevel@tonic-gate 			hasu = 1;
3767c478bd9Sstevel@tonic-gate 			break;
3777c478bd9Sstevel@tonic-gate 		case PT_SUNWSTACK:
3787c478bd9Sstevel@tonic-gate 			args->stk_prot = PROT_USER;
3797c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_R)
3807c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_READ;
3817c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_W)
3827c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_WRITE;
3837c478bd9Sstevel@tonic-gate 			if (phdrp->p_flags & PF_X)
3847c478bd9Sstevel@tonic-gate 				args->stk_prot |= PROT_EXEC;
3857c478bd9Sstevel@tonic-gate 			break;
3867c478bd9Sstevel@tonic-gate 		case PT_LOAD:
3877c478bd9Sstevel@tonic-gate 			dataphdrp = phdrp;
3887c478bd9Sstevel@tonic-gate 			break;
389a0de58d6SRoger A. Faulkner 		case PT_SUNWCAP:
390a0de58d6SRoger A. Faulkner 			capphdr = phdrp;
391a0de58d6SRoger A. Faulkner 			break;
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 		phdrp = (Phdr *)((caddr_t)phdrp + hsize);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (ehdrp->e_type != ET_EXEC) {
3977c478bd9Sstevel@tonic-gate 		dataphdrp = NULL;
3987c478bd9Sstevel@tonic-gate 		hasauxv = 1;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* Copy BSS permissions to args->dat_prot */
4027c478bd9Sstevel@tonic-gate 	if (dataphdrp != NULL) {
4037c478bd9Sstevel@tonic-gate 		args->dat_prot = PROT_USER;
4047c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_R)
4057c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_READ;
4067c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_W)
4077c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_WRITE;
4087c478bd9Sstevel@tonic-gate 		if (dataphdrp->p_flags & PF_X)
4097c478bd9Sstevel@tonic-gate 			args->dat_prot |= PROT_EXEC;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/*
4137c478bd9Sstevel@tonic-gate 	 * If a auxvector will be required - reserve the space for
4147c478bd9Sstevel@tonic-gate 	 * it now.  This may be increased by exec_args if there are
4157c478bd9Sstevel@tonic-gate 	 * ISA-specific types (included in __KERN_NAUXV_IMPL).
4167c478bd9Sstevel@tonic-gate 	 */
4177c478bd9Sstevel@tonic-gate 	if (hasauxv) {
4187c478bd9Sstevel@tonic-gate 		/*
4197c478bd9Sstevel@tonic-gate 		 * If a AUX vector is being built - the base AUX
4207c478bd9Sstevel@tonic-gate 		 * entries are:
4217c478bd9Sstevel@tonic-gate 		 *
4227c478bd9Sstevel@tonic-gate 		 *	AT_BASE
4237c478bd9Sstevel@tonic-gate 		 *	AT_FLAGS
4247c478bd9Sstevel@tonic-gate 		 *	AT_PAGESZ
425386e9c9eSJerry Jelinek 		 *	AT_SUN_AUXFLAGS
4267c478bd9Sstevel@tonic-gate 		 *	AT_SUN_HWCAP
427ebb8ac07SRobert Mustacchi 		 *	AT_SUN_HWCAP2
428386e9c9eSJerry Jelinek 		 *	AT_SUN_PLATFORM (added in stk_copyout)
429386e9c9eSJerry Jelinek 		 *	AT_SUN_EXECNAME (added in stk_copyout)
4307c478bd9Sstevel@tonic-gate 		 *	AT_NULL
4317c478bd9Sstevel@tonic-gate 		 *
432ebb8ac07SRobert Mustacchi 		 * total == 9
4337c478bd9Sstevel@tonic-gate 		 */
4347c478bd9Sstevel@tonic-gate 		if (hasdy && hasu) {
4357c478bd9Sstevel@tonic-gate 			/*
4367c478bd9Sstevel@tonic-gate 			 * Has PT_INTERP & PT_PHDR - the auxvectors that
4377c478bd9Sstevel@tonic-gate 			 * will be built are:
4387c478bd9Sstevel@tonic-gate 			 *
4397c478bd9Sstevel@tonic-gate 			 *	AT_PHDR
4407c478bd9Sstevel@tonic-gate 			 *	AT_PHENT
4417c478bd9Sstevel@tonic-gate 			 *	AT_PHNUM
4427c478bd9Sstevel@tonic-gate 			 *	AT_ENTRY
4437c478bd9Sstevel@tonic-gate 			 *	AT_LDDATA
4447c478bd9Sstevel@tonic-gate 			 *
4457c478bd9Sstevel@tonic-gate 			 * total = 5
4467c478bd9Sstevel@tonic-gate 			 */
447ebb8ac07SRobert Mustacchi 			args->auxsize = (9 + 5) * sizeof (aux_entry_t);
4487c478bd9Sstevel@tonic-gate 		} else if (hasdy) {
4497c478bd9Sstevel@tonic-gate 			/*
4507c478bd9Sstevel@tonic-gate 			 * Has PT_INTERP but no PT_PHDR
4517c478bd9Sstevel@tonic-gate 			 *
4527c478bd9Sstevel@tonic-gate 			 *	AT_EXECFD
4537c478bd9Sstevel@tonic-gate 			 *	AT_LDDATA
4547c478bd9Sstevel@tonic-gate 			 *
4557c478bd9Sstevel@tonic-gate 			 * total = 2
4567c478bd9Sstevel@tonic-gate 			 */
457ebb8ac07SRobert Mustacchi 			args->auxsize = (9 + 2) * sizeof (aux_entry_t);
4587c478bd9Sstevel@tonic-gate 		} else {
459ebb8ac07SRobert Mustacchi 			args->auxsize = 9 * sizeof (aux_entry_t);
4607c478bd9Sstevel@tonic-gate 		}
461a0de58d6SRoger A. Faulkner 	} else {
4627c478bd9Sstevel@tonic-gate 		args->auxsize = 0;
463a0de58d6SRoger A. Faulkner 	}
4647c478bd9Sstevel@tonic-gate 
4659acbbeafSnn35248 	/*
4669acbbeafSnn35248 	 * If this binary is using an emulator, we need to add an
4679acbbeafSnn35248 	 * AT_SUN_EMULATOR aux entry.
4689acbbeafSnn35248 	 */
4699acbbeafSnn35248 	if (args->emulator != NULL)
4709acbbeafSnn35248 		args->auxsize += sizeof (aux_entry_t);
4719acbbeafSnn35248 
472*263f549eSPatrick Mooney 	/*
473*263f549eSPatrick Mooney 	 * On supported kernels (x86_64) make room in the auxv for the
474*263f549eSPatrick Mooney 	 * AT_SUN_COMMPAGE entry.  This will go unpopulated on i86xpv systems
475*263f549eSPatrick Mooney 	 * which do not provide such functionality.
476*263f549eSPatrick Mooney 	 */
477*263f549eSPatrick Mooney #if defined(__amd64)
478*263f549eSPatrick Mooney 	args->auxsize += sizeof (aux_entry_t);
479*263f549eSPatrick Mooney #endif /* defined(__amd64) */
480*263f549eSPatrick Mooney 
4819acbbeafSnn35248 	if ((brand_action != EBA_NATIVE) && (PROC_IS_BRANDED(p))) {
4829acbbeafSnn35248 		branded = 1;
4839acbbeafSnn35248 		/*
48407678296Ssl108498 		 * We will be adding 4 entries to the aux vectors.  One for
48507678296Ssl108498 		 * the the brandname and 3 for the brand specific aux vectors.
4869acbbeafSnn35248 		 */
48707678296Ssl108498 		args->auxsize += 4 * sizeof (aux_entry_t);
4889acbbeafSnn35248 	}
4899acbbeafSnn35248 
490a0de58d6SRoger A. Faulkner 	/* Hardware/Software capabilities */
491a0de58d6SRoger A. Faulkner 	if (capphdr != NULL &&
492a0de58d6SRoger A. Faulkner 	    (capsize = capphdr->p_filesz) > 0 &&
493a0de58d6SRoger A. Faulkner 	    capsize <= 16 * sizeof (*cap)) {
494a0de58d6SRoger A. Faulkner 		int ncaps = capsize / sizeof (*cap);
495a0de58d6SRoger A. Faulkner 		Cap *cp;
496a0de58d6SRoger A. Faulkner 
497a0de58d6SRoger A. Faulkner 		cap = kmem_alloc(capsize, KM_SLEEP);
498a0de58d6SRoger A. Faulkner 		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
499a0de58d6SRoger A. Faulkner 		    capsize, (offset_t)capphdr->p_offset,
500a0de58d6SRoger A. Faulkner 		    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
501a0de58d6SRoger A. Faulkner 			uprintf("%s: Cannot read capabilities section\n",
502a0de58d6SRoger A. Faulkner 			    exec_file);
503a0de58d6SRoger A. Faulkner 			goto out;
504a0de58d6SRoger A. Faulkner 		}
505a0de58d6SRoger A. Faulkner 		for (cp = cap; cp < cap + ncaps; cp++) {
506a0de58d6SRoger A. Faulkner 			if (cp->c_tag == CA_SUNW_SF_1 &&
507a0de58d6SRoger A. Faulkner 			    (cp->c_un.c_val & SF1_SUNW_ADDR32)) {
508a0de58d6SRoger A. Faulkner 				if (args->to_model == DATAMODEL_LP64)
509a0de58d6SRoger A. Faulkner 					args->addr32 = 1;
510a0de58d6SRoger A. Faulkner 				break;
511a0de58d6SRoger A. Faulkner 			}
512a0de58d6SRoger A. Faulkner 		}
513a0de58d6SRoger A. Faulkner 	}
514a0de58d6SRoger A. Faulkner 
5157c478bd9Sstevel@tonic-gate 	aux = bigwad->elfargs;
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * Move args to the user's stack.
518386e9c9eSJerry Jelinek 	 * This can fill in the AT_SUN_PLATFORM and AT_SUN_EXECNAME aux entries.
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 	if ((error = exec_args(uap, args, idatap, (void **)&aux)) != 0) {
5217c478bd9Sstevel@tonic-gate 		if (error == -1) {
5227c478bd9Sstevel@tonic-gate 			error = ENOEXEC;
5237c478bd9Sstevel@tonic-gate 			goto bad;
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 		goto out;
5267c478bd9Sstevel@tonic-gate 	}
5279acbbeafSnn35248 	/* we're single threaded after this point */
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/*
5307c478bd9Sstevel@tonic-gate 	 * If this is an ET_DYN executable (shared object),
5317c478bd9Sstevel@tonic-gate 	 * determine its memory size so that mapelfexec() can load it.
5327c478bd9Sstevel@tonic-gate 	 */
5337c478bd9Sstevel@tonic-gate 	if (ehdrp->e_type == ET_DYN)
53430da1432Sahl 		len = elfsize(ehdrp, nphdrs, phdrbase, NULL);
5357c478bd9Sstevel@tonic-gate 	else
5367c478bd9Sstevel@tonic-gate 		len = 0;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	dtrphdr = NULL;
5397c478bd9Sstevel@tonic-gate 
54030da1432Sahl 	if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr,
5419acbbeafSnn35248 	    &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
5429acbbeafSnn35248 	    len, execsz, &brksize)) != 0)
5437c478bd9Sstevel@tonic-gate 		goto bad;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	if (uphdr != NULL && dyphdr == NULL)
5467c478bd9Sstevel@tonic-gate 		goto bad;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if (dtrphdr != NULL && dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
5497c478bd9Sstevel@tonic-gate 		uprintf("%s: Bad DTrace phdr in %s\n", exec_file, exec_file);
5507c478bd9Sstevel@tonic-gate 		goto bad;
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	if (dyphdr != NULL) {
5547c478bd9Sstevel@tonic-gate 		size_t		len;
5557c478bd9Sstevel@tonic-gate 		uintptr_t	lddata;
5567c478bd9Sstevel@tonic-gate 		char		*p;
5577c478bd9Sstevel@tonic-gate 		struct vnode	*nvp;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 		dlnsize = dyphdr->p_filesz;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		if (dlnsize > MAXPATHLEN || dlnsize <= 0)
5627c478bd9Sstevel@tonic-gate 			goto bad;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		/*
5657c478bd9Sstevel@tonic-gate 		 * Read in "interpreter" pathname.
5667c478bd9Sstevel@tonic-gate 		 */
5677c478bd9Sstevel@tonic-gate 		if ((error = vn_rdwr(UIO_READ, vp, dlnp, dyphdr->p_filesz,
5687c478bd9Sstevel@tonic-gate 		    (offset_t)dyphdr->p_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
5697c478bd9Sstevel@tonic-gate 		    CRED(), &resid)) != 0) {
5707c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot obtain interpreter pathname\n",
5717c478bd9Sstevel@tonic-gate 			    exec_file);
5727c478bd9Sstevel@tonic-gate 			goto bad;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		if (resid != 0 || dlnp[dlnsize - 1] != '\0')
5767c478bd9Sstevel@tonic-gate 			goto bad;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		/*
5797c478bd9Sstevel@tonic-gate 		 * Search for '$ORIGIN' token in interpreter path.
5807c478bd9Sstevel@tonic-gate 		 * If found, expand it.
5817c478bd9Sstevel@tonic-gate 		 */
5827c478bd9Sstevel@tonic-gate 		for (p = dlnp; p = strchr(p, '$'); ) {
5837c478bd9Sstevel@tonic-gate 			uint_t	len, curlen;
5847c478bd9Sstevel@tonic-gate 			char	*_ptr;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 			if (strncmp(++p, ORIGIN_STR, ORIGIN_STR_SIZE))
5877c478bd9Sstevel@tonic-gate 				continue;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 			curlen = 0;
5907c478bd9Sstevel@tonic-gate 			len = p - dlnp - 1;
5917c478bd9Sstevel@tonic-gate 			if (len) {
5927c478bd9Sstevel@tonic-gate 				bcopy(dlnp, pathbufp, len);
5937c478bd9Sstevel@tonic-gate 				curlen += len;
5947c478bd9Sstevel@tonic-gate 			}
5957c478bd9Sstevel@tonic-gate 			if (_ptr = strrchr(args->pathname, '/')) {
5967c478bd9Sstevel@tonic-gate 				len = _ptr - args->pathname;
5977c478bd9Sstevel@tonic-gate 				if ((curlen + len) > MAXPATHLEN)
5987c478bd9Sstevel@tonic-gate 					break;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 				bcopy(args->pathname, &pathbufp[curlen], len);
6017c478bd9Sstevel@tonic-gate 				curlen += len;
6027c478bd9Sstevel@tonic-gate 			} else {
6037c478bd9Sstevel@tonic-gate 				/*
6047c478bd9Sstevel@tonic-gate 				 * executable is a basename found in the
6057c478bd9Sstevel@tonic-gate 				 * current directory.  So - just substitue
6067c478bd9Sstevel@tonic-gate 				 * '.' for ORIGIN.
6077c478bd9Sstevel@tonic-gate 				 */
6087c478bd9Sstevel@tonic-gate 				pathbufp[curlen] = '.';
6097c478bd9Sstevel@tonic-gate 				curlen++;
6107c478bd9Sstevel@tonic-gate 			}
6117c478bd9Sstevel@tonic-gate 			p += ORIGIN_STR_SIZE;
6127c478bd9Sstevel@tonic-gate 			len = strlen(p);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 			if ((curlen + len) > MAXPATHLEN)
6157c478bd9Sstevel@tonic-gate 				break;
6167c478bd9Sstevel@tonic-gate 			bcopy(p, &pathbufp[curlen], len);
6177c478bd9Sstevel@tonic-gate 			curlen += len;
6187c478bd9Sstevel@tonic-gate 			pathbufp[curlen++] = '\0';
6197c478bd9Sstevel@tonic-gate 			bcopy(pathbufp, dlnp, curlen);
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 		/*
6237c478bd9Sstevel@tonic-gate 		 * /usr/lib/ld.so.1 is known to be a symlink to /lib/ld.so.1
6247c478bd9Sstevel@tonic-gate 		 * (and /usr/lib/64/ld.so.1 is a symlink to /lib/64/ld.so.1).
6257c478bd9Sstevel@tonic-gate 		 * Just in case /usr is not mounted, change it now.
6267c478bd9Sstevel@tonic-gate 		 */
6277c478bd9Sstevel@tonic-gate 		if (strcmp(dlnp, USR_LIB_RTLD) == 0)
6287c478bd9Sstevel@tonic-gate 			dlnp += 4;
6297c478bd9Sstevel@tonic-gate 		error = lookupname(dlnp, UIO_SYSSPACE, FOLLOW, NULLVPP, &nvp);
6307c478bd9Sstevel@tonic-gate 		if (error && dlnp != bigwad->dl_name) {
6317c478bd9Sstevel@tonic-gate 			/* new kernel, old user-level */
6327c478bd9Sstevel@tonic-gate 			error = lookupname(dlnp -= 4, UIO_SYSSPACE, FOLLOW,
6337c478bd9Sstevel@tonic-gate 			    NULLVPP, &nvp);
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		if (error) {
6367c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot find %s\n", exec_file, dlnp);
6377c478bd9Sstevel@tonic-gate 			goto bad;
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		/*
6417c478bd9Sstevel@tonic-gate 		 * Setup the "aux" vector.
6427c478bd9Sstevel@tonic-gate 		 */
6437c478bd9Sstevel@tonic-gate 		if (uphdr) {
6447c478bd9Sstevel@tonic-gate 			if (ehdrp->e_type == ET_DYN) {
6457c478bd9Sstevel@tonic-gate 				/* don't use the first page */
6467c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_brkbase = (caddr_t)PAGESIZE;
6477c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_bssbase = (caddr_t)PAGESIZE;
6487c478bd9Sstevel@tonic-gate 			} else {
6497c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_bssbase = bssbase;
6507c478bd9Sstevel@tonic-gate 				bigwad->exenv.ex_brkbase = brkbase;
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = brksize;
6537c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_magic = elfmagic;
6547c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_vp = vp;
6557c478bd9Sstevel@tonic-gate 			setexecenv(&bigwad->exenv);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset)
6587c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize)
65930da1432Sahl 			ADDAUX(aux, AT_PHNUM, nphdrs)
6607c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset)
6617c478bd9Sstevel@tonic-gate 		} else {
6627c478bd9Sstevel@tonic-gate 			if ((error = execopen(&vp, &fd)) != 0) {
6637c478bd9Sstevel@tonic-gate 				VN_RELE(nvp);
6647c478bd9Sstevel@tonic-gate 				goto bad;
6657c478bd9Sstevel@tonic-gate 			}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_EXECFD, fd)
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		if ((error = execpermissions(nvp, &bigwad->vattr, args)) != 0) {
6717c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
6727c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot execute %s\n", exec_file, dlnp);
6737c478bd9Sstevel@tonic-gate 			goto bad;
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		/*
6777c478bd9Sstevel@tonic-gate 		 * Now obtain the ELF header along with the entire program
6787c478bd9Sstevel@tonic-gate 		 * header contained in "nvp".
6797c478bd9Sstevel@tonic-gate 		 */
6807c478bd9Sstevel@tonic-gate 		kmem_free(phdrbase, phdrsize);
6817c478bd9Sstevel@tonic-gate 		phdrbase = NULL;
68230da1432Sahl 		if ((error = getelfhead(nvp, CRED(), ehdrp, &nshdrs,
68330da1432Sahl 		    &shstrndx, &nphdrs)) != 0 ||
68430da1432Sahl 		    (error = getelfphdr(nvp, CRED(), ehdrp, nphdrs, &phdrbase,
6857c478bd9Sstevel@tonic-gate 		    &phdrsize)) != 0) {
6867c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
6877c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot read %s\n", exec_file, dlnp);
6887c478bd9Sstevel@tonic-gate 			goto bad;
6897c478bd9Sstevel@tonic-gate 		}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		/*
6927c478bd9Sstevel@tonic-gate 		 * Determine memory size of the "interpreter's" loadable
6937c478bd9Sstevel@tonic-gate 		 * sections.  This size is then used to obtain the virtual
6947c478bd9Sstevel@tonic-gate 		 * address of a hole, in the user's address space, large
6957c478bd9Sstevel@tonic-gate 		 * enough to map the "interpreter".
6967c478bd9Sstevel@tonic-gate 		 */
69730da1432Sahl 		if ((len = elfsize(ehdrp, nphdrs, phdrbase, &lddata)) == 0) {
6987c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
6997c478bd9Sstevel@tonic-gate 			uprintf("%s: Nothing to load in %s\n", exec_file, dlnp);
7007c478bd9Sstevel@tonic-gate 			goto bad;
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 		dtrphdr = NULL;
7047c478bd9Sstevel@tonic-gate 
70530da1432Sahl 		error = mapelfexec(nvp, ehdrp, nphdrs, phdrbase, &junk, &junk,
7069acbbeafSnn35248 		    &junk, &dtrphdr, NULL, NULL, NULL, &voffset, NULL, len,
7079acbbeafSnn35248 		    execsz, NULL);
7087c478bd9Sstevel@tonic-gate 		if (error || junk != NULL) {
7097c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
7107c478bd9Sstevel@tonic-gate 			uprintf("%s: Cannot map %s\n", exec_file, dlnp);
7117c478bd9Sstevel@tonic-gate 			goto bad;
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		/*
7157c478bd9Sstevel@tonic-gate 		 * We use the DTrace program header to initialize the
7167c478bd9Sstevel@tonic-gate 		 * architecture-specific user per-LWP location. The dtrace
7177c478bd9Sstevel@tonic-gate 		 * fasttrap provider requires ready access to per-LWP scratch
7187c478bd9Sstevel@tonic-gate 		 * space. We assume that there is only one such program header
7197c478bd9Sstevel@tonic-gate 		 * in the interpreter.
7207c478bd9Sstevel@tonic-gate 		 */
7217c478bd9Sstevel@tonic-gate 		if (dtrphdr != NULL &&
7227c478bd9Sstevel@tonic-gate 		    dtrace_safe_phdr(dtrphdr, args, voffset) != 0) {
7237c478bd9Sstevel@tonic-gate 			VN_RELE(nvp);
7247c478bd9Sstevel@tonic-gate 			uprintf("%s: Bad DTrace phdr in %s\n", exec_file, dlnp);
7257c478bd9Sstevel@tonic-gate 			goto bad;
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		VN_RELE(nvp);
7297c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_SUN_LDDATA, voffset + lddata)
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (hasauxv) {
7337c478bd9Sstevel@tonic-gate 		int auxf = AF_SUN_HWCAPVERIFY;
734*263f549eSPatrick Mooney 
7357c478bd9Sstevel@tonic-gate 		/*
736386e9c9eSJerry Jelinek 		 * Note: AT_SUN_PLATFORM and AT_SUN_EXECNAME were filled in via
737386e9c9eSJerry Jelinek 		 * exec_args()
7387c478bd9Sstevel@tonic-gate 		 */
7397c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_BASE, voffset)
7407c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_FLAGS, at_flags)
7417c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_PAGESZ, PAGESIZE)
7427c478bd9Sstevel@tonic-gate 		/*
7437c478bd9Sstevel@tonic-gate 		 * Linker flags. (security)
7447c478bd9Sstevel@tonic-gate 		 * p_flag not yet set at this time.
7457c478bd9Sstevel@tonic-gate 		 * We rely on gexec() to provide us with the information.
746cc4b03b5Scasper 		 * If the application is set-uid but this is not reflected
747cc4b03b5Scasper 		 * in a mismatch between real/effective uids/gids, then
748cc4b03b5Scasper 		 * don't treat this as a set-uid exec.  So we care about
749cc4b03b5Scasper 		 * the EXECSETID_UGIDS flag but not the ...SETID flag.
7507c478bd9Sstevel@tonic-gate 		 */
751b71d513aSedp 		if ((setid &= ~EXECSETID_SETID) != 0)
752b71d513aSedp 			auxf |= AF_SUN_SETUGID;
7531022fd2aS 
7541022fd2aS 		/*
7551022fd2aS 		 * If we're running a native process from within a branded
7561022fd2aS 		 * zone under pfexec then we clear the AF_SUN_SETUGID flag so
7571022fd2aS 		 * that the native ld.so.1 is able to link with the native
7581022fd2aS 		 * libraries instead of using the brand libraries that are
7591022fd2aS 		 * installed in the zone.  We only do this for processes
7601022fd2aS 		 * which we trust because we see they are already running
7611022fd2aS 		 * under pfexec (where uid != euid).  This prevents a
7621022fd2aS 		 * malicious user within the zone from crafting a wrapper to
7631022fd2aS 		 * run native suid commands with unsecure libraries interposed.
7641022fd2aS 		 */
7651022fd2aS 		if ((brand_action == EBA_NATIVE) && (PROC_IS_BRANDED(p) &&
7661022fd2aS 		    (setid &= ~EXECSETID_SETID) != 0))
7671022fd2aS 			auxf &= ~AF_SUN_SETUGID;
7681022fd2aS 
769b71d513aSedp 		/*
770b71d513aSedp 		 * Record the user addr of the auxflags aux vector entry
771b71d513aSedp 		 * since brands may optionally want to manipulate this field.
772b71d513aSedp 		 */
773b71d513aSedp 		args->auxp_auxflags =
774b71d513aSedp 		    (char *)((char *)args->stackend +
775b71d513aSedp 		    ((char *)&aux->a_type -
776b71d513aSedp 		    (char *)bigwad->elfargs));
777b71d513aSedp 		ADDAUX(aux, AT_SUN_AUXFLAGS, auxf);
7787c478bd9Sstevel@tonic-gate 		/*
7797c478bd9Sstevel@tonic-gate 		 * Hardware capability flag word (performance hints)
7807c478bd9Sstevel@tonic-gate 		 * Used for choosing faster library routines.
7817c478bd9Sstevel@tonic-gate 		 * (Potentially different between 32-bit and 64-bit ABIs)
7827c478bd9Sstevel@tonic-gate 		 */
7837c478bd9Sstevel@tonic-gate #if defined(_LP64)
784ebb8ac07SRobert Mustacchi 		if (args->to_model == DATAMODEL_NATIVE) {
7857c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
786ebb8ac07SRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
787ebb8ac07SRobert Mustacchi 		} else {
7887c478bd9Sstevel@tonic-gate 			ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap32)
789ebb8ac07SRobert Mustacchi 			ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap32_2)
790ebb8ac07SRobert Mustacchi 		}
7917c478bd9Sstevel@tonic-gate #else
7927c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_SUN_HWCAP, auxv_hwcap)
793ebb8ac07SRobert Mustacchi 		ADDAUX(aux, AT_SUN_HWCAP2, auxv_hwcap_2)
7947c478bd9Sstevel@tonic-gate #endif
7959acbbeafSnn35248 		if (branded) {
7969acbbeafSnn35248 			/*
79707678296Ssl108498 			 * Reserve space for the brand-private aux vectors,
7989acbbeafSnn35248 			 * and record the user addr of that space.
7999acbbeafSnn35248 			 */
80007678296Ssl108498 			args->auxp_brand =
801396a100bSedp 			    (char *)((char *)args->stackend +
802396a100bSedp 			    ((char *)&aux->a_type -
803396a100bSedp 			    (char *)bigwad->elfargs));
80407678296Ssl108498 			ADDAUX(aux, AT_SUN_BRAND_AUX1, 0)
80507678296Ssl108498 			ADDAUX(aux, AT_SUN_BRAND_AUX2, 0)
80607678296Ssl108498 			ADDAUX(aux, AT_SUN_BRAND_AUX3, 0)
8079acbbeafSnn35248 		}
8089acbbeafSnn35248 
809*263f549eSPatrick Mooney 		/*
810*263f549eSPatrick Mooney 		 * Add the comm page auxv entry, mapping it in if needed.
811*263f549eSPatrick Mooney 		 */
812*263f549eSPatrick Mooney #if defined(__amd64)
813*263f549eSPatrick Mooney 		if (args->commpage != NULL ||
814*263f549eSPatrick Mooney 		    (args->commpage = (uintptr_t)comm_page_mapin()) != NULL) {
815*263f549eSPatrick Mooney 			ADDAUX(aux, AT_SUN_COMMPAGE, args->commpage)
816*263f549eSPatrick Mooney 		} else {
817*263f549eSPatrick Mooney 			/*
818*263f549eSPatrick Mooney 			 * If the comm page cannot be mapped, pad out the auxv
819*263f549eSPatrick Mooney 			 * to satisfy later size checks.
820*263f549eSPatrick Mooney 			 */
821*263f549eSPatrick Mooney 			ADDAUX(aux, AT_NULL, 0)
822*263f549eSPatrick Mooney 		}
823*263f549eSPatrick Mooney #endif /* defined(__amd64) */
824*263f549eSPatrick Mooney 
8257c478bd9Sstevel@tonic-gate 		ADDAUX(aux, AT_NULL, 0)
8267c478bd9Sstevel@tonic-gate 		postfixsize = (char *)aux - (char *)bigwad->elfargs;
827386e9c9eSJerry Jelinek 
828386e9c9eSJerry Jelinek 		/*
829386e9c9eSJerry Jelinek 		 * We make assumptions above when we determine how many aux
830386e9c9eSJerry Jelinek 		 * vector entries we will be adding. However, if we have an
831386e9c9eSJerry Jelinek 		 * invalid elf file, it is possible that mapelfexec might
832386e9c9eSJerry Jelinek 		 * behave differently (but not return an error), in which case
833386e9c9eSJerry Jelinek 		 * the number of aux entries we actually add will be different.
834386e9c9eSJerry Jelinek 		 * We detect that now and error out.
835386e9c9eSJerry Jelinek 		 */
836386e9c9eSJerry Jelinek 		if (postfixsize != args->auxsize) {
837386e9c9eSJerry Jelinek 			DTRACE_PROBE2(elfexec_badaux, int, postfixsize,
838386e9c9eSJerry Jelinek 			    int, args->auxsize);
839386e9c9eSJerry Jelinek 			goto bad;
840386e9c9eSJerry Jelinek 		}
8417c478bd9Sstevel@tonic-gate 		ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t));
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	/*
8457c478bd9Sstevel@tonic-gate 	 * For the 64-bit kernel, the limit is big enough that rounding it up
8467c478bd9Sstevel@tonic-gate 	 * to a page can overflow the 64-bit limit, so we check for btopr()
8477c478bd9Sstevel@tonic-gate 	 * overflowing here by comparing it with the unrounded limit in pages.
8487c478bd9Sstevel@tonic-gate 	 * If it hasn't overflowed, compare the exec size with the rounded up
8497c478bd9Sstevel@tonic-gate 	 * limit in pages.  Otherwise, just compare with the unrounded limit.
8507c478bd9Sstevel@tonic-gate 	 */
8517c478bd9Sstevel@tonic-gate 	limit = btop(p->p_vmem_ctl);
8527c478bd9Sstevel@tonic-gate 	roundlimit = btopr(p->p_vmem_ctl);
8537c478bd9Sstevel@tonic-gate 	if ((roundlimit > limit && *execsz > roundlimit) ||
8547c478bd9Sstevel@tonic-gate 	    (roundlimit < limit && *execsz > limit)) {
8557c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
8567c478bd9Sstevel@tonic-gate 		(void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], p->p_rctls, p,
8577c478bd9Sstevel@tonic-gate 		    RCA_SAFE);
8587c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
8597c478bd9Sstevel@tonic-gate 		error = ENOMEM;
8607c478bd9Sstevel@tonic-gate 		goto bad;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	bzero(up->u_auxv, sizeof (up->u_auxv));
864*263f549eSPatrick Mooney 	up->u_commpagep = args->commpage;
8657c478bd9Sstevel@tonic-gate 	if (postfixsize) {
8667c478bd9Sstevel@tonic-gate 		int num_auxv;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		/*
8697c478bd9Sstevel@tonic-gate 		 * Copy the aux vector to the user stack.
8707c478bd9Sstevel@tonic-gate 		 */
8717c478bd9Sstevel@tonic-gate 		error = execpoststack(args, bigwad->elfargs, postfixsize);
8727c478bd9Sstevel@tonic-gate 		if (error)
8737c478bd9Sstevel@tonic-gate 			goto bad;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 		/*
8767c478bd9Sstevel@tonic-gate 		 * Copy auxv to the process's user structure for use by /proc.
8779acbbeafSnn35248 		 * If this is a branded process, the brand's exec routine will
8789acbbeafSnn35248 		 * copy it's private entries to the user structure later. It
8799acbbeafSnn35248 		 * relies on the fact that the blank entries are at the end.
8807c478bd9Sstevel@tonic-gate 		 */
8817c478bd9Sstevel@tonic-gate 		num_auxv = postfixsize / sizeof (aux_entry_t);
8827c478bd9Sstevel@tonic-gate 		ASSERT(num_auxv <= sizeof (up->u_auxv) / sizeof (auxv_t));
8837c478bd9Sstevel@tonic-gate 		aux = bigwad->elfargs;
8847c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_auxv; i++) {
8857c478bd9Sstevel@tonic-gate 			up->u_auxv[i].a_type = aux[i].a_type;
8867c478bd9Sstevel@tonic-gate 			up->u_auxv[i].a_un.a_val = (aux_val_t)aux[i].a_un.a_val;
8877c478bd9Sstevel@tonic-gate 		}
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	/*
8917c478bd9Sstevel@tonic-gate 	 * Pass back the starting address so we can set the program counter.
8927c478bd9Sstevel@tonic-gate 	 */
8937c478bd9Sstevel@tonic-gate 	args->entry = (uintptr_t)(ehdrp->e_entry + voffset);
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	if (!uphdr) {
8967c478bd9Sstevel@tonic-gate 		if (ehdrp->e_type == ET_DYN) {
8977c478bd9Sstevel@tonic-gate 			/*
8987c478bd9Sstevel@tonic-gate 			 * If we are executing a shared library which doesn't
8997c478bd9Sstevel@tonic-gate 			 * have a interpreter (probably ld.so.1) then
9007c478bd9Sstevel@tonic-gate 			 * we don't set the brkbase now.  Instead we
9017c478bd9Sstevel@tonic-gate 			 * delay it's setting until the first call
9027c478bd9Sstevel@tonic-gate 			 * via grow.c::brk().  This permits ld.so.1 to
9037c478bd9Sstevel@tonic-gate 			 * initialize brkbase to the tail of the executable it
9047c478bd9Sstevel@tonic-gate 			 * loads (which is where it needs to be).
9057c478bd9Sstevel@tonic-gate 			 */
9067c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brkbase = (caddr_t)0;
9077c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_bssbase = (caddr_t)0;
9087c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = 0;
9097c478bd9Sstevel@tonic-gate 		} else {
9107c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brkbase = brkbase;
9117c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_bssbase = bssbase;
9127c478bd9Sstevel@tonic-gate 			bigwad->exenv.ex_brksize = brksize;
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 		bigwad->exenv.ex_magic = elfmagic;
9157c478bd9Sstevel@tonic-gate 		bigwad->exenv.ex_vp = vp;
9167c478bd9Sstevel@tonic-gate 		setexecenv(&bigwad->exenv);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	ASSERT(error == 0);
9207c478bd9Sstevel@tonic-gate 	goto out;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate bad:
9237c478bd9Sstevel@tonic-gate 	if (fd != -1)		/* did we open the a.out yet */
9247c478bd9Sstevel@tonic-gate 		(void) execclose(fd);
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	psignal(p, SIGKILL);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if (error == 0)
9297c478bd9Sstevel@tonic-gate 		error = ENOEXEC;
9307c478bd9Sstevel@tonic-gate out:
9317c478bd9Sstevel@tonic-gate 	if (phdrbase != NULL)
9327c478bd9Sstevel@tonic-gate 		kmem_free(phdrbase, phdrsize);
933a0de58d6SRoger A. Faulkner 	if (cap != NULL)
934a0de58d6SRoger A. Faulkner 		kmem_free(cap, capsize);
9357c478bd9Sstevel@tonic-gate 	kmem_free(bigwad, sizeof (struct bigwad));
9367c478bd9Sstevel@tonic-gate 	return (error);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate  * Compute the memory size requirement for the ELF file.
9417c478bd9Sstevel@tonic-gate  */
9427c478bd9Sstevel@tonic-gate static size_t
94330da1432Sahl elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	size_t	len;
9467c478bd9Sstevel@tonic-gate 	Phdr	*phdrp = (Phdr *)phdrbase;
9477c478bd9Sstevel@tonic-gate 	int	hsize = ehdrp->e_phentsize;
9487c478bd9Sstevel@tonic-gate 	int	first = 1;
9497c478bd9Sstevel@tonic-gate 	int	dfirst = 1;	/* first data segment */
9507c478bd9Sstevel@tonic-gate 	uintptr_t loaddr = 0;
9517c478bd9Sstevel@tonic-gate 	uintptr_t hiaddr = 0;
9527c478bd9Sstevel@tonic-gate 	uintptr_t lo, hi;
9537c478bd9Sstevel@tonic-gate 	int	i;
9547c478bd9Sstevel@tonic-gate 
95530da1432Sahl 	for (i = nphdrs; i > 0; i--) {
9567c478bd9Sstevel@tonic-gate 		if (phdrp->p_type == PT_LOAD) {
9577c478bd9Sstevel@tonic-gate 			lo = phdrp->p_vaddr;
9587c478bd9Sstevel@tonic-gate 			hi = lo + phdrp->p_memsz;
9597c478bd9Sstevel@tonic-gate 			if (first) {
9607c478bd9Sstevel@tonic-gate 				loaddr = lo;
9617c478bd9Sstevel@tonic-gate 				hiaddr = hi;
9627c478bd9Sstevel@tonic-gate 				first = 0;
9637c478bd9Sstevel@tonic-gate 			} else {
9647c478bd9Sstevel@tonic-gate 				if (loaddr > lo)
9657c478bd9Sstevel@tonic-gate 					loaddr = lo;
9667c478bd9Sstevel@tonic-gate 				if (hiaddr < hi)
9677c478bd9Sstevel@tonic-gate 					hiaddr = hi;
9687c478bd9Sstevel@tonic-gate 			}
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 			/*
9717c478bd9Sstevel@tonic-gate 			 * save the address of the first data segment
9727c478bd9Sstevel@tonic-gate 			 * of a object - used for the AT_SUNW_LDDATA
9737c478bd9Sstevel@tonic-gate 			 * aux entry.
9747c478bd9Sstevel@tonic-gate 			 */
9757c478bd9Sstevel@tonic-gate 			if ((lddata != NULL) && dfirst &&
9767c478bd9Sstevel@tonic-gate 			    (phdrp->p_flags & PF_W)) {
9777c478bd9Sstevel@tonic-gate 				*lddata = lo;
9787c478bd9Sstevel@tonic-gate 				dfirst = 0;
9797c478bd9Sstevel@tonic-gate 			}
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 		phdrp = (Phdr *)((caddr_t)phdrp + hsize);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	len = hiaddr - (loaddr & PAGEMASK);
9857c478bd9Sstevel@tonic-gate 	len = roundup(len, PAGESIZE);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	return (len);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * Read in the ELF header and program header table.
9927c478bd9Sstevel@tonic-gate  * SUSV3 requires:
9937c478bd9Sstevel@tonic-gate  *	ENOEXEC	File format is not recognized
9947c478bd9Sstevel@tonic-gate  *	EINVAL	Format recognized but execution not supported
9957c478bd9Sstevel@tonic-gate  */
9967c478bd9Sstevel@tonic-gate static int
99730da1432Sahl getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
99830da1432Sahl     int *nphdrs)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate 	int error;
10017c478bd9Sstevel@tonic-gate 	ssize_t resid;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	/*
10047c478bd9Sstevel@tonic-gate 	 * We got here by the first two bytes in ident,
10057c478bd9Sstevel@tonic-gate 	 * now read the entire ELF header.
10067c478bd9Sstevel@tonic-gate 	 */
10077c478bd9Sstevel@tonic-gate 	if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr,
10087c478bd9Sstevel@tonic-gate 	    sizeof (Ehdr), (offset_t)0, UIO_SYSSPACE, 0,
10097c478bd9Sstevel@tonic-gate 	    (rlim64_t)0, credp, &resid)) != 0)
10107c478bd9Sstevel@tonic-gate 		return (error);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	/*
10137c478bd9Sstevel@tonic-gate 	 * Since a separate version is compiled for handling 32-bit and
10147c478bd9Sstevel@tonic-gate 	 * 64-bit ELF executables on a 64-bit kernel, the 64-bit version
10157c478bd9Sstevel@tonic-gate 	 * doesn't need to be able to deal with 32-bit ELF files.
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 	if (resid != 0 ||
10187c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
10197c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG3] != ELFMAG3)
10207c478bd9Sstevel@tonic-gate 		return (ENOEXEC);
102130da1432Sahl 
10227c478bd9Sstevel@tonic-gate 	if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
10237c478bd9Sstevel@tonic-gate #if defined(_ILP32) || defined(_ELF32_COMPAT)
10247c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
10257c478bd9Sstevel@tonic-gate #else
10267c478bd9Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
10277c478bd9Sstevel@tonic-gate #endif
10287c478bd9Sstevel@tonic-gate 	    !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
10297c478bd9Sstevel@tonic-gate 	    ehdr->e_flags))
10307c478bd9Sstevel@tonic-gate 		return (EINVAL);
10317c478bd9Sstevel@tonic-gate 
103230da1432Sahl 	*nshdrs = ehdr->e_shnum;
103330da1432Sahl 	*shstrndx = ehdr->e_shstrndx;
103430da1432Sahl 	*nphdrs = ehdr->e_phnum;
103530da1432Sahl 
103630da1432Sahl 	/*
103730da1432Sahl 	 * If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need
103830da1432Sahl 	 * to read in the section header at index zero to acces the true
103930da1432Sahl 	 * values for those fields.
104030da1432Sahl 	 */
104130da1432Sahl 	if ((*nshdrs == 0 && ehdr->e_shoff != 0) ||
104230da1432Sahl 	    *shstrndx == SHN_XINDEX || *nphdrs == PN_XNUM) {
104330da1432Sahl 		Shdr shdr;
104430da1432Sahl 
104530da1432Sahl 		if (ehdr->e_shoff == 0)
104630da1432Sahl 			return (EINVAL);
104730da1432Sahl 
104830da1432Sahl 		if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr,
104930da1432Sahl 		    sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0,
105030da1432Sahl 		    (rlim64_t)0, credp, &resid)) != 0)
105130da1432Sahl 			return (error);
105230da1432Sahl 
105330da1432Sahl 		if (*nshdrs == 0)
105430da1432Sahl 			*nshdrs = shdr.sh_size;
105530da1432Sahl 		if (*shstrndx == SHN_XINDEX)
105630da1432Sahl 			*shstrndx = shdr.sh_link;
105730da1432Sahl 		if (*nphdrs == PN_XNUM && shdr.sh_info != 0)
105830da1432Sahl 			*nphdrs = shdr.sh_info;
105930da1432Sahl 	}
106030da1432Sahl 
10617c478bd9Sstevel@tonic-gate 	return (0);
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT
10657c478bd9Sstevel@tonic-gate extern size_t elf_nphdr_max;
10667c478bd9Sstevel@tonic-gate #else
10677c478bd9Sstevel@tonic-gate size_t elf_nphdr_max = 1000;
10687c478bd9Sstevel@tonic-gate #endif
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate static int
107130da1432Sahl getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
10727c478bd9Sstevel@tonic-gate     caddr_t *phbasep, ssize_t *phsizep)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	ssize_t resid, minsize;
10757c478bd9Sstevel@tonic-gate 	int err;
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	/*
10787c478bd9Sstevel@tonic-gate 	 * Since we're going to be using e_phentsize to iterate down the
10797c478bd9Sstevel@tonic-gate 	 * array of program headers, it must be 8-byte aligned or else
10807c478bd9Sstevel@tonic-gate 	 * a we might cause a misaligned access. We use all members through
10817c478bd9Sstevel@tonic-gate 	 * p_flags on 32-bit ELF files and p_memsz on 64-bit ELF files so
10827c478bd9Sstevel@tonic-gate 	 * e_phentsize must be at least large enough to include those
10837c478bd9Sstevel@tonic-gate 	 * members.
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate #if !defined(_LP64) || defined(_ELF32_COMPAT)
10867c478bd9Sstevel@tonic-gate 	minsize = offsetof(Phdr, p_flags) + sizeof (((Phdr *)NULL)->p_flags);
10877c478bd9Sstevel@tonic-gate #else
10887c478bd9Sstevel@tonic-gate 	minsize = offsetof(Phdr, p_memsz) + sizeof (((Phdr *)NULL)->p_memsz);
10897c478bd9Sstevel@tonic-gate #endif
10907c478bd9Sstevel@tonic-gate 	if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3))
10917c478bd9Sstevel@tonic-gate 		return (EINVAL);
10927c478bd9Sstevel@tonic-gate 
109330da1432Sahl 	*phsizep = nphdrs * ehdr->e_phentsize;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	if (*phsizep > sizeof (Phdr) * elf_nphdr_max) {
10967c478bd9Sstevel@tonic-gate 		if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL)
10977c478bd9Sstevel@tonic-gate 			return (ENOMEM);
10987c478bd9Sstevel@tonic-gate 	} else {
10997c478bd9Sstevel@tonic-gate 		*phbasep = kmem_alloc(*phsizep, KM_SLEEP);
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	if ((err = vn_rdwr(UIO_READ, vp, *phbasep, *phsizep,
11037c478bd9Sstevel@tonic-gate 	    (offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0,
11047c478bd9Sstevel@tonic-gate 	    credp, &resid)) != 0) {
11057c478bd9Sstevel@tonic-gate 		kmem_free(*phbasep, *phsizep);
11067c478bd9Sstevel@tonic-gate 		*phbasep = NULL;
11077c478bd9Sstevel@tonic-gate 		return (err);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	return (0);
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT
11147c478bd9Sstevel@tonic-gate extern size_t elf_nshdr_max;
11157c478bd9Sstevel@tonic-gate extern size_t elf_shstrtab_max;
11167c478bd9Sstevel@tonic-gate #else
11177c478bd9Sstevel@tonic-gate size_t elf_nshdr_max = 10000;
11187c478bd9Sstevel@tonic-gate size_t elf_shstrtab_max = 100 * 1024;
11197c478bd9Sstevel@tonic-gate #endif
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate static int
11237c478bd9Sstevel@tonic-gate getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
112430da1432Sahl     int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep,
11257c478bd9Sstevel@tonic-gate     char **shstrbasep, ssize_t *shstrsizep)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	ssize_t resid, minsize;
11287c478bd9Sstevel@tonic-gate 	int err;
11297c478bd9Sstevel@tonic-gate 	Shdr *shdr;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	/*
11327c478bd9Sstevel@tonic-gate 	 * Since we're going to be using e_shentsize to iterate down the
11337c478bd9Sstevel@tonic-gate 	 * array of section headers, it must be 8-byte aligned or else
11347c478bd9Sstevel@tonic-gate 	 * a we might cause a misaligned access. We use all members through
11357c478bd9Sstevel@tonic-gate 	 * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize
113630da1432Sahl 	 * must be at least large enough to include that member. The index
113730da1432Sahl 	 * of the string table section must also be valid.
11387c478bd9Sstevel@tonic-gate 	 */
11397c478bd9Sstevel@tonic-gate 	minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize);
11407c478bd9Sstevel@tonic-gate 	if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) ||
114130da1432Sahl 	    shstrndx >= nshdrs)
11427c478bd9Sstevel@tonic-gate 		return (EINVAL);
11437c478bd9Sstevel@tonic-gate 
114430da1432Sahl 	*shsizep = nshdrs * ehdr->e_shentsize;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if (*shsizep > sizeof (Shdr) * elf_nshdr_max) {
11477c478bd9Sstevel@tonic-gate 		if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL)
11487c478bd9Sstevel@tonic-gate 			return (ENOMEM);
11497c478bd9Sstevel@tonic-gate 	} else {
11507c478bd9Sstevel@tonic-gate 		*shbasep = kmem_alloc(*shsizep, KM_SLEEP);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	if ((err = vn_rdwr(UIO_READ, vp, *shbasep, *shsizep,
11547c478bd9Sstevel@tonic-gate 	    (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0,
11557c478bd9Sstevel@tonic-gate 	    credp, &resid)) != 0) {
11567c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
11577c478bd9Sstevel@tonic-gate 		return (err);
11587c478bd9Sstevel@tonic-gate 	}
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	/*
11617c478bd9Sstevel@tonic-gate 	 * Pull the section string table out of the vnode; fail if the size
11627c478bd9Sstevel@tonic-gate 	 * is zero.
11637c478bd9Sstevel@tonic-gate 	 */
116430da1432Sahl 	shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize);
11657c478bd9Sstevel@tonic-gate 	if ((*shstrsizep = shdr->sh_size) == 0) {
11667c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
11677c478bd9Sstevel@tonic-gate 		return (EINVAL);
11687c478bd9Sstevel@tonic-gate 	}
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	if (*shstrsizep > elf_shstrtab_max) {
11717c478bd9Sstevel@tonic-gate 		if ((*shstrbasep = kmem_alloc(*shstrsizep,
11727c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP)) == NULL) {
11737c478bd9Sstevel@tonic-gate 			kmem_free(*shbasep, *shsizep);
11747c478bd9Sstevel@tonic-gate 			return (ENOMEM);
11757c478bd9Sstevel@tonic-gate 		}
11767c478bd9Sstevel@tonic-gate 	} else {
11777c478bd9Sstevel@tonic-gate 		*shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP);
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, *shstrsizep,
11817c478bd9Sstevel@tonic-gate 	    (offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
11827c478bd9Sstevel@tonic-gate 	    credp, &resid)) != 0) {
11837c478bd9Sstevel@tonic-gate 		kmem_free(*shbasep, *shsizep);
11847c478bd9Sstevel@tonic-gate 		kmem_free(*shstrbasep, *shstrsizep);
11857c478bd9Sstevel@tonic-gate 		return (err);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	/*
11897c478bd9Sstevel@tonic-gate 	 * Make sure the strtab is null-terminated to make sure we
11907c478bd9Sstevel@tonic-gate 	 * don't run off the end of the table.
11917c478bd9Sstevel@tonic-gate 	 */
11927c478bd9Sstevel@tonic-gate 	(*shstrbasep)[*shstrsizep - 1] = '\0';
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	return (0);
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate static int
11987c478bd9Sstevel@tonic-gate mapelfexec(
11997c478bd9Sstevel@tonic-gate 	vnode_t *vp,
12007c478bd9Sstevel@tonic-gate 	Ehdr *ehdr,
120130da1432Sahl 	int nphdrs,
12027c478bd9Sstevel@tonic-gate 	caddr_t phdrbase,
12037c478bd9Sstevel@tonic-gate 	Phdr **uphdr,
12047c478bd9Sstevel@tonic-gate 	Phdr **dyphdr,
12057c478bd9Sstevel@tonic-gate 	Phdr **stphdr,
12067c478bd9Sstevel@tonic-gate 	Phdr **dtphdr,
12077c478bd9Sstevel@tonic-gate 	Phdr *dataphdrp,
12087c478bd9Sstevel@tonic-gate 	caddr_t *bssbase,
12097c478bd9Sstevel@tonic-gate 	caddr_t *brkbase,
12107c478bd9Sstevel@tonic-gate 	intptr_t *voffset,
12119acbbeafSnn35248 	intptr_t *minaddr,
12127c478bd9Sstevel@tonic-gate 	size_t len,
12137c478bd9Sstevel@tonic-gate 	long *execsz,
12147c478bd9Sstevel@tonic-gate 	size_t *brksize)
12157c478bd9Sstevel@tonic-gate {
12167c478bd9Sstevel@tonic-gate 	Phdr *phdr;
12177c478bd9Sstevel@tonic-gate 	int i, prot, error;
121860946fe0Smec 	caddr_t addr = NULL;
12197c478bd9Sstevel@tonic-gate 	size_t zfodsz;
12207c478bd9Sstevel@tonic-gate 	int ptload = 0;
12217c478bd9Sstevel@tonic-gate 	int page;
12227c478bd9Sstevel@tonic-gate 	off_t offset;
12237c478bd9Sstevel@tonic-gate 	int hsize = ehdr->e_phentsize;
12249acbbeafSnn35248 	caddr_t mintmp = (caddr_t)-1;
1225ec25b48fSsusans 	extern int use_brk_lpg;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (ehdr->e_type == ET_DYN) {
12287c478bd9Sstevel@tonic-gate 		/*
12297c478bd9Sstevel@tonic-gate 		 * Obtain the virtual address of a hole in the
12307c478bd9Sstevel@tonic-gate 		 * address space to map the "interpreter".
12317c478bd9Sstevel@tonic-gate 		 */
12327c478bd9Sstevel@tonic-gate 		map_addr(&addr, len, (offset_t)0, 1, 0);
12337c478bd9Sstevel@tonic-gate 		if (addr == NULL)
12347c478bd9Sstevel@tonic-gate 			return (ENOMEM);
12357c478bd9Sstevel@tonic-gate 		*voffset = (intptr_t)addr;
123682e77048Seh208807 
123782e77048Seh208807 		/*
123882e77048Seh208807 		 * Calculate the minimum vaddr so it can be subtracted out.
123982e77048Seh208807 		 * According to the ELF specification, since PT_LOAD sections
124082e77048Seh208807 		 * must be sorted by increasing p_vaddr values, this is
124182e77048Seh208807 		 * guaranteed to be the first PT_LOAD section.
124282e77048Seh208807 		 */
124382e77048Seh208807 		phdr = (Phdr *)phdrbase;
124482e77048Seh208807 		for (i = nphdrs; i > 0; i--) {
124582e77048Seh208807 			if (phdr->p_type == PT_LOAD) {
124682e77048Seh208807 				*voffset -= (uintptr_t)phdr->p_vaddr;
124782e77048Seh208807 				break;
124882e77048Seh208807 			}
124982e77048Seh208807 			phdr = (Phdr *)((caddr_t)phdr + hsize);
125082e77048Seh208807 		}
125182e77048Seh208807 
12527c478bd9Sstevel@tonic-gate 	} else {
12537c478bd9Sstevel@tonic-gate 		*voffset = 0;
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 	phdr = (Phdr *)phdrbase;
125630da1432Sahl 	for (i = nphdrs; i > 0; i--) {
12577c478bd9Sstevel@tonic-gate 		switch (phdr->p_type) {
12587c478bd9Sstevel@tonic-gate 		case PT_LOAD:
12597c478bd9Sstevel@tonic-gate 			if ((*dyphdr != NULL) && (*uphdr == NULL))
12607c478bd9Sstevel@tonic-gate 				return (0);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 			ptload = 1;
12637c478bd9Sstevel@tonic-gate 			prot = PROT_USER;
12647c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_R)
12657c478bd9Sstevel@tonic-gate 				prot |= PROT_READ;
12667c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_W)
12677c478bd9Sstevel@tonic-gate 				prot |= PROT_WRITE;
12687c478bd9Sstevel@tonic-gate 			if (phdr->p_flags & PF_X)
12697c478bd9Sstevel@tonic-gate 				prot |= PROT_EXEC;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 			addr = (caddr_t)((uintptr_t)phdr->p_vaddr + *voffset);
12729acbbeafSnn35248 
12739acbbeafSnn35248 			/*
12749acbbeafSnn35248 			 * Keep track of the segment with the lowest starting
12759acbbeafSnn35248 			 * address.
12769acbbeafSnn35248 			 */
12779acbbeafSnn35248 			if (addr < mintmp)
12789acbbeafSnn35248 				mintmp = addr;
12799acbbeafSnn35248 
12807c478bd9Sstevel@tonic-gate 			zfodsz = (size_t)phdr->p_memsz - phdr->p_filesz;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 			offset = phdr->p_offset;
12837c478bd9Sstevel@tonic-gate 			if (((uintptr_t)offset & PAGEOFFSET) ==
12847c478bd9Sstevel@tonic-gate 			    ((uintptr_t)addr & PAGEOFFSET) &&
12857c478bd9Sstevel@tonic-gate 			    (!(vp->v_flag & VNOMAP))) {
12867c478bd9Sstevel@tonic-gate 				page = 1;
12877c478bd9Sstevel@tonic-gate 			} else {
12887c478bd9Sstevel@tonic-gate 				page = 0;
12897c478bd9Sstevel@tonic-gate 			}
12907c478bd9Sstevel@tonic-gate 
1291ec25b48fSsusans 			/*
1292ec25b48fSsusans 			 * Set the heap pagesize for OOB when the bss size
1293ec25b48fSsusans 			 * is known and use_brk_lpg is not 0.
1294ec25b48fSsusans 			 */
1295ec25b48fSsusans 			if (brksize != NULL && use_brk_lpg &&
1296ec25b48fSsusans 			    zfodsz != 0 && phdr == dataphdrp &&
1297ec25b48fSsusans 			    (prot & PROT_WRITE)) {
1298ec25b48fSsusans 				size_t tlen = P2NPHASE((uintptr_t)addr +
1299ec25b48fSsusans 				    phdr->p_filesz, PAGESIZE);
1300ec25b48fSsusans 
1301ec25b48fSsusans 				if (zfodsz > tlen) {
1302ec25b48fSsusans 					curproc->p_brkpageszc =
1303ec25b48fSsusans 					    page_szc(map_pgsz(MAPPGSZ_HEAP,
1304ec25b48fSsusans 					    curproc, addr + phdr->p_filesz +
1305ec25b48fSsusans 					    tlen, zfodsz - tlen, 0));
1306ec25b48fSsusans 				}
1307ec25b48fSsusans 			}
1308ec25b48fSsusans 
13093486346cSdavemq 			if (curproc->p_brkpageszc != 0 && phdr == dataphdrp &&
13103486346cSdavemq 			    (prot & PROT_WRITE)) {
13117c478bd9Sstevel@tonic-gate 				uint_t	szc = curproc->p_brkpageszc;
13127c478bd9Sstevel@tonic-gate 				size_t pgsz = page_get_pagesize(szc);
1313ec25b48fSsusans 				caddr_t ebss = addr + phdr->p_memsz;
1314ec25b48fSsusans 				size_t extra_zfodsz;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 				ASSERT(pgsz > PAGESIZE);
13177c478bd9Sstevel@tonic-gate 
1318ec25b48fSsusans 				extra_zfodsz = P2NPHASE((uintptr_t)ebss, pgsz);
1319ec25b48fSsusans 
13207c478bd9Sstevel@tonic-gate 				if (error = execmap(vp, addr, phdr->p_filesz,
1321ec25b48fSsusans 				    zfodsz + extra_zfodsz, phdr->p_offset,
1322ec25b48fSsusans 				    prot, page, szc))
13237c478bd9Sstevel@tonic-gate 					goto bad;
13247c478bd9Sstevel@tonic-gate 				if (brksize != NULL)
1325ec25b48fSsusans 					*brksize = extra_zfodsz;
13267c478bd9Sstevel@tonic-gate 			} else {
13277c478bd9Sstevel@tonic-gate 				if (error = execmap(vp, addr, phdr->p_filesz,
13287c478bd9Sstevel@tonic-gate 				    zfodsz, phdr->p_offset, prot, page, 0))
13297c478bd9Sstevel@tonic-gate 					goto bad;
13307c478bd9Sstevel@tonic-gate 			}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 			if (bssbase != NULL && addr >= *bssbase &&
13337c478bd9Sstevel@tonic-gate 			    phdr == dataphdrp) {
13347c478bd9Sstevel@tonic-gate 				*bssbase = addr + phdr->p_filesz;
13357c478bd9Sstevel@tonic-gate 			}
13367c478bd9Sstevel@tonic-gate 			if (brkbase != NULL && addr >= *brkbase) {
13377c478bd9Sstevel@tonic-gate 				*brkbase = addr + phdr->p_memsz;
13387c478bd9Sstevel@tonic-gate 			}
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 			*execsz += btopr(phdr->p_memsz);
13417c478bd9Sstevel@tonic-gate 			break;
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		case PT_INTERP:
13447c478bd9Sstevel@tonic-gate 			if (ptload)
13457c478bd9Sstevel@tonic-gate 				goto bad;
13467c478bd9Sstevel@tonic-gate 			*dyphdr = phdr;
13477c478bd9Sstevel@tonic-gate 			break;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 		case PT_SHLIB:
13507c478bd9Sstevel@tonic-gate 			*stphdr = phdr;
13517c478bd9Sstevel@tonic-gate 			break;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		case PT_PHDR:
13547c478bd9Sstevel@tonic-gate 			if (ptload)
13557c478bd9Sstevel@tonic-gate 				goto bad;
13567c478bd9Sstevel@tonic-gate 			*uphdr = phdr;
13577c478bd9Sstevel@tonic-gate 			break;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		case PT_NULL:
13607c478bd9Sstevel@tonic-gate 		case PT_DYNAMIC:
13617c478bd9Sstevel@tonic-gate 		case PT_NOTE:
13627c478bd9Sstevel@tonic-gate 			break;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		case PT_SUNWDTRACE:
13657c478bd9Sstevel@tonic-gate 			if (dtphdr != NULL)
13667c478bd9Sstevel@tonic-gate 				*dtphdr = phdr;
13677c478bd9Sstevel@tonic-gate 			break;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 		default:
13707c478bd9Sstevel@tonic-gate 			break;
13717c478bd9Sstevel@tonic-gate 		}
13727c478bd9Sstevel@tonic-gate 		phdr = (Phdr *)((caddr_t)phdr + hsize);
13737c478bd9Sstevel@tonic-gate 	}
13749acbbeafSnn35248 
13759acbbeafSnn35248 	if (minaddr != NULL) {
13769acbbeafSnn35248 		ASSERT(mintmp != (caddr_t)-1);
13779acbbeafSnn35248 		*minaddr = (intptr_t)mintmp;
13789acbbeafSnn35248 	}
13799acbbeafSnn35248 
13807c478bd9Sstevel@tonic-gate 	return (0);
13817c478bd9Sstevel@tonic-gate bad:
13827c478bd9Sstevel@tonic-gate 	if (error == 0)
13837c478bd9Sstevel@tonic-gate 		error = EINVAL;
13847c478bd9Sstevel@tonic-gate 	return (error);
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate int
13887c478bd9Sstevel@tonic-gate elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
13897c478bd9Sstevel@tonic-gate     rlim64_t rlimit, cred_t *credp)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate 	Note note;
13927c478bd9Sstevel@tonic-gate 	int error;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	bzero(&note, sizeof (note));
13957c478bd9Sstevel@tonic-gate 	bcopy("CORE", note.name, 4);
13967c478bd9Sstevel@tonic-gate 	note.nhdr.n_type = type;
13977c478bd9Sstevel@tonic-gate 	/*
13987c478bd9Sstevel@tonic-gate 	 * The System V ABI states that n_namesz must be the length of the
13997c478bd9Sstevel@tonic-gate 	 * string that follows the Nhdr structure including the terminating
14007c478bd9Sstevel@tonic-gate 	 * null. The ABI also specifies that sufficient padding should be
14017c478bd9Sstevel@tonic-gate 	 * included so that the description that follows the name string
14027c478bd9Sstevel@tonic-gate 	 * begins on a 4- or 8-byte boundary for 32- and 64-bit binaries
14037c478bd9Sstevel@tonic-gate 	 * respectively. However, since this change was not made correctly
14047c478bd9Sstevel@tonic-gate 	 * at the time of the 64-bit port, both 32- and 64-bit binaries
14057c478bd9Sstevel@tonic-gate 	 * descriptions are only guaranteed to begin on a 4-byte boundary.
14067c478bd9Sstevel@tonic-gate 	 */
14077c478bd9Sstevel@tonic-gate 	note.nhdr.n_namesz = 5;
14087c478bd9Sstevel@tonic-gate 	note.nhdr.n_descsz = roundup(descsz, sizeof (Word));
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, *offsetp, &note,
14117c478bd9Sstevel@tonic-gate 	    sizeof (note), rlimit, credp))
14127c478bd9Sstevel@tonic-gate 		return (error);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	*offsetp += sizeof (note);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, *offsetp, desc,
14177c478bd9Sstevel@tonic-gate 	    note.nhdr.n_descsz, rlimit, credp))
14187c478bd9Sstevel@tonic-gate 		return (error);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	*offsetp += note.nhdr.n_descsz;
14217c478bd9Sstevel@tonic-gate 	return (0);
14227c478bd9Sstevel@tonic-gate }
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate /*
14257c478bd9Sstevel@tonic-gate  * Copy the section data from one vnode to the section of another vnode.
14267c478bd9Sstevel@tonic-gate  */
14277c478bd9Sstevel@tonic-gate static void
14287c478bd9Sstevel@tonic-gate copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
14297c478bd9Sstevel@tonic-gate     void *buf, size_t size, cred_t *credp, rlim64_t rlimit)
14307c478bd9Sstevel@tonic-gate {
14317c478bd9Sstevel@tonic-gate 	ssize_t resid;
14327c478bd9Sstevel@tonic-gate 	size_t len, n = src->sh_size;
14337c478bd9Sstevel@tonic-gate 	offset_t off = 0;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	while (n != 0) {
14367c478bd9Sstevel@tonic-gate 		len = MIN(size, n);
14377c478bd9Sstevel@tonic-gate 		if (vn_rdwr(UIO_READ, src_vp, buf, len, src->sh_offset + off,
14387c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 ||
14397c478bd9Sstevel@tonic-gate 		    resid >= len ||
14407c478bd9Sstevel@tonic-gate 		    core_write(dst_vp, UIO_SYSSPACE, *doffset + off,
14417c478bd9Sstevel@tonic-gate 		    buf, len - resid, rlimit, credp) != 0) {
14427c478bd9Sstevel@tonic-gate 			dst->sh_size = 0;
14437c478bd9Sstevel@tonic-gate 			dst->sh_offset = 0;
14447c478bd9Sstevel@tonic-gate 			return;
14457c478bd9Sstevel@tonic-gate 		}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 		ASSERT(n >= len - resid);
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 		n -= len - resid;
14507c478bd9Sstevel@tonic-gate 		off += len - resid;
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	*doffset += src->sh_size;
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate #ifdef _ELF32_COMPAT
14577c478bd9Sstevel@tonic-gate extern size_t elf_datasz_max;
14587c478bd9Sstevel@tonic-gate #else
14597c478bd9Sstevel@tonic-gate size_t elf_datasz_max = 1 * 1024 * 1024;
14607c478bd9Sstevel@tonic-gate #endif
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * This function processes mappings that correspond to load objects to
14647c478bd9Sstevel@tonic-gate  * examine their respective sections for elfcore(). It's called once with
14657c478bd9Sstevel@tonic-gate  * v set to NULL to count the number of sections that we're going to need
14667c478bd9Sstevel@tonic-gate  * and then again with v set to some allocated buffer that we fill in with
14677c478bd9Sstevel@tonic-gate  * all the section data.
14687c478bd9Sstevel@tonic-gate  */
14697c478bd9Sstevel@tonic-gate static int
14707c478bd9Sstevel@tonic-gate process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
1471ab9a77c7Sahl     Shdr *v, int nv, rlim64_t rlimit, Off *doffsetp, int *nshdrsp)
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate 	vnode_t *lastvp = NULL;
14747c478bd9Sstevel@tonic-gate 	struct seg *seg;
14757c478bd9Sstevel@tonic-gate 	int i, j;
14767c478bd9Sstevel@tonic-gate 	void *data = NULL;
14777c478bd9Sstevel@tonic-gate 	size_t datasz = 0;
14787c478bd9Sstevel@tonic-gate 	shstrtab_t shstrtab;
14797c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
14807c478bd9Sstevel@tonic-gate 	int error = 0;
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	if (v != NULL)
14837c478bd9Sstevel@tonic-gate 		shstrtab_init(&shstrtab);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	i = 1;
14867c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
14877c478bd9Sstevel@tonic-gate 		uint_t prot;
14887c478bd9Sstevel@tonic-gate 		vnode_t *mvp;
14897c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
14907c478bd9Sstevel@tonic-gate 		caddr_t saddr = seg->s_base;
14917c478bd9Sstevel@tonic-gate 		caddr_t naddr;
14927c478bd9Sstevel@tonic-gate 		caddr_t eaddr;
14937c478bd9Sstevel@tonic-gate 		size_t segsize;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 		Ehdr ehdr;
149630da1432Sahl 		int nshdrs, shstrndx, nphdrs;
14977c478bd9Sstevel@tonic-gate 		caddr_t shbase;
14987c478bd9Sstevel@tonic-gate 		ssize_t shsize;
14997c478bd9Sstevel@tonic-gate 		char *shstrbase;
15007c478bd9Sstevel@tonic-gate 		ssize_t shstrsize;
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 		Shdr *shdr;
15037c478bd9Sstevel@tonic-gate 		const char *name;
15047c478bd9Sstevel@tonic-gate 		size_t sz;
15057c478bd9Sstevel@tonic-gate 		uintptr_t off;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		int ctf_ndx = 0;
15087c478bd9Sstevel@tonic-gate 		int symtab_ndx = 0;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 		/*
15117c478bd9Sstevel@tonic-gate 		 * Since we're just looking for text segments of load
15127c478bd9Sstevel@tonic-gate 		 * objects, we only care about the protection bits; we don't
15137c478bd9Sstevel@tonic-gate 		 * care about the actual size of the segment so we use the
15147c478bd9Sstevel@tonic-gate 		 * reserved size. If the segment's size is zero, there's
15157c478bd9Sstevel@tonic-gate 		 * something fishy going on so we ignore this segment.
15167c478bd9Sstevel@tonic-gate 		 */
15177c478bd9Sstevel@tonic-gate 		if (seg->s_ops != &segvn_ops ||
15187c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
15197c478bd9Sstevel@tonic-gate 		    mvp == lastvp || mvp == NULL || mvp->v_type != VREG ||
15207c478bd9Sstevel@tonic-gate 		    (segsize = pr_getsegsize(seg, 1)) == 0)
15217c478bd9Sstevel@tonic-gate 			continue;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		eaddr = saddr + segsize;
15247c478bd9Sstevel@tonic-gate 		prot = pr_getprot(seg, 1, &tmp, &saddr, &naddr, eaddr);
15257c478bd9Sstevel@tonic-gate 		pr_getprot_done(&tmp);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 		/*
15287c478bd9Sstevel@tonic-gate 		 * Skip this segment unless the protection bits look like
15297c478bd9Sstevel@tonic-gate 		 * what we'd expect for a text segment.
15307c478bd9Sstevel@tonic-gate 		 */
15317c478bd9Sstevel@tonic-gate 		if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
15327c478bd9Sstevel@tonic-gate 			continue;
15337c478bd9Sstevel@tonic-gate 
153430da1432Sahl 		if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx,
153530da1432Sahl 		    &nphdrs) != 0 ||
153630da1432Sahl 		    getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx,
153730da1432Sahl 		    &shbase, &shsize, &shstrbase, &shstrsize) != 0)
15387c478bd9Sstevel@tonic-gate 			continue;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 		off = ehdr.e_shentsize;
154130da1432Sahl 		for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) {
15427c478bd9Sstevel@tonic-gate 			Shdr *symtab = NULL, *strtab;
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 			shdr = (Shdr *)(shbase + off);
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 			if (shdr->sh_name >= shstrsize)
15477c478bd9Sstevel@tonic-gate 				continue;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 			name = shstrbase + shdr->sh_name;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 			if (strcmp(name, shstrtab_data[STR_CTF]) == 0) {
15527c478bd9Sstevel@tonic-gate 				if ((content & CC_CONTENT_CTF) == 0 ||
15537c478bd9Sstevel@tonic-gate 				    ctf_ndx != 0)
15547c478bd9Sstevel@tonic-gate 					continue;
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 				if (shdr->sh_link > 0 &&
155730da1432Sahl 				    shdr->sh_link < nshdrs) {
15587c478bd9Sstevel@tonic-gate 					symtab = (Shdr *)(shbase +
15597c478bd9Sstevel@tonic-gate 					    shdr->sh_link * ehdr.e_shentsize);
15607c478bd9Sstevel@tonic-gate 				}
15617c478bd9Sstevel@tonic-gate 
1562ab9a77c7Sahl 				if (v != NULL && i < nv - 1) {
15637c478bd9Sstevel@tonic-gate 					if (shdr->sh_size > datasz &&
15647c478bd9Sstevel@tonic-gate 					    shdr->sh_size <= elf_datasz_max) {
15657c478bd9Sstevel@tonic-gate 						if (data != NULL)
15667c478bd9Sstevel@tonic-gate 							kmem_free(data, datasz);
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 						datasz = shdr->sh_size;
15697c478bd9Sstevel@tonic-gate 						data = kmem_alloc(datasz,
15707c478bd9Sstevel@tonic-gate 						    KM_SLEEP);
15717c478bd9Sstevel@tonic-gate 					}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 					v[i].sh_name = shstrtab_ndx(&shstrtab,
15747c478bd9Sstevel@tonic-gate 					    STR_CTF);
15757c478bd9Sstevel@tonic-gate 					v[i].sh_addr = (Addr)(uintptr_t)saddr;
15767c478bd9Sstevel@tonic-gate 					v[i].sh_type = SHT_PROGBITS;
15777c478bd9Sstevel@tonic-gate 					v[i].sh_addralign = 4;
15787c478bd9Sstevel@tonic-gate 					*doffsetp = roundup(*doffsetp,
15797c478bd9Sstevel@tonic-gate 					    v[i].sh_addralign);
15807c478bd9Sstevel@tonic-gate 					v[i].sh_offset = *doffsetp;
15817c478bd9Sstevel@tonic-gate 					v[i].sh_size = shdr->sh_size;
15827c478bd9Sstevel@tonic-gate 					if (symtab == NULL)  {
15837c478bd9Sstevel@tonic-gate 						v[i].sh_link = 0;
15847c478bd9Sstevel@tonic-gate 					} else if (symtab->sh_type ==
15857c478bd9Sstevel@tonic-gate 					    SHT_SYMTAB &&
15867c478bd9Sstevel@tonic-gate 					    symtab_ndx != 0) {
15877c478bd9Sstevel@tonic-gate 						v[i].sh_link =
15887c478bd9Sstevel@tonic-gate 						    symtab_ndx;
15897c478bd9Sstevel@tonic-gate 					} else {
15907c478bd9Sstevel@tonic-gate 						v[i].sh_link = i + 1;
15917c478bd9Sstevel@tonic-gate 					}
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 					copy_scn(shdr, mvp, &v[i], vp,
15947c478bd9Sstevel@tonic-gate 					    doffsetp, data, datasz, credp,
15957c478bd9Sstevel@tonic-gate 					    rlimit);
15967c478bd9Sstevel@tonic-gate 				}
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 				ctf_ndx = i++;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 				/*
16017c478bd9Sstevel@tonic-gate 				 * We've already dumped the symtab.
16027c478bd9Sstevel@tonic-gate 				 */
16037c478bd9Sstevel@tonic-gate 				if (symtab != NULL &&
16047c478bd9Sstevel@tonic-gate 				    symtab->sh_type == SHT_SYMTAB &&
16057c478bd9Sstevel@tonic-gate 				    symtab_ndx != 0)
16067c478bd9Sstevel@tonic-gate 					continue;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 			} else if (strcmp(name,
16097c478bd9Sstevel@tonic-gate 			    shstrtab_data[STR_SYMTAB]) == 0) {
16107c478bd9Sstevel@tonic-gate 				if ((content & CC_CONTENT_SYMTAB) == 0 ||
16117c478bd9Sstevel@tonic-gate 				    symtab != 0)
16127c478bd9Sstevel@tonic-gate 					continue;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 				symtab = shdr;
16157c478bd9Sstevel@tonic-gate 			}
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 			if (symtab != NULL) {
16187c478bd9Sstevel@tonic-gate 				if ((symtab->sh_type != SHT_DYNSYM &&
16197c478bd9Sstevel@tonic-gate 				    symtab->sh_type != SHT_SYMTAB) ||
16207c478bd9Sstevel@tonic-gate 				    symtab->sh_link == 0 ||
162130da1432Sahl 				    symtab->sh_link >= nshdrs)
16227c478bd9Sstevel@tonic-gate 					continue;
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 				strtab = (Shdr *)(shbase +
16257c478bd9Sstevel@tonic-gate 				    symtab->sh_link * ehdr.e_shentsize);
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 				if (strtab->sh_type != SHT_STRTAB)
16287c478bd9Sstevel@tonic-gate 					continue;
16297c478bd9Sstevel@tonic-gate 
1630ab9a77c7Sahl 				if (v != NULL && i < nv - 2) {
16317c478bd9Sstevel@tonic-gate 					sz = MAX(symtab->sh_size,
16327c478bd9Sstevel@tonic-gate 					    strtab->sh_size);
16337c478bd9Sstevel@tonic-gate 					if (sz > datasz &&
16347c478bd9Sstevel@tonic-gate 					    sz <= elf_datasz_max) {
16357c478bd9Sstevel@tonic-gate 						if (data != NULL)
16367c478bd9Sstevel@tonic-gate 							kmem_free(data, datasz);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 						datasz = sz;
16397c478bd9Sstevel@tonic-gate 						data = kmem_alloc(datasz,
16407c478bd9Sstevel@tonic-gate 						    KM_SLEEP);
16417c478bd9Sstevel@tonic-gate 					}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 					if (symtab->sh_type == SHT_DYNSYM) {
16447c478bd9Sstevel@tonic-gate 						v[i].sh_name = shstrtab_ndx(
16457c478bd9Sstevel@tonic-gate 						    &shstrtab, STR_DYNSYM);
16467c478bd9Sstevel@tonic-gate 						v[i + 1].sh_name = shstrtab_ndx(
16477c478bd9Sstevel@tonic-gate 						    &shstrtab, STR_DYNSTR);
16487c478bd9Sstevel@tonic-gate 					} else {
16497c478bd9Sstevel@tonic-gate 						v[i].sh_name = shstrtab_ndx(
16507c478bd9Sstevel@tonic-gate 						    &shstrtab, STR_SYMTAB);
16517c478bd9Sstevel@tonic-gate 						v[i + 1].sh_name = shstrtab_ndx(
16527c478bd9Sstevel@tonic-gate 						    &shstrtab, STR_STRTAB);
16537c478bd9Sstevel@tonic-gate 					}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 					v[i].sh_type = symtab->sh_type;
16567c478bd9Sstevel@tonic-gate 					v[i].sh_addr = symtab->sh_addr;
16577c478bd9Sstevel@tonic-gate 					if (ehdr.e_type == ET_DYN ||
16587c478bd9Sstevel@tonic-gate 					    v[i].sh_addr == 0)
16597c478bd9Sstevel@tonic-gate 						v[i].sh_addr +=
16607c478bd9Sstevel@tonic-gate 						    (Addr)(uintptr_t)saddr;
16617c478bd9Sstevel@tonic-gate 					v[i].sh_addralign =
16627c478bd9Sstevel@tonic-gate 					    symtab->sh_addralign;
16637c478bd9Sstevel@tonic-gate 					*doffsetp = roundup(*doffsetp,
16647c478bd9Sstevel@tonic-gate 					    v[i].sh_addralign);
16657c478bd9Sstevel@tonic-gate 					v[i].sh_offset = *doffsetp;
16667c478bd9Sstevel@tonic-gate 					v[i].sh_size = symtab->sh_size;
16677c478bd9Sstevel@tonic-gate 					v[i].sh_link = i + 1;
16687c478bd9Sstevel@tonic-gate 					v[i].sh_entsize = symtab->sh_entsize;
16697c478bd9Sstevel@tonic-gate 					v[i].sh_info = symtab->sh_info;
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 					copy_scn(symtab, mvp, &v[i], vp,
16727c478bd9Sstevel@tonic-gate 					    doffsetp, data, datasz, credp,
16737c478bd9Sstevel@tonic-gate 					    rlimit);
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 					v[i + 1].sh_type = SHT_STRTAB;
16767c478bd9Sstevel@tonic-gate 					v[i + 1].sh_flags = SHF_STRINGS;
16777c478bd9Sstevel@tonic-gate 					v[i + 1].sh_addr = symtab->sh_addr;
16787c478bd9Sstevel@tonic-gate 					if (ehdr.e_type == ET_DYN ||
16797c478bd9Sstevel@tonic-gate 					    v[i + 1].sh_addr == 0)
16807c478bd9Sstevel@tonic-gate 						v[i + 1].sh_addr +=
16817c478bd9Sstevel@tonic-gate 						    (Addr)(uintptr_t)saddr;
16827c478bd9Sstevel@tonic-gate 					v[i + 1].sh_addralign =
16837c478bd9Sstevel@tonic-gate 					    strtab->sh_addralign;
16847c478bd9Sstevel@tonic-gate 					*doffsetp = roundup(*doffsetp,
16857c478bd9Sstevel@tonic-gate 					    v[i + 1].sh_addralign);
16867c478bd9Sstevel@tonic-gate 					v[i + 1].sh_offset = *doffsetp;
16877c478bd9Sstevel@tonic-gate 					v[i + 1].sh_size = strtab->sh_size;
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 					copy_scn(strtab, mvp, &v[i + 1], vp,
16907c478bd9Sstevel@tonic-gate 					    doffsetp, data, datasz, credp,
16917c478bd9Sstevel@tonic-gate 					    rlimit);
16927c478bd9Sstevel@tonic-gate 				}
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 				if (symtab->sh_type == SHT_SYMTAB)
16957c478bd9Sstevel@tonic-gate 					symtab_ndx = i;
16967c478bd9Sstevel@tonic-gate 				i += 2;
16977c478bd9Sstevel@tonic-gate 			}
16987c478bd9Sstevel@tonic-gate 		}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 		kmem_free(shstrbase, shstrsize);
17017c478bd9Sstevel@tonic-gate 		kmem_free(shbase, shsize);
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 		lastvp = mvp;
17047c478bd9Sstevel@tonic-gate 	}
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	if (v == NULL) {
17077c478bd9Sstevel@tonic-gate 		if (i == 1)
17087c478bd9Sstevel@tonic-gate 			*nshdrsp = 0;
17097c478bd9Sstevel@tonic-gate 		else
17107c478bd9Sstevel@tonic-gate 			*nshdrsp = i + 1;
17117c478bd9Sstevel@tonic-gate 		goto done;
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
1714ab9a77c7Sahl 	if (i != nv - 1) {
17157c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "elfcore: core dump failed for "
17167c478bd9Sstevel@tonic-gate 		    "process %d; address space is changing", p->p_pid);
17177c478bd9Sstevel@tonic-gate 		error = EIO;
17187c478bd9Sstevel@tonic-gate 		goto done;
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	v[i].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
17227c478bd9Sstevel@tonic-gate 	v[i].sh_size = shstrtab_size(&shstrtab);
17237c478bd9Sstevel@tonic-gate 	v[i].sh_addralign = 1;
17247c478bd9Sstevel@tonic-gate 	*doffsetp = roundup(*doffsetp, v[i].sh_addralign);
17257c478bd9Sstevel@tonic-gate 	v[i].sh_offset = *doffsetp;
17267c478bd9Sstevel@tonic-gate 	v[i].sh_flags = SHF_STRINGS;
17277c478bd9Sstevel@tonic-gate 	v[i].sh_type = SHT_STRTAB;
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	if (v[i].sh_size > datasz) {
17307c478bd9Sstevel@tonic-gate 		if (data != NULL)
17317c478bd9Sstevel@tonic-gate 			kmem_free(data, datasz);
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 		datasz = v[i].sh_size;
17347c478bd9Sstevel@tonic-gate 		data = kmem_alloc(datasz,
17357c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
17367c478bd9Sstevel@tonic-gate 	}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	shstrtab_dump(&shstrtab, data);
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	if ((error = core_write(vp, UIO_SYSSPACE, *doffsetp,
17417c478bd9Sstevel@tonic-gate 	    data, v[i].sh_size, rlimit, credp)) != 0)
17427c478bd9Sstevel@tonic-gate 		goto done;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	*doffsetp += v[i].sh_size;
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate done:
17477c478bd9Sstevel@tonic-gate 	if (data != NULL)
17487c478bd9Sstevel@tonic-gate 		kmem_free(data, datasz);
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	return (error);
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate int
17547c478bd9Sstevel@tonic-gate elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
17557c478bd9Sstevel@tonic-gate     core_content_t content)
17567c478bd9Sstevel@tonic-gate {
17577c478bd9Sstevel@tonic-gate 	offset_t poffset, soffset;
17587c478bd9Sstevel@tonic-gate 	Off doffset;
17597c478bd9Sstevel@tonic-gate 	int error, i, nphdrs, nshdrs;
17607c478bd9Sstevel@tonic-gate 	int overflow = 0;
17617c478bd9Sstevel@tonic-gate 	struct seg *seg;
17627c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
17637c478bd9Sstevel@tonic-gate 	union {
17647c478bd9Sstevel@tonic-gate 		Ehdr ehdr;
17657c478bd9Sstevel@tonic-gate 		Phdr phdr[1];
17667c478bd9Sstevel@tonic-gate 		Shdr shdr[1];
17677c478bd9Sstevel@tonic-gate 	} *bigwad;
17687c478bd9Sstevel@tonic-gate 	size_t bigsize;
17697c478bd9Sstevel@tonic-gate 	size_t phdrsz, shdrsz;
17707c478bd9Sstevel@tonic-gate 	Ehdr *ehdr;
17717c478bd9Sstevel@tonic-gate 	Phdr *v;
17727c478bd9Sstevel@tonic-gate 	caddr_t brkbase;
17737c478bd9Sstevel@tonic-gate 	size_t brksize;
17747c478bd9Sstevel@tonic-gate 	caddr_t stkbase;
17757c478bd9Sstevel@tonic-gate 	size_t stksize;
17767c478bd9Sstevel@tonic-gate 	int ntries = 0;
1777f971a346SBryan Cantrill 	klwp_t *lwp = ttolwp(curthread);
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate top:
17807c478bd9Sstevel@tonic-gate 	/*
17817c478bd9Sstevel@tonic-gate 	 * Make sure we have everything we need (registers, etc.).
17827c478bd9Sstevel@tonic-gate 	 * All other lwps have already stopped and are in an orderly state.
17837c478bd9Sstevel@tonic-gate 	 */
17847c478bd9Sstevel@tonic-gate 	ASSERT(p == ttoproc(curthread));
17857c478bd9Sstevel@tonic-gate 	prstop(0, 0);
17867c478bd9Sstevel@tonic-gate 
1787dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
17887c478bd9Sstevel@tonic-gate 	nphdrs = prnsegs(as, 0) + 2;		/* two CORE note sections */
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	/*
17917c478bd9Sstevel@tonic-gate 	 * Count the number of section headers we're going to need.
17927c478bd9Sstevel@tonic-gate 	 */
17937c478bd9Sstevel@tonic-gate 	nshdrs = 0;
17947c478bd9Sstevel@tonic-gate 	if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
17957c478bd9Sstevel@tonic-gate 		(void) process_scns(content, p, credp, NULL, NULL, NULL, 0,
17967c478bd9Sstevel@tonic-gate 		    NULL, &nshdrs);
17977c478bd9Sstevel@tonic-gate 	}
1798dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
17997c478bd9Sstevel@tonic-gate 
180030da1432Sahl 	ASSERT(nshdrs == 0 || nshdrs > 1);
180130da1432Sahl 
180230da1432Sahl 	/*
180330da1432Sahl 	 * The core file contents may required zero section headers, but if
180430da1432Sahl 	 * we overflow the 16 bits allotted to the program header count in
180530da1432Sahl 	 * the ELF header, we'll need that program header at index zero.
180630da1432Sahl 	 */
180730da1432Sahl 	if (nshdrs == 0 && nphdrs >= PN_XNUM)
180830da1432Sahl 		nshdrs = 1;
180930da1432Sahl 
18107c478bd9Sstevel@tonic-gate 	phdrsz = nphdrs * sizeof (Phdr);
18117c478bd9Sstevel@tonic-gate 	shdrsz = nshdrs * sizeof (Shdr);
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	bigsize = MAX(sizeof (*bigwad), MAX(phdrsz, shdrsz));
18147c478bd9Sstevel@tonic-gate 	bigwad = kmem_alloc(bigsize, KM_SLEEP);
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	ehdr = &bigwad->ehdr;
18177c478bd9Sstevel@tonic-gate 	bzero(ehdr, sizeof (*ehdr));
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG0] = ELFMAG0;
18207c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG1] = ELFMAG1;
18217c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG2] = ELFMAG2;
18227c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_MAG3] = ELFMAG3;
18237c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_CLASS] = ELFCLASS;
18247c478bd9Sstevel@tonic-gate 	ehdr->e_type = ET_CORE;
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate #if !defined(_LP64) || defined(_ELF32_COMPAT)
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate #if defined(__sparc)
18297c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
18307c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_SPARC;
18317c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__i386_COMPAT)
18327c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
18337c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_386;
18347c478bd9Sstevel@tonic-gate #else
18357c478bd9Sstevel@tonic-gate #error "no recognized machine type is defined"
18367c478bd9Sstevel@tonic-gate #endif
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate #else	/* !defined(_LP64) || defined(_ELF32_COMPAT) */
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate #if defined(__sparc)
18417c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
18427c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_SPARCV9;
18437c478bd9Sstevel@tonic-gate #elif defined(__amd64)
18447c478bd9Sstevel@tonic-gate 	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
18457c478bd9Sstevel@tonic-gate 	ehdr->e_machine = EM_AMD64;
18467c478bd9Sstevel@tonic-gate #else
18477c478bd9Sstevel@tonic-gate #error "no recognized 64-bit machine type is defined"
18487c478bd9Sstevel@tonic-gate #endif
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate #endif	/* !defined(_LP64) || defined(_ELF32_COMPAT) */
18517c478bd9Sstevel@tonic-gate 
185230da1432Sahl 	/*
185330da1432Sahl 	 * If the count of program headers or section headers or the index
185430da1432Sahl 	 * of the section string table can't fit in the mere 16 bits
185530da1432Sahl 	 * shortsightedly allotted to them in the ELF header, we use the
185630da1432Sahl 	 * extended formats and put the real values in the section header
185730da1432Sahl 	 * as index 0.
185830da1432Sahl 	 */
18597c478bd9Sstevel@tonic-gate 	ehdr->e_version = EV_CURRENT;
18607c478bd9Sstevel@tonic-gate 	ehdr->e_ehsize = sizeof (Ehdr);
186130da1432Sahl 
186230da1432Sahl 	if (nphdrs >= PN_XNUM)
186330da1432Sahl 		ehdr->e_phnum = PN_XNUM;
186430da1432Sahl 	else
18657c478bd9Sstevel@tonic-gate 		ehdr->e_phnum = (unsigned short)nphdrs;
18667c478bd9Sstevel@tonic-gate 
186730da1432Sahl 	ehdr->e_phoff = sizeof (Ehdr);
186830da1432Sahl 	ehdr->e_phentsize = sizeof (Phdr);
186930da1432Sahl 
18707c478bd9Sstevel@tonic-gate 	if (nshdrs > 0) {
187130da1432Sahl 		if (nshdrs >= SHN_LORESERVE)
187230da1432Sahl 			ehdr->e_shnum = 0;
187330da1432Sahl 		else
18747c478bd9Sstevel@tonic-gate 			ehdr->e_shnum = (unsigned short)nshdrs;
187530da1432Sahl 
187630da1432Sahl 		if (nshdrs - 1 >= SHN_LORESERVE)
187730da1432Sahl 			ehdr->e_shstrndx = SHN_XINDEX;
187830da1432Sahl 		else
187930da1432Sahl 			ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
188030da1432Sahl 
188130da1432Sahl 		ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs;
188230da1432Sahl 		ehdr->e_shentsize = sizeof (Shdr);
18837c478bd9Sstevel@tonic-gate 	}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
18867c478bd9Sstevel@tonic-gate 	    sizeof (Ehdr), rlimit, credp))
18877c478bd9Sstevel@tonic-gate 		goto done;
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	poffset = sizeof (Ehdr);
18907c478bd9Sstevel@tonic-gate 	soffset = sizeof (Ehdr) + phdrsz;
18917c478bd9Sstevel@tonic-gate 	doffset = sizeof (Ehdr) + phdrsz + shdrsz;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	v = &bigwad->phdr[0];
18947c478bd9Sstevel@tonic-gate 	bzero(v, phdrsz);
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 	setup_old_note_header(&v[0], p);
18977c478bd9Sstevel@tonic-gate 	v[0].p_offset = doffset = roundup(doffset, sizeof (Word));
18987c478bd9Sstevel@tonic-gate 	doffset += v[0].p_filesz;
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	setup_note_header(&v[1], p);
19017c478bd9Sstevel@tonic-gate 	v[1].p_offset = doffset = roundup(doffset, sizeof (Word));
19027c478bd9Sstevel@tonic-gate 	doffset += v[1].p_filesz;
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	brkbase = p->p_brkbase;
19077c478bd9Sstevel@tonic-gate 	brksize = p->p_brksize;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	stkbase = p->p_usrstack - p->p_stksize;
19107c478bd9Sstevel@tonic-gate 	stksize = p->p_stksize;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
19137c478bd9Sstevel@tonic-gate 
1914dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_WRITER);
19157c478bd9Sstevel@tonic-gate 	i = 2;
19167c478bd9Sstevel@tonic-gate 	for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
19177c478bd9Sstevel@tonic-gate 		caddr_t eaddr = seg->s_base + pr_getsegsize(seg, 0);
19187c478bd9Sstevel@tonic-gate 		caddr_t saddr, naddr;
19197c478bd9Sstevel@tonic-gate 		void *tmp = NULL;
19207c478bd9Sstevel@tonic-gate 		extern struct seg_ops segspt_shmops;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 		for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
19237c478bd9Sstevel@tonic-gate 			uint_t prot;
19247c478bd9Sstevel@tonic-gate 			size_t size;
19257c478bd9Sstevel@tonic-gate 			int type;
19267c478bd9Sstevel@tonic-gate 			vnode_t *mvp;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 			prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
19297c478bd9Sstevel@tonic-gate 			prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
19307c478bd9Sstevel@tonic-gate 			if ((size = (size_t)(naddr - saddr)) == 0)
19317c478bd9Sstevel@tonic-gate 				continue;
19327c478bd9Sstevel@tonic-gate 			if (i == nphdrs) {
19337c478bd9Sstevel@tonic-gate 				overflow++;
19347c478bd9Sstevel@tonic-gate 				continue;
19357c478bd9Sstevel@tonic-gate 			}
19367c478bd9Sstevel@tonic-gate 			v[i].p_type = PT_LOAD;
19377c478bd9Sstevel@tonic-gate 			v[i].p_vaddr = (Addr)(uintptr_t)saddr;
19387c478bd9Sstevel@tonic-gate 			v[i].p_memsz = size;
19397c478bd9Sstevel@tonic-gate 			if (prot & PROT_READ)
19407c478bd9Sstevel@tonic-gate 				v[i].p_flags |= PF_R;
19417c478bd9Sstevel@tonic-gate 			if (prot & PROT_WRITE)
19427c478bd9Sstevel@tonic-gate 				v[i].p_flags |= PF_W;
19437c478bd9Sstevel@tonic-gate 			if (prot & PROT_EXEC)
19447c478bd9Sstevel@tonic-gate 				v[i].p_flags |= PF_X;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 			/*
19477c478bd9Sstevel@tonic-gate 			 * Figure out which mappings to include in the core.
19487c478bd9Sstevel@tonic-gate 			 */
19497c478bd9Sstevel@tonic-gate 			type = SEGOP_GETTYPE(seg, saddr);
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 			if (saddr == stkbase && size == stksize) {
19527c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_STACK))
19537c478bd9Sstevel@tonic-gate 					goto exclude;
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 			} else if (saddr == brkbase && size == brksize) {
19567c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_HEAP))
19577c478bd9Sstevel@tonic-gate 					goto exclude;
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 			} else if (seg->s_ops == &segspt_shmops) {
19607c478bd9Sstevel@tonic-gate 				if (type & MAP_NORESERVE) {
19617c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_DISM))
19627c478bd9Sstevel@tonic-gate 						goto exclude;
19637c478bd9Sstevel@tonic-gate 				} else {
19647c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_ISM))
19657c478bd9Sstevel@tonic-gate 						goto exclude;
19667c478bd9Sstevel@tonic-gate 				}
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 			} else if (seg->s_ops != &segvn_ops) {
19697c478bd9Sstevel@tonic-gate 				goto exclude;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 			} else if (type & MAP_SHARED) {
19727c478bd9Sstevel@tonic-gate 				if (shmgetid(p, saddr) != SHMID_NONE) {
19737c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHM))
19747c478bd9Sstevel@tonic-gate 						goto exclude;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 				} else if (SEGOP_GETVP(seg, seg->s_base,
19777c478bd9Sstevel@tonic-gate 				    &mvp) != 0 || mvp == NULL ||
19787c478bd9Sstevel@tonic-gate 				    mvp->v_type != VREG) {
19797c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHANON))
19807c478bd9Sstevel@tonic-gate 						goto exclude;
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 				} else {
19837c478bd9Sstevel@tonic-gate 					if (!(content & CC_CONTENT_SHFILE))
19847c478bd9Sstevel@tonic-gate 						goto exclude;
19857c478bd9Sstevel@tonic-gate 				}
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 			} else if (SEGOP_GETVP(seg, seg->s_base, &mvp) != 0 ||
19887c478bd9Sstevel@tonic-gate 			    mvp == NULL || mvp->v_type != VREG) {
19897c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_ANON))
19907c478bd9Sstevel@tonic-gate 					goto exclude;
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 			} else if (prot == (PROT_READ | PROT_EXEC)) {
19937c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_TEXT))
19947c478bd9Sstevel@tonic-gate 					goto exclude;
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 			} else if (prot == PROT_READ) {
19977c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_RODATA))
19987c478bd9Sstevel@tonic-gate 					goto exclude;
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 			} else {
20017c478bd9Sstevel@tonic-gate 				if (!(content & CC_CONTENT_DATA))
20027c478bd9Sstevel@tonic-gate 					goto exclude;
20037c478bd9Sstevel@tonic-gate 			}
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 			doffset = roundup(doffset, sizeof (Word));
20067c478bd9Sstevel@tonic-gate 			v[i].p_offset = doffset;
20077c478bd9Sstevel@tonic-gate 			v[i].p_filesz = size;
20087c478bd9Sstevel@tonic-gate 			doffset += size;
20097c478bd9Sstevel@tonic-gate exclude:
20107c478bd9Sstevel@tonic-gate 			i++;
20117c478bd9Sstevel@tonic-gate 		}
20127c478bd9Sstevel@tonic-gate 		ASSERT(tmp == NULL);
20137c478bd9Sstevel@tonic-gate 	}
2014dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	if (overflow || i != nphdrs) {
20177c478bd9Sstevel@tonic-gate 		if (ntries++ == 0) {
20187c478bd9Sstevel@tonic-gate 			kmem_free(bigwad, bigsize);
201914c26162SMita Solanky 			overflow = 0;
20207c478bd9Sstevel@tonic-gate 			goto top;
20217c478bd9Sstevel@tonic-gate 		}
20227c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "elfcore: core dump failed for "
20237c478bd9Sstevel@tonic-gate 		    "process %d; address space is changing", p->p_pid);
20247c478bd9Sstevel@tonic-gate 		error = EIO;
20257c478bd9Sstevel@tonic-gate 		goto done;
20267c478bd9Sstevel@tonic-gate 	}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	if ((error = core_write(vp, UIO_SYSSPACE, poffset,
20297c478bd9Sstevel@tonic-gate 	    v, phdrsz, rlimit, credp)) != 0)
20307c478bd9Sstevel@tonic-gate 		goto done;
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	if ((error = write_old_elfnotes(p, sig, vp, v[0].p_offset, rlimit,
20337c478bd9Sstevel@tonic-gate 	    credp)) != 0)
20347c478bd9Sstevel@tonic-gate 		goto done;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	if ((error = write_elfnotes(p, sig, vp, v[1].p_offset, rlimit,
20377c478bd9Sstevel@tonic-gate 	    credp, content)) != 0)
20387c478bd9Sstevel@tonic-gate 		goto done;
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	for (i = 2; i < nphdrs; i++) {
2041f971a346SBryan Cantrill 		prkillinfo_t killinfo;
2042f971a346SBryan Cantrill 		sigqueue_t *sq;
2043f971a346SBryan Cantrill 		int sig, j;
2044f971a346SBryan Cantrill 
20457c478bd9Sstevel@tonic-gate 		if (v[i].p_filesz == 0)
20467c478bd9Sstevel@tonic-gate 			continue;
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 		/*
20497c478bd9Sstevel@tonic-gate 		 * If dumping out this segment fails, rather than failing
20507c478bd9Sstevel@tonic-gate 		 * the core dump entirely, we reset the size of the mapping
20517c478bd9Sstevel@tonic-gate 		 * to zero to indicate that the data is absent from the core
20527c478bd9Sstevel@tonic-gate 		 * file and or in the PF_SUNW_FAILURE flag to differentiate
20537c478bd9Sstevel@tonic-gate 		 * this from mappings that were excluded due to the core file
20547c478bd9Sstevel@tonic-gate 		 * content settings.
20557c478bd9Sstevel@tonic-gate 		 */
20567c478bd9Sstevel@tonic-gate 		if ((error = core_seg(p, vp, v[i].p_offset,
20577c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz,
2058f971a346SBryan Cantrill 		    rlimit, credp)) == 0) {
2059f971a346SBryan Cantrill 			continue;
2060f971a346SBryan Cantrill 		}
20617c478bd9Sstevel@tonic-gate 
2062f971a346SBryan Cantrill 		if ((sig = lwp->lwp_cursig) == 0) {
20637c478bd9Sstevel@tonic-gate 			/*
2064f971a346SBryan Cantrill 			 * We failed due to something other than a signal.
20657c478bd9Sstevel@tonic-gate 			 * Since the space reserved for the segment is now
20667c478bd9Sstevel@tonic-gate 			 * unused, we stash the errno in the first four
20677c478bd9Sstevel@tonic-gate 			 * bytes. This undocumented interface will let us
20687c478bd9Sstevel@tonic-gate 			 * understand the nature of the failure.
20697c478bd9Sstevel@tonic-gate 			 */
20707c478bd9Sstevel@tonic-gate 			(void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
20717c478bd9Sstevel@tonic-gate 			    &error, sizeof (error), rlimit, credp);
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 			v[i].p_filesz = 0;
20747c478bd9Sstevel@tonic-gate 			v[i].p_flags |= PF_SUNW_FAILURE;
20757c478bd9Sstevel@tonic-gate 			if ((error = core_write(vp, UIO_SYSSPACE,
20767c478bd9Sstevel@tonic-gate 			    poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]),
20777c478bd9Sstevel@tonic-gate 			    rlimit, credp)) != 0)
20787c478bd9Sstevel@tonic-gate 				goto done;
2079f971a346SBryan Cantrill 
2080f971a346SBryan Cantrill 			continue;
20817c478bd9Sstevel@tonic-gate 		}
2082f971a346SBryan Cantrill 
2083f971a346SBryan Cantrill 		/*
2084f971a346SBryan Cantrill 		 * We took a signal.  We want to abort the dump entirely, but
2085f971a346SBryan Cantrill 		 * we also want to indicate what failed and why.  We therefore
2086f971a346SBryan Cantrill 		 * use the space reserved for the first failing segment to
2087f971a346SBryan Cantrill 		 * write our error (which, for purposes of compatability with
2088f971a346SBryan Cantrill 		 * older core dump readers, we set to EINTR) followed by any
2089f971a346SBryan Cantrill 		 * siginfo associated with the signal.
2090f971a346SBryan Cantrill 		 */
2091f971a346SBryan Cantrill 		bzero(&killinfo, sizeof (killinfo));
2092f971a346SBryan Cantrill 		killinfo.prk_error = EINTR;
2093f971a346SBryan Cantrill 
2094f971a346SBryan Cantrill 		sq = sig == SIGKILL ? curproc->p_killsqp : lwp->lwp_curinfo;
2095f971a346SBryan Cantrill 
2096f971a346SBryan Cantrill 		if (sq != NULL) {
2097f971a346SBryan Cantrill 			bcopy(&sq->sq_info, &killinfo.prk_info,
2098ea260350SBryan Cantrill 			    sizeof (sq->sq_info));
2099f971a346SBryan Cantrill 		} else {
2100f971a346SBryan Cantrill 			killinfo.prk_info.si_signo = lwp->lwp_cursig;
2101f971a346SBryan Cantrill 			killinfo.prk_info.si_code = SI_NOINFO;
2102f971a346SBryan Cantrill 		}
2103f971a346SBryan Cantrill 
2104f971a346SBryan Cantrill #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
2105f971a346SBryan Cantrill 		/*
2106f971a346SBryan Cantrill 		 * If this is a 32-bit process, we need to translate from the
2107f971a346SBryan Cantrill 		 * native siginfo to the 32-bit variant.  (Core readers must
2108f971a346SBryan Cantrill 		 * always have the same data model as their target or must
2109f971a346SBryan Cantrill 		 * be aware of -- and compensate for -- data model differences.)
2110f971a346SBryan Cantrill 		 */
2111f971a346SBryan Cantrill 		if (curproc->p_model == DATAMODEL_ILP32) {
2112f971a346SBryan Cantrill 			siginfo32_t si32;
2113f971a346SBryan Cantrill 
2114f971a346SBryan Cantrill 			siginfo_kto32((k_siginfo_t *)&killinfo.prk_info, &si32);
2115f971a346SBryan Cantrill 			bcopy(&si32, &killinfo.prk_info, sizeof (si32));
2116f971a346SBryan Cantrill 		}
2117f971a346SBryan Cantrill #endif
2118f971a346SBryan Cantrill 
2119f971a346SBryan Cantrill 		(void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
2120f971a346SBryan Cantrill 		    &killinfo, sizeof (killinfo), rlimit, credp);
2121f971a346SBryan Cantrill 
2122f971a346SBryan Cantrill 		/*
2123f971a346SBryan Cantrill 		 * For the segment on which we took the signal, indicate that
2124f971a346SBryan Cantrill 		 * its data now refers to a siginfo.
2125f971a346SBryan Cantrill 		 */
2126f971a346SBryan Cantrill 		v[i].p_filesz = 0;
2127f971a346SBryan Cantrill 		v[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
2128f971a346SBryan Cantrill 		    PF_SUNW_SIGINFO;
2129f971a346SBryan Cantrill 
2130f971a346SBryan Cantrill 		/*
2131f971a346SBryan Cantrill 		 * And for every other segment, indicate that its absence
2132f971a346SBryan Cantrill 		 * is due to a signal.
2133f971a346SBryan Cantrill 		 */
2134f971a346SBryan Cantrill 		for (j = i + 1; j < nphdrs; j++) {
2135f971a346SBryan Cantrill 			v[j].p_filesz = 0;
2136f971a346SBryan Cantrill 			v[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
2137f971a346SBryan Cantrill 		}
2138f971a346SBryan Cantrill 
2139f971a346SBryan Cantrill 		/*
2140f971a346SBryan Cantrill 		 * Finally, write out our modified program headers.
2141f971a346SBryan Cantrill 		 */
2142f971a346SBryan Cantrill 		if ((error = core_write(vp, UIO_SYSSPACE,
2143f971a346SBryan Cantrill 		    poffset + sizeof (v[i]) * i, &v[i],
2144f971a346SBryan Cantrill 		    sizeof (v[i]) * (nphdrs - i), rlimit, credp)) != 0)
2145f971a346SBryan Cantrill 			goto done;
2146f971a346SBryan Cantrill 
2147f971a346SBryan Cantrill 		break;
21487c478bd9Sstevel@tonic-gate 	}
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	if (nshdrs > 0) {
21517c478bd9Sstevel@tonic-gate 		bzero(&bigwad->shdr[0], shdrsz);
21527c478bd9Sstevel@tonic-gate 
215330da1432Sahl 		if (nshdrs >= SHN_LORESERVE)
215430da1432Sahl 			bigwad->shdr[0].sh_size = nshdrs;
215530da1432Sahl 
215630da1432Sahl 		if (nshdrs - 1 >= SHN_LORESERVE)
215730da1432Sahl 			bigwad->shdr[0].sh_link = nshdrs - 1;
215830da1432Sahl 
215930da1432Sahl 		if (nphdrs >= PN_XNUM)
216030da1432Sahl 			bigwad->shdr[0].sh_info = nphdrs;
216130da1432Sahl 
216230da1432Sahl 		if (nshdrs > 1) {
2163dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
21647c478bd9Sstevel@tonic-gate 			if ((error = process_scns(content, p, credp, vp,
216530da1432Sahl 			    &bigwad->shdr[0], nshdrs, rlimit, &doffset,
216630da1432Sahl 			    NULL)) != 0) {
2167dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_EXIT(as);
21687c478bd9Sstevel@tonic-gate 				goto done;
21697c478bd9Sstevel@tonic-gate 			}
2170dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
217130da1432Sahl 		}
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 		if ((error = core_write(vp, UIO_SYSSPACE, soffset,
21747c478bd9Sstevel@tonic-gate 		    &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
21757c478bd9Sstevel@tonic-gate 			goto done;
21767c478bd9Sstevel@tonic-gate 	}
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate done:
21797c478bd9Sstevel@tonic-gate 	kmem_free(bigwad, bigsize);
21807c478bd9Sstevel@tonic-gate 	return (error);
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate #ifndef	_ELF32_COMPAT
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate static struct execsw esw = {
21867c478bd9Sstevel@tonic-gate #ifdef	_LP64
21877c478bd9Sstevel@tonic-gate 	elf64magicstr,
21887c478bd9Sstevel@tonic-gate #else	/* _LP64 */
21897c478bd9Sstevel@tonic-gate 	elf32magicstr,
21907c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
21917c478bd9Sstevel@tonic-gate 	0,
21927c478bd9Sstevel@tonic-gate 	5,
21937c478bd9Sstevel@tonic-gate 	elfexec,
21947c478bd9Sstevel@tonic-gate 	elfcore
21957c478bd9Sstevel@tonic-gate };
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate static struct modlexec modlexec = {
2198a0de58d6SRoger A. Faulkner 	&mod_execops, "exec module for elf", &esw
21997c478bd9Sstevel@tonic-gate };
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate #ifdef	_LP64
22027c478bd9Sstevel@tonic-gate extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args,
22037c478bd9Sstevel@tonic-gate 			intpdata_t *idatap, int level, long *execsz,
22049acbbeafSnn35248 			int setid, caddr_t exec_file, cred_t *cred,
22059acbbeafSnn35248 			int brand_action);
22067c478bd9Sstevel@tonic-gate extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp,
22077c478bd9Sstevel@tonic-gate 			rlim64_t rlimit, int sig, core_content_t content);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate static struct execsw esw32 = {
22107c478bd9Sstevel@tonic-gate 	elf32magicstr,
22117c478bd9Sstevel@tonic-gate 	0,
22127c478bd9Sstevel@tonic-gate 	5,
22137c478bd9Sstevel@tonic-gate 	elf32exec,
22147c478bd9Sstevel@tonic-gate 	elf32core
22157c478bd9Sstevel@tonic-gate };
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate static struct modlexec modlexec32 = {
22187c478bd9Sstevel@tonic-gate 	&mod_execops, "32-bit exec module for elf", &esw32
22197c478bd9Sstevel@tonic-gate };
22207c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
22237c478bd9Sstevel@tonic-gate 	MODREV_1,
22247c478bd9Sstevel@tonic-gate 	(void *)&modlexec,
22257c478bd9Sstevel@tonic-gate #ifdef	_LP64
22267c478bd9Sstevel@tonic-gate 	(void *)&modlexec32,
22277c478bd9Sstevel@tonic-gate #endif	/* _LP64 */
22287c478bd9Sstevel@tonic-gate 	NULL
22297c478bd9Sstevel@tonic-gate };
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate int
22327c478bd9Sstevel@tonic-gate _init(void)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate int
22387c478bd9Sstevel@tonic-gate _fini(void)
22397c478bd9Sstevel@tonic-gate {
22407c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
22417c478bd9Sstevel@tonic-gate }
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate int
22447c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
22457c478bd9Sstevel@tonic-gate {
22467c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
22477c478bd9Sstevel@tonic-gate }
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate #endif	/* !_ELF32_COMPAT */
2250