Blame elf/dl-fini.c

Packit Service 82fcde
/* Call the termination functions of loaded shared objects.
Packit Service 82fcde
   Copyright (C) 1995-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 <assert.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Type of the constructor functions.  */
Packit Service 82fcde
typedef void (*fini_t) (void);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_fini (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Lots of fun ahead.  We have to call the destructors for all still
Packit Service 82fcde
     loaded objects, in all namespaces.  The problem is that the ELF
Packit Service 82fcde
     specification now demands that dependencies between the modules
Packit Service 82fcde
     are taken into account.  I.e., the destructor for a module is
Packit Service 82fcde
     called before the ones for any of its dependencies.
Packit Service 82fcde
Packit Service 82fcde
     To make things more complicated, we cannot simply use the reverse
Packit Service 82fcde
     order of the constructors.  Since the user might have loaded objects
Packit Service 82fcde
     using `dlopen' there are possibly several other modules with its
Packit Service 82fcde
     dependencies to be taken into account.  Therefore we have to start
Packit Service 82fcde
     determining the order of the modules once again from the beginning.  */
Packit Service 82fcde
Packit Service 82fcde
  /* We run the destructors of the main namespaces last.  As for the
Packit Service 82fcde
     other namespaces, we pick run the destructors in them in reverse
Packit Service 82fcde
     order of the namespace ID.  */
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  int do_audit = 0;
Packit Service 82fcde
 again:
Packit Service 82fcde
#endif
Packit Service 82fcde
  for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Protect against concurrent loads and unloads.  */
Packit Service 82fcde
      __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
Packit Service 82fcde
      /* No need to do anything for empty namespaces or those used for
Packit Service 82fcde
	 auditing DSOs.  */
Packit Service 82fcde
      if (nloaded == 0
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
	  || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
Packit Service 82fcde
#endif
Packit Service 82fcde
	  )
Packit Service 82fcde
	__rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Now we can allocate an array to hold all the pointers and
Packit Service 82fcde
	     copy the pointers in.  */
Packit Service 82fcde
	  struct link_map *maps[nloaded];
Packit Service 82fcde
Packit Service 82fcde
	  unsigned int i;
Packit Service 82fcde
	  struct link_map *l;
Packit Service 82fcde
	  assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
Packit Service 82fcde
	  for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
Packit Service 82fcde
	    /* Do not handle ld.so in secondary namespaces.  */
Packit Service 82fcde
	    if (l == l->l_real)
Packit Service 82fcde
	      {
Packit Service 82fcde
		assert (i < nloaded);
Packit Service 82fcde
Packit Service 82fcde
		maps[i] = l;
Packit Service 82fcde
		l->l_idx = i;
Packit Service 82fcde
		++i;
Packit Service 82fcde
Packit Service 82fcde
		/* Bump l_direct_opencount of all objects so that they
Packit Service 82fcde
		   are not dlclose()ed from underneath us.  */
Packit Service 82fcde
		++l->l_direct_opencount;
Packit Service 82fcde
	      }
Packit Service 82fcde
	  assert (ns != LM_ID_BASE || i == nloaded);
Packit Service 82fcde
	  assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
Packit Service 82fcde
	  unsigned int nmaps = i;
Packit Service 82fcde
Packit Service 82fcde
	  /* Now we have to do the sorting.  We can skip looking for the
Packit Service 82fcde
	     binary itself which is at the front of the search list for
Packit Service 82fcde
	     the main namespace.  */
Packit Service 82fcde
	  _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),
Packit Service 82fcde
			 NULL, true);
Packit Service 82fcde
Packit Service 82fcde
	  /* We do not rely on the linked list of loaded object anymore
Packit Service 82fcde
	     from this point on.  We have our own list here (maps).  The
Packit Service 82fcde
	     various members of this list cannot vanish since the open
Packit Service 82fcde
	     count is too high and will be decremented in this loop.  So
Packit Service 82fcde
	     we release the lock so that some code which might be called
Packit Service 82fcde
	     from a destructor can directly or indirectly access the
Packit Service 82fcde
	     lock.  */
Packit Service 82fcde
	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
	  /* 'maps' now contains the objects in the right order.  Now
Packit Service 82fcde
	     call the destructors.  We have to process this array from
Packit Service 82fcde
	     the front.  */
Packit Service 82fcde
	  for (i = 0; i < nmaps; ++i)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      struct link_map *l = maps[i];
Packit Service 82fcde
Packit Service 82fcde
	      if (l->l_init_called)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Make sure nothing happens if we are called twice.  */
Packit Service 82fcde
		  l->l_init_called = 0;
Packit Service 82fcde
Packit Service 82fcde
		  /* Is there a destructor function?  */
Packit Service 82fcde
		  if (l->l_info[DT_FINI_ARRAY] != NULL
Packit Service 82fcde
		      || l->l_info[DT_FINI] != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* When debugging print a message first.  */
Packit Service 82fcde
		      if (__builtin_expect (GLRO(dl_debug_mask)
Packit Service 82fcde
					    & DL_DEBUG_IMPCALLS, 0))
Packit Service 82fcde
			_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
Packit Service 82fcde
					  DSO_FILENAME (l->l_name),
Packit Service 82fcde
					  ns);
Packit Service 82fcde
Packit Service 82fcde
		      /* First see whether an array is given.  */
Packit Service 82fcde
		      if (l->l_info[DT_FINI_ARRAY] != NULL)
Packit Service 82fcde
			{
Packit Service 82fcde
			  ElfW(Addr) *array =
Packit Service 82fcde
			    (ElfW(Addr) *) (l->l_addr
Packit Service 82fcde
					    + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
Packit Service 82fcde
			  unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
Packit Service 82fcde
					    / sizeof (ElfW(Addr)));
Packit Service 82fcde
			  while (i-- > 0)
Packit Service 82fcde
			    ((fini_t) array[i]) ();
Packit Service 82fcde
			}
Packit Service 82fcde
Packit Service 82fcde
		      /* Next try the old-style destructor.  */
Packit Service 82fcde
		      if (l->l_info[DT_FINI] != NULL)
Packit Service 82fcde
			DL_CALL_DT_FINI
Packit Service 82fcde
			  (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
		  /* Auditing checkpoint: another object closed.  */
Packit Service 82fcde
		  if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
Packit Service 82fcde
		    {
Packit Service 82fcde
		      struct audit_ifaces *afct = GLRO(dl_audit);
Packit Service 82fcde
		      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Service 82fcde
			{
Packit Service 82fcde
			  if (afct->objclose != NULL)
Packit Service 82fcde
			    /* Return value is ignored.  */
Packit Service 82fcde
			    (void) afct->objclose (&l->l_audit[cnt].cookie);
Packit Service 82fcde
Packit Service 82fcde
			  afct = afct->next;
Packit Service 82fcde
			}
Packit Service 82fcde
		    }
Packit Service 82fcde
#endif
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      /* Correct the previous increment.  */
Packit Service 82fcde
	      --l->l_direct_opencount;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  if (! do_audit && GLRO(dl_naudit) > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      do_audit = 1;
Packit Service 82fcde
      goto again;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
Packit Service 82fcde
    _dl_debug_printf ("\nruntime linker statistics:\n"
Packit Service 82fcde
		      "           final number of relocations: %lu\n"
Packit Service 82fcde
		      "final number of relocations from cache: %lu\n",
Packit Service 82fcde
		      GL(dl_num_relocations),
Packit Service 82fcde
		      GL(dl_num_cache_relocations));
Packit Service 82fcde
#endif
Packit Service 82fcde
}