about summary refs log tree commit diff
path: root/sysdeps/generic/dl-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/generic/dl-cache.c')
-rw-r--r--sysdeps/generic/dl-cache.c275
1 files changed, 139 insertions, 136 deletions
diff --git a/sysdeps/generic/dl-cache.c b/sysdeps/generic/dl-cache.c
index 2ab13d8d3f..28fab0b19e 100644
--- a/sysdeps/generic/dl-cache.c
+++ b/sysdeps/generic/dl-cache.c
@@ -22,31 +22,16 @@
 #include <sys/mman.h>
 #include <dl-cache.h>
 
+
 /* System-dependent function to read a file's whole contents
    in the most convenient manner available.  */
 extern void *_dl_sysdep_read_whole_file (const char *filename,
 					 size_t *filesize_ptr,
 					 int mmap_prot);
 
-#ifndef LD_SO_CACHE
-# define LD_SO_CACHE "/etc/ld.so.cache"
-#endif
-
-#define CACHEMAGIC "ld.so-1.7.0"
-
-struct cache_file
-  {
-    char magic[sizeof CACHEMAGIC - 1];
-    unsigned int nlibs;
-    struct
-      {
-	int flags;		/* This is 1 for an ELF library.  */
-	unsigned int key, value; /* String table indices.  */
-      } libs[0];
-  };
-
 /* This is the starting address and the size of the mmap()ed file.  */
 static struct cache_file *cache;
+static struct cache_file_new *cache_new;
 static size_t cachesize;
 
 /* 1 if cache_data + PTR points into the cache.  */
@@ -56,45 +41,100 @@ static size_t cachesize;
    binaries.  */
 int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
 
-/* Helper function which must match the one in ldconfig, so that
-   we rely on the same sort order.  */
-static int
-_dl_cache_libcmp (const char *p1, const char *p2)
-{
-  while (*p1 != '\0')
-    {
-      if (*p1 >= '0' && *p1 <= '9')
-        {
-          if (*p2 >= '0' && *p2 <= '9')
-            {
-	      /* Must compare this numerically.  */
-	      int val1;
-	      int val2;
-
-	      val1 = *p1++ - '0';
-	      val2 = *p2++ - '0';
-	      while (*p1 >= '0' && *p1 <= '9')
-	        val1 = val1 * 10 + *p1++ - '0';
-	      while (*p2 >= '0' && *p2 <= '9')
-	        val2 = val2 * 10 + *p2++ - '0';
-	      if (val1 != val2)
-		return val1 - val2;
-	    }
-	  else
-            return 1;
-        }
-      else if (*p2 >= '0' && *p2 <= '9')
-        return -1;
-      else if (*p1 != *p2)
-        return *p1 - *p2;
-      else
-	{
-	  ++p1;
-	  ++p2;
-	}
-    }
-  return *p1 - *p2;
-}
+#define SEARCH_CACHE(cache)						  \
+/* We use binary search since the table is sorted in the cache file.	  \
+   The first matching entry in the table is returned.			  \
+   It is important to use the same algorithm as used while generating	  \
+   the cache file.  */							  \
+do									  \
+  {									  \
+    left = 0;								  \
+    right = cache->nlibs - 1;						  \
+    middle = (left + right) / 2;					  \
+    cmpres = 1;								  \
+    									  \
+    while (left <= right)						  \
+      {									  \
+	/* Make sure string table indices are not bogus before using	  \
+	   them.  */							  \
+	if (! _dl_cache_verify_ptr (cache->libs[middle].key))		  \
+	  {								  \
+	    cmpres = 1;							  \
+	    break;							  \
+	  }								  \
+									  \
+	/* Actually compare the entry with the key.  */			  \
+	cmpres = _dl_cache_libcmp (name,				  \
+				   cache_data + cache->libs[middle].key); \
+	if (cmpres == 0)						  \
+	  /* Found it.  */						  \
+	  break;							  \
+									  \
+	if (cmpres < 0)							  \
+	  left = middle + 1;						  \
+	else								  \
+	  right = middle - 1;						  \
+									  \
+	middle = (left + right) / 2;					  \
+      }									  \
+									  \
+    if (cmpres == 0)							  \
+      {									  \
+	/* LEFT now marks the last entry for which we know the name is	  \
+	   correct.  */							  \
+	left = middle;							  \
+									  \
+	/* There might be entries with this name before the one we	  \
+	   found.  So we have to find the beginning.  */		  \
+	while (middle > 0						  \
+	       /* Make sure string table indices are not bogus before	  \
+		  using them.  */					  \
+	       && _dl_cache_verify_ptr (cache->libs[middle - 1].key)	  \
+	       /* Actually compare the entry.  */			  \
+	       && (_dl_cache_libcmp (name,				  \
+				     cache_data				  \
+				     + cache->libs[middle - 1].key)	  \
+		   == 0))						  \
+	  --middle;							  \
+									  \
+	do								  \
+	  {								  \
+	    int flags;							  \
+									  \
+	    /* Only perform the name test if necessary.  */		  \
+	    if (middle > left						  \
+		/* We haven't seen this string so far.  Test whether the  \
+		   index is ok and whether the name matches.  Otherwise	  \
+		   we are done.  */					  \
+		&& (! _dl_cache_verify_ptr (cache->libs[middle].key)	  \
+		    || (_dl_cache_libcmp (name,				  \
+					  cache_data			  \
+					  + cache->libs[middle].key)	  \
+			!= 0)))						  \
+	      break;							  \
+									  \
+	    flags = cache->libs[middle].flags;				  \
+	    if (_dl_cache_check_flags (flags)				  \
+		&& _dl_cache_verify_ptr (cache->libs[middle].value))	  \
+	      {								  \
+		if (best == NULL || flags == _dl_correct_cache_id)	  \
+		  {							  \
+		    HWCAP_CHECK;					  \
+		    best = cache_data + cache->libs[middle].value;	  \
+		    							  \
+		    if (flags == _dl_correct_cache_id)			  \
+		      /* We've found an exact match for the shared	  \
+			 object and no general `ELF' release.  Stop	  \
+			 searching.  */					  \
+		      break;						  \
+		  }							  \
+	      }								  \
+	  }								  \
+	while (++middle <= right);					  \
+      }									  \
+  }									  \
+while (0)
+
 
 
 /* Look up NAME in ld.so.cache and return the file name stored there,
@@ -117,10 +157,38 @@ _dl_load_cache_lookup (const char *name)
       /* Read the contents of the file.  */
       void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
 					       PROT_READ);
