2001-08-22 Roland McGrath <roland@frob.com>
[kopensolaris-gnu/glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2    Copyright (C) 1996,1997,1998,1999,2000,2001 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 ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
52     /* Nope.  Do nothing.  */
53     return;
54
55   if (__builtin_expect (map->l_opencount, 1) == 0)
56     _dl_signal_error (0, map->l_name, N_("shared object not open"));
57
58   /* Acquire the lock.  */
59   __libc_lock_lock_recursive (_dl_load_lock);
60
61   /* Decrement the reference count.  */
62   if (map->l_opencount > 1 || map->l_type != lt_loaded)
63     {
64       /* There are still references to this object.  Do nothing more.  */
65       if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
66         {
67           char buf[20];
68
69           buf[sizeof buf - 1] = '\0';
70
71           _dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
72                             map->l_name, map->l_opencount);
73         }
74
75       /* One decrement the object itself, not the dependencies.  */
76       --map->l_opencount;
77
78       __libc_lock_unlock_recursive (_dl_load_lock);
79       return;
80     }
81
82   list = map->l_initfini;
83
84   /* Compute the new l_opencount values.  */
85   new_opencount = (unsigned int *) alloca (map->l_searchlist.r_nlist
86                                            * sizeof (unsigned int));
87   for (i = 0; list[i] != NULL; ++i)
88     {
89       list[i]->l_idx = i;
90       new_opencount[i] = list[i]->l_opencount;
91     }
92   --new_opencount[0];
93   for (i = 1; list[i] != NULL; ++i)
94     if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
95         /* Decrement counter.  */
96         && --new_opencount[i] == 0
97         /* Test whether this object was also loaded directly.  */
98         && list[i]->l_searchlist.r_list != NULL)
99       {
100         /* In this case we have the decrement all the dependencies of
101            this object.  They are all in MAP's dependency list.  */
102         unsigned int j;
103         struct link_map **dep_list = list[i]->l_searchlist.r_list;
104
105         for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
106           if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
107               || ! dep_list[j]->l_init_called)
108             {
109               assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
110               --new_opencount[dep_list[j]->l_idx];
111             }
112       }
113   assert (new_opencount[0] == 0);
114
115   /* Call all termination functions at once.  */
116   for (i = 0; list[i] != NULL; ++i)
117     {
118       struct link_map *imap = list[i];
119       if (new_opencount[i] == 0 && imap->l_type == lt_loaded
120           && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
121           && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
122           /* Skip any half-cooked objects that were never initialized.  */
123           && imap->l_init_called)
124         {
125           /* When debugging print a message first.  */
126           if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
127             _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
128
129           /* Call its termination function.  */
130           if (imap->l_info[DT_FINI_ARRAY] != NULL)
131             {
132               ElfW(Addr) *array =
133                 (ElfW(Addr) *) (imap->l_addr
134                                 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
135               unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
136                                  / sizeof (ElfW(Addr)));
137               unsigned int cnt;
138
139               for (cnt = 0; cnt < sz; ++cnt)
140                 ((fini_t) (imap->l_addr + array[cnt])) ();
141             }
142
143           /* Next try the old-style destructor.  */
144           if (imap->l_info[DT_FINI] != NULL)
145             (*(void (*) (void)) DL_DT_FINI_ADDRESS
146               (imap, (void *) imap->l_addr
147                      + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
148         }
149
150       /* Store the new l_opencount value.  */
151       imap->l_opencount = new_opencount[i];
152       /* Just a sanity check.  */
153       assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
154     }
155
156   /* Notify the debugger we are about to remove some loaded objects.  */
157   _r_debug.r_state = RT_DELETE;
158   _dl_debug_state ();
159
160   /* Check each element of the search list to see if all references to
161      it are gone.  */
162   for (i = 0; list[i] != NULL; ++i)
163     {
164       struct link_map *imap = list[i];
165       if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
166         {
167           struct libname_list *lnp;
168
169           /* That was the last reference, and this was a dlopen-loaded
170              object.  We can unmap it.  */
171           if (__builtin_expect (imap->l_global, 0))
172             {
173               /* This object is in the global scope list.  Remove it.  */
174               unsigned int cnt = _dl_main_searchlist->r_nlist;
175
176               do
177                 --cnt;
178               while (_dl_main_searchlist->r_list[cnt] != imap);
179
180               /* The object was already correctly registered.  */
181               while (++cnt < _dl_main_searchlist->r_nlist)
182                 _dl_main_searchlist->r_list[cnt - 1]
183                   = _dl_main_searchlist->r_list[cnt];
184
185               --_dl_main_searchlist->r_nlist;
186             }
187
188           /* We can unmap all the maps at once.  We determined the
189              start address and length when we loaded the object and
190              the `munmap' call does the rest.  */
191           DL_UNMAP (imap);
192
193           /* Finally, unlink the data structure and free it.  */
194 #ifdef SHARED
195           /* We will unlink the first object only if this is a statically
196              linked program.  */
197           assert (imap->l_prev != NULL);
198           imap->l_prev->l_next = imap->l_next;
199 #else
200           if (imap->l_prev != NULL)
201             imap->l_prev->l_next = imap->l_next;
202           else
203             _dl_loaded = imap->l_next;
204 #endif
205           --_dl_nloaded;
206           if (imap->l_next)
207             imap->l_next->l_prev = imap->l_prev;
208
209           if (imap->l_versions != NULL)
210             free (imap->l_versions);
211           if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
212             free ((char *) imap->l_origin);
213
214           /* If the object has relocation dependencies save this
215              information for latter.  */
216           if (__builtin_expect (imap->l_reldeps != NULL, 0))
217             {
218               struct reldep_list *newrel;
219
220               newrel = (struct reldep_list *) alloca (sizeof (*reldeps));
221               newrel->rellist = imap->l_reldeps;
222               newrel->nrellist = imap->l_reldepsact;
223               newrel->next = reldeps;
224
225               reldeps = newrel;
226             }
227
228           /* This name always is allocated.  */
229           free (imap->l_name);
230           /* Remove the list with all the names of the shared object.  */
231           lnp = imap->l_libname;
232           do
233             {
234               struct libname_list *this = lnp;
235               lnp = lnp->next;
236               free (this);
237             }
238           while (lnp != NULL);
239
240           /* Remove the searchlists.  */
241           if (imap != map)
242               free (imap->l_initfini);
243
244           if (imap->l_phdr_allocated)
245             free ((void *) imap->l_phdr);
246
247           if (imap->l_rpath_dirs.dirs != (void *) -1)
248             free (imap->l_rpath_dirs.dirs);
249           if (imap->l_runpath_dirs.dirs != (void *) -1)
250             free (imap->l_runpath_dirs.dirs);
251
252           free (imap);
253         }
254     }
255
256   /* Notify the debugger those objects are finalized and gone.  */
257   _r_debug.r_state = RT_CONSISTENT;
258   _dl_debug_state ();
259
260   /* Now we can perhaps also remove the modules for which we had
261      dependencies because of symbol lookup.  */
262   while (__builtin_expect (reldeps != NULL, 0))
263     {
264       while (reldeps->nrellist-- > 0)
265         _dl_close (reldeps->rellist[reldeps->nrellist]);
266
267       free (reldeps->rellist);
268
269       reldeps = reldeps->next;
270     }
271
272   free (list);
273
274   /* Release the lock.  */
275   __libc_lock_unlock_recursive (_dl_load_lock);
276 }
277
278
279 static void
280 free_mem (void)
281 {
282   if (__builtin_expect (_dl_global_scope_alloc, 0) != 0
283       && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
284     {
285       /* All object dynamically loaded by the program are unloaded.  Free
286          the memory allocated for the global scope variable.  */
287       struct link_map **old = _dl_main_searchlist->r_list;
288
289       /* Put the old map in.  */
290       _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
291       /* Signal that the original map is used.  */
292       _dl_global_scope_alloc = 0;
293
294       /* Now free the old map.  */
295       free (old);
296     }
297 }
298 text_set_element (__libc_subfreeres, free_mem);