Update.
[platform/upstream/glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2    Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <libintl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <bits/libc-lock.h>
26 #include <ldsodefs.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29
30
31 /* Type of the constructor functions.  */
32 typedef void (*fini_t) (void);
33
34
35 void
36 internal_function
37 _dl_close (void *_map)
38 {
39   struct reldep_list
40   {
41     struct link_map **rellist;
42     unsigned int nrellist;
43     struct reldep_list *next;
44   } *reldeps = NULL;
45   struct link_map **list;
46   struct link_map *map = _map;
47   unsigned int i;
48   unsigned int *new_opencount;
49
50   /* First see whether we can remove the object at all.  */
51   if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
52       && map->l_init_called)
53     /* Nope.  Do nothing.  */
54     return;
55
56   if (__builtin_expect (map->l_opencount, 1) == 0)
57     _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
58
59   /* Acquire the lock.  */
60   __libc_lock_lock_recursive (GL(dl_load_lock));
61
62   /* Decrement the reference count.  */
63   if (map->l_opencount > 1 || map->l_type != lt_loaded)
64     {
65       /* There are still references to this object.  Do nothing more.  */
66       if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0))
67         _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
68                           map->l_name, map->l_opencount);
69
70       /* One decrement the object itself, not the dependencies.  */
71       --map->l_opencount;
72
73       __libc_lock_unlock_recursive (GL(dl_load_lock));
74       return;
75     }
76
77   list = map->l_initfini;
78
79   /* Compute the new l_opencount values.  */
80   i = map->l_searchlist.r_nlist;
81   if (__builtin_expect (i == 0, 0))
82     /* This can happen if we handle relocation dependencies for an
83        object which wasn't loaded directly.  */
84     for (i = 1; list[i] != NULL; ++i)
85       ;
86
87   new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int));
88
89   for (i = 0; list[i] != NULL; ++i)
90     {
91       list[i]->l_idx = i;
92       new_opencount[i] = list[i]->l_opencount;
93     }
94   --new_opencount[0];
95   for (i = 1; list[i] != NULL; ++i)
96     if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
97         /* Decrement counter.  */
98         && --new_opencount[i] == 0
99         /* Test whether this object was also loaded directly.  */
100         && list[i]->l_searchlist.r_list != NULL)
101       {
102         /* In this case we have the decrement all the dependencies of
103            this object.  They are all in MAP's dependency list.  */
104         unsigned int j;
105         struct link_map **dep_list = list[i]->l_searchlist.r_list;
106
107         for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
108           if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
109               || ! dep_list[j]->l_init_called)
110             {
111               assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
112               --new_opencount[dep_list[j]->l_idx];
113             }
114       }
115   assert (new_opencount[0] == 0);
116
117   /* Call all termination functions at once.  */
118   for (i = 0; list[i] != NULL; ++i)
119     {
120       struct link_map *imap = list[i];
121       if (new_opencount[i] == 0 && imap->l_type == lt_loaded
122           && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
123           && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
124           /* Skip any half-cooked objects that were never initialized.  */
125           && imap->l_init_called)
126         {
127           /* When debugging print a message first.  */
128           if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
129             _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
130
131           /* Call its termination function.  */
132           if (imap->l_info[DT_FINI_ARRAY] != NULL)
133             {
134               ElfW(Addr) *array =
135                 (ElfW(Addr) *) (imap->l_addr
136                                 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
137               unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
138                                  / sizeof (ElfW(Addr)));
139               unsigned int cnt;
140
141               for (cnt = 0; cnt < sz; ++cnt)
142                 ((fini_t) (imap->l_addr + array[cnt])) ();
143             }
144
145           /* Next try the old-style destructor.  */
146           if (imap->l_info[DT_FINI] != NULL)
147             (*(void (*) (void)) DL_DT_FINI_ADDRESS
148               (imap, (void *) imap->l_addr
149                      + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
150         }
151       else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
152         {
153           /* The object is still used.  But the object we are unloading
154              right now is responsible for loading it and therefore we
155              have the search list of the current object in its scope.
156              Remove it.  */
157           struct r_scope_elem **runp = imap->l_scope;
158
159           while (*runp != NULL)
160             if (*runp == &map->l_searchlist)
161               {
162                 /* Copy all later elements.  */
163                 while ((runp[0] = runp[1]) != NULL)
164                   ++runp;
165                 break;
166               }
167           else
168             ++runp;
169         }
170
171       /* Store the new l_opencount value.  */
172       imap->l_opencount = new_opencount[i];
173       /* Just a sanity check.  */
174       assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
175     }
176
177   /* Notify the debugger we are about to remove some loaded objects.  */
178   _r_debug.r_state = RT_DELETE;
179   _dl_debug_state ();
180
181   /* Check each element of the search list to see if all references to
182      it are gone.  */
183   for (i = 0; list[i] != NULL; ++i)
184     {
185       struct link_map *imap = list[i];
186       if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
187         {
188           struct libname_list *lnp;
189
190           /* That was the last reference, and this was a dlopen-loaded
191              object.  We can unmap it.  */
192           if (__builtin_expect (imap->l_global, 0))
193             {
194               /* This object is in the global scope list.  Remove it.  */
195               unsigned int cnt = GL(dl_main_searchlist)->r_nlist;
196
197               do
198                 --cnt;
199               while (GL(dl_main_searchlist)->r_list[cnt] != imap);
200
201               /* The object was already correctly registered.  */
202               while (++cnt < GL(dl_main_searchlist)->r_nlist)
203                 GL(dl_main_searchlist)->r_list[cnt - 1]
204                   = GL(dl_main_searchlist)->r_list[cnt];
205
206               --GL(dl_main_searchlist)->r_nlist;
207             }
208
209           /* We can unmap all the maps at once.  We determined the
210              start address and length when we loaded the object and
211              the `munmap' call does the rest.  */
212           DL_UNMAP (imap);
213
214           /* Finally, unlink the data structure and free it.  */
215 #ifdef SHARED
216           /* We will unlink the first object only if this is a statically
217              linked program.  */
218           assert (imap->l_prev != NULL);
219           imap->l_prev->l_next = imap->l_next;
220 #else
221           if (imap->l_prev != NULL)
222             imap->l_prev->l_next = imap->l_next;
223           else
224             GL(dl_loaded) = imap->l_next;
225 #endif
226           --GL(dl_nloaded);
227           if (imap->l_next)
228             imap->l_next->l_prev = imap->l_prev;
229
230           if (imap->l_versions != NULL)
231             free (imap->l_versions);
232           if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
233             free ((char *) imap->l_origin);
234
235           /* If the object has relocation dependencies save this
236              information for latter.  */
237           if (__builtin_expect (imap->l_reldeps != NULL, 0))
238             {
239               struct reldep_list *newrel;
240
241               newrel = (struct reldep_list *) alloca (sizeof (*reldeps));
242               newrel->rellist = imap->l_reldeps;
243               newrel->nrellist = imap->l_reldepsact;
244               newrel->next = reldeps;
245
246               reldeps = newrel;
247             }
248
249           /* This name always is allocated.  */
250           free (imap->l_name);
251           /* Remove the list with all the names of the shared object.  */
252           lnp = imap->l_libname;
253           do
254             {
255               struct libname_list *this = lnp;
256               lnp = lnp->next;
257               if (!this->dont_free)
258                 free (this);
259             }
260           while (lnp != NULL);
261
262           /* Remove the searchlists.  */
263           if (imap != map)
264               free (imap->l_initfini);
265
266           /* Remove the scope array if we allocated it.  */
267           if (imap->l_scope != imap->l_scope_mem)
268             free (imap->l_scope);
269
270           if (imap->l_phdr_allocated)
271             free ((void *) imap->l_phdr);
272
273           if (imap->l_rpath_dirs.dirs != (void *) -1)
274             free (imap->l_rpath_dirs.dirs);
275           if (imap->l_runpath_dirs.dirs != (void *) -1)
276             free (imap->l_runpath_dirs.dirs);
277
278           free (imap);
279         }
280     }
281
282   /* Notify the debugger those objects are finalized and gone.  */
283   _r_debug.r_state = RT_CONSISTENT;
284   _dl_debug_state ();
285
286   /* Now we can perhaps also remove the modules for which we had
287      dependencies because of symbol lookup.  */
288   while (__builtin_expect (reldeps != NULL, 0))
289     {
290       while (reldeps->nrellist-- > 0)
291         _dl_close (reldeps->rellist[reldeps->nrellist]);
292
293       free (reldeps->rellist);
294
295       reldeps = reldeps->next;
296     }
297
298   free (list);
299
300   /* Release the lock.  */
301   __libc_lock_unlock_recursive (GL(dl_load_lock));
302 }
303
304
305 static void
306 free_mem (void)
307 {
308   if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0
309       && GL(dl_main_searchlist)->r_nlist == GL(dl_initial_searchlist).r_nlist)
310     {
311       /* All object dynamically loaded by the program are unloaded.  Free
312          the memory allocated for the global scope variable.  */
313       struct link_map **old = GL(dl_main_searchlist)->r_list;
314
315       /* Put the old map in.  */
316       GL(dl_main_searchlist)->r_list = GL(dl_initial_searchlist).r_list;
317       /* Signal that the original map is used.  */
318       GL(dl_global_scope_alloc) = 0;
319
320       /* Now free the old map.  */
321       free (old);
322     }
323 }
324 text_set_element (__libc_subfreeres, free_mem);