+
+      /* We can handle three different cache file formats here:
+	 - the old libc5/glibc2.0/2.1 format
+	 - the old format with the new format in it
+	 - only the new format
+	 The following checks if the cache contains any of these formats.  */
       if (file && cachesize > sizeof *cache &&
 	  !memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1))
-	/* Looks ok.  */
-	cache = file;
+	{
+	  /* Looks ok.  */
+	  cache = file;
+
+	  /* Check for new version.  */
+	  cache_new = (struct cache_file_new *) &cache->libs[cache->nlibs];
+	  if (cachesize <
+	      (sizeof (struct cache_file) + cache->nlibs * sizeof (struct file_entry)
+	       + sizeof (struct cache_file_new))
+	      || memcmp (cache_new->magic, CACHEMAGIC_NEW,
+			  sizeof CACHEMAGIC_NEW - 1)
+	      || memcmp (cache_new->version, CACHE_VERSION,
+			 sizeof CACHE_VERSION - 1))
+	    cache_new = (void *) -1;
+	}
+      else if (file && cachesize > sizeof *cache_new)
+	{
+	  cache_new = (struct cache_file_new *) file;
+	  if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
+		      sizeof CACHEMAGIC_NEW - 1)
+	      || memcmp (cache_new->version, CACHE_VERSION,
+			 sizeof CACHE_VERSION - 1))
+	    cache_new = (void *) -1;
+	}
       else
 	{
 	  if (file)
@@ -139,88 +207,23 @@ _dl_load_cache_lookup (const char *name)
 
   best = NULL;
 
-  /* We use binary search since the table is sorted in the cache file.
-     It is important to use the same algorithm as used while generating
-     the cache file.  */
-  left = 0;
-  right = cache->nlibs - 1;
-  middle = (left + right) / 2;
-  cmpres = 1;
-
-  while (left <= right)
+  if (cache_new != (void *) -1)
     {
-      /* Make sure string table indices are not bogus before using them.  */
-      if (! _dl_cache_verify_ptr (cache->libs[middle].key))
-	{
-	  cmpres = 1;
-	  break;
-	}
+      /* This file ends in static libraries where we don't have a hwcap.  */
+      unsigned long int *hwcap;
+      weak_extern (_dl_hwcap);
 
-      /* Actually compare the entry with the key.  */
-      cmpres = _dl_cache_libcmp (name, cache_data + cache->libs[middle].key);
-      if (cmpres == 0)
-	/* Found it.  */
-	break;
+      hwcap = &_dl_hwcap;
 
-      if (cmpres < 0)
-	left = middle + 1;
-      else
-	right = middle - 1;
-
-      middle = (left + right) / 2;
-    }
-
-  if (cmpres == 0)
-    {
-      /* LEFT now marks the last entry for which we know the name is
-	 correct.  */
-      left = middle;
-
-      /* There might be entries with this name before the one we
-         found.  So we have to find the beginning.  */
-      while (middle > 0
-	     /* Make sure string table indices are not bogus before
-                using them.  */
-	     && _dl_cache_verify_ptr (cache->libs[middle - 1].key)
-	     /* Actually compare the entry.  */
-	     && (_dl_cache_libcmp (name,
-				   cache_data + cache->libs[middle - 1].key)
-		 == 0))
-	--middle;
-
-      do
-	{
-	  int flags;
-
-	  /* Only perform the name test if necessary.  */
-	  if (middle > left
-	      /* We haven't seen this string so far.  Test whether the
-		 index is ok and whether the name matches.  Otherwise
-		 we are done.  */
-	      && (! _dl_cache_verify_ptr (cache->libs[middle].key)
-		  || (_dl_cache_libcmp (name,
-					cache_data + cache->libs[middle].key)
-		      != 0)))
-	    break;
-
-	  flags = cache->libs[middle].flags;
-	  if (_dl_cache_check_flags (flags)
-	      && _dl_cache_verify_ptr (cache->libs[middle].value))
-	    {
-	      if (best == NULL || flags == _dl_correct_cache_id)
-		{
-		  best = cache_data + cache->libs[middle].value;
-
-		  if (flags == _dl_correct_cache_id)
-		    /* We've found an exact match for the shared
-		       object and no general `ELF' release.  Stop
-		       searching.  */
-		    break;
-		}
-	    }
-	}
-      while (++middle <= right);
+#define HWCAP_CHECK							     \
+      if (hwcap && (cache_new->libs[middle].hwcap & *hwcap) > _dl_hwcap)     \
+	continue
+      SEARCH_CACHE (cache_new);
     }
+  else
+#undef HWCAP_CHECK
+#define HWCAP_CHECK do {} while (0)
+    SEARCH_CACHE (cache);
 
   /* Print our result if wanted.  */
   if (_dl_debug_libs && best != NULL)