/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
- Copyright (C) 1996-2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <dl-cache.h>
#include <dl-procinfo.h>
-
-#include <stdio-common/_itoa.h>
+#include <stdint.h>
+#include <_itoa.h>
#ifndef _DL_PLATFORMS_COUNT
# define _DL_PLATFORMS_COUNT 0
\
/* Actually compare the entry with the key. */ \
cmpres = _dl_cache_libcmp (name, cache_data + key); \
- if (__builtin_expect (cmpres == 0, 0)) \
+ if (__glibc_unlikely (cmpres == 0)) \
{ \
/* Found it. LEFT now marks the last entry for which we \
know the name is correct. */ \
}
-/* Look up NAME in ld.so.cache and return the file name stored there,
- or null if none is found. */
-
-const char *
+/* Look up NAME in ld.so.cache and return the file name stored there, or null
+ if none is found. The cache is loaded if it was not already. If loading
+ the cache previously failed there will be no more attempts to load it.
+ The caller is responsible for freeing the returned string. The ld.so.cache
+ may be unmapped at any time by a completing recursive dlopen and
+ this function must take care that it does not return references to
+ any data in the mapping. */
+char *
internal_function
_dl_load_cache_lookup (const char *name)
{
const char *best;
/* Print a message if the loading of libs is traced. */
- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
_dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
if (cache == NULL)
if (platform != (uint64_t) -1)
platform = 1ULL << platform;
- /* Only accept hwcap if it's for the right platform. */
#define _DL_HWCAP_TLS_MASK (1LL << 63)
+ uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & GLRO(dl_hwcap_mask))
+ | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
+
+ /* Only accept hwcap if it's for the right platform. */
#define HWCAP_CHECK \
+ if (lib->hwcap & hwcap_exclude) \
+ continue; \
if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \
continue; \
if (_DL_PLATFORMS_COUNT \
&& (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
&& (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
- continue; \
- if (lib->hwcap \
- & ~(GLRO(dl_hwcap) | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK)) \
continue
SEARCH_CACHE (cache_new);
}
&& best != NULL)
_dl_debug_printf (" trying file=%s\n", best);
- return best;
+ if (best == NULL)
+ return NULL;
+
+ /* The double copy is *required* since malloc may be interposed
+ and call dlopen itself whose completion would unmap the data
+ we are accessing. Therefore we must make the copy of the
+ mapping data without using malloc. */
+ char *temp;
+ temp = alloca (strlen (best) + 1);
+ strcpy (temp, best);
+ return strdup (temp);
}
#ifndef MAP_COPY