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