Blame elf/dl-deps.c

Packit Service 82fcde
/* Load the dependencies of a mapped object.
Packit Service 82fcde
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <atomic.h>
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <scratch_buffer.h>
Packit Service 82fcde
Packit Service 82fcde
#include <dl-dst.h>
Packit Service 82fcde
Packit Service 82fcde
/* Whether an shared object references one or more auxiliary objects
Packit Service 82fcde
   is signaled by the AUXTAG entry in l_info.  */
Packit Service 82fcde
#define AUXTAG	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
Packit Service 82fcde
		 + DT_EXTRATAGIDX (DT_AUXILIARY))
Packit Service 82fcde
/* Whether an shared object references one or more auxiliary objects
Packit Service 82fcde
   is signaled by the AUXTAG entry in l_info.  */
Packit Service 82fcde
#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
Packit Service 82fcde
		   + DT_EXTRATAGIDX (DT_FILTER))
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* When loading auxiliary objects we must ignore errors.  It's ok if
Packit Service 82fcde
   an object is missing.  */
Packit Service 82fcde
struct openaux_args
Packit Service 82fcde
  {
Packit Service 82fcde
    /* The arguments to openaux.  */
Packit Service 82fcde
    struct link_map *map;
Packit Service 82fcde
    int trace_mode;
Packit Service 82fcde
    int open_mode;
Packit Service 82fcde
    const char *strtab;
Packit Service 82fcde
    const char *name;
Packit Service 82fcde
Packit Service 82fcde
    /* The return value of openaux.  */
Packit Service 82fcde
    struct link_map *aux;
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
openaux (void *a)
Packit Service 82fcde
{
Packit Service 82fcde
  struct openaux_args *args = (struct openaux_args *) a;
Packit Service 82fcde
Packit Service 82fcde
  args->aux = _dl_map_object (args->map, args->name,
Packit Service 82fcde
			      (args->map->l_type == lt_executable
Packit Service 82fcde
			       ? lt_library : args->map->l_type),
Packit Service 82fcde
			      args->trace_mode, args->open_mode,
Packit Service 82fcde
			      args->map->l_ns);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static ptrdiff_t
Packit Service 82fcde
_dl_build_local_scope (struct link_map **list, struct link_map *map)
Packit Service 82fcde
{
Packit Service 82fcde
  struct link_map **p = list;
Packit Service 82fcde
  struct link_map **q;
Packit Service 82fcde
Packit Service 82fcde
  *p++ = map;
Packit Service 82fcde
  map->l_reserved = 1;
Packit Service 82fcde
  if (map->l_initfini)
Packit Service 82fcde
    for (q = map->l_initfini + 1; *q; ++q)
Packit Service 82fcde
      if (! (*q)->l_reserved)
Packit Service 82fcde
	p += _dl_build_local_scope (p, *q);
Packit Service 82fcde
  return p - list;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* We use a very special kind of list to track the path
Packit Service 82fcde
   through the list of loaded shared objects.  We have to
Packit Service 82fcde
   produce a flat list with unique members of all involved objects.
Packit Service 82fcde
*/
Packit Service 82fcde
struct list
Packit Service 82fcde
  {
Packit Service 82fcde
    int done;			/* Nonzero if this map was processed.  */
Packit Service 82fcde
    struct link_map *map;	/* The data.  */
Packit Service 82fcde
    struct list *next;		/* Elements for normal list.  */
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Macro to expand DST.  It is an macro since we use `alloca'.  */
Packit Service 82fcde
#define expand_dst(l, str, fatal) \
Packit Service 82fcde
  ({									      \
Packit Service 82fcde
    const char *__str = (str);						      \
Packit Service 82fcde
    const char *__result = __str;					      \
Packit Service 82fcde
    size_t __dst_cnt = _dl_dst_count (__str);				      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    if (__dst_cnt != 0)							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	char *__newp;							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	/* DST must not appear in SUID/SGID programs.  */		      \
Packit Service 82fcde
	if (__libc_enable_secure)					      \
Packit Service 82fcde
	  _dl_signal_error (0, __str, NULL, N_("\
Packit Service 82fcde
DST not allowed in SUID/SGID programs"));				      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str),  \
Packit Service 82fcde
						   __dst_cnt));		      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	__result = _dl_dst_substitute (l, __str, __newp);		      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	if (*__result == '\0')						      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    /* The replacement for the DST is not known.  We can't	      \
Packit Service 82fcde
	       processed.  */						      \
Packit Service 82fcde
	    if (fatal)							      \
Packit Service 82fcde
	      _dl_signal_error (0, __str, NULL, N_("\
Packit Service 82fcde
empty dynamic string token substitution"));				      \
Packit Service 82fcde
	    else							      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		/* This is for DT_AUXILIARY.  */			      \
Packit Service 82fcde
		if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))   \
Packit Service 82fcde
		  _dl_debug_printf (N_("\
Packit Service 82fcde
cannot load auxiliary `%s' because of empty dynamic string token "	      \
Packit Service 82fcde
					    "substitution\n"), __str);	      \
Packit Service 82fcde
		continue;						      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    __result; })
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
preload (struct list *known, unsigned int *nlist, struct link_map *map)
Packit Service 82fcde
{
Packit Service 82fcde
  known[*nlist].done = 0;
Packit Service 82fcde
  known[*nlist].map = map;
Packit Service 82fcde
  known[*nlist].next = &known[*nlist + 1];
Packit Service 82fcde
Packit Service 82fcde
  ++*nlist;
Packit Service 82fcde
  /* We use `l_reserved' as a mark bit to detect objects we have
Packit Service 82fcde
     already put in the search list and avoid adding duplicate
Packit Service 82fcde
     elements later in the list.  */
Packit Service 82fcde
  map->l_reserved = 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_map_object_deps (struct link_map *map,
Packit Service 82fcde
		     struct link_map **preloads, unsigned int npreloads,
Packit Service 82fcde
		     int trace_mode, int open_mode)
Packit Service 82fcde
{
Packit Service 82fcde
  struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
Packit Service 82fcde
  struct list *runp, *tail;
Packit Service 82fcde
  unsigned int nlist, i;
Packit Service 82fcde
  /* Object name.  */
Packit Service 82fcde
  const char *name;
Packit Service 82fcde
  int errno_saved;
Packit Service 82fcde
  int errno_reason;
Packit Service 82fcde
  struct dl_exception exception;
Packit Service 82fcde
Packit Service 82fcde
  /* No loaded object so far.  */
Packit Service 82fcde
  nlist = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* First load MAP itself.  */
Packit Service 82fcde
  preload (known, &nlist, map);
Packit Service 82fcde
Packit Service 82fcde
  /* Add the preloaded items after MAP but before any of its dependencies.  */
Packit Service 82fcde
  for (i = 0; i < npreloads; ++i)
Packit Service 82fcde
    preload (known, &nlist, preloads[i]);
Packit Service 82fcde
Packit Service 82fcde
  /* Terminate the lists.  */
Packit Service 82fcde
  known[nlist - 1].next = NULL;
Packit Service 82fcde
Packit Service 82fcde
  /* Pointer to last unique object.  */
Packit Service 82fcde
  tail = &known[nlist - 1];
Packit Service 82fcde
Packit Service 82fcde
  struct scratch_buffer needed_space;
Packit Service 82fcde
  scratch_buffer_init (&needed_space);
Packit Service 82fcde
Packit Service 82fcde
  /* Process each element of the search list, loading each of its
Packit Service 82fcde
     auxiliary objects and immediate dependencies.  Auxiliary objects
Packit Service 82fcde
     will be added in the list before the object itself and
Packit Service 82fcde
     dependencies will be appended to the list as we step through it.
Packit Service 82fcde
     This produces a flat, ordered list that represents a
Packit Service 82fcde
     breadth-first search of the dependency tree.
Packit Service 82fcde
Packit Service 82fcde
     The whole process is complicated by the fact that we better
Packit Service 82fcde
     should use alloca for the temporary list elements.  But using
Packit Service 82fcde
     alloca means we cannot use recursive function calls.  */
Packit Service 82fcde
  errno_saved = errno;
Packit Service 82fcde
  errno_reason = 0;
Packit Service 82fcde
  errno = 0;
Packit Service 82fcde
  name = NULL;
Packit Service 82fcde
  for (runp = known; runp; )
Packit Service 82fcde
    {
Packit Service 82fcde
      struct link_map *l = runp->map;
Packit Service 82fcde
      struct link_map **needed = NULL;
Packit Service 82fcde
      unsigned int nneeded = 0;
Packit Service 82fcde
Packit Service 82fcde
      /* Unless otherwise stated, this object is handled.  */
Packit Service 82fcde
      runp->done = 1;
Packit Service 82fcde
Packit Service 82fcde
      /* Allocate a temporary record to contain the references to the
Packit Service 82fcde
	 dependencies of this object.  */
Packit Service 82fcde
      if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
Packit Service 82fcde
	  && l != map && l->l_ldnum > 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* l->l_ldnum includes space for the terminating NULL.  */
Packit Service 82fcde
	  if (!scratch_buffer_set_array_size
Packit Service 82fcde
	      (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
Packit Service 82fcde
	    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit Service 82fcde
			      N_("cannot allocate dependency buffer"));
Packit Service 82fcde
	  needed = needed_space.data;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
Packit Service 82fcde
	{
Packit Service 82fcde
	  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
Packit Service 82fcde
	  struct openaux_args args;
Packit Service 82fcde
	  struct list *orig;
Packit Service 82fcde
	  const ElfW(Dyn) *d;
Packit Service 82fcde
Packit Service 82fcde
	  args.strtab = strtab;
Packit Service 82fcde
	  args.map = l;
Packit Service 82fcde
	  args.trace_mode = trace_mode;
Packit Service 82fcde
	  args.open_mode = open_mode;
Packit Service 82fcde
	  orig = runp;
Packit Service 82fcde
Packit Service 82fcde
	  for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
Packit Service 82fcde
	    if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Map in the needed object.  */
Packit Service 82fcde
		struct link_map *dep;
Packit Service 82fcde
Packit Service 82fcde
		/* Recognize DSTs.  */
Packit Service 82fcde
		name = expand_dst (l, strtab + d->d_un.d_val, 0);
Packit Service 82fcde
		/* Store the tag in the argument structure.  */
Packit Service 82fcde
		args.name = name;
Packit Service 82fcde
Packit Service 82fcde
		int err = _dl_catch_exception (&exception, openaux, &args);
Packit Service 82fcde
		if (__glibc_unlikely (exception.errstring != NULL))
Packit Service 82fcde
		  {
Packit Service 82fcde
		    if (err)
Packit Service 82fcde
		      errno_reason = err;
Packit Service 82fcde
		    else
Packit Service 82fcde
		      errno_reason = -1;
Packit Service 82fcde
		    goto out;
Packit Service 82fcde
		  }
Packit Service 82fcde
		else
Packit Service 82fcde
		  dep = args.aux;
Packit Service 82fcde
Packit Service 82fcde
		if (! dep->l_reserved)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    /* Allocate new entry.  */
Packit Service 82fcde
		    struct list *newp;
Packit Service 82fcde
Packit Service 82fcde
		    newp = alloca (sizeof (struct list));
Packit Service 82fcde
Packit Service 82fcde
		    /* Append DEP to the list.  */
Packit Service 82fcde
		    newp->map = dep;
Packit Service 82fcde
		    newp->done = 0;
Packit Service 82fcde
		    newp->next = NULL;
Packit Service 82fcde
		    tail->next = newp;
Packit Service 82fcde
		    tail = newp;
Packit Service 82fcde
		    ++nlist;
Packit Service 82fcde
		    /* Set the mark bit that says it's already in the list.  */
Packit Service 82fcde
		    dep->l_reserved = 1;
Packit Service 82fcde
		  }
Packit Service 82fcde
Packit Service 82fcde
		/* Remember this dependency.  */
Packit Service 82fcde
		if (needed != NULL)
Packit Service 82fcde
		  needed[nneeded++] = dep;
Packit Service 82fcde
	      }
Packit Service 82fcde
	    else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
Packit Service 82fcde
	      {
Packit Service 82fcde
		struct list *newp;
Packit Service 82fcde
Packit Service 82fcde
		/* Recognize DSTs.  */
Packit Service 82fcde
		name = expand_dst (l, strtab + d->d_un.d_val,
Packit Service 82fcde
				   d->d_tag == DT_AUXILIARY);
Packit Service 82fcde
		/* Store the tag in the argument structure.  */
Packit Service 82fcde
		args.name = name;
Packit Service 82fcde
Packit Service 82fcde
		/* Say that we are about to load an auxiliary library.  */
Packit Service 82fcde
		if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
Packit Service 82fcde
				      0))
Packit Service 82fcde
		  _dl_debug_printf ("load auxiliary object=%s"
Packit Service 82fcde
				    " requested by file=%s\n",
Packit Service 82fcde
				    name,
Packit Service 82fcde
				    DSO_FILENAME (l->l_name));
Packit Service 82fcde
Packit Service 82fcde
		/* We must be prepared that the addressed shared
Packit Service 82fcde
		   object is not available.  For filter objects the dependency
Packit Service 82fcde
		   must be available.  */
Packit Service 82fcde
		int err = _dl_catch_exception (&exception, openaux, &args);
Packit Service 82fcde
		if (__glibc_unlikely (exception.errstring != NULL))
Packit Service 82fcde
		  {
Packit Service 82fcde
		    if (d->d_tag == DT_AUXILIARY)
Packit Service 82fcde
		      {
Packit Service 82fcde
			/* We are not interested in the error message.  */
Packit Service 82fcde
			_dl_exception_free (&exception);
Packit Service 82fcde
			/* Simply ignore this error and continue the work.  */
Packit Service 82fcde
			continue;
Packit Service 82fcde
		      }
Packit Service 82fcde
		    else
Packit Service 82fcde
		      {
Packit Service 82fcde
			if (err)
Packit Service 82fcde
			  errno_reason = err;
Packit Service 82fcde
			else
Packit Service 82fcde
			  errno_reason = -1;
Packit Service 82fcde
			goto out;
Packit Service 82fcde
		      }
Packit Service 82fcde
		  }
Packit Service 82fcde
Packit Service 82fcde
		/* The auxiliary object is actually available.
Packit Service 82fcde
		   Incorporate the map in all the lists.  */
Packit Service 82fcde
Packit Service 82fcde
		/* Allocate new entry.  This always has to be done.  */
Packit Service 82fcde
		newp = alloca (sizeof (struct list));
Packit Service 82fcde
Packit Service 82fcde
		/* We want to insert the new map before the current one,
Packit Service 82fcde
		   but we have no back links.  So we copy the contents of
Packit Service 82fcde
		   the current entry over.  Note that ORIG and NEWP now
Packit Service 82fcde
		   have switched their meanings.  */
Packit Service 82fcde
		memcpy (newp, orig, sizeof (*newp));
Packit Service 82fcde
Packit Service 82fcde
		/* Initialize new entry.  */
Packit Service 82fcde
		orig->done = 0;
Packit Service 82fcde
		orig->map = args.aux;
Packit Service 82fcde
Packit Service 82fcde
		/* Remember this dependency.  */
Packit Service 82fcde
		if (needed != NULL)
Packit Service 82fcde
		  needed[nneeded++] = args.aux;
Packit Service 82fcde
Packit Service 82fcde
		/* We must handle two situations here: the map is new,
Packit Service 82fcde
		   so we must add it in all three lists.  If the map
Packit Service 82fcde
		   is already known, we have two further possibilities:
Packit Service 82fcde
		   - if the object is before the current map in the
Packit Service 82fcde
		   search list, we do nothing.  It is already found
Packit Service 82fcde
		   early
Packit Service 82fcde
		   - if the object is after the current one, we must
Packit Service 82fcde
		   move it just before the current map to make sure
Packit Service 82fcde
		   the symbols are found early enough
Packit Service 82fcde
		*/
Packit Service 82fcde
		if (args.aux->l_reserved)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    /* The object is already somewhere in the list.
Packit Service 82fcde
		       Locate it first.  */
Packit Service 82fcde
		    struct list *late;
Packit Service 82fcde
Packit Service 82fcde
		    /* This object is already in the search list we
Packit Service 82fcde
		       are building.  Don't add a duplicate pointer.
Packit Service 82fcde
		       Just added by _dl_map_object.  */
Packit Service 82fcde
		    for (late = newp; late->next != NULL; late = late->next)
Packit Service 82fcde
		      if (late->next->map == args.aux)
Packit Service 82fcde
			break;
Packit Service 82fcde
Packit Service 82fcde
		    if (late->next != NULL)
Packit Service 82fcde
		      {
Packit Service 82fcde
			/* The object is somewhere behind the current
Packit Service 82fcde
			   position in the search path.  We have to
Packit Service 82fcde
			   move it to this earlier position.  */
Packit Service 82fcde
			orig->next = newp;
Packit Service 82fcde
Packit Service 82fcde
			/* Now remove the later entry from the list
Packit Service 82fcde
			   and adjust the tail pointer.  */
Packit Service 82fcde
			if (tail == late->next)
Packit Service 82fcde
			  tail = late;
Packit Service 82fcde
			late->next = late->next->next;
Packit Service 82fcde
Packit Service 82fcde
			/* We must move the object earlier in the chain.  */
Packit Service 82fcde
			if (args.aux->l_prev != NULL)
Packit Service 82fcde
			  args.aux->l_prev->l_next = args.aux->l_next;
Packit Service 82fcde
			if (args.aux->l_next != NULL)
Packit Service 82fcde
			  args.aux->l_next->l_prev = args.aux->l_prev;
Packit Service 82fcde
Packit Service 82fcde
			args.aux->l_prev = newp->map->l_prev;
Packit Service 82fcde
			newp->map->l_prev = args.aux;
Packit Service 82fcde
			if (args.aux->l_prev != NULL)
Packit Service 82fcde
			  args.aux->l_prev->l_next = args.aux;
Packit Service 82fcde
			args.aux->l_next = newp->map;
Packit Service 82fcde
		      }
Packit Service 82fcde
		    else
Packit Service 82fcde
		      {
Packit Service 82fcde
			/* The object must be somewhere earlier in the
Packit Service 82fcde
			   list.  Undo to the current list element what
Packit Service 82fcde
			   we did above.  */
Packit Service 82fcde
			memcpy (orig, newp, sizeof (*newp));
Packit Service 82fcde
			continue;
Packit Service 82fcde
		      }
Packit Service 82fcde
		  }
Packit Service 82fcde
		else
Packit Service 82fcde
		  {
Packit Service 82fcde
		    /* This is easy.  We just add the symbol right here.  */
Packit Service 82fcde
		    orig->next = newp;
Packit Service 82fcde
		    ++nlist;
Packit Service 82fcde
		    /* Set the mark bit that says it's already in the list.  */
Packit Service 82fcde
		    args.aux->l_reserved = 1;
Packit Service 82fcde
Packit Service 82fcde
		    /* The only problem is that in the double linked
Packit Service 82fcde
		       list of all objects we don't have this new
Packit Service 82fcde
		       object at the correct place.  Correct this here.  */
Packit Service 82fcde
		    if (args.aux->l_prev)
Packit Service 82fcde
		      args.aux->l_prev->l_next = args.aux->l_next;
Packit Service 82fcde
		    if (args.aux->l_next)
Packit Service 82fcde
		      args.aux->l_next->l_prev = args.aux->l_prev;
Packit Service 82fcde
Packit Service 82fcde
		    args.aux->l_prev = newp->map->l_prev;
Packit Service 82fcde
		    newp->map->l_prev = args.aux;
Packit Service 82fcde
		    if (args.aux->l_prev != NULL)
Packit Service 82fcde
		      args.aux->l_prev->l_next = args.aux;
Packit Service 82fcde
		    args.aux->l_next = newp->map;
Packit Service 82fcde
		  }
Packit Service 82fcde
Packit Service 82fcde
		/* Move the tail pointer if necessary.  */
Packit Service 82fcde
		if (orig == tail)
Packit Service 82fcde
		  tail = newp;
Packit Service 82fcde
Packit Service 82fcde
		/* Move on the insert point.  */
Packit Service 82fcde
		orig = newp;
Packit Service 82fcde
	      }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Terminate the list of dependencies and store the array address.  */
