]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/gen/auxv.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 "un-namespace.h"
37 #include "libc_private.h"
38
39 extern char **environ;
40 extern int _DYNAMIC;
41 #pragma weak _DYNAMIC
42
43 void *__elf_aux_vector;
44 static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
45
46 static void
47 init_aux_vector_once(void)
48 {
49         Elf_Addr *sp;
50
51         sp = (Elf_Addr *)environ;
52         while (*sp++ != 0)
53                 ;
54         __elf_aux_vector = (Elf_Auxinfo *)sp;
55 }
56
57 void
58 __init_elf_aux_vector(void)
59 {
60
61         if (&_DYNAMIC != NULL)
62                 return;
63         _once(&aux_vector_once, init_aux_vector_once);
64 }
65
66 static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
67 static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
68 static char *canary, *pagesizes;
69 static void *timekeep;
70
71 static void
72 init_aux(void)
73 {
74         Elf_Auxinfo *aux;
75
76         for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
77                 switch (aux->a_type) {
78                 case AT_CANARY:
79                         canary = (char *)(aux->a_un.a_ptr);
80                         break;
81
82                 case AT_CANARYLEN:
83                         canary_len = aux->a_un.a_val;
84                         break;
85
86                 case AT_PAGESIZES:
87                         pagesizes = (char *)(aux->a_un.a_ptr);
88                         break;
89
90                 case AT_PAGESIZESLEN:
91                         pagesizes_len = aux->a_un.a_val;
92                         break;
93
94                 case AT_PAGESZ:
95                         pagesize = aux->a_un.a_val;
96                         break;
97
98                 case AT_OSRELDATE:
99                         osreldate = aux->a_un.a_val;
100                         break;
101
102                 case AT_NCPUS:
103                         ncpus = aux->a_un.a_val;
104                         break;
105
106                 case AT_TIMEKEEP:
107                         timekeep = aux->a_un.a_ptr;
108                         break;
109                 }
110         }
111 }
112
113 int
114 _elf_aux_info(int aux, void *buf, int buflen)
115 {
116         int res;
117
118         __init_elf_aux_vector();
119         if (__elf_aux_vector == NULL)
120                 return (ENOSYS);
121         _once(&aux_once, init_aux);
122
123         switch (aux) {
124         case AT_CANARY:
125                 if (canary != NULL && canary_len >= buflen) {
126                         memcpy(buf, canary, buflen);
127                         memset(canary, 0, canary_len);
128                         canary = NULL;
129                         res = 0;
130                 } else
131                         res = ENOENT;
132                 break;
133         case AT_PAGESIZES:
134                 if (pagesizes != NULL && pagesizes_len >= buflen) {
135                         memcpy(buf, pagesizes, buflen);
136                         res = 0;
137                 } else
138                         res = ENOENT;
139                 break;
140
141         case AT_PAGESZ:
142                 if (buflen == sizeof(int)) {
143                         if (pagesize != 0) {
144                                 *(int *)buf = pagesize;
145                                 res = 0;
146                         } else
147                                 res = ENOENT;
148                 } else
149                         res = EINVAL;
150                 break;
151         case AT_OSRELDATE:
152                 if (buflen == sizeof(int)) {
153                         if (osreldate != 0) {
154                                 *(int *)buf = osreldate;
155                                 res = 0;
156                         } else
157                                 res = ENOENT;
158                 } else
159                         res = EINVAL;
160                 break;
161         case AT_NCPUS:
162                 if (buflen == sizeof(int)) {
163                         if (ncpus != 0) {
164                                 *(int *)buf = ncpus;
165                                 res = 0;
166                         } else
167                                 res = ENOENT;
168                 } else
169                         res = EINVAL;
170                 break;
171         case AT_TIMEKEEP:
172                 if (buflen == sizeof(void *)) {
173                         if (timekeep != NULL) {
174                                 *(void **)buf = timekeep;
175                                 res = 0;
176                         } else
177                                 res = ENOENT;
178                 } else
179                         res = EINVAL;
180                 break;
181         default:
182                 res = ENOENT;
183                 break;
184         }
185         return (res);
186 }