(dl_open_worker): Use l_map_start and l_map_end to test for pointer in
[kopensolaris-gnu/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_map_start
114             && caller < (const void *) l->l_map_end)
115           {
116             /* There must be exactly one DSO for the range of the virtual
117                memory.  Otherwise something is really broken.  */
118             call_map = l;
119             break;
120           }
121
122       if (call_map == NULL)
123         /* In this case we assume this is the main application.  */
124         call_map = _dl_loaded;
125
126       /* Determine how much space we need.  We have to allocate the
127          memory locally.  */
128       required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
129
130       /* Get space for the new file name.  */
131       new_file = (char *) alloca (required + 1);
132
133       /* Generate the new file name.  */
134       DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
135
136       /* If the substitution failed don't try to load.  */
137       if (*new_file == '\0')
138         _dl_signal_error (0, "dlopen",
139                           "empty dynamic string token substitution");
140
141       /* Now we have a new file name.  */
142       file = new_file;
143     }
144
145   /* Load the named object.  */
146   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
147   if (new->l_searchlist.r_list)
148     /* It was already open.  */
149     return;
150
151   /* Load that object's dependencies.  */
152   _dl_map_object_deps (new, NULL, 0, 0);
153
154   /* So far, so good.  Now check the versions.  */
155   (void) _dl_check_all_versions (new, 0, 0);
156
157 #ifdef SCOPE_DEBUG
158   show_scope (new);
159 #endif
160
161   /* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
162   lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy;
163
164   /* Relocate the objects loaded.  We do this in reverse order so that copy
165      relocs of earlier objects overwrite the data written by later objects.  */
166
167   l = new;
168   while (l->l_next)
169     l = l->l_next;
170   while (1)
171     {
172       if (! l->l_relocated)
173         {
174 #ifdef SHARED
175           if (_dl_profile != NULL)
176             {
177               /* If this here is the shared object which we want to profile
178                  make sure the profile is started.  We can find out whether
179                  this is necessary or not by observing the `_dl_profile_map'
180                  variable.  If was NULL but is not NULL afterwars we must
181                  start the profiling.  */
182               struct link_map *old_profile_map = _dl_profile_map;
183
184               _dl_relocate_object (l, l->l_scope, 1, 1);
185
186               if (old_profile_map == NULL && _dl_profile_map != NULL)
187                 /* We must prepare the profiling.  */
188                 _dl_start_profile (_dl_profile_map, _dl_profile_output);
189             }
190           else
191 #endif
192             _dl_relocate_object (l, l->l_scope, lazy, 0);
193         }
194
195       if (l == new)
196         break;
197       l = l->l_prev;
198     }
199
200   /* Run the initializer functions of new objects.  */
201   _dl_init (new, __libc_argc, __libc_argv, __environ);
202
203   /* Now we can make the new map available in the global scope.  */
204   if (mode & RTLD_GLOBAL)
205     {
206       struct link_map **new_global;
207       unsigned int to_add = 0;
208       unsigned int cnt;
209
210       /* Count the objects we have to put in the global scope.  */
211       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
212         if (new->l_searchlist.r_list[cnt]->l_global == 0)
213           ++to_add;
214
215       /* The symbols of the new objects and its dependencies are to be
216          introduced into the global scope that will be used to resolve
217          references from other dynamically-loaded objects.
218
219          The global scope is the searchlist in the main link map.  We
220          extend this list if necessary.  There is one problem though:
221          since this structure was allocated very early (before the libc
222          is loaded) the memory it uses is allocated by the malloc()-stub
223          in the ld.so.  When we come here these functions are not used
224          anymore.  Instead the malloc() implementation of the libc is
225          used.  But this means the block from the main map cannot be used
226          in an realloc() call.  Therefore we allocate a completely new
227          array the first time we have to add something to the locale scope.  */
228
229       if (_dl_global_scope_alloc == 0)
230         {
231           /* This is the first dynamic object given global scope.  */
232           _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
233           new_global = (struct link_map **)
234             malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
235           if (new_global == NULL)
236             {
237               _dl_global_scope_alloc = 0;
238             nomem:
239               _dl_signal_error (ENOMEM, new->l_libname->name,
240                                 "cannot extend global scope");
241               return;
242             }
243
244           /* Copy over the old entries.  */
245           memcpy (new_global, _dl_main_searchlist->r_list,
246                   (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
247
248           _dl_main_searchlist->r_list = new_global;
249         }
250       else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
251         {
252           /* We have to extend the existing array of link maps in the
253              main map.  */
254           new_global = (struct link_map **)
255             realloc (_dl_main_searchlist->r_list,
256                      ((_dl_global_scope_alloc + to_add + 8)
257                       * sizeof (struct link_map *)));
258           if (new_global == NULL)
259             goto nomem;
260
261           _dl_global_scope_alloc += to_add + 8;
262           _dl_main_searchlist->r_list = new_global;
263         }
264
265       /* Now add the new entries.  */
266       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
267         {
268           struct link_map *map = new->l_searchlist.r_list[cnt];
269
270           if (map->l_global == 0)
271             {
272               map->l_global = 1;
273               _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
274               ++_dl_main_searchlist->r_nlist;
275             }
276         }
277
278       /* XXX Do we have to add something to r_dupsearchlist???  --drepper */
279     }
280
281   if (_dl_sysdep_start == NULL)
282     /* We must be the static _dl_open in libc.a.  A static program that
283        has loaded a dynamic object now has competition.  */
284     __libc_multiple_libcs = 1;
285 }
286
287
288 void *
289 internal_function
290 _dl_open (const char *file, int mode, const void *caller)
291 {
292   struct dl_open_args args;
293   char *errstring;
294   int errcode;
295
296   if ((mode & RTLD_BINDING_MASK) == 0)
297     /* One of the flags must be set.  */
298     _dl_signal_error (EINVAL, file, _("invalid mode for dlopen()"));
299
300   /* Make sure we are alone.  */
301   __libc_lock_lock (_dl_load_lock);
302
303   args.file = file;
304   args.mode = mode;
305   args.caller = caller;
306   args.map = NULL;
307   errcode = _dl_catch_error (&errstring, dl_open_worker, &args);
308
309 #ifndef MAP_COPY
310   /* We must munmap() the cache file.  */
311   _dl_unload_cache ();
312 #endif
313
314   /* Release the lock.  */
315   __libc_lock_unlock (_dl_load_lock);
316
317   if (errstring)
318     {
319       /* Some error occurred during loading.  */
320       char *local_errstring;
321
322       /* Remove the object from memory.  It may be in an inconsistent
323          state if relocation failed, for example.  */
324       if (args.map)
325         _dl_close (args.map);
326
327       /* Make a local copy of the error string so that we can release the
328          memory allocated for it.  */
329       local_errstring = strdupa (errstring);
330       free (errstring);
331
332       /* Reraise the error.  */
333       _dl_signal_error (errcode, NULL, local_errstring);
334     }
335
336   return args.map;
337 }
338
339
340 #ifdef SCOPE_DEBUG
341 #include <unistd.h>
342
343 static void
344 show_scope (struct link_map *new)
345 {
346   int scope_cnt;
347
348   for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
349     {
350       char numbuf[2];
351       unsigned int cnt;
352
353       numbuf[0] = '0' + scope_cnt;
354       numbuf[1] = '\0';
355       _dl_sysdep_message ("scope ", numbuf, ":", NULL);
356
357       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
358         if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
359           _dl_sysdep_message (" ",
360                               new->l_scope[scope_cnt]->r_list[cnt]->l_name,
361                               NULL);
362         else
363           _dl_sysdep_message (" <main>", NULL);
364
365       _dl_sysdep_message ("\n", NULL);
366     }
367 }
368 #endif