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