(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[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-2001, 2002, 2003, 2004 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 <assert.h>
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <libintl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/mman.h>           /* Check whether MAP_COPY is defined.  */
29 #include <sys/param.h>
30 #include <bits/libc-lock.h>
31 #include <ldsodefs.h>
32 #include <bp-sym.h>
33 #include <caller.h>
34
35 #include <dl-dst.h>
36
37
38 #ifndef SHARED
39 /* Giving this initialized value preallocates some surplus bytes in the
40    static TLS area, see __libc_setup_tls (libc-tls.c).  */
41 size_t _dl_tls_static_size = 2048;
42 #endif
43
44 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
45                                     void (*dl_main) (const ElfW(Phdr) *phdr,
46                                                      ElfW(Word) phnum,
47                                                      ElfW(Addr) *user_entry));
48 weak_extern (BP_SYM (_dl_sysdep_start))
49
50 extern int __libc_multiple_libcs;       /* Defined in init-first.c.  */
51
52 extern int __libc_argc attribute_hidden;
53 extern char **__libc_argv attribute_hidden;
54
55 extern char **__environ;
56
57 /* Undefine the following for debugging.  */
58 /* #define SCOPE_DEBUG 1 */
59 #ifdef SCOPE_DEBUG
60 static void show_scope (struct link_map *new);
61 #endif
62
63 /* We must be carefull not to leave us in an inconsistent state.  Thus we
64    catch any error and re-raise it after cleaning up.  */
65
66 struct dl_open_args
67 {
68   const char *file;
69   int mode;
70   /* This is the caller of the dlopen() function.  */
71   const void *caller_dlopen;
72   /* This is the caller if _dl_open().  */
73   const void *caller_dl_open;
74   struct link_map *map;
75   /* Namespace ID.  */
76   Lmid_t nsid;
77 };
78
79
80 static int
81 add_to_global (struct link_map *new)
82 {
83   struct link_map **new_global;
84   unsigned int to_add = 0;
85   unsigned int cnt;
86
87   /* Count the objects we have to put in the global scope.  */
88   for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
89     if (new->l_searchlist.r_list[cnt]->l_global == 0)
90       ++to_add;
91
92   /* The symbols of the new objects and its dependencies are to be
93      introduced into the global scope that will be used to resolve
94      references from other dynamically-loaded objects.
95
96      The global scope is the searchlist in the main link map.  We
97      extend this list if necessary.  There is one problem though:
98      since this structure was allocated very early (before the libc
99      is loaded) the memory it uses is allocated by the malloc()-stub
100      in the ld.so.  When we come here these functions are not used
101      anymore.  Instead the malloc() implementation of the libc is
102      used.  But this means the block from the main map cannot be used
103      in an realloc() call.  Therefore we allocate a completely new
104      array the first time we have to add something to the locale scope.  */
105
106   if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0)
107     {
108       /* This is the first dynamic object given global scope.  */
109       GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
110         = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8;
111       new_global = (struct link_map **)
112         malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
113                 * sizeof (struct link_map *));
114       if (new_global == NULL)
115         {
116           GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
117         nomem:
118           GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
119                                  N_("cannot extend global scope"));
120           return 1;
121         }
122
123       /* Copy over the old entries.  */
124       GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list
125         = memcpy (new_global,
126                   GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
127                   (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist
128                    * sizeof (struct link_map *)));
129     }
130   else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add
131            > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc)
132     {
133       /* We have to extend the existing array of link maps in the
134          main map.  */
135       new_global = (struct link_map **)
136         realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
137                  ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8)
138                   * sizeof (struct link_map *)));
139       if (new_global == NULL)
140         goto nomem;
141
142       GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
143       GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
144     }
145
146   /* Now add the new entries.  */
147   for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
148     {
149       struct link_map *map = new->l_searchlist.r_list[cnt];
150
151       if (map->l_global == 0)
152         {
153           map->l_global = 1;
154           GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist]
155             = map;
156           ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist;
157         }
158     }
159
160   return 0;
161 }
162
163
164 static void
165 dl_open_worker (void *a)
166 {
167   struct dl_open_args *args = a;
168   const char *file = args->file;
169   int mode = args->mode;
170   struct link_map *new, *l;
171   int lazy;
172   unsigned int i;
173 #ifdef USE_TLS
174   bool any_tls;
175 #endif
176   struct link_map *call_map = NULL;
177
178   /* Check whether _dl_open() has been called from a valid DSO.  */
179   if (__check_caller (args->caller_dl_open, allow_libc|allow_libdl) != 0)
180     GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
181
182   /* Determine the caller's map if necessary.  This is needed in case
183      we have a DST, when we don't know the namespace ID we have to put
184      the new object in, or when the file name has no path in which
185      case we need to look along the RUNPATH/RPATH of the caller.  */
186   const char *dst = strchr (file, '$');
187   if (dst != NULL || args->nsid == __LM_ID_CALLER
188       || strchr (file, '/') == NULL)
189     {
190       const void *caller_dlopen = args->caller_dlopen;
191
192       /* We have to find out from which object the caller is calling.
193          By default we assume this is the main application.  */
194       call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
195
196       for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
197         for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
198           if (caller_dlopen >= (const void *) l->l_map_start
199               && caller_dlopen < (const void *) l->l_map_end)
200             {
201               /* There must be exactly one DSO for the range of the virtual
202                  memory.  Otherwise something is really broken.  */
203               assert (ns == l->l_ns);
204               call_map = l;
205               goto found_caller;
206             }
207
208     found_caller:
209       if (args->nsid == __LM_ID_CALLER)
210         {
211 #ifndef SHARED
212           /* In statically linked apps there might be no loaded object.  */
213           if (call_map == NULL)
214             args->nsid = LM_ID_BASE;
215           else
216 #endif
217             args->nsid = call_map->l_ns;
218         }
219     }
220
221   /* Maybe we have to expand a DST.  */
222   if (__builtin_expect (dst != NULL, 0))
223     {
224       size_t len = strlen (file);
225       size_t required;
226       char *new_file;
227
228       /* DSTs must not appear in SUID/SGID programs.  */
229       if (__libc_enable_secure)
230         /* This is an error.  */
231         GLRO(dl_signal_error) (0, "dlopen", NULL,
232                                N_("DST not allowed in SUID/SGID programs"));
233
234
235       /* Determine how much space we need.  We have to allocate the
236          memory locally.  */
237       required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
238
239       /* Get space for the new file name.  */
240       new_file = (char *) alloca (required + 1);
241
242       /* Generate the new file name.  */
243       _dl_dst_substitute (call_map, file, new_file, 0);
244
245       /* If the substitution failed don't try to load.  */
246       if (*new_file == '\0')
247         GLRO(dl_signal_error) (0, "dlopen", NULL,
248                                N_("empty dynamic string token substitution"));
249
250       /* Now we have a new file name.  */
251       file = new_file;
252
253       /* It does not matter whether call_map is set even if we
254          computed it only because of the DST.  Since the path contains
255          a slash the value is not used.  See dl-load.c.  */
256     }
257
258   /* Load the named object.  */
259   args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
260                                          mode | __RTLD_CALLMAP, args->nsid);
261
262   /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
263      set and the object is not already loaded.  */
264   if (new == NULL)
265     {
266       assert (mode & RTLD_NOLOAD);
267       return;
268     }
269
270   if (__builtin_expect (mode & __RTLD_SPROF, 0))
271     /* This happens only if we load a DSO for 'sprof'.  */
272     return;
273
274   /* This object is directly loaded.  */
275   ++new->l_direct_opencount;
276
277   /* It was already open.  */
278   if (__builtin_expect (new->l_searchlist.r_list != NULL, 0))
279     {
280       /* Let the user know about the opencount.  */
281       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
282         GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
283                                new->l_name, new->l_ns, new->l_opencount);
284
285       /* If the user requested the object to be in the global namespace
286          but it is not so far, add it now.  */
287       if ((mode & RTLD_GLOBAL) && new->l_global == 0)
288         (void) add_to_global (new);
289
290       if (new->l_direct_opencount == 1)
291         /* This is the only direct reference.  Increment all the
292            dependencies' reference counter.  */
293         for (i = 0; i < new->l_searchlist.r_nlist; ++i)
294           ++new->l_searchlist.r_list[i]->l_opencount;
295       else
296         /* Increment just the reference counter of the object.  */
297         ++new->l_opencount;
298
299       return;
300     }
301
302   /* Load that object's dependencies.  */
303   GLRO(dl_map_object_deps) (new, NULL, 0, 0,
304                             mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
305
306   /* So far, so good.  Now check the versions.  */
307   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
308     if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
309       (void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real,
310                                           0, 0);
311
312 #ifdef SCOPE_DEBUG
313   show_scope (new);
314 #endif
315
316   /* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
317   lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GLRO(dl_lazy);
318
319   /* Relocate the objects loaded.  We do this in reverse order so that copy
320      relocs of earlier objects overwrite the data written by later objects.  */
321
322   l = new;
323   while (l->l_next)
324     l = l->l_next;
325   while (1)
326     {
327       if (! l->l_real->l_relocated)
328         {
329 #ifdef SHARED
330           if (GLRO(dl_profile) != NULL)
331             {
332               /* If this here is the shared object which we want to profile
333                  make sure the profile is started.  We can find out whether
334                  this is necessary or not by observing the `_dl_profile_map'
335                  variable.  If was NULL but is not NULL afterwars we must
336                  start the profiling.  */
337               struct link_map *old_profile_map = GL(dl_profile_map);
338
339               GLRO(dl_relocate_object) (l, l->l_scope, 1, 1);
340
341               if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
342                 {
343                   /* We must prepare the profiling.  */
344                   GLRO(dl_start_profile) ();
345
346                   /* Prevent unloading the object.  */
347                   GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
348                 }
349             }
350           else
351 #endif
352             GLRO(dl_relocate_object) (l, l->l_scope, lazy, 0);
353         }
354
355       if (l == new)
356         break;
357       l = l->l_prev;
358     }
359
360 #ifdef USE_TLS
361   /* Do static TLS initialization now if it has been delayed because
362      the TLS template might not be fully relocated at _dl_allocate_static_tls
363      time.  */
364   for (l = new; l; l = l->l_next)
365     if (l->l_need_tls_init)
366       {
367         l->l_need_tls_init = 0;
368         GL(dl_init_static_tls) (l);
369       }
370
371   /* We normally don't bump the TLS generation counter.  There must be
372      actually a need to do this.  */
373   any_tls = false;
374 #endif
375
376   /* Increment the open count for all dependencies.  If the file is
377      not loaded as a dependency here add the search list of the newly
378      loaded object to the scope.  */
379   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
380     if (++new->l_searchlist.r_list[i]->l_opencount > 1
381         && new->l_real->l_searchlist.r_list[i]->l_type == lt_loaded)
382       {
383         struct link_map *imap = new->l_searchlist.r_list[i];
384         struct r_scope_elem **runp = imap->l_scope;
385         size_t cnt = 0;
386
387         while (*runp != NULL)
388           {
389             /* This can happen if imap was just loaded, but during
390                relocation had l_opencount bumped because of relocation
391                dependency.  Avoid duplicates in l_scope.  */
392             if (__builtin_expect (*runp == &new->l_searchlist, 0))
393               break;
394
395             ++cnt;
396             ++runp;
397           }
398
399         if (*runp != NULL)
400           /* Avoid duplicates.  */
401           continue;
402
403         if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
404           {
405             /* The 'r_scope' array is too small.  Allocate a new one
406                dynamically.  */
407             struct r_scope_elem **newp;
408             size_t new_size = imap->l_scope_max * 2;
409
410             if (imap->l_scope == imap->l_scope_mem)
411               {
412                 newp = (struct r_scope_elem **)
413                   malloc (new_size * sizeof (struct r_scope_elem *));
414                 if (newp == NULL)
415                   GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
416                                          N_("cannot create scope list"));
417                 imap->l_scope = memcpy (newp, imap->l_scope,
418                                         cnt * sizeof (imap->l_scope[0]));
419               }
420             else
421               {
422                 newp = (struct r_scope_elem **)
423                   realloc (imap->l_scope,
424                            new_size * sizeof (struct r_scope_elem *));
425                 if (newp == NULL)
426                   GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
427                                          N_("cannot create scope list"));
428                 imap->l_scope = newp;
429               }
430
431             imap->l_scope_max = new_size;
432           }
433
434         imap->l_scope[cnt++] = &new->l_searchlist;
435         imap->l_scope[cnt] = NULL;
436       }
437 #if USE_TLS
438     else if (new->l_searchlist.r_list[i]->l_opencount == 1
439              /* Only if the module defines thread local data.  */
440              && __builtin_expect (new->l_searchlist.r_list[i]->l_tls_blocksize
441                                   > 0, 0))
442       {
443         /* Now that we know the object is loaded successfully add
444            modules containing TLS data to the dtv info table.  We
445            might have to increase its size.  */
446         struct dtv_slotinfo_list *listp;
447         struct dtv_slotinfo_list *prevp;
448         size_t idx = new->l_searchlist.r_list[i]->l_tls_modid;
449
450         assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
451
452         /* Find the place in the dtv slotinfo list.  */
453         listp = GL(dl_tls_dtv_slotinfo_list);
454         prevp = NULL;           /* Needed to shut up gcc.  */
455         do
456           {
457             /* Does it fit in the array of this list element?  */
458             if (idx < listp->len)
459               break;
460             idx -= listp->len;
461             prevp = listp;
462             listp = listp->next;
463           }
464         while (listp != NULL);
465
466         if (listp == NULL)
467           {
468             /* When we come here it means we have to add a new element
469                to the slotinfo list.  And the new module must be in
470                the first slot.  */
471             assert (idx == 0);
472
473             listp = prevp->next = (struct dtv_slotinfo_list *)
474               malloc (sizeof (struct dtv_slotinfo_list)
475                       + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
476             if (listp == NULL)
477               {
478                 /* We ran out of memory.  We will simply fail this
479                    call but don't undo anything we did so far.  The
480                    application will crash or be terminated anyway very
481                    soon.  */
482
483                 /* We have to do this since some entries in the dtv
484                    slotinfo array might already point to this
485                    generation.  */
486                 ++GL(dl_tls_generation);
487
488                 GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL, N_("\
489 cannot create TLS data structures"));
490               }
491
492             listp->len = TLS_SLOTINFO_SURPLUS;
493             listp->next = NULL;
494             memset (listp->slotinfo, '\0',
495                     TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
496           }
497
498         /* Add the information into the slotinfo data structure.  */
499         listp->slotinfo[idx].map = new->l_searchlist.r_list[i];
500         listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
501
502         /* We have to bump the generation counter.  */
503         any_tls = true;
504       }
505
506   /* Bump the generation number if necessary.  */
507   if (any_tls)
508     if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
509       __libc_fatal (_("TLS generation counter wrapped!  Please report this."));
510 #endif
511
512   /* Run the initializer functions of new objects.  */
513   GLRO(dl_init) (new, __libc_argc, __libc_argv, __environ);
514
515   /* Now we can make the new map available in the global scope.  */
516   if (mode & RTLD_GLOBAL)
517     /* Move the object in the global namespace.  */
518     if (add_to_global (new) != 0)
519       /* It failed.  */
520       return;
521
522   /* Mark the object as not deletable if the RTLD_NODELETE flags was
523      passed.  */
524   if (__builtin_expect (mode & RTLD_NODELETE, 0))
525     new->l_flags_1 |= DF_1_NODELETE;
526
527 #ifndef SHARED
528   /* We must be the static _dl_open in libc.a.  A static program that
529      has loaded a dynamic object now has competition.  */
530   __libc_multiple_libcs = 1;
531 #endif
532
533   /* Let the user know about the opencount.  */
534   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
535     GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
536                            new->l_name, new->l_ns, new->l_opencount);
537 }
538
539
540 void *
541 internal_function
542 _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
543 {
544   struct dl_open_args args;
545   const char *objname;
546   const char *errstring;
547   int errcode;
548
549   if ((mode & RTLD_BINDING_MASK) == 0)
550     /* One of the flags must be set.  */
551     GLRO(dl_signal_error) (EINVAL, file, NULL,
552                            N_("invalid mode for dlopen()"));
553
554   /* Make sure we are alone.  */
555   __rtld_lock_lock_recursive (GL(dl_load_lock));
556
557   if (nsid == LM_ID_NEWLM)
558     {
559       /* Find a new namespace.  */
560       for (nsid = 1; nsid < DL_NNS; ++nsid)
561         if (GL(dl_ns)[nsid]._ns_loaded == NULL)
562           break;
563
564       if (nsid == DL_NNS)
565         {
566           /* No more namespace available.  */
567           __rtld_lock_unlock_recursive (GL(dl_load_lock));
568
569           GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\
570 no more namespaces available for dlmopen()"));
571         }
572     }
573   /* Never allow loading a DSO in a namespace which is empty.  Such
574      direct placements is only causing problems.  */
575   else if (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER
576            && GL(dl_ns)[nsid]._ns_nloaded == 0)
577     GLRO(dl_signal_error) (EINVAL, file, NULL,
578                            N_("invalid target namespace in dlmopen()"));
579
580   args.file = file;
581   args.mode = mode;
582   args.caller_dlopen = caller_dlopen;
583   args.caller_dl_open = RETURN_ADDRESS (0);
584   args.map = NULL;
585   args.nsid = nsid;
586   errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args);
587
588 #ifndef MAP_COPY
589   /* We must munmap() the cache file.  */
590   GLRO(dl_unload_cache) ();
591 #endif
592
593   /* Release the lock.  */
594   __rtld_lock_unlock_recursive (GL(dl_load_lock));
595
596   if (__builtin_expect (errstring != NULL, 0))
597     {
598       /* Some error occurred during loading.  */
599       char *local_errstring;
600       size_t len_errstring;
601
602       /* Remove the object from memory.  It may be in an inconsistent
603          state if relocation failed, for example.  */
604       if (args.map)
605         {
606           unsigned int i;
607
608           /* Increment open counters for all objects since this
609              sometimes has not happened yet.  */
610           if (args.map->l_searchlist.r_list[0]->l_opencount == 0)
611             for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
612               ++args.map->l_searchlist.r_list[i]->l_opencount;
613
614 #ifdef USE_TLS
615           /* Maybe some of the modules which were loaded uses TLS.
616              Since it will be removed in the following _dl_close call
617              we have to mark the dtv array as having gaps to fill
618              the holes.  This is a pessimistic assumption which won't
619              hurt if not true.  */
620           GL(dl_tls_dtv_gaps) = true;
621 #endif
622
623           _dl_close (args.map);
624         }
625
626       /* Make a local copy of the error string so that we can release the
627          memory allocated for it.  */
628       len_errstring = strlen (errstring) + 1;
629       if (objname == errstring + len_errstring)
630         {
631           size_t total_len = len_errstring + strlen (objname) + 1;
632           local_errstring = alloca (total_len);
633           memcpy (local_errstring, errstring, total_len);
634           objname = local_errstring + len_errstring;
635         }
636       else
637         {
638           local_errstring = alloca (len_errstring);
639           memcpy (local_errstring, errstring, len_errstring);
640         }
641
642       if (errstring != _dl_out_of_memory)
643         free ((char *) errstring);
644
645       /* Reraise the error.  */
646       GLRO(dl_signal_error) (errcode, objname, NULL, local_errstring);
647     }
648
649 #ifndef SHARED
650   DL_STATIC_INIT (args.map);
651 #endif
652
653   return args.map;
654 }
655 libc_hidden_def (_dl_open)
656
657
658 #ifdef SCOPE_DEBUG
659 #include <unistd.h>
660
661 static void
662 show_scope (struct link_map *new)
663 {
664   int scope_cnt;
665
666   for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
667     {
668       char numbuf[2];
669       unsigned int cnt;
670
671       numbuf[0] = '0' + scope_cnt;
672       numbuf[1] = '\0';
673       _dl_printf ("scope %s:", numbuf);
674
675       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
676         if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
677           _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name);
678         else
679           _dl_printf (" <main>");
680
681       _dl_printf ("\n");
682     }
683 }
684 #endif