(_dl_open): Take extra parameter with address of caller. Pass address
[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 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 <stdlib.h>
24 #include <string.h>
25 #include <sys/mman.h>           /* Check whether MAP_COPY is defined.  */
26 #include <sys/param.h>
27 #include <bits/libc-lock.h>
28 #include <elf/ldsodefs.h>
29
30 #include <dl-dst.h>
31
32
33 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
34                                     void (*dl_main) (const ElfW(Phdr) *phdr,
35                                                      ElfW(Word) phnum,
36                                                      ElfW(Addr) *user_entry));
37 weak_extern (_dl_sysdep_start)
38
39 /* This function is used to unload the cache file if necessary.  */
40 extern void _dl_unload_cache (void);
41
42 extern int __libc_multiple_libcs;       /* Defined in init-first.c.  */
43
44 extern int __libc_argc;
45 extern char **__libc_argv;
46
47 extern char **__environ;
48
49 /* Undefine the following for debugging.  */
50 /* #define SCOPE_DEBUG 1 */
51 #ifdef SCOPE_DEBUG
52 static void show_scope (struct link_map *new);
53 #endif
54
55 /* During the program run we must not modify the global data of
56    loaded shared object simultanously in two threads.  Therefore we
57    protect `_dl_open' and `_dl_close' in dl-close.c.
58
59    This must be a recursive lock since the initializer function of
60    the loaded object might as well require a call to this function.
61    At this time it is not anymore a problem to modify the tables.  */
62 __libc_lock_define_initialized_recursive (, _dl_load_lock)
63
64 extern size_t _dl_platformlen;
65
66 /* We must be carefull not to leave us in an inconsistent state.  Thus we
67    catch any error and re-raise it after cleaning up.  */
68
69 struct dl_open_args
70 {
71   const char *file;
72   int mode;
73   const void *caller;
74   struct link_map *map;
75 };
76
77 static void
78 dl_open_worker (void *a)
79 {
80   struct dl_open_args *args = a;
81   const char *file = args->file;
82   int mode = args->mode;
83   struct link_map *new, *l;
84   ElfW(Addr) init;
85   struct r_debug *r;
86   unsigned int global_add;
87   const char *dst;
88
89   /* Maybe we have to expand a DST.  */
90   dst = strchr (file, '$');
91   if (dst != NULL)
92     {
93       const void *caller = args->caller;
94       size_t len = strlen (file);
95       size_t required;
96       struct link_map *call_map;
97       char *new_file;
98
99       /* We have to find out from which object the caller is calling.
100          Find the highest-addressed object that ADDRESS is not below.  */
101       call_map = NULL;
102       for (l = _dl_loaded; l; l = l->l_next)
103         if (l->l_addr != 0 /* Make sure we do not currently set this map up
104                               in this moment.  */
105             && caller >= (const void *) l->l_addr
106             && (call_map == NULL || call_map->l_addr < l->l_addr))
107           call_map = l;
108
109       if (call_map == NULL)
110         /* In this case we assume this is the main application.  */
111         call_map = _dl_loaded;
112
113       /* Determine how much space we need.  We have to allocate the
114          memory locally.  */
115       required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
116
117       /* Get space for the new file name.  */
118       new_file = (char *) alloca (required + 1);
119
120       /* Generate the new file name.  */
121       DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
122
123       /* If the substitution failed don't try to load.  */
124       if (*new_file == '\0')
125         _dl_signal_error (0, "dlopen",
126                           "empty dynamics string token substitution");
127
128       /* Now we have a new file name.  */
129       file = new_file;
130     }
131
132   /* Load the named object.  */
133   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
134   if (new->l_searchlist.r_list)
135     /* It was already open.  */
136     return;
137
138   /* Load that object's dependencies.  */
139   global_add = _dl_map_object_deps (new, NULL, 0, 0, mode & RTLD_GLOBAL);
140
141   /* So far, so good.  Now check the versions.  */
142   (void) _dl_check_all_versions (new, 0);
143
144 #ifdef SCOPE_DEBUG
145   show_scope (new);
146 #endif
147
148   /* Relocate the objects loaded.  We do this in reverse order so that copy
149      relocs of earlier objects overwrite the data written by later objects.  */
150
151   l = new;
152   while (l->l_next)
153     l = l->l_next;
154   while (1)
155     {
156       if (! l->l_relocated)
157         {
158 #ifdef PIC
159           if (_dl_profile != NULL)
160             {
161               /* If this here is the shared object which we want to profile
162                  make sure the profile is started.  We can find out whether
163                  this is necessary or not by observing the `_dl_profile_map'
164                  variable.  If was NULL but is not NULL afterwars we must
165                  start the profiling.  */
166               struct link_map *old_profile_map = _dl_profile_map;
167
168               _dl_relocate_object (l, l->l_scope, 1, 1);
169
170               if (old_profile_map == NULL && _dl_profile_map != NULL)
171                 /* We must prepare the profiling.  */
172                 _dl_start_profile (_dl_profile_map, _dl_profile_output);
173             }
174           else
175 #endif
176             _dl_relocate_object (l, l->l_scope,
177                                  (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
178         }
179
180       if (l == new)
181         break;
182       l = l->l_prev;
183     }
184
185   /* Notify the debugger we have added some objects.  We need to call
186      _dl_debug_initialize in a static program in case dynamic linking has
187      not been used before.  */
188   r = _dl_debug_initialize (0);
189   r->r_state = RT_ADD;
190   _dl_debug_state ();
191
192   /* Run the initializer functions of new objects.  */
193   while ((init = _dl_init_next (&new->l_searchlist)))
194     (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv,
195                                                 __environ);
196
197   /* Now we can make the new map available in the global scope.  */
198   while (global_add-- > 0)
199     _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist++]->l_global = 1;
200
201   if (_dl_sysdep_start == NULL)
202     /* We must be the static _dl_open in libc.a.  A static program that
203        has loaded a dynamic object now has competition.  */
204     __libc_multiple_libcs = 1;
205 }
206
207
208 struct link_map *
209 internal_function
210 _dl_open (const char *file, int mode, const void *caller)
211 {
212   struct dl_open_args args;
213   char *errstring;
214   int errcode;
215
216   if ((mode & RTLD_BINDING_MASK) == 0)
217     /* One of the flags must be set.  */
218     _dl_signal_error (EINVAL, file, _("invalid mode for dlopen()"));
219
220   /* Make sure we are alone.  */
221   __libc_lock_lock (_dl_load_lock);
222
223   args.file = file;
224   args.mode = mode;
225   args.caller = caller;
226   args.map = NULL;
227   errcode = _dl_catch_error (&errstring, dl_open_worker, &args);
228
229 #ifndef MAP_COPY
230   /* We must munmap() the cache file.  */
231   _dl_unload_cache ();
232 #endif
233
234   /* Release the lock.  */
235   __libc_lock_unlock (_dl_load_lock);
236
237   if (errstring)
238     {
239       /* Some error occured during loading.  */
240       char *local_errstring;
241
242       /* Remove the object from memory.  It may be in an inconsistent
243          state if relocation failed, for example.  */
244       if (args.map)
245         _dl_close (args.map);
246
247       /* Make a local copy of the error string so that we can release the
248          memory allocated for it.  */
249       local_errstring = strdupa (errstring);
250       free (errstring);
251
252       /* Reraise the error.  */
253       _dl_signal_error (errcode, NULL, local_errstring);
254     }
255
256   return args.map;
257 }
258
259
260 #ifdef SCOPE_DEBUG
261 #include <unistd.h>
262
263 static void
264 show_scope (struct link_map *new)
265 {
266   int scope_cnt;
267
268   for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
269     {
270       char numbuf[2];
271       unsigned int cnt;
272
273       numbuf[0] = '0' + scope_cnt;
274       numbuf[1] = '\0';
275       _dl_sysdep_message ("scope ", numbuf, ":", NULL);
276
277       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
278         if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
279           _dl_sysdep_message (" ",
280                               new->l_scope[scope_cnt]->r_list[cnt]->l_name,
281                               NULL);
282         else
283           _dl_sysdep_message (" <main>", NULL);
284
285       _dl_sysdep_message ("\n", NULL);
286     }
287 }
288 #endif