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