Back to index

glibc  2.9
dl-cache.c
Go to the documentation of this file.
00001 /* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
00002    Copyright (C) 1996-2002, 2003, 2004, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <unistd.h>
00022 #include <ldsodefs.h>
00023 #include <sys/mman.h>
00024 #include <dl-cache.h>
00025 #include <dl-procinfo.h>
00026 
00027 #include <stdio-common/_itoa.h>
00028 
00029 #ifndef _DL_PLATFORMS_COUNT
00030 # define _DL_PLATFORMS_COUNT 0
00031 #endif
00032 
00033 /* This is the starting address and the size of the mmap()ed file.  */
00034 static struct cache_file *cache;
00035 static struct cache_file_new *cache_new;
00036 static size_t cachesize;
00037 
00038 /* 1 if cache_data + PTR points into the cache.  */
00039 #define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
00040 
00041 #define SEARCH_CACHE(cache) \
00042 /* We use binary search since the table is sorted in the cache file.        \
00043    The first matching entry in the table is returned.                       \
00044    It is important to use the same algorithm as used while generating       \
00045    the cache file.  */                                                      \
00046 do                                                                   \
00047   {                                                                  \
00048     left = 0;                                                        \
00049     right = cache->nlibs - 1;                                               \
00050                                                                      \
00051     while (left <= right)                                            \
00052       {                                                                     \
00053        __typeof__ (cache->libs[0].key) key;                                 \
00054                                                                      \
00055        middle = (left + right) / 2;                                         \
00056                                                                      \
00057        key = cache->libs[middle].key;                                       \
00058                                                                      \
00059        /* Make sure string table indices are not bogus before using         \
00060           them.  */                                                  \
00061        if (! _dl_cache_verify_ptr (key))                             \
00062          {                                                           \
00063            cmpres = 1;                                                      \
00064            break;                                                    \
00065          }                                                           \
00066                                                                      \
00067        /* Actually compare the entry with the key.  */                      \
00068        cmpres = _dl_cache_libcmp (name, cache_data + key);                  \
00069        if (__builtin_expect (cmpres == 0, 0))                               \
00070          {                                                           \
00071            /* Found it.  LEFT now marks the last entry for which we         \
00072               know the name is correct.  */                                 \
00073            left = middle;                                            \
00074                                                                      \
00075            /* There might be entries with this name before the one we       \
00076               found.  So we have to find the beginning.  */                 \
00077            while (middle > 0)                                               \
00078              {                                                              \
00079               __typeof__ (cache->libs[0].key) key;                          \
00080                                                                      \
00081               key = cache->libs[middle - 1].key;                     \
00082               /* Make sure string table indices are not bogus before        \
00083                  using them.  */                                     \
00084               if (! _dl_cache_verify_ptr (key)                       \
00085                   /* Actually compare the entry.  */                        \
00086                   || _dl_cache_libcmp (name, cache_data + key) != 0)        \
00087                 break;                                               \
00088               --middle;                                              \
00089              }                                                              \
00090                                                                      \
00091            do                                                        \
00092              {                                                              \
00093               int flags;                                             \
00094               __typeof__ (cache->libs[0]) *lib = &cache->libs[middle];      \
00095                                                                      \
00096               /* Only perform the name test if necessary.  */               \
00097               if (middle > left                                      \
00098                   /* We haven't seen this string so far.  Test whether the  \
00099                      index is ok and whether the name matches.  Otherwise   \
00100                      we are done.  */                                       \
00101                   && (! _dl_cache_verify_ptr (lib->key)              \
00102                      || (_dl_cache_libcmp (name, cache_data + lib->key)    \
00103                          != 0)))                                     \
00104                 break;                                               \
00105                                                                      \
00106               flags = lib->flags;                                    \
00107               if (_dl_cache_check_flags (flags)                      \
00108                   && _dl_cache_verify_ptr (lib->value))              \
00109                 {                                                    \
00110                   if (best == NULL || flags == GLRO(dl_correct_cache_id))   \
00111                     {                                                       \
00112                      HWCAP_CHECK;                                    \
00113                      best = cache_data + lib->value;                        \
00114                                                                      \
00115                      if (flags == GLRO(dl_correct_cache_id))                \
00116                        /* We've found an exact match for the shared         \
00117                           object and no general `ELF' release.  Stop        \
00118                           searching.  */                             \
00119                        break;                                        \
00120                     }                                                       \
00121                 }                                                    \
00122              }                                                              \
00123            while (++middle <= right);                                       \
00124            break;                                                    \
00125        }                                                             \
00126                                                                      \
00127        if (cmpres < 0)                                                      \
00128          left = middle + 1;                                          \
00129        else                                                          \
00130          right = middle - 1;                                                \
00131       }                                                                     \
00132   }                                                                  \
00133 while (0)
00134 
00135 
00136 int
00137 internal_function
00138 _dl_cache_libcmp (const char *p1, const char *p2)
00139 {
00140   while (*p1 != '\0')
00141     {
00142       if (*p1 >= '0' && *p1 <= '9')
00143         {
00144           if (*p2 >= '0' && *p2 <= '9')
00145             {
00146              /* Must compare this numerically.  */
00147              int val1;
00148              int val2;
00149 
00150              val1 = *p1++ - '0';
00151              val2 = *p2++ - '0';
00152              while (*p1 >= '0' && *p1 <= '9')
00153                val1 = val1 * 10 + *p1++ - '0';
00154              while (*p2 >= '0' && *p2 <= '9')
00155                val2 = val2 * 10 + *p2++ - '0';
00156              if (val1 != val2)
00157               return val1 - val2;
00158            }
00159          else
00160             return 1;
00161         }
00162       else if (*p2 >= '0' && *p2 <= '9')
00163         return -1;
00164       else if (*p1 != *p2)
00165         return *p1 - *p2;
00166       else
00167        {
00168          ++p1;
00169          ++p2;
00170        }
00171     }
00172   return *p1 - *p2;
00173 }
00174 
00175 
00176 /* Look up NAME in ld.so.cache and return the file name stored there,
00177    or null if none is found.  */
00178 
00179 const char *
00180 internal_function
00181 _dl_load_cache_lookup (const char *name)
00182 {
00183   int left, right, middle;
00184   int cmpres;
00185   const char *cache_data;
00186   uint32_t cache_data_size;
00187   const char *best;
00188 
00189   /* Print a message if the loading of libs is traced.  */
00190   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
00191     _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
00192 
00193   if (cache == NULL)
00194     {
00195       /* Read the contents of the file.  */
00196       void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
00197                                           PROT_READ);
00198 
00199       /* We can handle three different cache file formats here:
00200         - the old libc5/glibc2.0/2.1 format
00201         - the old format with the new format in it
00202         - only the new format
00203         The following checks if the cache contains any of these formats.  */
00204       if (file != MAP_FAILED && cachesize > sizeof *cache
00205          && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
00206        {
00207          size_t offset;
00208          /* Looks ok.  */
00209          cache = file;
00210 
00211          /* Check for new version.  */
00212          offset = ALIGN_CACHE (sizeof (struct cache_file)
00213                             + cache->nlibs * sizeof (struct file_entry));
00214 
00215          cache_new = (struct cache_file_new *) ((void *) cache + offset);
00216          if (cachesize < (offset + sizeof (struct cache_file_new))
00217              || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
00218                       sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
00219            cache_new = (void *) -1;
00220        }
00221       else if (file != MAP_FAILED && cachesize > sizeof *cache_new
00222               && memcmp (file, CACHEMAGIC_VERSION_NEW,
00223                        sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
00224        {
00225          cache_new = file;
00226          cache = file;
00227        }
00228       else
00229        {
00230          if (file != MAP_FAILED)
00231            __munmap (file, cachesize);
00232          cache = (void *) -1;
00233        }
00234 
00235       assert (cache != NULL);
00236     }
00237 
00238   if (cache == (void *) -1)
00239     /* Previously looked for the cache file and didn't find it.  */
00240     return NULL;
00241 
00242   best = NULL;
00243 
00244   if (cache_new != (void *) -1)
00245     {
00246       uint64_t platform;
00247 
00248       /* This is where the strings start.  */
00249       cache_data = (const char *) cache_new;
00250 
00251       /* Now we can compute how large the string table is.  */
00252       cache_data_size = (const char *) cache + cachesize - cache_data;
00253 
00254       platform = _dl_string_platform (GLRO(dl_platform));
00255       if (platform != (uint64_t) -1)
00256        platform = 1ULL << platform;
00257 
00258       /* Only accept hwcap if it's for the right platform.  */
00259 #define _DL_HWCAP_TLS_MASK (1LL << 63)
00260 #define HWCAP_CHECK \
00261       if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion))        \
00262        continue;                                                     \
00263       if (_DL_PLATFORMS_COUNT                                               \
00264          && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0                          \
00265          && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform)                  \
00266        continue;                                                     \
00267       if (lib->hwcap                                                 \
00268          & ~(GLRO(dl_hwcap) | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK))      \
00269        continue
00270       SEARCH_CACHE (cache_new);
00271     }
00272   else
00273     {
00274       /* This is where the strings start.  */
00275       cache_data = (const char *) &cache->libs[cache->nlibs];
00276 
00277       /* Now we can compute how large the string table is.  */
00278       cache_data_size = (const char *) cache + cachesize - cache_data;
00279 
00280 #undef HWCAP_CHECK
00281 #define HWCAP_CHECK do {} while (0)
00282       SEARCH_CACHE (cache);
00283     }
00284 
00285   /* Print our result if wanted.  */
00286   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
00287       && best != NULL)
00288     _dl_debug_printf ("  trying file=%s\n", best);
00289 
00290   return best;
00291 }
00292 
00293 #ifndef MAP_COPY
00294 /* If the system does not support MAP_COPY we cannot leave the file open
00295    all the time since this would create problems when the file is replaced.
00296    Therefore we provide this function to close the file and open it again
00297    once needed.  */
00298 void
00299 _dl_unload_cache (void)
00300 {
00301   if (cache != NULL && cache != (struct cache_file *) -1)
00302     {
00303       __munmap (cache, cachesize);
00304       cache = NULL;
00305     }
00306 }
00307 #endif