Packit Service 82fcde
      if (needed != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  needed[nneeded++] = NULL;
Packit Service 82fcde
Packit Service 82fcde
	  struct link_map **l_initfini = (struct link_map **)
Packit Service 82fcde
	    malloc ((2 * nneeded + 1) * sizeof needed[0]);
Packit Service 82fcde
	  if (l_initfini == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      scratch_buffer_free (&needed_space);
Packit Service 82fcde
	      _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit Service 82fcde
				N_("cannot allocate dependency list"));
Packit Service 82fcde
	    }
Packit Service 82fcde
	  l_initfini[0] = l;
Packit Service 82fcde
	  memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
Packit Service 82fcde
	  memcpy (&l_initfini[nneeded + 1], l_initfini,
Packit Service 82fcde
		  nneeded * sizeof needed[0]);
Packit Service 82fcde
	  atomic_write_barrier ();
Packit Service 82fcde
	  l->l_initfini = l_initfini;
Packit Service 82fcde
	  l->l_free_initfini = 1;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* If we have no auxiliary objects just go on to the next map.  */
Packit Service 82fcde
      if (runp->done)
Packit Service 82fcde
	do
Packit Service 82fcde
	  runp = runp->next;
Packit Service 82fcde
	while (runp != NULL && runp->done);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
 out:
