xref: /netbsd-src/sys/compat/linux/common/linux_exec_elf32.c (revision 47cd9b85d6a332197ded483a60806624c9c28d24)
1*47cd9b85Sjdolecek /*	$NetBSD: linux_exec_elf32.c,v 1.60 2002/11/29 19:13:16 jdolecek Exp $	*/
28fb507a3Schristos 
38fb507a3Schristos /*-
4ac10cf69Smanu  * Copyright (c) 1995, 1998, 2000, 2001 The NetBSD Foundation, Inc.
58fb507a3Schristos  * All rights reserved.
68fb507a3Schristos  *
78fb507a3Schristos  * This code is derived from software contributed to The NetBSD Foundation
8ac10cf69Smanu  * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and
9ac10cf69Smanu  * Emmanuel Dreyfus.
108fb507a3Schristos  *
118fb507a3Schristos  * Redistribution and use in source and binary forms, with or without
128fb507a3Schristos  * modification, are permitted provided that the following conditions
138fb507a3Schristos  * are met:
148fb507a3Schristos  * 1. Redistributions of source code must retain the above copyright
158fb507a3Schristos  *    notice, this list of conditions and the following disclaimer.
168fb507a3Schristos  * 2. Redistributions in binary form must reproduce the above copyright
178fb507a3Schristos  *    notice, this list of conditions and the following disclaimer in the
188fb507a3Schristos  *    documentation and/or other materials provided with the distribution.
198fb507a3Schristos  * 3. All advertising materials mentioning features or use of this software
208fb507a3Schristos  *    must display the following acknowledgement:
218fb507a3Schristos  *	This product includes software developed by the NetBSD
228fb507a3Schristos  *	Foundation, Inc. and its contributors.
238fb507a3Schristos  * 4. Neither the name of The NetBSD Foundation nor the names of its
248fb507a3Schristos  *    contributors may be used to endorse or promote products derived
258fb507a3Schristos  *    from this software without specific prior written permission.
268fb507a3Schristos  *
278fb507a3Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
288fb507a3Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
298fb507a3Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
308fb507a3Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
318fb507a3Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
328fb507a3Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
338fb507a3Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
348fb507a3Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
358fb507a3Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
368fb507a3Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
378fb507a3Schristos  * POSSIBILITY OF SUCH DAMAGE.
388fb507a3Schristos  */
393bf459f3Sfvdl 
403bf459f3Sfvdl /*
41fb777788Sfvdl  * based on exec_aout.c, sunos_exec.c and svr4_exec.c
423bf459f3Sfvdl  */
433bf459f3Sfvdl 
44dab6ef8bSlukem #include <sys/cdefs.h>
45*47cd9b85Sjdolecek __KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.60 2002/11/29 19:13:16 jdolecek Exp $");
46dab6ef8bSlukem 
47f7ac1bd3Serh #ifndef ELFSIZE
48ea0cda2cSchristos /* XXX should die */
49ea0cda2cSchristos #define	ELFSIZE		32
50f7ac1bd3Serh #endif
519c3e274cScgd 
523bf459f3Sfvdl #include <sys/param.h>
533bf459f3Sfvdl #include <sys/systm.h>
543bf459f3Sfvdl #include <sys/kernel.h>
553bf459f3Sfvdl #include <sys/proc.h>
563bf459f3Sfvdl #include <sys/malloc.h>
573bf459f3Sfvdl #include <sys/namei.h>
583bf459f3Sfvdl #include <sys/vnode.h>
59151fa70fSchristos #include <sys/mount.h>
60d551a4edSchristos #include <sys/exec.h>
61c4aaa600Sfvdl #include <sys/exec_elf.h>
62cee43b67Sjdolecek #include <sys/stat.h>
633bf459f3Sfvdl 
643bf459f3Sfvdl #include <sys/mman.h>
65151fa70fSchristos #include <sys/syscallargs.h>
66151fa70fSchristos 
673bf459f3Sfvdl #include <machine/cpu.h>
683bf459f3Sfvdl #include <machine/reg.h>
693bf459f3Sfvdl 
70908291d2Schristos #include <compat/linux/common/linux_types.h>
71908291d2Schristos #include <compat/linux/common/linux_signal.h>
72908291d2Schristos #include <compat/linux/common/linux_util.h>
73908291d2Schristos #include <compat/linux/common/linux_exec.h>
74908291d2Schristos #include <compat/linux/common/linux_machdep.h>
753bf459f3Sfvdl 
76908291d2Schristos #include <compat/linux/linux_syscallargs.h>
77908291d2Schristos #include <compat/linux/linux_syscall.h>
78fc7cfb5fSfvdl 
79f7ac1bd3Serh static int ELFNAME2(linux,signature) __P((struct proc *, struct exec_package *,
80b29180b2Smycroft 	Elf_Ehdr *, char *));
81f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
82f7ac1bd3Serh static int ELFNAME2(linux,gcc_signature) __P((struct proc *p,
83f7ac1bd3Serh 	struct exec_package *, Elf_Ehdr *));
84f7ac1bd3Serh #endif
85ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
86ac10cf69Smanu static int ELFNAME2(linux,atexit_signature) __P((struct proc *p,
87ac10cf69Smanu 	struct exec_package *, Elf_Ehdr *));
88ac10cf69Smanu #endif
89ac10cf69Smanu 
9065fc8539Schristos #ifdef DEBUG_LINUX
9165fc8539Schristos #define DPRINTF(a)	uprintf a
9265fc8539Schristos #else
9365fc8539Schristos #define DPRINTF(a)
9465fc8539Schristos #endif
9565fc8539Schristos 
96ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
97ac10cf69Smanu /*
98ac10cf69Smanu  * On the PowerPC, statically linked Linux binaries are not recognized
99ac10cf69Smanu  * by linux_signature nor by linux_gcc_signature. Fortunately, thoses
100ac10cf69Smanu  * binaries features a __libc_atexit ELF section. We therefore assume we
101ac10cf69Smanu  * have a Linux binary if we find this section.
102ac10cf69Smanu  */
103ac10cf69Smanu static int
104ac10cf69Smanu ELFNAME2(linux,atexit_signature)(p, epp, eh)
105ac10cf69Smanu 	struct proc *p;
106ac10cf69Smanu 	struct exec_package *epp;
107ac10cf69Smanu 	Elf_Ehdr *eh;
108ac10cf69Smanu {
109ac10cf69Smanu 	size_t shsize;
110ac10cf69Smanu 	int	strndx;
111ac10cf69Smanu 	size_t i;
112ac10cf69Smanu 	static const char signature[] = "__libc_atexit";
113ac10cf69Smanu 	char* strtable;
114ac10cf69Smanu 	Elf_Shdr *sh;
115ac10cf69Smanu 
116ac10cf69Smanu 	int error;
117ac10cf69Smanu 
118ac10cf69Smanu 	/*
119ac10cf69Smanu 	 * load the section header table
120ac10cf69Smanu 	 */
121ac10cf69Smanu 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
122ac10cf69Smanu 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
12397c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
124ac10cf69Smanu 	if (error)
125ac10cf69Smanu 		goto out;
126ac10cf69Smanu 
127ac10cf69Smanu 	/*
128ac10cf69Smanu 	 * Now let's find the string table. If it does not exists, give up.
129ac10cf69Smanu 	 */
130ac10cf69Smanu 	strndx = (int)(eh->e_shstrndx);
131ac10cf69Smanu 	if (strndx == SHN_UNDEF) {
132ac10cf69Smanu 		error = ENOEXEC;
133ac10cf69Smanu 		goto out;
134ac10cf69Smanu 	}
135ac10cf69Smanu 
136ac10cf69Smanu 	/*
13797c9d7a9Schristos 	 * strndx is the index in section header table of the string table
13897c9d7a9Schristos 	 * section get the whole string table in strtable, and then we get access to the names
139ac10cf69Smanu 	 * s->sh_name is the offset of the section name in strtable.
140ac10cf69Smanu 	 */
141ac10cf69Smanu 	strtable = malloc(sh[strndx].sh_size, M_TEMP, M_WAITOK);
14297c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, sh[strndx].sh_offset, strtable,
14397c9d7a9Schristos 	    sh[strndx].sh_size);
144ac10cf69Smanu 	if (error)
145ac10cf69Smanu 		goto out;
146ac10cf69Smanu 
147ac10cf69Smanu 	for (i = 0; i < eh->e_shnum; i++) {
148ac10cf69Smanu 		Elf_Shdr *s = &sh[i];
149ac10cf69Smanu 		if (!memcmp((void*)(&(strtable[s->sh_name])), signature,
150ac10cf69Smanu 				sizeof(signature))) {
15165fc8539Schristos 			DPRINTF(("linux_atexit_sig=%s\n",
15265fc8539Schristos 			    &(strtable[s->sh_name])));
153ac10cf69Smanu 			error = 0;
154ac10cf69Smanu 			goto out;
155ac10cf69Smanu 		}
156ac10cf69Smanu 	}
157ac10cf69Smanu 	error = ENOEXEC;
158ac10cf69Smanu 
159ac10cf69Smanu out:
160ac10cf69Smanu 	free(sh, M_TEMP);
161ac10cf69Smanu 	free(strtable, M_TEMP);
162ac10cf69Smanu 	return (error);
163ac10cf69Smanu }
164ac10cf69Smanu #endif
165f7ac1bd3Serh 
166f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
1674d9a6e09Schristos /*
1684d9a6e09Schristos  * Take advantage of the fact that all the linux binaries are compiled
1694d9a6e09Schristos  * with gcc, and gcc sticks in the comment field a signature. Note that
1704d9a6e09Schristos  * on SVR4 binaries, the gcc signature will follow the OS name signature,
1714d9a6e09Schristos  * that will not be a problem. We don't bother to read in the string table,
1724d9a6e09Schristos  * but we check all the progbits headers.
173f7ac1bd3Serh  *
174f7ac1bd3Serh  * XXX This only works in the i386.  On the alpha (at least)
175f7ac1bd3Serh  * XXX we have the same gcc signature which incorrectly identifies
176f7ac1bd3Serh  * XXX NetBSD binaries as Linux.
1774d9a6e09Schristos  */
1784d9a6e09Schristos static int
179f7ac1bd3Serh ELFNAME2(linux,gcc_signature)(p, epp, eh)
180fc7cfb5fSfvdl 	struct proc *p;
181fc7cfb5fSfvdl 	struct exec_package *epp;
182f7ac1bd3Serh 	Elf_Ehdr *eh;
1834d9a6e09Schristos {
184b29180b2Smycroft 	size_t shsize;
1854d9a6e09Schristos 	size_t i;
1864d9a6e09Schristos 	static const char signature[] = "\0GCC: (GNU) ";
1874d9a6e09Schristos 	char buf[sizeof(signature) - 1];
188f7ac1bd3Serh 	Elf_Shdr *sh;
1894d9a6e09Schristos 	int error;
1904d9a6e09Schristos 
191b29180b2Smycroft 	shsize = eh->e_shnum * sizeof(Elf_Shdr);
192f7ac1bd3Serh 	sh = (Elf_Shdr *) malloc(shsize, M_TEMP, M_WAITOK);
19397c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_shoff, sh, shsize);
194b29180b2Smycroft 	if (error)
1954d9a6e09Schristos 		goto out;
1964d9a6e09Schristos 
1974d9a6e09Schristos 	for (i = 0; i < eh->e_shnum; i++) {
198f7ac1bd3Serh 		Elf_Shdr *s = &sh[i];
1994d9a6e09Schristos 
2004d9a6e09Schristos 		/*
2014d9a6e09Schristos 		 * Identify candidates for the comment header;
202d83602c1Schristos 		 * Header cannot have a load address, or flags and
2034d9a6e09Schristos 		 * it must be large enough.
2044d9a6e09Schristos 		 */
205522cbf02Skleink 		if (s->sh_type != SHT_PROGBITS ||
2064d9a6e09Schristos 		    s->sh_addr != 0 ||
2074d9a6e09Schristos 		    s->sh_flags != 0 ||
2084d9a6e09Schristos 		    s->sh_size < sizeof(signature) - 1)
2094d9a6e09Schristos 			continue;
2104d9a6e09Schristos 
21197c9d7a9Schristos 		error = exec_read_from(p, epp->ep_vp, s->sh_offset, buf,
21297c9d7a9Schristos 		    sizeof(signature) - 1);
213b29180b2Smycroft 		if (error)
214b29180b2Smycroft 			continue;
2154d9a6e09Schristos 
216d83602c1Schristos 		/*
217d83602c1Schristos 		 * error is 0, if the signatures match we are done.
218d83602c1Schristos 		 */
21965fc8539Schristos 		DPRINTF(("linux_gcc_sig: sig=%s\n", buf));
220b29180b2Smycroft 		if (!memcmp(buf, signature, sizeof(signature) - 1)) {
221b29180b2Smycroft 			error = 0;
2224d9a6e09Schristos 			goto out;
2234d9a6e09Schristos 		}
224b29180b2Smycroft 	}
225b29180b2Smycroft 	error = ENOEXEC;
2264d9a6e09Schristos 
2274d9a6e09Schristos out:
2284d9a6e09Schristos 	free(sh, M_TEMP);
229b29180b2Smycroft 	return (error);
2304d9a6e09Schristos }
231f7ac1bd3Serh #endif
2324d9a6e09Schristos 
233f7ac1bd3Serh static int
234b29180b2Smycroft ELFNAME2(linux,signature)(p, epp, eh, itp)
2354d9a6e09Schristos 	struct proc *p;
2364d9a6e09Schristos 	struct exec_package *epp;
237f7ac1bd3Serh 	Elf_Ehdr *eh;
238b29180b2Smycroft 	char *itp;
239f7ac1bd3Serh {
240f7ac1bd3Serh 	size_t i;
241f7ac1bd3Serh 	Elf_Phdr *ph;
242f7ac1bd3Serh 	size_t phsize;
243b29180b2Smycroft 	int error;
2446cc14962Schristos 	static const char linux[] = "Linux";
2456cc14962Schristos 
2466cc14962Schristos 	if (eh->e_ident[EI_OSABI] == 3 ||
2476cc14962Schristos 	    memcmp(&eh->e_ident[EI_ABIVERSION], linux, sizeof(linux)) == 0)
2486cc14962Schristos 		return 0;
249f7ac1bd3Serh 
250f7ac1bd3Serh 	phsize = eh->e_phnum * sizeof(Elf_Phdr);
251f7ac1bd3Serh 	ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
25297c9d7a9Schristos 	error = exec_read_from(p, epp->ep_vp, eh->e_phoff, ph, phsize);
253b29180b2Smycroft 	if (error)
254b29180b2Smycroft 		goto out;
255f7ac1bd3Serh 
256f7ac1bd3Serh 	for (i = 0; i < eh->e_phnum; i++) {
257f7ac1bd3Serh 		Elf_Phdr *ephp = &ph[i];
258b29180b2Smycroft 		Elf_Nhdr *np;
259b29180b2Smycroft 		u_int32_t *abi;
260f7ac1bd3Serh 
261b29180b2Smycroft 		if (ephp->p_type != PT_NOTE ||
262b29180b2Smycroft 		    ephp->p_filesz > 1024 ||
263b29180b2Smycroft 		    ephp->p_filesz < sizeof(Elf_Nhdr) + 20)
264f7ac1bd3Serh 			continue;
265f7ac1bd3Serh 
266b29180b2Smycroft 		np = (Elf_Nhdr *)malloc(ephp->p_filesz, M_TEMP, M_WAITOK);
26797c9d7a9Schristos 		error = exec_read_from(p, epp->ep_vp, ephp->p_offset, np,
26897c9d7a9Schristos 		    ephp->p_filesz);
269b29180b2Smycroft 		if (error)
270b29180b2Smycroft 			goto next;
271f7ac1bd3Serh 
272b29180b2Smycroft 		if (np->n_type != ELF_NOTE_TYPE_ABI_TAG ||
273b29180b2Smycroft 		    np->n_namesz != ELF_NOTE_ABI_NAMESZ ||
274b29180b2Smycroft 		    np->n_descsz != ELF_NOTE_ABI_DESCSZ ||
275b29180b2Smycroft 		    memcmp((caddr_t)(np + 1), ELF_NOTE_ABI_NAME,
276b29180b2Smycroft 		    ELF_NOTE_ABI_NAMESZ))
277b29180b2Smycroft 			goto next;
278b29180b2Smycroft 
279b29180b2Smycroft 		/* Make sure the OS is Linux. */
280b29180b2Smycroft 		abi = (u_int32_t *)((caddr_t)np + sizeof(Elf_Nhdr) +
281b29180b2Smycroft 		    np->n_namesz);
282b29180b2Smycroft 		if (abi[0] == ELF_NOTE_ABI_OS_LINUX)
283f7ac1bd3Serh 			error = 0;
284b29180b2Smycroft 		else
285b29180b2Smycroft 			error = ENOEXEC;
286b29180b2Smycroft 		free(np, M_TEMP);
287b29180b2Smycroft 		goto out;
288f7ac1bd3Serh 
289b29180b2Smycroft 	next:
290b29180b2Smycroft 		free(np, M_TEMP);
291f7ac1bd3Serh 		continue;
292f7ac1bd3Serh 	}
293f7ac1bd3Serh 
294b29180b2Smycroft 	/* Check for certain intepreter names. */
295b29180b2Smycroft 	if (itp[0]) {
296b29180b2Smycroft 		if (!strncmp(itp, "/lib/ld-linux", 13) ||
297b29180b2Smycroft 		    !strncmp(itp, "/lib/ld.so.", 11))
298f7ac1bd3Serh 			error = 0;
299b29180b2Smycroft 		else
300b29180b2Smycroft 			error = ENOEXEC;
301b29180b2Smycroft 		goto out;
302f7ac1bd3Serh 	}
303f7ac1bd3Serh 
304f7ac1bd3Serh 	error = ENOEXEC;
305b29180b2Smycroft out:
306f7ac1bd3Serh 	free(ph, M_TEMP);
307b29180b2Smycroft 	return (error);
308f7ac1bd3Serh }
309f7ac1bd3Serh 
310f7ac1bd3Serh int
311f7ac1bd3Serh ELFNAME2(linux,probe)(p, epp, eh, itp, pos)
312f7ac1bd3Serh 	struct proc *p;
313f7ac1bd3Serh 	struct exec_package *epp;
314baae0324Sjdolecek 	void *eh;
315c4aaa600Sfvdl 	char *itp;
316baae0324Sjdolecek 	vaddr_t *pos;
317fc7cfb5fSfvdl {
318fc7cfb5fSfvdl 	int error;
319fc7cfb5fSfvdl 
3208537f76cSmanu 	if (((error = ELFNAME2(linux,signature)(p, epp, eh, itp)) != 0) &&
321f7ac1bd3Serh #ifdef LINUX_GCC_SIGNATURE
3228537f76cSmanu 	    ((error = ELFNAME2(linux,gcc_signature)(p, epp, eh)) != 0) &&
3238537f76cSmanu #endif
324ac10cf69Smanu #ifdef LINUX_ATEXIT_SIGNATURE
3258537f76cSmanu 	    ((error = ELFNAME2(linux,atexit_signature)(p, epp, eh)) != 0) &&
326ac10cf69Smanu #endif
3278537f76cSmanu 	    1)
3288537f76cSmanu 			return error;
3294d9a6e09Schristos 
330c4aaa600Sfvdl 	if (itp[0]) {
331*47cd9b85Sjdolecek 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
332*47cd9b85Sjdolecek 		    itp)))
333*47cd9b85Sjdolecek 			return (error);
334fc7cfb5fSfvdl 	}
335f7ac1bd3Serh 	*pos = ELF_NO_ADDR;
33665fc8539Schristos 	DPRINTF(("linux_probe: returning 0\n"));
337c4aaa600Sfvdl 	return 0;
338fc7cfb5fSfvdl }
339c4aaa600Sfvdl 
340cee43b67Sjdolecek #ifndef LINUX_MACHDEP_ELF_COPYARGS
341cee43b67Sjdolecek /*
342cee43b67Sjdolecek  * Copy arguments onto the stack in the normal way, but add some
343cee43b67Sjdolecek  * extra information in case of dynamic binding.
344cee43b67Sjdolecek  */
345cee43b67Sjdolecek int
346cee43b67Sjdolecek ELFNAME2(linux,copyargs)(struct proc *p, struct exec_package *pack,
347cee43b67Sjdolecek     struct ps_strings *arginfo, char **stackp, void *argp)
348cee43b67Sjdolecek {
349cee43b67Sjdolecek 	size_t len;
350cee43b67Sjdolecek 	AuxInfo ai[LINUX_ELF_AUX_ENTRIES], *a;
351cee43b67Sjdolecek 	struct elf_args *ap;
352cee43b67Sjdolecek 	int error;
353cee43b67Sjdolecek 	struct vattr *vap;
354cee43b67Sjdolecek 
355cee43b67Sjdolecek 	if ((error = copyargs(p, pack, arginfo, stackp, argp)) != 0)
356cee43b67Sjdolecek 		return error;
357cee43b67Sjdolecek 
358cee43b67Sjdolecek 	a = ai;
359cee43b67Sjdolecek 
360cee43b67Sjdolecek 	/*
361cee43b67Sjdolecek 	 * Push extra arguments used by glibc on the stack.
362cee43b67Sjdolecek 	 */
363cee43b67Sjdolecek 
364cee43b67Sjdolecek 	a->a_type = AT_PAGESZ;
365cee43b67Sjdolecek 	a->a_v = PAGE_SIZE;
366cee43b67Sjdolecek 	a++;
367cee43b67Sjdolecek 
368cee43b67Sjdolecek 	if ((ap = (struct elf_args *)pack->ep_emul_arg)) {
369cee43b67Sjdolecek 
370cee43b67Sjdolecek 		a->a_type = AT_PHDR;
371cee43b67Sjdolecek 		a->a_v = ap->arg_phaddr;
372cee43b67Sjdolecek 		a++;
373cee43b67Sjdolecek 
374cee43b67Sjdolecek 		a->a_type = AT_PHENT;
375cee43b67Sjdolecek 		a->a_v = ap->arg_phentsize;
376cee43b67Sjdolecek 		a++;
377cee43b67Sjdolecek 
378cee43b67Sjdolecek 		a->a_type = AT_PHNUM;
379cee43b67Sjdolecek 		a->a_v = ap->arg_phnum;
380cee43b67Sjdolecek 		a++;
381cee43b67Sjdolecek 
382cee43b67Sjdolecek 		a->a_type = AT_BASE;
383cee43b67Sjdolecek 		a->a_v = ap->arg_interp;
384cee43b67Sjdolecek 		a++;
385cee43b67Sjdolecek 
386cee43b67Sjdolecek 		a->a_type = AT_FLAGS;
387cee43b67Sjdolecek 		a->a_v = 0;
388cee43b67Sjdolecek 		a++;
389cee43b67Sjdolecek 
390cee43b67Sjdolecek 		a->a_type = AT_ENTRY;
391cee43b67Sjdolecek 		a->a_v = ap->arg_entry;
392cee43b67Sjdolecek 		a++;
393cee43b67Sjdolecek 
394cee43b67Sjdolecek 		free(pack->ep_emul_arg, M_TEMP);
395cee43b67Sjdolecek 		pack->ep_emul_arg = NULL;
396cee43b67Sjdolecek 	}
397cee43b67Sjdolecek 
398cee43b67Sjdolecek 	/* Linux-specific items */
399cee43b67Sjdolecek 	a->a_type = LINUX_AT_CLKTCK;
400cee43b67Sjdolecek 	a->a_v = hz;
401cee43b67Sjdolecek 	a++;
402cee43b67Sjdolecek 
403cee43b67Sjdolecek 	vap = pack->ep_vap;
404cee43b67Sjdolecek 
405cee43b67Sjdolecek 	a->a_type = LINUX_AT_UID;
406cee43b67Sjdolecek 	a->a_v = p->p_cred->p_ruid;
407cee43b67Sjdolecek 	a++;
408cee43b67Sjdolecek 
409cee43b67Sjdolecek 	a->a_type = LINUX_AT_EUID;
410cee43b67Sjdolecek 	if (vap->va_mode & S_ISUID)
411cee43b67Sjdolecek 		a->a_v = vap->va_uid;
412cee43b67Sjdolecek 	else
413cee43b67Sjdolecek 		a->a_v = p->p_ucred->cr_uid;
414cee43b67Sjdolecek 	a++;
415cee43b67Sjdolecek 
416cee43b67Sjdolecek 	a->a_type = LINUX_AT_GID;
417cee43b67Sjdolecek 	a->a_v = p->p_cred->p_rgid;
418cee43b67Sjdolecek 	a++;
419cee43b67Sjdolecek 
420cee43b67Sjdolecek 	a->a_type = LINUX_AT_EGID;
421cee43b67Sjdolecek 	if (vap->va_mode & S_ISGID)
422cee43b67Sjdolecek 		a->a_v = vap->va_gid;
423cee43b67Sjdolecek 	else
424cee43b67Sjdolecek 		a->a_v = p->p_ucred->cr_gid;
425cee43b67Sjdolecek 	a++;
426cee43b67Sjdolecek 
427cee43b67Sjdolecek 	a->a_type = AT_NULL;
428cee43b67Sjdolecek 	a->a_v = 0;
429cee43b67Sjdolecek 	a++;
430cee43b67Sjdolecek 
431cee43b67Sjdolecek 	len = (a - ai) * sizeof(AuxInfo);
432cee43b67Sjdolecek 	if ((error = copyout(ai, *stackp, len)) != 0)
433cee43b67Sjdolecek 		return error;
434cee43b67Sjdolecek 	*stackp += len;
435cee43b67Sjdolecek 
436cee43b67Sjdolecek 	return 0;
437cee43b67Sjdolecek }
438cee43b67Sjdolecek #endif /* !LINUX_MACHDEP_ELF_COPYARGS */
439