]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/auxv.c
Merge bmake-20180512
[FreeBSD/FreeBSD.git] / lib / libc / gen / auxv.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "namespace.h"
33 #include <elf.h>
34 #include <errno.h>
35 #include <link.h>
36 #include <pthread.h>
37 #include <string.h>
38 #include <sys/auxv.h>
39 #include "un-namespace.h"
40 #include "libc_private.h"
41
42 extern char **environ;
43 extern int _DYNAMIC;
44 #pragma weak _DYNAMIC
45
46 void *__elf_aux_vector;
47 static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
48
49 static void
50 init_aux_vector_once(void)
51 {
52         Elf_Addr *sp;
53
54         sp = (Elf_Addr *)environ;
55         while (*sp++ != 0)
56                 ;
57         __elf_aux_vector = (Elf_Auxinfo *)sp;
58 }
59
60 void
61 __init_elf_aux_vector(void)
62 {
63
64         if (&_DYNAMIC != NULL)
65                 return;
66         _once(&aux_vector_once, init_aux_vector_once);
67 }
68
69 static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
70 static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
71 static int hwcap_present, hwcap2_present;
72 static char *canary, *pagesizes;
73 static void *timekeep;
74 static u_long hwcap, hwcap2;
75
76 static void
77 init_aux(void)
78 {
79         Elf_Auxinfo *aux;
80
81         for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
82                 switch (aux->a_type) {
83                 case AT_CANARY:
84                         canary = (char *)(aux->a_un.a_ptr);
85                         break;
86
87                 case AT_CANARYLEN:
88                         canary_len = aux->a_un.a_val;
89                         break;
90
91                 case AT_HWCAP:
92                         hwcap_present = 1;
93                         hwcap = (u_long)(aux->a_un.a_val);
94                         break;
95
96                 case AT_HWCAP2:
97                         hwcap2_present = 1;
98                         hwcap2 = (u_long)(aux->a_un.a_val);
99                         break;
100
101                 case AT_PAGESIZES:
102                         pagesizes = (char *)(aux->a_un.a_ptr);
103                         break;
104
105                 case AT_PAGESIZESLEN:
106                         pagesizes_len = aux->a_un.a_val;
107                         break;
108
109                 case AT_PAGESZ:
110                         pagesize = aux->a_un.a_val;
111                         break;
112
113                 case AT_OSRELDATE:
114                         osreldate = aux->a_un.a_val;
115                         break;
116
117                 case AT_NCPUS:
118                         ncpus = aux->a_un.a_val;
119                         break;
120
121                 case AT_TIMEKEEP:
122                         timekeep = aux->a_un.a_ptr;
123                         break;
124                 }
125         }
126 }
127
128 __weak_reference(_elf_aux_info, elf_aux_info);
129
130 int
131 _elf_aux_info(int aux, void *buf, int buflen)
132 {
133         int res;
134
135         __init_elf_aux_vector();
136         if (__elf_aux_vector == NULL)
137                 return (ENOSYS);
138         _once(&aux_once, init_aux);
139
140         switch (aux) {
141         case AT_CANARY:
142                 if (canary != NULL && canary_len >= buflen) {
143                         memcpy(buf, canary, buflen);
144                         memset(canary, 0, canary_len);
145                         canary = NULL;
146                         res = 0;
147                 } else
148                         res = ENOENT;
149                 break;
150         case AT_HWCAP:
151                 if (hwcap_present && buflen == sizeof(u_long)) {
152                         *(u_long *)buf = hwcap;
153                         res = 0;
154                 } else
155                         res = ENOENT;
156                 break;
157         case AT_HWCAP2:
158                 if (hwcap2_present && buflen == sizeof(u_long)) {
159                         *(u_long *)buf = hwcap2;
160                         res = 0;
161                 } else
162                         res = ENOENT;
163                 break;
164         case AT_PAGESIZES:
165                 if (pagesizes != NULL && pagesizes_len >= buflen) {
166                         memcpy(buf, pagesizes, buflen);
167                         res = 0;
168                 } else
169                         res = ENOENT;
170                 break;
171         case AT_PAGESZ:
172                 if (buflen == sizeof(int)) {
173                         if (pagesize != 0) {
174                                 *(int *)buf = pagesize;
175                                 res = 0;
176                         } else
177                                 res = ENOENT;
178                 } else
179                         res = EINVAL;
180                 break;
181         case AT_OSRELDATE:
182                 if (buflen == sizeof(int)) {
183                         if (osreldate != 0) {
184                                 *(int *)buf = osreldate;
185                                 res = 0;
186                         } else
187                                 res = ENOENT;
188                 } else
189                         res = EINVAL;
190                 break;
191         case AT_NCPUS:
192                 if (buflen == sizeof(int)) {
193                         if (ncpus != 0) {
194                                 *(int *)buf = ncpus;
195                                 res = 0;
196                         } else
197                                 res = ENOENT;
198                 } else
199                         res = EINVAL;
200                 break;
201         case AT_TIMEKEEP:
202                 if (buflen == sizeof(void *)) {
203                         if (timekeep != NULL) {
204                                 *(void **)buf = timekeep;
205                                 res = 0;
206                         } else
207                                 res = ENOENT;
208                 } else
209                         res = EINVAL;
210                 break;
211         default:
212                 res = ENOENT;
213                 break;
214         }
215         return (res);
216 }