* include/malloc.h: Remove _int_new_arena prototype.
[platform/upstream/glibc.git] / elf / dl-fini.c
1 /* Call the termination functions of loaded shared objects.
2    Copyright (C) 1995,96,1998-2002,2004, 2005 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 <alloca.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <ldsodefs.h>
24
25
26 /* Type of the constructor functions.  */
27 typedef void (*fini_t) (void);
28
29
30 void
31 internal_function
32 _dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps,
33                char *used, Lmid_t ns)
34 {
35   if (ns == LM_ID_BASE)
36     /* The main executable always comes first.  */
37     l = l->l_next;
38
39   for (; l != NULL; l = l->l_next)
40     /* Do not handle ld.so in secondary namespaces and object which
41        are not removed.  */
42     if (l == l->l_real && l->l_idx != -1)
43       {
44         /* Find the place in the 'maps' array.  */
45         unsigned int j;
46         for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
47           assert (j < nmaps);
48
49         /* Find all object for which the current one is a dependency
50            and move the found object (if necessary) in front.  */
51         for (unsigned int k = j + 1; k < nmaps; ++k)
52           {
53             struct link_map **runp = maps[k]->l_initfini;
54             if (runp != NULL)
55               {
56                 while (*runp != NULL)
57                   if (*runp == l)
58                     {
59                       struct link_map *here = maps[k];
60
61                       /* Move it now.  */
62                       memmove (&maps[j] + 1,
63                                &maps[j], (k - j) * sizeof (struct link_map *));
64                       maps[j] = here;
65
66                       if (used != NULL)
67                         {
68                           char here_used = used[k];
69
70                           memmove (&used[j] + 1,
71                                    &used[j], (k - j) * sizeof (char));
72                           used[j] = here_used;
73                         }
74
75                       ++j;
76
77                       break;
78                     }
79                   else
80                     ++runp;
81               }
82
83             if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
84               {
85                 unsigned int m = maps[k]->l_reldepsact;
86                 struct link_map **relmaps = maps[k]->l_reldeps;
87
88                 while (m-- > 0)
89                   {
90                     if (relmaps[m] == l)
91                       {
92                         struct link_map *here = maps[k];
93
94                         /* Move it now.  */
95                         memmove (&maps[j] + 1,
96                                  &maps[j],
97                                  (k - j) * sizeof (struct link_map *));
98                         maps[j] = here;
99
100                         if (used != NULL)
101                           {
102                             char here_used = used[k];
103
104                             memmove (&used[j] + 1,
105                                      &used[j], (k - j) * sizeof (char));
106                             used[j] = here_used;
107                           }
108
109                         break;
110                       }
111                   }
112               }
113           }
114       }
115 }
116
117
118 void
119 internal_function
120 _dl_fini (void)
121 {
122   /* Lots of fun ahead.  We have to call the destructors for all still
123      loaded objects, in all namespaces.  The problem is that the ELF
124      specification now demands that dependencies between the modules
125      are taken into account.  I.e., the destructor for a module is
126      called before the ones for any of its dependencies.
127
128      To make things more complicated, we cannot simply use the reverse
129      order of the constructors.  Since the user might have loaded objects
130      using `dlopen' there are possibly several other modules with its
131      dependencies to be taken into account.  Therefore we have to start
132      determining the order of the modules once again from the beginning.  */
133   struct link_map **maps = NULL;
134   size_t maps_size = 0;
135
136   /* We run the destructors of the main namespaces last.  As for the
137      other namespaces, we pick run the destructors in them in reverse
138      order of the namespace ID.  */
139 #ifdef SHARED
140   int do_audit = 0;
141  again:
142 #endif
143   for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
144     {
145       /* Protect against concurrent loads and unloads.  */
146       __rtld_lock_lock_recursive (GL(dl_load_lock));
147
148       unsigned int nmaps = 0;
149       unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
150       /* No need to do anything for empty namespaces or those used for
151          auditing DSOs.  */
152       if (nloaded == 0
153 #ifdef SHARED
154           || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
155 #endif
156           )
157         goto out;
158
159       /* XXX Could it be (in static binaries) that there is no object
160          loaded?  */
161       assert (ns != LM_ID_BASE || nloaded > 0);
162
163       /* Now we can allocate an array to hold all the pointers and copy
164          the pointers in.  */
165       if (maps_size < nloaded * sizeof (struct link_map *))
166         {
167           if (maps_size == 0)
168             {
169               maps_size = nloaded * sizeof (struct link_map *);
170               maps = (struct link_map **) alloca (maps_size);
171             }
172           else
173             maps = (struct link_map **)
174               extend_alloca (maps, maps_size,
175                              nloaded * sizeof (struct link_map *));
176         }
177
178       unsigned int i;
179       struct link_map *l;
180       assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
181       for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
182         /* Do not handle ld.so in secondary namespaces.  */
183         if (l == l->l_real)
184           {
185             assert (i < nloaded);
186
187             maps[i] = l;
188             l->l_idx = i;
189             ++i;
190
191             /* Bump l_direct_opencount of all objects so that they are
192                not dlclose()ed from underneath us.  */
193             ++l->l_direct_opencount;
194           }
195       assert (ns != LM_ID_BASE || i == nloaded);
196       assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
197       nmaps = i;
198
199       if (nmaps != 0)
200         /* Now we have to do the sorting.  */
201         _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);
202
203       /* We do not rely on the linked list of loaded object anymore from
204          this point on.  We have our own list here (maps).  The various
205          members of this list cannot vanish since the open count is too
206          high and will be decremented in this loop.  So we release the
207          lock so that some code which might be called from a destructor
208          can directly or indirectly access the lock.  */
209     out:
210       __rtld_lock_unlock_recursive (GL(dl_load_lock));
211
212       /* 'maps' now contains the objects in the right order.  Now call the
213          destructors.  We have to process this array from the front.  */
214       for (i = 0; i < nmaps; ++i)
215         {
216           l = maps[i];
217
218           if (l->l_init_called)
219             {
220               /* Make sure nothing happens if we are called twice.  */
221               l->l_init_called = 0;
222
223               /* Is there a destructor function?  */
224               if (l->l_info[DT_FINI_ARRAY] != NULL
225                   || l->l_info[DT_FINI] != NULL)
226                 {
227                   /* When debugging print a message first.  */
228                   if (__builtin_expect (GLRO(dl_debug_mask)
229                                         & DL_DEBUG_IMPCALLS, 0))
230                     _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
231                                       l->l_name[0] ? l->l_name : rtld_progname,
232                                       ns);
233
234                   /* First see whether an array is given.  */
235                   if (l->l_info[DT_FINI_ARRAY] != NULL)
236                     {
237                       ElfW(Addr) *array =
238                         (ElfW(Addr) *) (l->l_addr
239                                         + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
240                       unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
241                                         / sizeof (ElfW(Addr)));
242                       while (i-- > 0)
243                         ((fini_t) array[i]) ();
244                     }
245
246                   /* Next try the old-style destructor.  */
247                   if (l->l_info[DT_FINI] != NULL)
248                     ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
249                 }
250
251 #ifdef SHARED
252               /* Auditing checkpoint: another object closed.  */
253               if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
254                 {
255                   struct audit_ifaces *afct = GLRO(dl_audit);
256                   for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
257                     {
258                       if (afct->objclose != NULL)
259                         /* Return value is ignored.  */
260                         (void) afct->objclose (&l->l_audit[cnt].cookie);
261
262                       afct = afct->next;
263                     }
264                 }
265 #endif
266             }
267
268           /* Correct the previous increment.  */
269           --l->l_direct_opencount;
270         }
271     }
272
273 #ifdef SHARED
274   if (! do_audit && GLRO(dl_naudit) > 0)
275     {
276       do_audit = 1;
277       goto again;
278     }
279
280   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
281     _dl_debug_printf ("\nruntime linker statistics:\n"
282                       "           final number of relocations: %lu\n"
283                       "final number of relocations from cache: %lu\n",
284                       GL(dl_num_relocations),
285                       GL(dl_num_cache_relocations));
286 #endif
287 }