]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/cache.c
s390x: Add glibc-hwcaps support
[thirdparty/glibc.git] / elf / cache.c
CommitLineData
d614a753 1/* Copyright (C) 1999-2020 Free Software Foundation, Inc.
591e1ffb
UD
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
4
43bc8ac6 5 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
591e1ffb 9
43bc8ac6 10 This program is distributed in the hope that it will be useful,
591e1ffb 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
591e1ffb 14
43bc8ac6 15 You should have received a copy of the GNU General Public License
5a82c748 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
591e1ffb 17
dfb3f101 18#include <assert.h>
591e1ffb
UD
19#include <errno.h>
20#include <error.h>
21#include <dirent.h>
68162753 22#include <inttypes.h>
27d9ffda 23#include <libgen.h>
591e1ffb
UD
24#include <libintl.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
e054f494 29#include <stdint.h>
591e1ffb
UD
30#include <sys/fcntl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34
8f480b4b
RM
35#include <ldconfig.h>
36#include <dl-cache.h>
dfb3f101 37#include <version.h>
73b6e50a
FW
38#include <stringtable.h>
39
40/* Used to store library names, paths, and other strings. */
41static struct stringtable strings;
591e1ffb 42
b44ac4f4
FW
43/* Keeping track of "glibc-hwcaps" subdirectories. During cache
44 construction, a linear search by name is performed to deduplicate
45 entries. */
46struct glibc_hwcaps_subdirectory
47{
48 struct glibc_hwcaps_subdirectory *next;
49
50 /* Interned string with the subdirectory name. */
51 struct stringtable_entry *name;
52
53 /* Array index in the cache_extension_tag_glibc_hwcaps section in
54 the stored cached file. This is computed after all the
55 subdirectories have been processed, so that subdirectory names in
56 the extension section can be sorted. */
57 uint32_t section_index;
58
59 /* True if the subdirectory is actually used for anything. */
60 bool used;
61};
62
63const char *
64glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir)
65{
66 return dir->name->string;
67}
68
69/* Linked list of known hwcaps subdirecty names. */
70static struct glibc_hwcaps_subdirectory *hwcaps;
71
72struct glibc_hwcaps_subdirectory *
73new_glibc_hwcaps_subdirectory (const char *name)
74{
75 struct stringtable_entry *name_interned = stringtable_add (&strings, name);
76 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
77 if (p->name == name_interned)
78 return p;
79 struct glibc_hwcaps_subdirectory *p = xmalloc (sizeof (*p));
80 p->next = hwcaps;
81 p->name = name_interned;
82 p->section_index = 0;
83 p->used = false;
84 hwcaps = p;
85 return p;
86}
87
88/* Helper for sorting struct glibc_hwcaps_subdirectory elements by
89 name. */
90static int
91assign_glibc_hwcaps_indices_compare (const void *l, const void *r)
92{
93 const struct glibc_hwcaps_subdirectory *left
94 = *(struct glibc_hwcaps_subdirectory **)l;
95 const struct glibc_hwcaps_subdirectory *right
96 = *(struct glibc_hwcaps_subdirectory **)r;
97 return strcmp (glibc_hwcaps_subdirectory_name (left),
98 glibc_hwcaps_subdirectory_name (right));
99}
100
101/* Count the number of hwcaps subdirectories which are actually
102 used. */
103static size_t
104glibc_hwcaps_count (void)
105{
106 size_t count = 0;
107 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
108 if (p->used)
109 ++count;
110 return count;
111}
112
113/* Compute the section_index fields for all */
114static void
115assign_glibc_hwcaps_indices (void)
116{
117 /* Convert the linked list into an array, so that we can use qsort.
118 Only copy the subdirectories which are actually used. */
119 size_t count = glibc_hwcaps_count ();
120 struct glibc_hwcaps_subdirectory **array
121 = xmalloc (sizeof (*array) * count);
122 {
123 size_t i = 0;
124 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
125 if (p->used)
126 {
127 array[i] = p;
128 ++i;
129 }
130 assert (i == count);
131 }
132
133 qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare);
134
135 /* Assign the array indices. */
136 for (size_t i = 0; i < count; ++i)
137 array[i]->section_index = i;
138
139 free (array);
140}
141
591e1ffb
UD
142struct cache_entry
143{
73b6e50a
FW
144 struct stringtable_entry *lib; /* Library name. */
145 struct stringtable_entry *path; /* Path to find library. */
45eca4d1 146 int flags; /* Flags to indicate kind of library. */
a986484f 147 unsigned int osversion; /* Required OS version. */
ad1a5cc7 148 uint64_t hwcap; /* Important hardware capabilities. */
45eca4d1 149 int bits_hwcap; /* Number of bits set in hwcap. */
b44ac4f4
FW
150
151 /* glibc-hwcaps subdirectory. If not NULL, hwcap must be zero. */
152 struct glibc_hwcaps_subdirectory *hwcaps;
153
45eca4d1 154 struct cache_entry *next; /* Next entry in list. */
591e1ffb
UD
155};
156
591e1ffb
UD
157/* List of all cache entries. */
158static struct cache_entry *entries;
159
160static const char *flag_descr[] =
161{ "libc4", "ELF", "libc5", "libc6"};
162
591e1ffb
UD
163/* Print a single entry. */
164static void
a986484f 165print_entry (const char *lib, int flag, unsigned int osversion,
b44ac4f4 166 uint64_t hwcap, const char *hwcap_string, const char *key)
591e1ffb
UD
167{
168 printf ("\t%s (", lib);
0b7219cc 169 switch (flag & FLAG_TYPE_MASK)
591e1ffb
UD
170 {
171 case FLAG_LIBC4:
172 case FLAG_ELF:
173 case FLAG_ELF_LIBC5:
174 case FLAG_ELF_LIBC6:
a986484f 175 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
591e1ffb
UD
176 break;
177 default:
96c0d65d 178 fputs (_("unknown"), stdout);
591e1ffb
UD
179 break;
180 }
181 switch (flag & FLAG_REQUIRED_MASK)
182 {
591e1ffb
UD
183 case FLAG_SPARC_LIB64:
184 fputs (",64bit", stdout);
48c53070 185 break;
95582174
UD
186 case FLAG_IA64_LIB64:
187 fputs (",IA-64", stdout);
fdedb42e 188 break;
fdedb42e
AJ
189 case FLAG_X8664_LIB64:
190 fputs (",x86-64", stdout);
191 break;
96c0d65d 192 case FLAG_S390_LIB64:
27d9ffda 193 fputs (",64bit", stdout);
48c53070
RM
194 break;
195 case FLAG_POWERPC_LIB64:
27d9ffda 196 fputs (",64bit", stdout);
48c53070 197 break;
b5bac573 198 case FLAG_MIPS64_LIBN32:
27d9ffda 199 fputs (",N32", stdout);
b5bac573
AO
200 break;
201 case FLAG_MIPS64_LIBN64:
27d9ffda 202 fputs (",64bit", stdout);
f1a77b01
L
203 break;
204 case FLAG_X8664_LIBX32:
205 fputs (",x32", stdout);
206 break;
6665d4a2
SM
207 case FLAG_ARM_LIBHF:
208 fputs (",hard-float", stdout);
209 break;
1f51ee92
SM
210 case FLAG_AARCH64_LIB64:
211 fputs (",AArch64", stdout);
212 break;
b39949d2
CD
213 /* Uses the ARM soft-float ABI. */
214 case FLAG_ARM_LIBSF:
215 fputs (",soft-float", stdout);
216 break;
9c21573c
MR
217 case FLAG_MIPS_LIB32_NAN2008:
218 fputs (",nan2008", stdout);
219 break;
220 case FLAG_MIPS64_LIBN32_NAN2008:
221 fputs (",N32,nan2008", stdout);
222 break;
223 case FLAG_MIPS64_LIBN64_NAN2008:
224 fputs (",64bit,nan2008", stdout);
225 break;
fb58aac5
PD
226 case FLAG_RISCV_FLOAT_ABI_SOFT:
227 fputs (",soft-float", stdout);
228 break;
229 case FLAG_RISCV_FLOAT_ABI_DOUBLE:
230 fputs (",double-float", stdout);
231 break;
591e1ffb
UD
232 case 0:
233 break;
234 default:
45eca4d1 235 printf (",%d", flag & FLAG_REQUIRED_MASK);
591e1ffb
UD
236 break;
237 }
b44ac4f4
FW
238 if (hwcap_string != NULL)
239 printf (", hwcap: \"%s\"", hwcap_string);
240 else if (hwcap != 0)
ab1d521d 241 printf (", hwcap: %#.16" PRIx64, hwcap);
a986484f
UD
242 if (osversion != 0)
243 {
244 static const char *const abi_tag_os[] =
245 {
246 [0] = "Linux",
247 [1] = "Hurd",
248 [2] = "Solaris",
82c26126 249 [3] = "FreeBSD",
ae0d550c 250 [4] = "kNetBSD",
8e856b5a
RM
251 [5] = "Syllable",
252 [6] = N_("Unknown OS")
a986484f 253 };
82c26126 254#define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
a986484f
UD
255 unsigned int os = osversion >> 24;
256
96c0d65d 257 printf (_(", OS ABI: %s %d.%d.%d"),
82c26126 258 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
a986484f
UD
259 (osversion >> 16) & 0xff,
260 (osversion >> 8) & 0xff,
261 osversion & 0xff);
262 }
591e1ffb
UD
263 printf (") => %s\n", key);
264}
265
b44ac4f4
FW
266/* Returns the string with the name of the glibcs-hwcaps subdirectory
267 associated with ENTRY->hwcap. file_base must be the base address
268 for string table indices. */
269static const char *
270glibc_hwcaps_string (struct cache_extension_all_loaded *ext,
271 const void *file_base, size_t file_size,
272 struct file_entry_new *entry)
273{
274 const uint32_t *hwcaps_array
275 = ext->sections[cache_extension_tag_glibc_hwcaps].base;
276 if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL)
277 {
278 uint32_t index = (uint32_t) entry->hwcap;
279 if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4)
280 {
281 uint32_t string_table_index = hwcaps_array[index];
282 if (string_table_index < file_size)
283 return file_base + string_table_index;
284 }
285 }
286 return NULL;
287}
288
84ba719b
FW
289/* Print an error and exit if the new-file cache is internally
290 inconsistent. */
291static void
292check_new_cache (struct cache_file_new *cache)
293{
294 if (! cache_file_new_matches_endian (cache))
295 error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
296}
591e1ffb 297
b44ac4f4 298/* Print the extension information in *EXT. */
dfb3f101
FW
299static void
300print_extensions (struct cache_extension_all_loaded *ext)
301{
302 if (ext->sections[cache_extension_tag_generator].base != NULL)
303 {
304 fputs (_("Cache generated by: "), stdout);
305 fwrite (ext->sections[cache_extension_tag_generator].base, 1,
306 ext->sections[cache_extension_tag_generator].size, stdout);
307 putchar ('\n');
308 }
309}
310
45eca4d1
UD
311/* Print the whole cache file, if a file contains the new cache format
312 hidden in the old one, print the contents of the new format. */
591e1ffb
UD
313void
314print_cache (const char *cache_name)
315{
27d9ffda 316 int fd = open (cache_name, O_RDONLY);
591e1ffb
UD
317 if (fd < 0)
318 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
319
27d9ffda 320 struct stat64 st;
04986243 321 if (__fstat64 (fd, &st) < 0
591e1ffb
UD
322 /* No need to map the file if it is empty. */
323 || st.st_size == 0)
324 {
325 close (fd);
326 return;
327 }
25ee87d6 328
27d9ffda
UD
329 struct cache_file *cache
330 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
591e1ffb
UD
331 if (cache == MAP_FAILED)
332 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
591e1ffb 333
27d9ffda 334 size_t cache_size = st.st_size;
45eca4d1
UD
335 if (cache_size < sizeof (struct cache_file))
336 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
337
27d9ffda
UD
338 struct cache_file_new *cache_new = NULL;
339 const char *cache_data;
340 int format = 0;
341
45eca4d1
UD
342 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
343 {
344 /* This can only be the new format without the old one. */
345 cache_new = (struct cache_file_new *) cache;
346
347 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
348 || memcmp (cache_new->version, CACHE_VERSION,
349 sizeof CACHE_VERSION - 1))
350 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
84ba719b 351 check_new_cache (cache_new);
45eca4d1
UD
352 format = 1;
353 /* This is where the strings start. */
e25054c4 354 cache_data = (const char *) cache_new;
45eca4d1
UD
355 }
356 else
357 {
2954daf0
AS
358 /* Check for corruption, avoiding overflow. */
359 if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry)
360 < cache->nlibs)
361 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
362
e25054c4 363 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
a986484f
UD
364 + (cache->nlibs
365 * sizeof (struct file_entry)));
45eca4d1
UD
366 /* This is where the strings start. */
367 cache_data = (const char *) &cache->libs[cache->nlibs];
368
369 /* Check for a new cache embedded in the old format. */
a04549c1
JM
370 if (cache_size
371 > (offset + sizeof (struct cache_file_new)))
45eca4d1 372 {
e25054c4
AJ
373
374 cache_new = (struct cache_file_new *) ((void *)cache + offset);
591e1ffb 375
a986484f
UD
376 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
377 sizeof CACHEMAGIC_NEW - 1) == 0
378 && memcmp (cache_new->version, CACHE_VERSION,
379 sizeof CACHE_VERSION - 1) == 0)
e25054c4 380 {
84ba719b 381 check_new_cache (cache_new);
e25054c4
AJ
382 cache_data = (const char *) cache_new;
383 format = 1;
384 }
45eca4d1
UD
385 }
386 }
25ee87d6 387
45eca4d1
UD
388 if (format == 0)
389 {
390 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
591e1ffb 391
45eca4d1 392 /* Print everything. */
27d9ffda 393 for (unsigned int i = 0; i < cache->nlibs; i++)
45eca4d1 394 print_entry (cache_data + cache->libs[i].key,
b44ac4f4 395 cache->libs[i].flags, 0, 0, NULL,
45eca4d1
UD
396 cache_data + cache->libs[i].value);
397 }
398 else if (format == 1)
399 {
dfb3f101
FW
400 struct cache_extension_all_loaded ext;
401 if (!cache_extension_load (cache_new, cache, cache_size, &ext))
402 error (EXIT_FAILURE, 0,
403 _("Malformed extension data in cache file %s\n"), cache_name);
404
a986484f
UD
405 printf (_("%d libs found in cache `%s'\n"),
406 cache_new->nlibs, cache_name);
45eca4d1
UD
407
408 /* Print everything. */
27d9ffda 409 for (unsigned int i = 0; i < cache_new->nlibs; i++)
b44ac4f4
FW
410 {
411 const char *hwcaps_string
412 = glibc_hwcaps_string (&ext, cache, cache_size,
413 &cache_new->libs[i]);
414 print_entry (cache_data + cache_new->libs[i].key,
415 cache_new->libs[i].flags,
416 cache_new->libs[i].osversion,
417 cache_new->libs[i].hwcap, hwcaps_string,
418 cache_data + cache_new->libs[i].value);
419 }
dfb3f101 420 print_extensions (&ext);
45eca4d1 421 }
591e1ffb
UD
422 /* Cleanup. */
423 munmap (cache, cache_size);
424 close (fd);
425}
426
427/* Initialize cache data structures. */
428void
429init_cache (void)
430{
431 entries = NULL;
432}
433
27d9ffda
UD
434static int
435compare (const struct cache_entry *e1, const struct cache_entry *e2)
591e1ffb 436{
591e1ffb 437 /* We need to swap entries here to get the correct sort order. */
73b6e50a 438 int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string);
591e1ffb
UD
439 if (res == 0)
440 {
441 if (e1->flags < e2->flags)
442 return 1;
443 else if (e1->flags > e2->flags)
444 return -1;
b44ac4f4
FW
445 /* Keep the glibc-hwcaps extension entries before the regular
446 entries, and sort them by their names. search_cache in
447 dl-cache.c stops searching once the first non-extension entry
448 is found, so the extension entries need to come first. */
449 else if (e1->hwcaps != NULL && e2->hwcaps == NULL)
450 return -1;
451 else if (e1->hwcaps == NULL && e2->hwcaps != NULL)
452 return 1;
453 else if (e1->hwcaps != NULL && e2->hwcaps != NULL)
454 {
455 res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps),
456 glibc_hwcaps_subdirectory_name (e2->hwcaps));
457 if (res != 0)
458 return res;
459 }
45eca4d1 460 /* Sort by most specific hwcap. */
b44ac4f4 461 if (e2->bits_hwcap > e1->bits_hwcap)
45eca4d1
UD
462 return 1;
463 else if (e2->bits_hwcap < e1->bits_hwcap)
464 return -1;
465 else if (e2->hwcap > e1->hwcap)
466 return 1;
467 else if (e2->hwcap < e1->hwcap)
468 return -1;
a986484f
UD
469 if (e2->osversion > e1->osversion)
470 return 1;
471 if (e2->osversion < e1->osversion)
472 return -1;
591e1ffb
UD
473 }
474 return res;
475}
476
dfb3f101
FW
477/* Size of the cache extension directory. All tags are assumed to be
478 present. */
479enum
480 {
481 cache_extension_size = (offsetof (struct cache_extension, sections)
482 + (cache_extension_count
483 * sizeof (struct cache_extension_section)))
484 };
485
b44ac4f4
FW
486/* Write the cache extensions to FD. The string table is shifted by
487 STRING_TABLE_OFFSET. The extension directory is assumed to be
488 located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices
489 must have been called. */
dfb3f101 490static void
b44ac4f4
FW
491write_extensions (int fd, uint32_t str_offset,
492 uint32_t cache_extension_offset)
dfb3f101
FW
493{
494 assert ((cache_extension_offset % 4) == 0);
495
b44ac4f4
FW
496 /* The length and contents of the glibc-hwcaps section. */
497 uint32_t hwcaps_count = glibc_hwcaps_count ();
498 uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size;
499 uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t);
500 uint32_t *hwcaps_array = xmalloc (hwcaps_size);
501 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
502 if (p->used)
503 hwcaps_array[p->section_index] = str_offset + p->name->offset;
504
505 /* This is the offset of the generator string. */
506 uint32_t generator_offset = hwcaps_offset;
507 if (hwcaps_count == 0)
508 /* There is no section for the hwcaps subdirectories. */
509 generator_offset -= sizeof (struct cache_extension_section);
510 else
511 /* The string table indices for the hwcaps subdirectories shift
512 the generator string backwards. */
513 generator_offset += hwcaps_size;
514
dfb3f101
FW
515 struct cache_extension *ext = xmalloc (cache_extension_size);
516 ext->magic = cache_extension_magic;
dfb3f101 517
b44ac4f4
FW
518 /* Extension index current being filled. */
519 size_t xid = 0;
dfb3f101
FW
520
521 const char *generator
522 = "ldconfig " PKGVERSION RELEASE " release version " VERSION;
b44ac4f4
FW
523 ext->sections[xid].tag = cache_extension_tag_generator;
524 ext->sections[xid].flags = 0;
525 ext->sections[xid].offset = generator_offset;
526 ext->sections[xid].size = strlen (generator);
527
528 if (hwcaps_count > 0)
529 {
530 ++xid;
531 ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps;
532 ext->sections[xid].flags = 0;
533 ext->sections[xid].offset = hwcaps_offset;
534 ext->sections[xid].size = hwcaps_size;
535 }
dfb3f101 536
b44ac4f4
FW
537 ++xid;
538 ext->count = xid;
539 assert (xid <= cache_extension_count);
540
541 size_t ext_size = (offsetof (struct cache_extension, sections)
542 + xid * sizeof (struct cache_extension_section));
543 if (write (fd, ext, ext_size) != ext_size
544 || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size
dfb3f101
FW
545 || write (fd, generator, strlen (generator)) != strlen (generator))
546 error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
547
548 free (ext);
549}
550
591e1ffb
UD
551/* Save the contents of the cache. */
552void
553save_cache (const char *cache_name)
554{
591e1ffb
UD
555 /* The cache entries are sorted already, save them in this order. */
556
b44ac4f4
FW
557 assign_glibc_hwcaps_indices ();
558
27d9ffda
UD
559 struct cache_entry *entry;
560 /* Number of cache entries. */
561 int cache_entry_count = 0;
73b6e50a
FW
562 /* The old format doesn't contain hwcap entries and doesn't contain
563 libraries in subdirectories with hwcaps entries. Count therefore
564 also all entries with hwcap == 0. */
27d9ffda
UD
565 int cache_entry_old_count = 0;
566
591e1ffb
UD
567 for (entry = entries; entry != NULL; entry = entry->next)
568 {
591e1ffb 569 ++cache_entry_count;
45eca4d1
UD
570 if (entry->hwcap == 0)
571 ++cache_entry_old_count;
591e1ffb 572 }
25ee87d6 573
73b6e50a
FW
574 struct stringtable_finalized strings_finalized;
575 stringtable_finalize (&strings, &strings_finalized);
576
591e1ffb 577 /* Create the on disk cache structure. */
27d9ffda
UD
578 struct cache_file *file_entries = NULL;
579 size_t file_entries_size = 0;
591e1ffb 580
db07fae8 581 if (opt_format != opt_format_new)
45eca4d1 582 {
062df960
UD
583 /* struct cache_file_new is 64-bit aligned on some arches while
584 only 32-bit aligned on other arches. Duplicate last old
585 cache entry so that new cache in ld.so.cache can be used by
586 both. */
db07fae8 587 if (opt_format != opt_format_old)
062df960
UD
588 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
589
45eca4d1
UD
590 /* And the list of all entries in the old format. */
591 file_entries_size = sizeof (struct cache_file)
592 + cache_entry_old_count * sizeof (struct file_entry);
27d9ffda 593 file_entries = xmalloc (file_entries_size);
45eca4d1
UD
594
595 /* Fill in the header. */
27d9ffda 596 memset (file_entries, '\0', sizeof (struct cache_file));
45eca4d1 597 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
591e1ffb 598
45eca4d1
UD
599 file_entries->nlibs = cache_entry_old_count;
600 }
25ee87d6 601
27d9ffda
UD
602 struct cache_file_new *file_entries_new = NULL;
603 size_t file_entries_new_size = 0;
604
db07fae8 605 if (opt_format != opt_format_old)
45eca4d1
UD
606 {
607 /* And the list of all entries in the new format. */
608 file_entries_new_size = sizeof (struct cache_file_new)
609 + cache_entry_count * sizeof (struct file_entry_new);
27d9ffda 610 file_entries_new = xmalloc (file_entries_new_size);
45eca4d1
UD
611
612 /* Fill in the header. */
27d9ffda 613 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
a986484f
UD
614 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
615 sizeof CACHEMAGIC_NEW - 1);
616 memcpy (file_entries_new->version, CACHE_VERSION,
617 sizeof CACHE_VERSION - 1);
45eca4d1
UD
618
619 file_entries_new->nlibs = cache_entry_count;
73b6e50a 620 file_entries_new->len_strings = strings_finalized.size;
84ba719b 621 file_entries_new->flags = cache_file_new_flags_endian_current;
45eca4d1 622 }
95582174 623
27d9ffda
UD
624 /* Pad for alignment of cache_file_new. */
625 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
95582174 626
45eca4d1
UD
627 /* If we have both formats, we hide the new format in the strings
628 table, we have to adjust all string indices for this so that
629 old libc5/glibc 2 dynamic linkers just ignore them. */
27d9ffda 630 unsigned int str_offset;
db07fae8 631 if (opt_format != opt_format_old)
45eca4d1
UD
632 str_offset = file_entries_new_size;
633 else
634 str_offset = 0;
591e1ffb 635
27d9ffda 636 /* An array for all strings. */
27d9ffda
UD
637 int idx_old;
638 int idx_new;
639
45eca4d1
UD
640 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
641 entry = entry->next, ++idx_new)
591e1ffb 642 {
db07fae8 643 if (opt_format != opt_format_new && entry->hwcap == 0)
45eca4d1
UD
644 {
645 file_entries->libs[idx_old].flags = entry->flags;
646 /* XXX: Actually we can optimize here and remove duplicates. */
e25054c4 647 file_entries->libs[idx_old].key = str_offset + pad;
73b6e50a
FW
648 file_entries->libs[idx_new].key = str_offset + entry->lib->offset;
649 file_entries->libs[idx_new].value
650 = str_offset + entry->path->offset;
45eca4d1 651 }
db07fae8 652 if (opt_format != opt_format_old)
45eca4d1
UD
653 {
654 /* We could subtract file_entries_new_size from str_offset -
655 not doing so makes the code easier, the string table
ded5b9b7 656 always begins at the beginning of the new cache
45eca4d1
UD
657 struct. */
658 file_entries_new->libs[idx_new].flags = entry->flags;
a986484f 659 file_entries_new->libs[idx_new].osversion = entry->osversion;
b44ac4f4
FW
660 if (entry->hwcaps == NULL)
661 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
662 else
663 file_entries_new->libs[idx_new].hwcap
664 = DL_CACHE_HWCAP_EXTENSION | entry->hwcaps->section_index;
73b6e50a
FW
665 file_entries_new->libs[idx_new].key
666 = str_offset + entry->lib->offset;
667 file_entries_new->libs[idx_new].value
668 = str_offset + entry->path->offset;
45eca4d1 669 }
27d9ffda 670
45eca4d1
UD
671 /* Ignore entries with hwcap for old format. */
672 if (entry->hwcap == 0)
673 ++idx_old;
591e1ffb 674 }
591e1ffb 675
062df960 676 /* Duplicate last old cache entry if needed. */
db07fae8 677 if (opt_format != opt_format_new
062df960
UD
678 && idx_old < cache_entry_old_count)
679 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
680
dfb3f101
FW
681 /* Compute the location of the extension directory. This
682 implementation puts the directory after the string table. The
683 size computation matches the write calls below. The extension
684 directory does not exist with format 0, so the value does not
685 matter. */
686 uint32_t extension_offset = 0;
687 if (opt_format != opt_format_new)
688 extension_offset += file_entries_size;
689 if (opt_format != opt_format_old)
690 {
691 if (opt_format != opt_format_new)
692 extension_offset += pad;
693 extension_offset += file_entries_new_size;
694 }
73b6e50a 695 extension_offset += strings_finalized.size;
dfb3f101
FW
696 extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
697 if (opt_format != opt_format_old)
698 file_entries_new->extension_offset = extension_offset;
699
591e1ffb
UD
700 /* Write out the cache. */
701
702 /* Write cache first to a temporary file and rename it later. */
27d9ffda 703 char *temp_name = xmalloc (strlen (cache_name) + 2);
591e1ffb 704 sprintf (temp_name, "%s~", cache_name);
591e1ffb
UD
705
706 /* Create file. */
27d9ffda
UD
707 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
708 S_IRUSR|S_IWUSR);
591e1ffb
UD
709 if (fd < 0)
710 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
711 temp_name);
712
713 /* Write contents. */
db07fae8 714 if (opt_format != opt_format_new)
45eca4d1 715 {
a986484f 716 if (write (fd, file_entries, file_entries_size)
0292b0dd 717 != (ssize_t) file_entries_size)
45eca4d1
UD
718 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
719 }
db07fae8 720 if (opt_format != opt_format_old)
45eca4d1 721 {
e25054c4 722 /* Align cache. */
db07fae8 723 if (opt_format != opt_format_new)
e25054c4 724 {
a986484f 725 char zero[pad];
0292b0dd
UD
726 memset (zero, '\0', pad);
727 if (write (fd, zero, pad) != (ssize_t) pad)
e25054c4
AJ
728 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
729 }
45eca4d1 730 if (write (fd, file_entries_new, file_entries_new_size)
0292b0dd 731 != (ssize_t) file_entries_new_size)
45eca4d1
UD
732 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
733 }
591e1ffb 734
73b6e50a
FW
735 if (write (fd, strings_finalized.strings, strings_finalized.size)
736 != (ssize_t) strings_finalized.size)
11bf311e 737 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
591e1ffb 738
dfb3f101
FW
739 if (opt_format != opt_format_old)
740 {
741 /* Align file position to 4. */
742 off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET);
743 assert ((unsigned long long int) (extension_offset - old_offset) < 4);
b44ac4f4 744 write_extensions (fd, str_offset, extension_offset);
dfb3f101
FW
745 }
746
25ee87d6 747 /* Make sure user can always read cache file */
ba9fcb3f 748 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
25ee87d6 749 error (EXIT_FAILURE, errno,
ba9fcb3f
UD
750 _("Changing access rights of %s to %#o failed"), temp_name,
751 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
25ee87d6 752
999a6dab
FW
753 /* Make sure that data is written to disk. */
754 if (fsync (fd) != 0 || close (fd) != 0)
755 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
756
591e1ffb
UD
757 /* Move temporary to its final location. */
758 if (rename (temp_name, cache_name))
759 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
760 cache_name);
25ee87d6 761
591e1ffb 762 /* Free all allocated memory. */
0292b0dd 763 free (file_entries_new);
591e1ffb 764 free (file_entries);
73b6e50a 765 free (strings_finalized.strings);
591e1ffb
UD
766
767 while (entries)
768 {
769 entry = entries;
591e1ffb
UD
770 entries = entries->next;
771 free (entry);
772 }
773}
774
45eca4d1 775
591e1ffb
UD
776/* Add one library to the cache. */
777void
b44ac4f4
FW
778add_to_cache (const char *path, const char *filename, const char *soname,
779 int flags, unsigned int osversion, uint64_t hwcap,
780 struct glibc_hwcaps_subdirectory *hwcaps)
591e1ffb 781{
73b6e50a
FW
782 struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
783
784 struct stringtable_entry *path_interned;
785 {
786 char *p;
b44ac4f4 787 if (asprintf (&p, "%s/%s", path, filename) < 0)
73b6e50a
FW
788 error (EXIT_FAILURE, errno, _("Could not create library path"));
789 path_interned = stringtable_add (&strings, p);
790 free (p);
791 }
792
b44ac4f4 793 new_entry->lib = stringtable_add (&strings, soname);
73b6e50a 794 new_entry->path = path_interned;
591e1ffb 795 new_entry->flags = flags;
a986484f 796 new_entry->osversion = osversion;
45eca4d1 797 new_entry->hwcap = hwcap;
b44ac4f4 798 new_entry->hwcaps = hwcaps;
45eca4d1
UD
799 new_entry->bits_hwcap = 0;
800
b44ac4f4
FW
801 if (hwcaps != NULL)
802 {
803 assert (hwcap == 0);
804 hwcaps->used = true;
805 }
806
45eca4d1 807 /* Count the number of bits set in the masked value. */
27d9ffda
UD
808 for (size_t i = 0;
809 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
ad1a5cc7 810 if ((hwcap & (1ULL << i)) != 0)
45eca4d1
UD
811 ++new_entry->bits_hwcap;
812
591e1ffb
UD
813
814 /* Keep the list sorted - search for right place to insert. */
27d9ffda
UD
815 struct cache_entry *ptr = entries;
816 struct cache_entry *prev = entries;
591e1ffb
UD
817 while (ptr != NULL)
818 {
819 if (compare (ptr, new_entry) > 0)
820 break;
821 prev = ptr;
822 ptr = ptr->next;
823 }
824 /* Is this the first entry? */
825 if (ptr == entries)
826 {
827 new_entry->next = entries;
828 entries = new_entry;
829 }
830 else
831 {
832 new_entry->next = prev->next;
833 prev->next = new_entry;
834 }
835}
27d9ffda
UD
836
837
838/* Auxiliary cache. */
839
840struct aux_cache_entry_id
841{
842 uint64_t ino;
843 uint64_t ctime;
844 uint64_t size;
845 uint64_t dev;
846};
847
848struct aux_cache_entry
849{
850 struct aux_cache_entry_id id;
851 int flags;
852 unsigned int osversion;
853 int used;
854 char *soname;
855 struct aux_cache_entry *next;
856};
857
858#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
859
860struct aux_cache_file_entry
861{
862 struct aux_cache_entry_id id; /* Unique id of entry. */
863 int32_t flags; /* This is 1 for an ELF library. */
864 uint32_t soname; /* String table indice. */
865 uint32_t osversion; /* Required OS version. */
866 int32_t pad;
867};
868
869/* ldconfig maintains an auxiliary cache file that allows
870 only reading those libraries that have changed since the last iteration.
871 For this for each library some information is cached in the auxiliary
872 cache. */
873struct aux_cache_file
874{
875 char magic[sizeof AUX_CACHEMAGIC - 1];
876 uint32_t nlibs; /* Number of entries. */
877 uint32_t len_strings; /* Size of string table. */
878 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
879 /* After this the string table of size len_strings is found. */
880};
881
3c87d79d 882static const unsigned int primes[] =
27d9ffda
UD
883{
884 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
885 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
886 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
887};
888
889static size_t aux_hash_size;
890static struct aux_cache_entry **aux_hash;
891
892/* Simplistic hash function for aux_cache_entry_id. */
893static unsigned int
894aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
895{
896 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
897 return ret ^ (ret >> 32);
898}
899
900static size_t nextprime (size_t x)
901{
902 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
903 if (primes[i] >= x)
904 return primes[i];
905 return x;
906}
907
908void
909init_aux_cache (void)
910{
911 aux_hash_size = primes[3];
912 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
913}
914
915int
916search_aux_cache (struct stat64 *stat_buf, int *flags,
917 unsigned int *osversion, char **soname)
918{
919 struct aux_cache_entry_id id;
920 id.ino = (uint64_t) stat_buf->st_ino;
921 id.ctime = (uint64_t) stat_buf->st_ctime;
922 id.size = (uint64_t) stat_buf->st_size;
923 id.dev = (uint64_t) stat_buf->st_dev;
924
925 unsigned int hash = aux_cache_entry_id_hash (&id);
926 struct aux_cache_entry *entry;
927 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
928 if (id.ino == entry->id.ino
929 && id.ctime == entry->id.ctime
930 && id.size == entry->id.size
931 && id.dev == entry->id.dev)
932 {
933 *flags = entry->flags;
934 *osversion = entry->osversion;
935 if (entry->soname != NULL)
936 *soname = xstrdup (entry->soname);
937 else
938 *soname = NULL;
939 entry->used = 1;
940 return 1;
941 }
942
943 return 0;
944}
945
946static void
947insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
948 unsigned int osversion, const char *soname, int used)
949{
950 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
951 struct aux_cache_entry *entry;
952 for (entry = aux_hash[hash]; entry; entry = entry->next)
953 if (id->ino == entry->id.ino
954 && id->ctime == entry->id.ctime
955 && id->size == entry->id.size
956 && id->dev == entry->id.dev)
957 abort ();
958
959 size_t len = soname ? strlen (soname) + 1 : 0;
960 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
961 entry->id = *id;
962 entry->flags = flags;
963 entry->osversion = osversion;
964 entry->used = used;
965 if (soname != NULL)
966 entry->soname = memcpy ((char *) (entry + 1), soname, len);
967 else
968 entry->soname = NULL;
969 entry->next = aux_hash[hash];
970 aux_hash[hash] = entry;
971}
972
973void
974add_to_aux_cache (struct stat64 *stat_buf, int flags,
975 unsigned int osversion, const char *soname)
976{
977 struct aux_cache_entry_id id;
978 id.ino = (uint64_t) stat_buf->st_ino;
979 id.ctime = (uint64_t) stat_buf->st_ctime;
980 id.size = (uint64_t) stat_buf->st_size;
981 id.dev = (uint64_t) stat_buf->st_dev;
982 insert_to_aux_cache (&id, flags, osversion, soname, 1);
983}
984
985/* Load auxiliary cache to search for unchanged entries. */
986void
987load_aux_cache (const char *aux_cache_name)
988{
989 int fd = open (aux_cache_name, O_RDONLY);
990 if (fd < 0)
991 {
992 init_aux_cache ();
993 return;
994 }
995
996 struct stat64 st;
04986243 997 if (__fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
27d9ffda
UD
998 {
999 close (fd);
1000 init_aux_cache ();
1001 return;
1002 }
1003
1004 size_t aux_cache_size = st.st_size;
1005 struct aux_cache_file *aux_cache
1006 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
1007 if (aux_cache == MAP_FAILED
1008 || aux_cache_size < sizeof (struct aux_cache_file)
1009 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
c4f50205
JM
1010 || aux_cache_size != (sizeof (struct aux_cache_file)
1011 + aux_cache->nlibs * sizeof (struct aux_cache_file_entry)
34a5a146 1012 + aux_cache->len_strings))
27d9ffda
UD
1013 {
1014 close (fd);
1015 init_aux_cache ();
1016 return;
1017 }
1018
1019 aux_hash_size = nextprime (aux_cache->nlibs);
1020 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
1021
1022 const char *aux_cache_data
1023 = (const char *) &aux_cache->libs[aux_cache->nlibs];
1024 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
1025 insert_to_aux_cache (&aux_cache->libs[i].id,
1026 aux_cache->libs[i].flags,
1027 aux_cache->libs[i].osversion,
1028 aux_cache->libs[i].soname == 0
1029 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
1030 0);
1031
1032 munmap (aux_cache, aux_cache_size);
1033 close (fd);
1034}
1035
1036/* Save the contents of the auxiliary cache. */
1037void
1038save_aux_cache (const char *aux_cache_name)
1039{
1040 /* Count the length of all sonames. We start with empty string. */
1041 size_t total_strlen = 1;
1042 /* Number of cache entries. */
1043 int cache_entry_count = 0;
1044
1045 for (size_t i = 0; i < aux_hash_size; ++i)
1046 for (struct aux_cache_entry *entry = aux_hash[i];
1047 entry != NULL; entry = entry->next)
1048 if (entry->used)
1049 {
1050 ++cache_entry_count;
1051 if (entry->soname != NULL)
1052 total_strlen += strlen (entry->soname) + 1;
1053 }
1054
1055 /* Auxiliary cache. */
1056 size_t file_entries_size
1057 = sizeof (struct aux_cache_file)
1058 + cache_entry_count * sizeof (struct aux_cache_file_entry);
1059 struct aux_cache_file *file_entries
1060 = xmalloc (file_entries_size + total_strlen);
1061
1062 /* Fill in the header of the auxiliary cache. */
1063 memset (file_entries, '\0', sizeof (struct aux_cache_file));
1064 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
1065
1066 file_entries->nlibs = cache_entry_count;
1067 file_entries->len_strings = total_strlen;
1068
1069 /* Initial String offset for auxiliary cache is always after the
1070 special empty string. */
1071 unsigned int str_offset = 1;
1072
1073 /* An array for all strings. */
1074 char *str = (char *) file_entries + file_entries_size;
1075 *str++ = '\0';
1076
1077 size_t idx = 0;
1078 for (size_t i = 0; i < aux_hash_size; ++i)
1079 for (struct aux_cache_entry *entry = aux_hash[i];
1080 entry != NULL; entry = entry->next)
1081 if (entry->used)
1082 {
1083 file_entries->libs[idx].id = entry->id;
1084 file_entries->libs[idx].flags = entry->flags;
1085 if (entry->soname == NULL)
1086 file_entries->libs[idx].soname = 0;
1087 else
1088 {
1089 file_entries->libs[idx].soname = str_offset;
1090
1091 size_t len = strlen (entry->soname) + 1;
1092 str = mempcpy (str, entry->soname, len);
1093 str_offset += len;
1094 }
1095 file_entries->libs[idx].osversion = entry->osversion;
1096 file_entries->libs[idx++].pad = 0;
1097 }
1098
1099 /* Write out auxiliary cache file. */
1100 /* Write auxiliary cache first to a temporary file and rename it later. */
1101
1102 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
1103 sprintf (temp_name, "%s~", aux_cache_name);
1104
1105 /* Check that directory exists and create if needed. */
1106 char *dir = strdupa (aux_cache_name);
1107 dir = dirname (dir);
1108
1109 struct stat64 st;
1110 if (stat64 (dir, &st) < 0)
1111 {
1112 if (mkdir (dir, 0700) < 0)
1113 goto out_fail;
1114 }
1115
1116 /* Create file. */
1117 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
1118 S_IRUSR|S_IWUSR);
1119 if (fd < 0)
1120 goto out_fail;
1121
1122 if (write (fd, file_entries, file_entries_size + total_strlen)
1123 != (ssize_t) (file_entries_size + total_strlen)
999a6dab
FW
1124 || fdatasync (fd) != 0
1125 || close (fd) != 0)
27d9ffda
UD
1126 {
1127 unlink (temp_name);
1128 goto out_fail;
1129 }
1130
1131 /* Move temporary to its final location. */
1132 if (rename (temp_name, aux_cache_name))
1133 unlink (temp_name);
1134
1135out_fail:
1136 /* Free allocated memory. */
78d6dd72 1137 free (temp_name);
27d9ffda
UD
1138 free (file_entries);
1139}