Replace FSF snail mail address with URLs.
[platform/upstream/glibc.git] / elf / dl-libc.c
1 /* Handle loading and unloading shared objects for internal libc purposes.
2    Copyright (C) 1999-2002,2004-2006,2009,2010,2011
3    Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <dlfcn.h>
22 #include <stdlib.h>
23 #include <ldsodefs.h>
24
25 extern int __libc_argc attribute_hidden;
26 extern char **__libc_argv attribute_hidden;
27
28 extern char **__environ;
29
30 /* The purpose of this file is to provide wrappers around the dynamic
31    linker error mechanism (similar to dlopen() et al in libdl) which
32    are usable from within libc.  Generally we want to throw away the
33    string that dlerror() would return and just pass back a null pointer
34    for errors.  This also lets the rest of libc not know about the error
35    handling mechanism.
36
37    Much of this code came from gconv_dl.c with slight modifications. */
38
39 static int
40 internal_function
41 dlerror_run (void (*operate) (void *), void *args)
42 {
43   const char *objname;
44   const char *last_errstring = NULL;
45   bool malloced;
46
47   int result = (GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
48                                       operate, args)
49                 ?: last_errstring != NULL);
50
51   if (result && malloced)
52     free ((char *) last_errstring);
53
54   return result;
55 }
56
57 /* These functions are called by dlerror_run... */
58
59 struct do_dlopen_args
60 {
61   /* Argument to do_dlopen.  */
62   const char *name;
63   /* Opening mode.  */
64   int mode;
65   /* This is the caller of the dlopen() function.  */
66   const void *caller_dlopen;
67
68   /* Return from do_dlopen.  */
69   struct link_map *map;
70 };
71
72 struct do_dlsym_args
73 {
74   /* Arguments to do_dlsym.  */
75   struct link_map *map;
76   const char *name;
77
78   /* Return values of do_dlsym.  */
79   lookup_t loadbase;
80   const ElfW(Sym) *ref;
81 };
82
83 static void
84 do_dlopen (void *ptr)
85 {
86   struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
87   /* Open and relocate the shared object.  */
88   args->map = GLRO(dl_open) (args->name, args->mode, args->caller_dlopen,
89                              __LM_ID_CALLER, __libc_argc, __libc_argv,
90                              __environ);
91 }
92
93 static void
94 do_dlsym (void *ptr)
95 {
96   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
97   args->ref = NULL;
98   args->loadbase = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
99                                              args->map->l_local_scope, NULL, 0,
100                                              DL_LOOKUP_RETURN_NEWEST, NULL);
101 }
102
103 static void
104 do_dlclose (void *ptr)
105 {
106   GLRO(dl_close) ((struct link_map *) ptr);
107 }
108
109 /* This code is to support __libc_dlopen from __libc_dlopen'ed shared
110    libraries.  We need to ensure the statically linked __libc_dlopen
111    etc. functions are used instead of the dynamically loaded.  */
112 struct dl_open_hook
113 {
114   void *(*dlopen_mode) (const char *name, int mode);
115   void *(*dlsym) (void *map, const char *name);
116   int (*dlclose) (void *map);
117 };
118
119 #ifdef SHARED
120 extern struct dl_open_hook *_dl_open_hook;
121 libc_hidden_proto (_dl_open_hook);
122 struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
123 libc_hidden_data_def (_dl_open_hook);
124 #else
125 static void
126 do_dlsym_private (void *ptr)
127 {
128   lookup_t l;
129   struct r_found_version vers;
130   vers.name = "GLIBC_PRIVATE";
131   vers.hidden = 1;
132   /* vers.hash = _dl_elf_hash (vers.name);  */
133   vers.hash = 0x0963cf85;
134   vers.filename = NULL;
135
136   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
137   args->ref = NULL;
138   l = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
139                                 args->map->l_scope, &vers, 0, 0, NULL);
140   args->loadbase = l;
141 }
142
143 static struct dl_open_hook _dl_open_hook =
144   {
145     .dlopen_mode = __libc_dlopen_mode,
146     .dlsym = __libc_dlsym,
147     .dlclose = __libc_dlclose
148   };
149 #endif
150
151 /* ... and these functions call dlerror_run. */
152
153 void *
154 __libc_dlopen_mode (const char *name, int mode)
155 {
156   struct do_dlopen_args args;
157   args.name = name;
158   args.mode = mode;
159   args.caller_dlopen = RETURN_ADDRESS (0);
160
161 #ifdef SHARED
162   if (__builtin_expect (_dl_open_hook != NULL, 0))
163     return _dl_open_hook->dlopen_mode (name, mode);
164   return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
165 #else
166   if (dlerror_run (do_dlopen, &args))
167     return NULL;
168
169   __libc_register_dl_open_hook (args.map);
170   __libc_register_dlfcn_hook (args.map);
171   return (void *) args.map;
172 #endif
173 }
174 libc_hidden_def (__libc_dlopen_mode)
175
176 #ifndef SHARED
177 void *
178 __libc_dlsym_private (struct link_map *map, const char *name)
179 {
180   struct do_dlsym_args sargs;
181   sargs.map = map;
182   sargs.name = name;
183
184   if (! dlerror_run (do_dlsym_private, &sargs))
185     return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
186   return NULL;
187 }
188
189 void
190 __libc_register_dl_open_hook (struct link_map *map)
191 {
192   struct dl_open_hook **hook;
193
194   hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
195   if (hook != NULL)
196     *hook = &_dl_open_hook;
197 }
198 #endif
199
200 void *
201 __libc_dlsym (void *map, const char *name)
202 {
203   struct do_dlsym_args args;
204   args.map = map;
205   args.name = name;
206
207 #ifdef SHARED
208   if (__builtin_expect (_dl_open_hook != NULL, 0))
209     return _dl_open_hook->dlsym (map, name);
210 #endif
211   return (dlerror_run (do_dlsym, &args) ? NULL
212           : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref)));
213 }
214 libc_hidden_def (__libc_dlsym)
215
216 int
217 __libc_dlclose (void *map)
218 {
219 #ifdef SHARED
220   if (__builtin_expect (_dl_open_hook != NULL, 0))
221     return _dl_open_hook->dlclose (map);
222 #endif
223   return dlerror_run (do_dlclose, map);
224 }
225 libc_hidden_def (__libc_dlclose)
226
227
228 static bool __libc_freeres_fn_section
229 free_slotinfo (struct dtv_slotinfo_list **elemp)
230 {
231   size_t cnt;
232
233   if (*elemp == NULL)
234     /* Nothing here, all is removed (or there never was anything).  */
235     return true;
236
237   if (!free_slotinfo (&(*elemp)->next))
238     /* We cannot free the entry.  */
239     return false;
240
241   /* That cleared our next pointer for us.  */
242
243   for (cnt = 0; cnt < (*elemp)->len; ++cnt)
244     if ((*elemp)->slotinfo[cnt].map != NULL)
245       /* Still used.  */
246       return false;
247
248   /* We can remove the list element.  */
249   free (*elemp);
250   *elemp = NULL;
251
252   return true;
253 }
254
255
256 libc_freeres_fn (free_mem)
257 {
258   struct link_map *l;
259   struct r_search_path_elem *d;
260
261   /* Remove all search directories.  */
262   d = GL(dl_all_dirs);
263   while (d != GLRO(dl_init_all_dirs))
264     {
265       struct r_search_path_elem *old = d;
266       d = d->next;
267       free (old);
268     }
269
270   for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
271     {
272       /* Remove all additional names added to the objects.  */
273       for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
274         {
275           struct libname_list *lnp = l->l_libname->next;
276
277           l->l_libname->next = NULL;
278
279           while (lnp != NULL)
280             {
281               struct libname_list *old = lnp;
282               lnp = lnp->next;
283               if (! old->dont_free)
284                 free (old);
285             }
286         }
287
288       if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
289           && (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist
290               // XXX Check whether we need NS-specific initial_searchlist
291               == GLRO(dl_initial_searchlist).r_nlist))
292         {
293           /* All object dynamically loaded by the program are unloaded.  Free
294              the memory allocated for the global scope variable.  */
295           struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list;
296
297           /* Put the old map in.  */
298           GL(dl_ns)[ns]._ns_main_searchlist->r_list
299             // XXX Check whether we need NS-specific initial_searchlist
300             = GLRO(dl_initial_searchlist).r_list;
301           /* Signal that the original map is used.  */
302           GL(dl_ns)[ns]._ns_global_scope_alloc = 0;
303
304           /* Now free the old map.  */
305           free (old);
306         }
307     }
308
309   /* Free the memory allocated for the dtv slotinfo array.  We can do
310      this only if all modules which used this memory are unloaded.  */
311 #ifdef SHARED
312   if (GL(dl_initial_dtv) == NULL)
313     /* There was no initial TLS setup, it was set up later when
314        it used the normal malloc.  */
315     free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
316   else
317 #endif
318     /* The first element of the list does not have to be deallocated.
319        It was allocated in the dynamic linker (i.e., with a different
320        malloc), and in the static library it's in .bss space.  */
321     free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
322
323   void *scope_free_list = GL(dl_scope_free_list);
324   GL(dl_scope_free_list) = NULL;
325   free (scope_free_list);
326 }