14c33415eSBrooks Davis /*-
24c33415eSBrooks Davis * SPDX-License-Identifier: BSD-2-Clause
34c33415eSBrooks Davis *
44c33415eSBrooks Davis * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
54c33415eSBrooks Davis * All rights reserved.
64c33415eSBrooks Davis *
74c33415eSBrooks Davis * Redistribution and use in source and binary forms, with or without
84c33415eSBrooks Davis * modification, are permitted provided that the following conditions
94c33415eSBrooks Davis * are met:
104c33415eSBrooks Davis * 1. Redistributions of source code must retain the above copyright
114c33415eSBrooks Davis * notice, this list of conditions and the following disclaimer.
124c33415eSBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright
134c33415eSBrooks Davis * notice, this list of conditions and the following disclaimer in the
144c33415eSBrooks Davis * documentation and/or other materials provided with the distribution.
154c33415eSBrooks Davis *
164c33415eSBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
174c33415eSBrooks Davis * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
184c33415eSBrooks Davis * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
194c33415eSBrooks Davis * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
204c33415eSBrooks Davis * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
214c33415eSBrooks Davis * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
224c33415eSBrooks Davis * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234c33415eSBrooks Davis * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
244c33415eSBrooks Davis * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
254c33415eSBrooks Davis * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264c33415eSBrooks Davis *
274c33415eSBrooks Davis */
284c33415eSBrooks Davis
294c33415eSBrooks Davis #include "namespace.h"
304c33415eSBrooks Davis #include <elf.h>
314c33415eSBrooks Davis #include <errno.h>
324c33415eSBrooks Davis #include <link.h>
334c33415eSBrooks Davis #include <pthread.h>
348271d9b9SKonstantin Belousov #include <stdbool.h>
354c33415eSBrooks Davis #include <string.h>
364c33415eSBrooks Davis #include <sys/auxv.h>
374c33415eSBrooks Davis #include "un-namespace.h"
384c33415eSBrooks Davis #include "libc_private.h"
39*2f4cbf45SKonstantin Belousov #include <machine/atomic.h>
404c33415eSBrooks Davis
414c33415eSBrooks Davis extern int _DYNAMIC;
424c33415eSBrooks Davis #pragma weak _DYNAMIC
434c33415eSBrooks Davis
444c33415eSBrooks Davis void *__elf_aux_vector;
458271d9b9SKonstantin Belousov
468271d9b9SKonstantin Belousov #ifndef PIC
474c33415eSBrooks Davis static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
484c33415eSBrooks Davis
494c33415eSBrooks Davis static void
init_aux_vector_once(void)504c33415eSBrooks Davis init_aux_vector_once(void)
514c33415eSBrooks Davis {
524c33415eSBrooks Davis Elf_Addr *sp;
534c33415eSBrooks Davis
544c33415eSBrooks Davis sp = (Elf_Addr *)environ;
554c33415eSBrooks Davis while (*sp++ != 0)
564c33415eSBrooks Davis ;
574c33415eSBrooks Davis __elf_aux_vector = (Elf_Auxinfo *)sp;
584c33415eSBrooks Davis }
594c33415eSBrooks Davis
604c33415eSBrooks Davis void
__init_elf_aux_vector(void)614c33415eSBrooks Davis __init_elf_aux_vector(void)
624c33415eSBrooks Davis {
634c33415eSBrooks Davis
644c33415eSBrooks Davis if (&_DYNAMIC != NULL)
654c33415eSBrooks Davis return;
664c33415eSBrooks Davis _once(&aux_vector_once, init_aux_vector_once);
674c33415eSBrooks Davis }
688271d9b9SKonstantin Belousov #endif
694c33415eSBrooks Davis
70*2f4cbf45SKonstantin Belousov static int aux_once;
714c33415eSBrooks Davis static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
724c33415eSBrooks Davis static int hwcap_present, hwcap2_present;
734c33415eSBrooks Davis static char *canary, *pagesizes, *execpath;
744c33415eSBrooks Davis static void *ps_strings, *timekeep;
754c33415eSBrooks Davis static u_long hwcap, hwcap2;
764c33415eSBrooks Davis static void *fxrng_seed_version;
774c33415eSBrooks Davis static u_long usrstackbase, usrstacklim;
784c33415eSBrooks Davis
794c33415eSBrooks Davis #ifdef __powerpc__
804c33415eSBrooks Davis static int powerpc_new_auxv_format = 0;
814c33415eSBrooks Davis static void _init_aux_powerpc_fixup(void);
824c33415eSBrooks Davis int _powerpc_elf_aux_info(int, void *, int);
834c33415eSBrooks Davis #endif
844c33415eSBrooks Davis
858271d9b9SKonstantin Belousov /*
868271d9b9SKonstantin Belousov * This function might be called and actual body executed more than
878271d9b9SKonstantin Belousov * once in multithreading environment. Due to this, it is and must
888271d9b9SKonstantin Belousov * continue to be idempotent. All stores are atomic (no store
898271d9b9SKonstantin Belousov * tearing), because we only assign to int/long/ptr.
908271d9b9SKonstantin Belousov */
914c33415eSBrooks Davis static void
init_aux(void)924c33415eSBrooks Davis init_aux(void)
934c33415eSBrooks Davis {
944c33415eSBrooks Davis Elf_Auxinfo *aux;
954c33415eSBrooks Davis
96*2f4cbf45SKonstantin Belousov if (atomic_load_acq_int(&aux_once))
978271d9b9SKonstantin Belousov return;
984c33415eSBrooks Davis for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
994c33415eSBrooks Davis switch (aux->a_type) {
1004c33415eSBrooks Davis case AT_BSDFLAGS:
1014c33415eSBrooks Davis bsdflags = aux->a_un.a_val;
1024c33415eSBrooks Davis break;
1034c33415eSBrooks Davis
1044c33415eSBrooks Davis case AT_CANARY:
1054c33415eSBrooks Davis canary = (char *)(aux->a_un.a_ptr);
1064c33415eSBrooks Davis break;
1074c33415eSBrooks Davis
1084c33415eSBrooks Davis case AT_CANARYLEN:
1094c33415eSBrooks Davis canary_len = aux->a_un.a_val;
1104c33415eSBrooks Davis break;
1114c33415eSBrooks Davis
1124c33415eSBrooks Davis case AT_EXECPATH:
1134c33415eSBrooks Davis execpath = (char *)(aux->a_un.a_ptr);
1144c33415eSBrooks Davis break;
1154c33415eSBrooks Davis
1164c33415eSBrooks Davis case AT_HWCAP:
1174c33415eSBrooks Davis hwcap_present = 1;
1184c33415eSBrooks Davis hwcap = (u_long)(aux->a_un.a_val);
1194c33415eSBrooks Davis break;
1204c33415eSBrooks Davis
1214c33415eSBrooks Davis case AT_HWCAP2:
1224c33415eSBrooks Davis hwcap2_present = 1;
1234c33415eSBrooks Davis hwcap2 = (u_long)(aux->a_un.a_val);
1244c33415eSBrooks Davis break;
1254c33415eSBrooks Davis
1264c33415eSBrooks Davis case AT_PAGESIZES:
1274c33415eSBrooks Davis pagesizes = (char *)(aux->a_un.a_ptr);
1284c33415eSBrooks Davis break;
1294c33415eSBrooks Davis
1304c33415eSBrooks Davis case AT_PAGESIZESLEN:
1314c33415eSBrooks Davis pagesizes_len = aux->a_un.a_val;
1324c33415eSBrooks Davis break;
1334c33415eSBrooks Davis
1344c33415eSBrooks Davis case AT_PAGESZ:
1354c33415eSBrooks Davis pagesize = aux->a_un.a_val;
1364c33415eSBrooks Davis break;
1374c33415eSBrooks Davis
1384c33415eSBrooks Davis case AT_OSRELDATE:
1394c33415eSBrooks Davis osreldate = aux->a_un.a_val;
1404c33415eSBrooks Davis break;
1414c33415eSBrooks Davis
1424c33415eSBrooks Davis case AT_NCPUS:
1434c33415eSBrooks Davis ncpus = aux->a_un.a_val;
1444c33415eSBrooks Davis break;
1454c33415eSBrooks Davis
1464c33415eSBrooks Davis case AT_TIMEKEEP:
1474c33415eSBrooks Davis timekeep = aux->a_un.a_ptr;
1484c33415eSBrooks Davis break;
1494c33415eSBrooks Davis
1504c33415eSBrooks Davis case AT_PS_STRINGS:
1514c33415eSBrooks Davis ps_strings = aux->a_un.a_ptr;
1524c33415eSBrooks Davis break;
1534c33415eSBrooks Davis
1544c33415eSBrooks Davis case AT_FXRNG:
1554c33415eSBrooks Davis fxrng_seed_version = aux->a_un.a_ptr;
1564c33415eSBrooks Davis break;
1574c33415eSBrooks Davis
1584c33415eSBrooks Davis case AT_USRSTACKBASE:
1594c33415eSBrooks Davis usrstackbase = aux->a_un.a_val;
1604c33415eSBrooks Davis break;
1614c33415eSBrooks Davis
1624c33415eSBrooks Davis case AT_USRSTACKLIM:
1634c33415eSBrooks Davis usrstacklim = aux->a_un.a_val;
1644c33415eSBrooks Davis break;
1654c33415eSBrooks Davis #ifdef __powerpc__
1664c33415eSBrooks Davis /*
1674c33415eSBrooks Davis * Since AT_STACKPROT is always set, and the common
1684c33415eSBrooks Davis * value 23 is mutually exclusive with the legacy powerpc
1694c33415eSBrooks Davis * value 21, the existence of AT_STACKPROT proves we are
1704c33415eSBrooks Davis * on the common format.
1714c33415eSBrooks Davis */
1724c33415eSBrooks Davis case AT_STACKPROT: /* 23 */
1734c33415eSBrooks Davis powerpc_new_auxv_format = 1;
1744c33415eSBrooks Davis break;
1754c33415eSBrooks Davis #endif
1764c33415eSBrooks Davis }
1774c33415eSBrooks Davis }
1784c33415eSBrooks Davis #ifdef __powerpc__
1794c33415eSBrooks Davis if (!powerpc_new_auxv_format)
1804c33415eSBrooks Davis _init_aux_powerpc_fixup();
1814c33415eSBrooks Davis #endif
1828271d9b9SKonstantin Belousov
183*2f4cbf45SKonstantin Belousov atomic_store_rel_int(&aux_once, 1);
1844c33415eSBrooks Davis }
1854c33415eSBrooks Davis
1864c33415eSBrooks Davis #ifdef __powerpc__
1874c33415eSBrooks Davis static void
_init_aux_powerpc_fixup(void)1884c33415eSBrooks Davis _init_aux_powerpc_fixup(void)
1894c33415eSBrooks Davis {
1904c33415eSBrooks Davis Elf_Auxinfo *aux;
1914c33415eSBrooks Davis
1924c33415eSBrooks Davis /*
1934c33415eSBrooks Davis * Before 1300070, PowerPC platforms had nonstandard numbering for
1944c33415eSBrooks Davis * the aux vector. When running old binaries, the kernel will pass
1954c33415eSBrooks Davis * the vector using the old numbering. Reload affected variables.
1964c33415eSBrooks Davis */
1974c33415eSBrooks Davis for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
1984c33415eSBrooks Davis switch (aux->a_type) {
1994c33415eSBrooks Davis case AT_OLD_CANARY:
2004c33415eSBrooks Davis canary = (char *)(aux->a_un.a_ptr);
2014c33415eSBrooks Davis break;
2024c33415eSBrooks Davis case AT_OLD_CANARYLEN:
2034c33415eSBrooks Davis canary_len = aux->a_un.a_val;
2044c33415eSBrooks Davis break;
2054c33415eSBrooks Davis case AT_OLD_EXECPATH:
2064c33415eSBrooks Davis execpath = (char *)(aux->a_un.a_ptr);
2074c33415eSBrooks Davis break;
2084c33415eSBrooks Davis case AT_OLD_PAGESIZES:
2094c33415eSBrooks Davis pagesizes = (char *)(aux->a_un.a_ptr);
2104c33415eSBrooks Davis break;
2114c33415eSBrooks Davis case AT_OLD_PAGESIZESLEN:
2124c33415eSBrooks Davis pagesizes_len = aux->a_un.a_val;
2134c33415eSBrooks Davis break;
2144c33415eSBrooks Davis case AT_OLD_OSRELDATE:
2154c33415eSBrooks Davis osreldate = aux->a_un.a_val;
2164c33415eSBrooks Davis break;
2174c33415eSBrooks Davis case AT_OLD_NCPUS:
2184c33415eSBrooks Davis ncpus = aux->a_un.a_val;
2194c33415eSBrooks Davis break;
2204c33415eSBrooks Davis }
2214c33415eSBrooks Davis }
2224c33415eSBrooks Davis }
2234c33415eSBrooks Davis
2244c33415eSBrooks Davis int
_powerpc_elf_aux_info(int aux,void * buf,int buflen)2254c33415eSBrooks Davis _powerpc_elf_aux_info(int aux, void *buf, int buflen)
2264c33415eSBrooks Davis {
2274c33415eSBrooks Davis
2284c33415eSBrooks Davis /*
2294c33415eSBrooks Davis * If we are in the old auxv format, we need to translate the aux
2304c33415eSBrooks Davis * parameter of elf_aux_info() calls into the common auxv format.
2314c33415eSBrooks Davis * Internal libc calls always use the common format, and they
2324c33415eSBrooks Davis * directly call _elf_aux_info instead of using the weak symbol.
2334c33415eSBrooks Davis */
2344c33415eSBrooks Davis if (!powerpc_new_auxv_format) {
2354c33415eSBrooks Davis switch (aux) {
2364c33415eSBrooks Davis case AT_OLD_EXECPATH:
2374c33415eSBrooks Davis aux = AT_EXECPATH;
2384c33415eSBrooks Davis break;
2394c33415eSBrooks Davis case AT_OLD_CANARY:
2404c33415eSBrooks Davis aux = AT_CANARY;
2414c33415eSBrooks Davis break;
2424c33415eSBrooks Davis case AT_OLD_CANARYLEN:
2434c33415eSBrooks Davis aux = AT_CANARYLEN;
2444c33415eSBrooks Davis break;
2454c33415eSBrooks Davis case AT_OLD_OSRELDATE:
2464c33415eSBrooks Davis aux = AT_OSRELDATE;
2474c33415eSBrooks Davis break;
2484c33415eSBrooks Davis case AT_OLD_NCPUS:
2494c33415eSBrooks Davis aux = AT_NCPUS;
2504c33415eSBrooks Davis break;
2514c33415eSBrooks Davis case AT_OLD_PAGESIZES:
2524c33415eSBrooks Davis aux = AT_PAGESIZES;
2534c33415eSBrooks Davis break;
2544c33415eSBrooks Davis case AT_OLD_PAGESIZESLEN:
2554c33415eSBrooks Davis aux = AT_PAGESIZESLEN;
2564c33415eSBrooks Davis break;
2574c33415eSBrooks Davis case AT_OLD_STACKPROT:
2584c33415eSBrooks Davis aux = AT_STACKPROT;
2594c33415eSBrooks Davis break;
2604c33415eSBrooks Davis }
2614c33415eSBrooks Davis }
2624c33415eSBrooks Davis return _elf_aux_info(aux, buf, buflen);
2634c33415eSBrooks Davis }
2644c33415eSBrooks Davis __weak_reference(_powerpc_elf_aux_info, elf_aux_info);
2654c33415eSBrooks Davis #else
2664c33415eSBrooks Davis __weak_reference(_elf_aux_info, elf_aux_info);
2674c33415eSBrooks Davis #endif
2684c33415eSBrooks Davis
2694c33415eSBrooks Davis int
_elf_aux_info(int aux,void * buf,int buflen)2704c33415eSBrooks Davis _elf_aux_info(int aux, void *buf, int buflen)
2714c33415eSBrooks Davis {
2724c33415eSBrooks Davis int res;
2734c33415eSBrooks Davis
2748271d9b9SKonstantin Belousov #ifndef PIC
2754c33415eSBrooks Davis __init_elf_aux_vector();
2768271d9b9SKonstantin Belousov #endif
2774c33415eSBrooks Davis if (__elf_aux_vector == NULL)
2784c33415eSBrooks Davis return (ENOSYS);
2798271d9b9SKonstantin Belousov init_aux(); /* idempotent */
2804c33415eSBrooks Davis
2814c33415eSBrooks Davis if (buflen < 0)
2824c33415eSBrooks Davis return (EINVAL);
2834c33415eSBrooks Davis
2844c33415eSBrooks Davis switch (aux) {
2854c33415eSBrooks Davis case AT_CANARY:
2864c33415eSBrooks Davis if (canary != NULL && canary_len >= buflen) {
2874c33415eSBrooks Davis memcpy(buf, canary, buflen);
2884c33415eSBrooks Davis memset(canary, 0, canary_len);
2894c33415eSBrooks Davis canary = NULL;
2904c33415eSBrooks Davis res = 0;
2914c33415eSBrooks Davis } else
2924c33415eSBrooks Davis res = ENOENT;
2934c33415eSBrooks Davis break;
2944c33415eSBrooks Davis case AT_EXECPATH:
2954c33415eSBrooks Davis if (execpath == NULL)
2964c33415eSBrooks Davis res = ENOENT;
2974c33415eSBrooks Davis else if (buf == NULL)
2984c33415eSBrooks Davis res = EINVAL;
2994c33415eSBrooks Davis else {
3004c33415eSBrooks Davis if (strlcpy(buf, execpath, buflen) >=
3014c33415eSBrooks Davis (unsigned int)buflen)
3024c33415eSBrooks Davis res = EINVAL;
3034c33415eSBrooks Davis else
3044c33415eSBrooks Davis res = 0;
3054c33415eSBrooks Davis }
3064c33415eSBrooks Davis break;
3074c33415eSBrooks Davis case AT_HWCAP:
3084c33415eSBrooks Davis if (hwcap_present && buflen == sizeof(u_long)) {
3094c33415eSBrooks Davis *(u_long *)buf = hwcap;
3104c33415eSBrooks Davis res = 0;
3114c33415eSBrooks Davis } else
3124c33415eSBrooks Davis res = ENOENT;
3134c33415eSBrooks Davis break;
3144c33415eSBrooks Davis case AT_HWCAP2:
3154c33415eSBrooks Davis if (hwcap2_present && buflen == sizeof(u_long)) {
3164c33415eSBrooks Davis *(u_long *)buf = hwcap2;
3174c33415eSBrooks Davis res = 0;
3184c33415eSBrooks Davis } else
3194c33415eSBrooks Davis res = ENOENT;
3204c33415eSBrooks Davis break;
3214c33415eSBrooks Davis case AT_PAGESIZES:
3224c33415eSBrooks Davis if (pagesizes != NULL && pagesizes_len >= buflen) {
3234c33415eSBrooks Davis memcpy(buf, pagesizes, buflen);
3244c33415eSBrooks Davis res = 0;
3254c33415eSBrooks Davis } else
3264c33415eSBrooks Davis res = ENOENT;
3274c33415eSBrooks Davis break;
3284c33415eSBrooks Davis case AT_PAGESZ:
3294c33415eSBrooks Davis if (buflen == sizeof(int)) {
3304c33415eSBrooks Davis if (pagesize != 0) {
3314c33415eSBrooks Davis *(int *)buf = pagesize;
3324c33415eSBrooks Davis res = 0;
3334c33415eSBrooks Davis } else
3344c33415eSBrooks Davis res = ENOENT;
3354c33415eSBrooks Davis } else
3364c33415eSBrooks Davis res = EINVAL;
3374c33415eSBrooks Davis break;
3384c33415eSBrooks Davis case AT_OSRELDATE:
3394c33415eSBrooks Davis if (buflen == sizeof(int)) {
3404c33415eSBrooks Davis if (osreldate != 0) {
3414c33415eSBrooks Davis *(int *)buf = osreldate;
3424c33415eSBrooks Davis res = 0;
3434c33415eSBrooks Davis } else
3444c33415eSBrooks Davis res = ENOENT;
3454c33415eSBrooks Davis } else
3464c33415eSBrooks Davis res = EINVAL;
3474c33415eSBrooks Davis break;
3484c33415eSBrooks Davis case AT_NCPUS:
3494c33415eSBrooks Davis if (buflen == sizeof(int)) {
3504c33415eSBrooks Davis if (ncpus != 0) {
3514c33415eSBrooks Davis *(int *)buf = ncpus;
3524c33415eSBrooks Davis res = 0;
3534c33415eSBrooks Davis } else
3544c33415eSBrooks Davis res = ENOENT;
3554c33415eSBrooks Davis } else
3564c33415eSBrooks Davis res = EINVAL;
3574c33415eSBrooks Davis break;
3584c33415eSBrooks Davis case AT_TIMEKEEP:
3594c33415eSBrooks Davis if (buflen == sizeof(void *)) {
3604c33415eSBrooks Davis if (timekeep != NULL) {
3614c33415eSBrooks Davis *(void **)buf = timekeep;
3624c33415eSBrooks Davis res = 0;
3634c33415eSBrooks Davis } else
3644c33415eSBrooks Davis res = ENOENT;
3654c33415eSBrooks Davis } else
3664c33415eSBrooks Davis res = EINVAL;
3674c33415eSBrooks Davis break;
3684c33415eSBrooks Davis case AT_BSDFLAGS:
3694c33415eSBrooks Davis if (buflen == sizeof(int)) {
3704c33415eSBrooks Davis *(int *)buf = bsdflags;
3714c33415eSBrooks Davis res = 0;
3724c33415eSBrooks Davis } else
3734c33415eSBrooks Davis res = EINVAL;
3744c33415eSBrooks Davis break;
3754c33415eSBrooks Davis case AT_PS_STRINGS:
3764c33415eSBrooks Davis if (buflen == sizeof(void *)) {
3774c33415eSBrooks Davis if (ps_strings != NULL) {
3784c33415eSBrooks Davis *(void **)buf = ps_strings;
3794c33415eSBrooks Davis res = 0;
3804c33415eSBrooks Davis } else
3814c33415eSBrooks Davis res = ENOENT;
3824c33415eSBrooks Davis } else
3834c33415eSBrooks Davis res = EINVAL;
3844c33415eSBrooks Davis break;
3854c33415eSBrooks Davis case AT_FXRNG:
3864c33415eSBrooks Davis if (buflen == sizeof(void *)) {
3874c33415eSBrooks Davis if (fxrng_seed_version != NULL) {
3884c33415eSBrooks Davis *(void **)buf = fxrng_seed_version;
3894c33415eSBrooks Davis res = 0;
3904c33415eSBrooks Davis } else
3914c33415eSBrooks Davis res = ENOENT;
3924c33415eSBrooks Davis } else
3934c33415eSBrooks Davis res = EINVAL;
3944c33415eSBrooks Davis break;
3954c33415eSBrooks Davis case AT_USRSTACKBASE:
3964c33415eSBrooks Davis if (buflen == sizeof(u_long)) {
3974c33415eSBrooks Davis if (usrstackbase != 0) {
3984c33415eSBrooks Davis *(u_long *)buf = usrstackbase;
3994c33415eSBrooks Davis res = 0;
4004c33415eSBrooks Davis } else
4014c33415eSBrooks Davis res = ENOENT;
4024c33415eSBrooks Davis } else
4034c33415eSBrooks Davis res = EINVAL;
4044c33415eSBrooks Davis break;
4054c33415eSBrooks Davis case AT_USRSTACKLIM:
4064c33415eSBrooks Davis if (buflen == sizeof(u_long)) {
4074c33415eSBrooks Davis if (usrstacklim != 0) {
4084c33415eSBrooks Davis *(u_long *)buf = usrstacklim;
4094c33415eSBrooks Davis res = 0;
4104c33415eSBrooks Davis } else
4114c33415eSBrooks Davis res = ENOENT;
4124c33415eSBrooks Davis } else
4134c33415eSBrooks Davis res = EINVAL;
4144c33415eSBrooks Davis break;
4154c33415eSBrooks Davis default:
4164c33415eSBrooks Davis res = ENOENT;
4174c33415eSBrooks Davis break;
4184c33415eSBrooks Davis }
4194c33415eSBrooks Davis return (res);
4204c33415eSBrooks Davis }
421