Add .cantunwind to _dl_start_user
[platform/upstream/glibc.git] / elf / dl-libc.c
index 1b995ed..df27324 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle loading and unloading shared objects for internal libc purposes.
-   Copyright (C) 1999,2000,2001,2002,2004,2005 Free Software Foundation, Inc.
+   Copyright (C) 1999-2015 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
 
@@ -14,9 +14,8 @@
    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 <dlfcn.h>
 #include <stdlib.h>
@@ -44,10 +43,10 @@ dlerror_run (void (*operate) (void *), void *args)
   const char *last_errstring = NULL;
   bool malloced;
 
-  (void) GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
-                              operate, args);
+  int result = (GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
+                                     operate, args)
+               ?: last_errstring != NULL);
 
-  int result = last_errstring != NULL;
   if (result && malloced)
     free ((char *) last_errstring);
 
@@ -62,6 +61,8 @@ struct do_dlopen_args
   const char *name;
   /* Opening mode.  */
   int mode;
+  /* This is the caller of the dlopen() function.  */
+  const void *caller_dlopen;
 
   /* Return from do_dlopen.  */
   struct link_map *map;
@@ -83,8 +84,9 @@ do_dlopen (void *ptr)
 {
   struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
   /* Open and relocate the shared object.  */
-  args->map = GLRO(dl_open) (args->name, args->mode, NULL, __LM_ID_CALLER,
-                            __libc_argc, __libc_argv, __environ);
+  args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen,
+                            __LM_ID_CALLER, __libc_argc, __libc_argv,
+                            __environ);
 }
 
 static void
@@ -153,9 +155,10 @@ __libc_dlopen_mode (const char *name, int mode)
   struct do_dlopen_args args;
   args.name = name;
   args.mode = mode;
+  args.caller_dlopen = RETURN_ADDRESS (0);
 
 #ifdef SHARED
-  if (__builtin_expect (_dl_open_hook != NULL, 0))
+  if (__glibc_unlikely (_dl_open_hook != NULL))
     return _dl_open_hook->dlopen_mode (name, mode);
   return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
 #else
@@ -201,7 +204,7 @@ __libc_dlsym (void *map, const char *name)
   args.name = name;
 
 #ifdef SHARED
-  if (__builtin_expect (_dl_open_hook != NULL, 0))
+  if (__glibc_unlikely (_dl_open_hook != NULL))
     return _dl_open_hook->dlsym (map, name);
 #endif
   return (dlerror_run (do_dlsym, &args) ? NULL
@@ -213,7 +216,7 @@ int
 __libc_dlclose (void *map)
 {
 #ifdef SHARED
-  if (__builtin_expect (_dl_open_hook != NULL, 0))
+  if (__glibc_unlikely (_dl_open_hook != NULL))
     return _dl_open_hook->dlclose (map);
 #endif
   return dlerror_run (do_dlclose, map);
@@ -221,6 +224,34 @@ __libc_dlclose (void *map)
 libc_hidden_def (__libc_dlclose)
 
 
+static bool __libc_freeres_fn_section
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+  size_t cnt;
+
+  if (*elemp == NULL)
+    /* Nothing here, all is removed (or there never was anything).  */
+    return true;
+
+  if (!free_slotinfo (&(*elemp)->next))
+    /* We cannot free the entry.  */
+    return false;
+
+  /* That cleared our next pointer for us.  */
+
+  for (cnt = 0; cnt < (*elemp)->len; ++cnt)
+    if ((*elemp)->slotinfo[cnt].map != NULL)
+      /* Still used.  */
+      return false;
+
+  /* We can remove the list element.  */
+  free (*elemp);
+  *elemp = NULL;
+
+  return true;
+}
+
+
 libc_freeres_fn (free_mem)
 {
   struct link_map *l;
@@ -235,20 +266,65 @@ libc_freeres_fn (free_mem)
       free (old);
     }
 
-  /* Remove all additional names added to the objects.  */
-  for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
-    for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
-      {
-       struct libname_list *lnp = l->l_libname->next;
-
-       l->l_libname->next = NULL;
-
-       while (lnp != NULL)
-         {
-           struct libname_list *old = lnp;
-           lnp = lnp->next;
-           if (! old->dont_free)
-           free (old);
-         }
-      }
+  for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
+    {
+      for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+       {
+         struct libname_list *lnp = l->l_libname->next;
+
+         l->l_libname->next = NULL;
+
+         /* Remove all additional names added to the objects.  */
+         while (lnp != NULL)
+           {
+             struct libname_list *old = lnp;
+             lnp = lnp->next;
+             if (! old->dont_free)
+               free (old);
+           }
+
+         /* Free the initfini dependency list.  */
+         if (l->l_free_initfini)
+           free (l->l_initfini);
+         l->l_initfini = NULL;
+       }
+
+      if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
+         && (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
+             // XXX Check whether we need NS-specific initial_searchlist
+             == GLRO(dl_initial_searchlist).r_nlist))
+       {
+         /* All object dynamically loaded by the program are unloaded.  Free
+            the memory allocated for the global scope variable.  */
+         struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
+
+         /* Put the old map in.  */
+         GL(dl_ns)[ns]._ns_main_searchlist->r_list
+           // XXX Check whether we need NS-specific initial_searchlist
+           = GLRO(dl_initial_searchlist).r_list;
+         /* Signal that the original map is used.  */
+         GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
+
+         /* Now free the old map.  */
+         free (old);
+       }
+    }
+
+  /* Free the memory allocated for the dtv slotinfo array.  We can do
+     this only if all modules which used this memory are unloaded.  */
+#ifdef SHARED
+  if (GL(dl_initial_dtv) == NULL)
+    /* There was no initial TLS setup, it was set up later when
+       it used the normal malloc.  */
+    free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
+  else
+#endif
+    /* The first element of the list does not have to be deallocated.
+       It was allocated in the dynamic linker (i.e., with a different
+       malloc), and in the static library it's in .bss space.  */
+    free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
+
+  void *scope_free_list = GL(dl_scope_free_list);
+  GL(dl_scope_free_list) = NULL;
+  free (scope_free_list);
 }