Update.
[platform/upstream/glibc.git] / elf / dl-open.c
1 /* Load a shared object at runtime, relocate it, and run its initializer.
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 <errno.h>
23 #include <libintl.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/mman.h>           /* Check whether MAP_COPY is defined.  */
28 #include <sys/param.h>
29 #include <bits/libc-lock.h>
30 #include <ldsodefs.h>
31
32 #include <dl-dst.h>
33
34
35 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
36                                     void (*dl_main) (const ElfW(Phdr) *phdr,
37                                                      ElfW(Word) phnum,
38                                                      ElfW(Addr) *user_entry));
39 weak_extern (_dl_sysdep_start)
40
41 /* This function is used to unload the cache file if necessary.  */
42 extern void _dl_unload_cache (void);
43
44 extern int __libc_multiple_libcs;       /* Defined in init-first.c.  */
45
46 extern int __libc_argc;
47 extern char **__libc_argv;
48
49 extern char **__environ;
50
51 extern int _dl_lazy;                    /* Do we do lazy relocations?  */
52
53 /* Undefine the following for debugging.  */
54 /* #define SCOPE_DEBUG 1 */
55 #ifdef SCOPE_DEBUG
56 static void show_scope (struct link_map *new);
57 #endif
58
59 /* During the program run we must not modify the global data of
60    loaded shared object simultanously in two threads.  Therefore we
61    protect `_dl_open' and `_dl_close' in dl-close.c.
62
63    This must be a recursive lock since the initializer function of
64    the loaded object might as well require a call to this function.
65    At this time it is not anymore a problem to modify the tables.  */
66 __libc_lock_define (extern, _dl_load_lock)
67
68 extern size_t _dl_platformlen;
69
70 /* We must be carefull not to leave us in an inconsistent state.  Thus we
71    catch any error and re-raise it after cleaning up.  */
72
73 struct dl_open_args
74 {
75   const char *file;
76   int mode;
77   const void *caller;
78   struct link_map *map;
79 };
80
81 static void
82 dl_open_worker (void *a)
83 {
84   struct dl_open_args *args = a;
85   const char *file = args->file;
86   int mode = args->mode;
87   struct link_map *new, *l;
88   const char *dst;
89   int lazy;
90
91   /* Maybe we have to expand a DST.  */
92   dst = strchr (file, '$');
93   if (dst != NULL)
94     {
95       const void *caller = args->caller;
96       size_t len = strlen (file);
97       size_t required;
98       struct link_map *call_map;
99       char *new_file;
100
101       /* DSTs must not appear in SUID/SGID programs.  */
102       if (__libc_enable_secure)
103         /* This is an error.  */
104         _dl_signal_error (0, "dlopen",
105                           "DST not allowed in SUID/SGID programs");
106
107       /* We have to find out from which object the caller is calling.
108          Find the highest-addressed object that ADDRESS is not below.  */
109       call_map = NULL;
110       for (l = _dl_loaded; l; l = l->l_next)
111         if (l->l_addr != 0 /* Make sure we do not currently set this map up
112                               in this moment.  */
113             && caller >= (const void *) l->l_addr
114             && (call_map == NULL || call_map->l_addr < l->l_addr))
115           call_map = l;
116
117       if (call_map == NULL)
118         /* In this case we assume this is the main application.  */
119         call_map = _dl_loaded;
120
121       /* Determine how much space we need.  We have to allocate the
122          memory locally.  */
123       required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
124
125       /* Get space for the new file name.  */
126       new_file = (char *) alloca (required + 1);
127
128       /* Generate the new file name.  */
129       DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
130
131       /* If the substitution failed don't try to load.  */
132       if (*new_file == '\0')
133         _dl_signal_error (0, "dlopen",
134                           "empty dynamic string token substitution");
135
136       /* Now we have a new file name.  */
137       file = new_file;
138     }
139
140   /* Load the named object.  */
141   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
142   if (new->l_searchlist.r_list)
143     /* It was already open.  */
144     return;
145
146   /* Load that object's dependencies.  */
147   _dl_map_object_deps (new, NULL, 0, 0);
148
149   /* So far, so good.  Now check the versions.  */
150   (void) _dl_check_all_versions (new, 0, 0);
151
152 #ifdef SCOPE_DEBUG
153   show_scope (new);
154 #endif
155
156   /* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
157   lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy;
158
159   /* Relocate the objects loaded.  We do this in reverse order so that copy
160      relocs of earlier objects overwrite the data written by later objects.  */
161
162   l = new;
163   while (l->l_next)
164     l = l->l_next;
165   while (1)
166     {
167       if (! l->l_relocated)
168         {
169 #ifdef SHARED
170           if (_dl_profile != NULL)
171             {
172               /* If this here is the shared object which we want to profile
173                  make sure the profile is started.  We can find out whether
174                  this is necessary or not by observing the `_dl_profile_map'
175                  variable.  If was NULL but is not NULL afterwars we must
176                  start the profiling.  */
177               struct link_map *old_profile_map = _dl_profile_map;
178
179               _dl_relocate_object (l, l->l_scope, 1, 1);
180
181               if (old_profile_map == NULL && _dl_profile_map != NULL)
182                 /* We must prepare the profiling.  */
183                 _dl_start_profile (_dl_profile_map, _dl_profile_output);
184             }
185           else
186 #endif
187             _dl_relocate_object (l, l->l_scope, lazy, 0);
188         }
189
190       if (l == new)
191         break;
192       l = l->l_prev;
193     }
194
195   /* Run the initializer functions of new objects.  */
196   _dl_init (new, __libc_argc, __libc_argv, __environ);
197
198   /* Now we can make the new map available in the global scope.  */
199   if (mode & RTLD_GLOBAL)
200     {
201       struct link_map **new_global;
202       unsigned int to_add = 0;
203       unsigned int cnt;
204
205       /* Count the objects we have to put in the global scope.  */
206       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
207         if (new->l_searchlist.r_list[cnt]->l_global == 0)
208           ++to_add;
209
210       /* The symbols of the new objects and its dependencies are to be
211          introduced into the global scope that will be used to resolve
212          references from other dynamically-loaded objects.
213
214          The global scope is the searchlist in the main link map.  We
215          extend this list if necessary.  There is one problem though:
216          since this structure was allocated very early (before the libc
217          is loaded) the memory it uses is allocated by the malloc()-stub
218          in the ld.so.  When we come here these functions are not used
219          anymore.  Instead the malloc() implementation of the libc is
220          used.  But this means the block from the main map cannot be used
221          in an realloc() call.  Therefore we allocate a completely new
222          array the first time we have to add something to the locale scope.  */
223
224       if (_dl_global_scope_alloc == 0)
225         {
226           /* This is the first dynamic object given global scope.  */
227           _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
228           new_global = (struct link_map **)
229             malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
230           if (new_global == NULL)
231             {
232               _dl_global_scope_alloc = 0;
233             nomem:
234               _dl_signal_error (ENOMEM, new->l_libname->name,
235                                 "cannot extend global scope");
236               return;
237             }
238
239           /* Copy over the old entries.  */
240           memcpy (new_global, _dl_main_searchlist->r_list,
241                   (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
242
243           _dl_main_searchlist->r_list = new_global;
244         }
245       else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
246         {
247           /* We have to extend the existing array of link maps in the
248              main map.  */
249           new_global = (struct link_map **)
250             realloc (_dl_main_searchlist->r_list,
251                      ((_dl_global_scope_alloc + to_add + 8)
252                       * sizeof (struct link_map *)));
253           if (new_global == NULL)
254             goto nomem;
255
256           _dl_global_scope_alloc += to_add + 8;
257           _dl_main_searchlist->r_list = new_global;
258         }
259
260       /* Now add the new entries.  */
261       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
262         {
263           struct link_map *map = new->l_searchlist.r_list[cnt];
264
265           if (map->l_global == 0)
266             {
267               map->l_global = 1;
268               _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
269               ++_dl_main_searchlist->r_nlist;
270             }
271         }
272
273       /* XXX Do we have to add something to r_dupsearchlist???  --drepper */
274     }
275
276   if (_dl_sysdep_start == NULL)
277     /* We must be the static _dl_open in libc.a.  A static program that
278        has loaded a dynamic object now has competition.  */
279     __libc_multiple_libcs = 1;
280 }
281
282
283 void *
284 internal_function
285 _dl_open (const char *file, int mode, const void *caller)
286 {
287   struct dl_open_args args;
288   char *errstring;
289   int errcode;
290
291   if ((mode & RTLD_BINDING_MASK) == 0)
292     /* One of the flags must be set.  */
293     _dl_signal_error (EINVAL, file, _("invalid mode for dlopen()"));
294
295   /* Make sure we are alone.  */
296   __libc_lock_lock (_dl_load_lock);
297
298   args.file = file;
299   args.mode = mode;
300   args.caller = caller;
301   args.map = NULL;
302   errcode = _dl_catch_error (&errstring, dl_open_worker, &args);
303
304 #ifndef MAP_COPY
305   /* We must munmap() the cache file.  */
306   _dl_unload_cache ();
307 #endif
308
309   /* Release the lock.  */
310   __libc_lock_unlock (_dl_load_lock);
311
312   if (errstring)
313     {
314       /* Some error occurred during loading.  */
315       char *local_errstring;
316
317       /* Remove the object from memory.  It may be in an inconsistent
318          state if relocation failed, for example.  */
319       if (args.map)
320         _dl_close (args.map);
321
322       /* Make a local copy of the error string so that we can release the
323          memory allocated for it.  */
324       local_errstring = strdupa (errstring);
325       free (errstring);
326
327       /* Reraise the error.  */
328       _dl_signal_error (errcode, NULL, local_errstring);
329     }
330
331   return args.map;
332 }
333
334
335 #ifdef SCOPE_DEBUG
336 #include <unistd.h>
337
338 static void
339 show_scope (struct link_map *new)
340 {
341   int scope_cnt;
342
343   for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
344     {
345       char numbuf[2];
346       unsigned int cnt;
347
348       numbuf[0] = '0' + scope_cnt;
349       numbuf[1] = '\0';
350       _dl_sysdep_message ("scope ", numbuf, ":", NULL);
351
352       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
353         if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
354           _dl_sysdep_message (" ",
355                               new->l_scope[scope_cnt]->r_list[cnt]->l_name,
356                               NULL);
357         else
358           _dl_sysdep_message (" <main>", NULL);
359
360       _dl_sysdep_message ("\n", NULL);
361     }
362 }
363 #endif