Packit Service 82fcde
  scratch_buffer_free (&needed_space);
Packit Service 82fcde
Packit Service 82fcde
  if (errno == 0 && errno_saved != 0)
Packit Service 82fcde
    __set_errno (errno_saved);
Packit Service 82fcde
Packit Service 82fcde
  struct link_map **old_l_initfini = NULL;
Packit Service 82fcde
  if (map->l_initfini != NULL && map->l_type == lt_loaded)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* This object was previously loaded as a dependency and we have
Packit Service 82fcde
	 a separate l_initfini list.  We don't need it anymore.  */
Packit Service 82fcde
      assert (map->l_searchlist.r_list == NULL);
Packit Service 82fcde
      old_l_initfini = map->l_initfini;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Store the search list we built in the object.  It will be used for
Packit Service 82fcde
     searches in the scope of this object.  */
Packit Service 82fcde
  struct link_map **l_initfini =
Packit Service 82fcde
    (struct link_map **) malloc ((2 * nlist + 1)
Packit Service 82fcde
				 * sizeof (struct link_map *));
Packit Service 82fcde
  if (l_initfini == NULL)
Packit Service 82fcde
    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit Service 82fcde
		      N_("cannot allocate symbol search list"));
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  map->l_searchlist.r_list = &l_initfini[nlist + 1];
Packit Service 82fcde
  map->l_searchlist.r_nlist = nlist;
