]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/generic/dl-cache.c
Update.
[thirdparty/glibc.git] / sysdeps / generic / dl-cache.c
1 /* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
2 Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #include <assert.h>
21 #include <unistd.h>
22 #include <ldsodefs.h>
23 #include <sys/mman.h>
24 #include <dl-cache.h>
25 #include <dl-procinfo.h>
26
27 #include <stdio-common/_itoa.h>
28
29 extern const char *_dl_platform;
30
31 #ifndef _DL_PLATFORMS_COUNT
32 # define _DL_PLATFORMS_COUNT 0
33 #endif
34
35 /* This is the starting address and the size of the mmap()ed file. */
36 static struct cache_file *cache;
37 static struct cache_file_new *cache_new;
38 static size_t cachesize;
39
40 /* 1 if cache_data + PTR points into the cache. */
41 #define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
42
43 /* This is the cache ID we expect. Normally it is 3 for glibc linked
44 binaries. */
45 int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
46
47 #define SEARCH_CACHE(cache) \
48 /* We use binary search since the table is sorted in the cache file. \
49 The first matching entry in the table is returned. \
50 It is important to use the same algorithm as used while generating \
51 the cache file. */ \
52 do \
53 { \
54 left = 0; \
55 right = cache->nlibs - 1; \
56 middle = (left + right) / 2; \
57 cmpres = 1; \
58 \
59 while (left <= right) \
60 { \
61 /* Make sure string table indices are not bogus before using \
62 them. */ \
63 if (! _dl_cache_verify_ptr (cache->libs[middle].key)) \
64 { \
65 cmpres = 1; \
66 break; \
67 } \
68 \
69 /* Actually compare the entry with the key. */ \
70 cmpres = _dl_cache_libcmp (name, \
71 cache_data + cache->libs[middle].key); \
72 if (cmpres == 0) \
73 /* Found it. */ \
74 break; \
75 \
76 if (cmpres < 0) \
77 left = middle + 1; \
78 else \
79 right = middle - 1; \
80 \
81 middle = (left + right) / 2; \
82 } \
83 \
84 if (cmpres == 0) \
85 { \
86 /* LEFT now marks the last entry for which we know the name is \
87 correct. */ \
88 left = middle; \
89 \
90 /* There might be entries with this name before the one we \
91 found. So we have to find the beginning. */ \
92 while (middle > 0 \
93 /* Make sure string table indices are not bogus before \
94 using them. */ \
95 && _dl_cache_verify_ptr (cache->libs[middle - 1].key) \
96 /* Actually compare the entry. */ \
97 && (_dl_cache_libcmp (name, \
98 cache_data \
99 + cache->libs[middle - 1].key) \
100 == 0)) \
101 --middle; \
102 \
103 do \
104 { \
105 int flags; \
106 \
107 /* Only perform the name test if necessary. */ \
108 if (middle > left \
109 /* We haven't seen this string so far. Test whether the \
110 index is ok and whether the name matches. Otherwise \
111 we are done. */ \
112 && (! _dl_cache_verify_ptr (cache->libs[middle].key) \
113 || (_dl_cache_libcmp (name, \
114 cache_data \
115 + cache->libs[middle].key) \
116 != 0))) \
117 break; \
118 \
119 flags = cache->libs[middle].flags; \
120 if (_dl_cache_check_flags (flags) \
121 && _dl_cache_verify_ptr (cache->libs[middle].value)) \
122 { \
123 if (best == NULL || flags == _dl_correct_cache_id) \
124 { \
125 HWCAP_CHECK; \
126 best = cache_data + cache->libs[middle].value; \
127 \
128 if (flags == _dl_correct_cache_id) \
129 /* We've found an exact match for the shared \
130 object and no general `ELF' release. Stop \
131 searching. */ \
132 break; \
133 } \
134 } \
135 } \
136 while (++middle <= right); \
137 } \
138 } \
139 while (0)
140
141
142
143 /* Look up NAME in ld.so.cache and return the file name stored there,
144 or null if none is found. */
145
146 const char *
147 internal_function
148 _dl_load_cache_lookup (const char *name)
149 {
150 int left, right, middle;
151 int cmpres;
152 const char *cache_data;
153 uint32_t cache_data_size;
154 const char *best;
155
156 /* Print a message if the loading of libs is traced. */
157 if (_dl_debug_libs)
158 _dl_debug_message (1, " search cache=", LD_SO_CACHE, "\n", NULL);
159
160 if (cache == NULL)
161 {
162 /* Read the contents of the file. */
163 void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
164 PROT_READ);
165
166 /* We can handle three different cache file formats here:
167 - the old libc5/glibc2.0/2.1 format
168 - the old format with the new format in it
169 - only the new format
170 The following checks if the cache contains any of these formats. */
171 if (file != NULL && cachesize > sizeof *cache
172 && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
173 {
174 size_t offset;
175 /* Looks ok. */
176 cache = file;
177
178 /* Check for new version. */
179 offset = ALIGN_CACHE (sizeof (struct cache_file)
180 + cache->nlibs * sizeof (struct file_entry));
181
182 cache_new = (struct cache_file_new *) ((void *) cache + offset);
183 if (cachesize < (offset + sizeof (struct cache_file_new))
184 || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
185 sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
186 cache_new = (void *) -1;
187 }
188 else if (file != NULL && cachesize > sizeof *cache_new
189 && memcmp (file, CACHEMAGIC_VERSION_NEW,
190 sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
191 {
192 cache_new = file;
193 cache = file;
194 }
195 else
196 {
197 if (file != NULL)
198 __munmap (file, cachesize);
199 cache = (void *) -1;
200 }
201
202 assert (cache != NULL);
203 }
204
205 if (cache == (void *) -1)
206 /* Previously looked for the cache file and didn't find it. */
207 return NULL;
208
209 best = NULL;
210
211 if (cache_new != (void *) -1)
212 {
213 /* This file ends in static libraries where we don't have a hwcap. */
214 unsigned long int *hwcap;
215 uint64_t platform;
216 weak_extern (_dl_hwcap);
217
218 /* This is where the strings start. */
219 cache_data = (const char *) cache_new;
220
221 /* Now we can compute how large the string table is. */
222 cache_data_size = (const char *) cache + cachesize - cache_data;
223
224 hwcap = &_dl_hwcap;
225 platform = _dl_string_platform (_dl_platform);
226 if (platform != -1)
227 platform = 1ULL << platform;
228
229 /* Only accept hwcap if it's for the right platform. */
230 #define HWCAP_CHECK \
231 if (_DL_PLATFORMS_COUNT && platform != -1 \
232 && (cache_new->libs[middle].hwcap & _DL_HWCAP_PLATFORM) != 0 \
233 && (cache_new->libs[middle].hwcap & _DL_HWCAP_PLATFORM) != platform) \
234 continue; \
235 if (hwcap \
236 && ((cache_new->libs[middle].hwcap & *hwcap & ~_DL_HWCAP_PLATFORM) \
237 > *hwcap)) \
238 continue
239 SEARCH_CACHE (cache_new);
240 }
241 else
242 {
243 /* This is where the strings start. */
244 cache_data = (const char *) &cache->libs[cache->nlibs];
245
246 /* Now we can compute how large the string table is. */
247 cache_data_size = (const char *) cache + cachesize - cache_data;
248
249 #undef HWCAP_CHECK
250 #define HWCAP_CHECK do {} while (0)
251 SEARCH_CACHE (cache);
252 }
253
254 /* Print our result if wanted. */
255 if (_dl_debug_libs && best != NULL)
256 _dl_debug_message (1, " trying file=", best, "\n", NULL);
257
258 return best;
259 }
260
261 #ifndef MAP_COPY
262 /* If the system does not support MAP_COPY we cannot leave the file open
263 all the time since this would create problems when the file is replaced.
264 Therefore we provide this function to close the file and open it again
265 once needed. */
266 void
267 _dl_unload_cache (void)
268 {
269 if (cache != NULL && cache != (struct cache_file *) -1)
270 {
271 __munmap (cache, cachesize);
272 cache = NULL;
273 }
274 }
275 #endif