Update.
[platform/upstream/glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 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 #include <stdio-common/_itoa.h>
31
32
33 /* Type of the constructor functions.  */
34 typedef void (*fini_t) (void);
35
36
37 /* During the program run we must not modify the global data of
38    loaded shared object simultanously in two threads.  Therefore we
39    protect `dlopen' and `dlclose' in dlclose.c.  */
40 __libc_lock_define (extern, _dl_load_lock)
41
42 void
43 internal_function
44 _dl_close (void *_map)
45 {
46   struct link_map **list;
47   struct link_map **rellist;
48   struct link_map *map = _map;
49   unsigned int nsearchlist;
50   unsigned int nrellist;
51   unsigned int i;
52
53   /* First see whether we can remove the object at all.  */
54   if (map->l_flags_1 & DF_1_NODELETE)
55     /* Nope.  Do nothing.  */
56     return;
57
58   if (map->l_opencount == 0)
59     _dl_signal_error (0, map->l_name, N_("shared object not open"));
60
61   /* Acquire the lock.  */
62   __libc_lock_lock (_dl_load_lock);
63
64   /* Decrement the reference count.  */
65   if (map->l_opencount > 1 || map->l_type != lt_loaded)
66     {
67       /* There are still references to this object.  Do nothing more.  */
68       if (__builtin_expect (_dl_debug_files, 0))
69         {
70           char buf[20];
71
72           buf[sizeof buf - 1] = '\0';
73
74           _dl_debug_message (1, "\nclosing file=", map->l_name,
75                              "; opencount == ",
76                              _itoa_word (map->l_opencount,
77                                          buf + sizeof buf - 1, 10, 0),
78                              "\n", NULL);
79         }
80
81       --map->l_opencount;
82       __libc_lock_unlock (_dl_load_lock);
83       return;
84     }
85
86   list = map->l_searchlist.r_list;
87   nsearchlist = map->l_searchlist.r_nlist;
88
89   rellist = map->l_reldeps;
90   nrellist = map->l_reldepsact;
91
92   /* Call all termination functions at once.  */
93   for (i = 0; i < nsearchlist; ++i)
94     {
95       struct link_map *imap = map->l_initfini[i];
96       if (imap->l_opencount == 1 && imap->l_type == lt_loaded
97           && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
98           && ! (list[i]->l_flags_1 & DF_1_NODELETE)
99           /* Skip any half-cooked objects that were never initialized.  */
100           && imap->l_init_called)
101         {
102           /* When debugging print a message first.  */
103           if (__builtin_expect (_dl_debug_impcalls, 0))
104             _dl_debug_message (1, "\ncalling fini: ", imap->l_name,
105                                "\n\n", NULL);
106
107           /* Call its termination function.  */
108           if (imap->l_info[DT_FINI_ARRAY] != NULL)
109             {
110               ElfW(Addr) *array =
111                 (ElfW(Addr) *) (imap->l_addr
112                                 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
113               unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
114                                  / sizeof (ElfW(Addr)));
115               unsigned int cnt;
116
117               for (cnt = 0; cnt < sz; ++cnt)
118                 ((fini_t) (imap->l_addr + array[cnt])) ();
119             }
120
121           /* Next try the old-style destructor.  */
122           if (imap->l_info[DT_FINI] != NULL)
123             (*(void (*) (void)) ((void *) imap->l_addr
124                                  + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
125         }
126     }
127
128   /* Notify the debugger we are about to remove some loaded objects.  */
129   _r_debug.r_state = RT_DELETE;
130   _dl_debug_state ();
131
132   /* The search list contains a counted reference to each object it
133      points to, the 0th elt being MAP itself.  Decrement the reference
134      counts on all the objects MAP depends on.  */
135   for (i = 0; i < nsearchlist; ++i)
136     if (! (list[i]->l_flags_1 & DF_1_NODELETE))
137       --list[i]->l_opencount;
138
139   /* Check each element of the search list to see if all references to
140      it are gone.  */
141   for (i = 0; i < nsearchlist; ++i)
142     {
143       struct link_map *imap = list[i];
144       if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
145         {
146           struct libname_list *lnp;
147
148           /* That was the last reference, and this was a dlopen-loaded
149              object.  We can unmap it.  */
150           if (imap->l_global)
151             {
152               /* This object is in the global scope list.  Remove it.  */
153               int cnt = _dl_main_searchlist->r_nlist;
154
155               do
156                 --cnt;
157               while (_dl_main_searchlist->r_list[cnt] != imap);
158
159               /* The object was already correctly registered.  */
160               while (++cnt < _dl_main_searchlist->r_nlist)
161                 _dl_main_searchlist->r_list[cnt - 1]
162                   = _dl_main_searchlist->r_list[cnt];
163
164               --_dl_main_searchlist->r_nlist;
165             }
166
167           /* We can unmap all the maps at once.  We determined the
168              start address and length when we loaded the object and
169              the `munmap' call does the rest.  */
170           __munmap ((void *) imap->l_map_start,
171                     imap->l_map_end - imap->l_map_start);
172
173           /* Finally, unlink the data structure and free it.  */
174 #ifdef SHARED
175           /* We will unlink the first object only if this is a statically
176              linked program.  */
177           assert (imap->l_prev != NULL);
178           imap->l_prev->l_next = imap->l_next;
179 #else
180           if (imap->l_prev != NULL)
181             imap->l_prev->l_next = imap->l_next;
182           else
183             _dl_loaded = imap->l_next;
184 #endif
185           --_dl_nloaded;
186           if (imap->l_next)
187             imap->l_next->l_prev = imap->l_prev;
188
189           if (imap->l_versions != NULL)
190             free (imap->l_versions);
191           if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
192             free ((char *) imap->l_origin);
193
194           /* This name always is allocated.  */
195           free (imap->l_name);
196           /* Remove the list with all the names of the shared object.  */
197           lnp = imap->l_libname;
198           do
199             {
200               struct libname_list *this = lnp;
201               lnp = lnp->next;
202               free (this);
203             }
204           while (lnp != NULL);
205
206           /* Remove the searchlists.  */
207           if (imap != map)
208             {
209               if (imap->l_searchlist.r_list != NULL)
210                 free (imap->l_searchlist.r_list);
211               else if (imap->l_initfini != NULL)
212                 free (imap->l_initfini);
213             }
214
215           if (imap->l_phdr_allocated)
216             free ((void *) imap->l_phdr);
217
218           if (imap->l_rpath_dirs.dirs != (void *) -1)
219             free (imap->l_rpath_dirs.dirs);
220           if (imap->l_runpath_dirs.dirs != (void *) -1)
221             free (imap->l_runpath_dirs.dirs);
222
223           free (imap);
224         }
225     }
226
227   /* Now we can perhaps also remove the modules for which we had
228      dependencies because of symbol lookup.  */
229   if (rellist != NULL)
230     {
231       while (nrellist-- > 0)
232         _dl_close (rellist[nrellist]);
233
234       free (rellist);
235     }
236
237   free (list);
238
239   if (_dl_global_scope_alloc != 0
240       && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
241     {
242       /* All object dynamically loaded by the program are unloaded.  Free
243          the memory allocated for the global scope variable.  */
244       struct link_map **old = _dl_main_searchlist->r_list;
245
246       /* Put the old map in.  */
247       _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
248       /* Signal that the original map is used.  */
249       _dl_global_scope_alloc = 0;
250
251       /* Now free the old map.  */
252       free (old);
253     }
254
255   /* Notify the debugger those objects are finalized and gone.  */
256   _r_debug.r_state = RT_CONSISTENT;
257   _dl_debug_state ();
258
259   /* Release the lock.  */
260   __libc_lock_unlock (_dl_load_lock);
261 }