Packit Service 82fcde
Packit Service 82fcde
  for (nlist = 0, runp = known; runp; runp = runp->next)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
Packit Service 82fcde
	/* This can happen when we trace the loading.  */
Packit Service 82fcde
	--map->l_searchlist.r_nlist;
Packit Service 1c5418
      else
Packit Service 82fcde
	map->l_searchlist.r_list[nlist++] = runp->map;
Packit Service 82fcde
Packit Service 82fcde
      /* Now clear all the mark bits we set in the objects on the search list
Packit Service 82fcde
	 to avoid duplicates, so the next call starts fresh.  */
Packit Service 82fcde
      runp->map->l_reserved = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
Packit Service 82fcde
      && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* If we are to compute conflicts, we have to build local scope
Packit Service 82fcde
	 for each library, not just the ultimate loader.  */
Packit Service 82fcde
      for (i = 0; i < nlist; ++i)
Packit Service 82fcde
	{
Packit Service 82fcde
	  struct link_map *l = map->l_searchlist.r_list[i];
Packit Service 82fcde
	  unsigned int j, cnt;
Packit Service 82fcde
Packit Service 82fcde
	  /* The local scope has been already computed.  */
Packit Service 82fcde
	  if (l == map
Packit Service 82fcde
	      || (l->l_local_scope[0]
Packit Service 82fcde
		  && l->l_local_scope[0]->r_nlist) != 0)
Packit Service 82fcde
	    continue;
Packit Service 82fcde
Packit Service 82fcde
	  if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* As current DT_AUXILIARY/DT_FILTER implementation needs to be
Packit Service 82fcde
		 rewritten, no need to bother with prelinking the old
Packit Service 82fcde
		 implementation.  */
Packit Service 82fcde
	      _dl_signal_error (EINVAL, l->l_name, NULL, N_("\
Packit Service 82fcde
Filters not supported with LD_TRACE_PRELINKING"));
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  cnt = _dl_build_local_scope (l_initfini, l);
Packit Service 82fcde
	  assert (cnt <= nlist);
Packit Service 82fcde
	  for (j = 0; j < cnt; j++)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      l_initfini[j]->l_reserved = 0;
Packit Service 82fcde
	      if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
Packit Service 82fcde
					 != NULL, 0))
Packit Service 82fcde
		l->l_symbolic_in_local_scope = true;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  l->l_local_scope[0] =
Packit Service 82fcde
	    (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
Packit Service 82fcde
					    + (cnt
Packit Service 82fcde
					       * sizeof (struct link_map *)));
Packit Service 82fcde
	  if (l->l_local_scope[0] == NULL)
Packit Service 82fcde
	    _dl_signal_error (ENOMEM, map->l_name, NULL,
Packit Service 82fcde
			      N_("cannot allocate symbol search list"));
Packit Service 82fcde
	  l->l_local_scope[0]->r_nlist = cnt;
Packit Service 82fcde
	  l->l_local_scope[0]->r_list =
Packit Service 82fcde
	    (struct link_map **) (l->l_local_scope[0] + 1);
Packit Service 82fcde
	  memcpy (l->l_local_scope[0]->r_list, l_initfini,
Packit Service 82fcde
		  cnt * sizeof (struct link_map *));
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Maybe we can remove some relocation dependencies now.  */
Packit Service 1c5418
  assert (map->l_searchlist.r_list[0] == map);
Packit Service 82fcde
  struct link_map_reldeps *l_reldeps = NULL;
Packit Service 82fcde
  if (map->l_reldeps != NULL)
Packit Service 82fcde
    {
Packit Service 1c5418
      for (i = 1; i < nlist; ++i)
Packit Service 82fcde
	map->l_searchlist.r_list[i]->l_reserved = 1;
Packit Service 82fcde
Packit Service 82fcde
      struct link_map **list = &map->l_reldeps->list[0];
Packit Service 82fcde
      for (i = 0; i < map->l_reldeps->act; ++i)
Packit Service 82fcde
	if (list[i]->l_reserved)
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* Need to allocate new array of relocation dependencies.  */
Packit Service 82fcde
	    l_reldeps = malloc (sizeof (*l_reldeps)
Packit Service 82fcde
				+ map->l_reldepsmax
Packit Service 82fcde
				  * sizeof (struct link_map *));
Packit Service 82fcde
	    if (l_reldeps == NULL)
Packit Service 82fcde
	      /* Bad luck, keep the reldeps duplicated between
Packit Service 82fcde
		 map->l_reldeps->list and map->l_initfini lists.  */
Packit Service 82fcde
	      ;
Packit Service 82fcde
	    else
Packit Service 82fcde
	      {
Packit Service 82fcde
		unsigned int j = i;
Packit Service 82fcde
		memcpy (&l_reldeps->list[0], &list[0],
Packit Service 82fcde
			i * sizeof (struct link_map *));
Packit Service 82fcde
		for (i = i + 1; i < map->l_reldeps->act; ++i)
Packit Service 82fcde
		  if (!list[i]->l_reserved)
Packit Service 82fcde
		    l_reldeps->list[j++] = list[i];
Packit Service 82fcde
		l_reldeps->act = j;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 1c5418
      for (i = 1; i < nlist; ++i)
Packit Service 82fcde
	map->l_searchlist.r_list[i]->l_reserved = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 1c5418
  /* Sort the initializer list to take dependencies into account.  The binary
Packit Service 1c5418
     itself will always be initialize last.  */
Packit Service 1c5418
  memcpy (l_initfini, map->l_searchlist.r_list,
Packit Service 1c5418
	  nlist * sizeof (struct link_map *));
Packit Service 1c5418
  /* We can skip looking for the binary itself which is at the front of
Packit Service 1c5418
     the search list.  */
Packit Service 82fcde
  _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
Packit Service 82fcde
Packit Service 82fcde
  /* Terminate the list of dependencies.  */
Packit Service 82fcde
  l_initfini[nlist] = NULL;
Packit Service 82fcde
  atomic_write_barrier ();
Packit Service 82fcde
  map->l_initfini = l_initfini;
Packit Service 82fcde
  map->l_free_initfini = 1;
Packit Service 82fcde
  if (l_reldeps != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      atomic_write_barrier ();
Packit Service 82fcde
      void *old_l_reldeps = map->l_reldeps;
Packit Service 82fcde
      map->l_reldeps = l_reldeps;
Packit Service 82fcde
      _dl_scope_free (old_l_reldeps);
Packit Service 82fcde
    }
Packit Service 82fcde
  if (old_l_initfini != NULL)
Packit Service 82fcde
    _dl_scope_free (old_l_initfini);
Packit Service 82fcde
Packit Service 82fcde
  if (errno_reason)
Packit Service 82fcde
    _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
Packit Service 82fcde
			  &exception, NULL);
Packit Service 82fcde
}