OSDN Git Service

cbbbcd49e7d98a5cd426c7d85ba1ffe5f59b2d1d
[uclinux-h8/uClibc.git] / ldso / libdl / libdl.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Program to load an ELF binary on a linux system, and run it
4  * after resolving ELF shared library symbols
5  *
6  * Copyright (C) 2000-2006 by Erik Andersen <andersen@uclibc.org>
7  * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
8  *                              David Engel, Hongjiu Lu and Mitch D'Souza
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. The name of the above contributors may not be
16  *    used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32
33 #include <ldso.h>
34 #include <stdio.h>
35 #include <string.h> /* Needed for 'strstr' prototype' */
36 #include <stdbool.h>
37
38 #ifdef __UCLIBC_HAS_TLS__
39 #include <tls.h>
40 #endif
41
42 #if defined(USE_TLS) && USE_TLS
43 #include <ldsodefs.h>
44 extern void _dl_add_to_slotinfo(struct link_map  *l);
45 #endif
46
47 #ifdef SHARED
48 # if defined(USE_TLS) && USE_TLS
49 # include <dl-tls.h>
50 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
51 # endif
52
53 /* When libdl is loaded as a shared library, we need to load in
54  * and use a pile of symbols from ldso... */
55 #include <dl-elf.h>
56 #if 0
57 extern struct elf_resolve * _dl_load_shared_library(unsigned, struct dyn_elf **,
58         struct elf_resolve *, char *, int);
59 extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
60 extern void _dl_protect_relro(struct elf_resolve * tpnt);
61 #endif
62 extern int _dl_errno;
63 extern struct dyn_elf *_dl_symbol_tables;
64 extern struct dyn_elf *_dl_handles;
65 extern struct elf_resolve *_dl_loaded_modules;
66 extern void _dl_free (void *__ptr);
67 extern struct r_debug *_dl_debug_addr;
68 extern unsigned long _dl_error_number;
69 extern void *(*_dl_malloc_function)(size_t);
70 extern void (*_dl_free_function) (void *p);
71 extern void _dl_run_init_array(struct elf_resolve *);
72 extern void _dl_run_fini_array(struct elf_resolve *);
73 #ifdef __LDSO_CACHE_SUPPORT__
74 int _dl_map_cache(void);
75 int _dl_unmap_cache(void);
76 #endif
77 #ifdef __mips__
78 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
79 #endif
80 #ifdef __SUPPORT_LD_DEBUG__
81 extern char *_dl_debug;
82 #endif
83
84 #else /* !SHARED */
85
86 #define _dl_malloc malloc
87 #define _dl_free free
88
89 /* When libdl is linked as a static library, we need to replace all
90  * the symbols that otherwise would have been loaded in from ldso... */
91
92 #ifdef __SUPPORT_LD_DEBUG__
93 char *_dl_debug  = NULL;
94 char *_dl_debug_symbols   = NULL;
95 char *_dl_debug_move      = NULL;
96 char *_dl_debug_reloc     = NULL;
97 char *_dl_debug_detail    = NULL;
98 char *_dl_debug_nofixups  = NULL;
99 char *_dl_debug_bindings  = NULL;
100 int   _dl_debug_file      = 2;
101 #endif
102 const char *_dl_progname       = "";        /* Program name */
103 void *(*_dl_malloc_function)(size_t);
104 void (*_dl_free_function) (void *p);
105 #ifdef __LDSO_LD_LIBRARY_PATH__
106 char *_dl_library_path         = NULL;         /* Where we look for libraries */
107 #endif
108 int _dl_errno                  = 0;         /* We can't use the real errno in ldso */
109 size_t _dl_pagesize            = PAGE_SIZE; /* Store the page size for use later */
110 /* This global variable is also to communicate with debuggers such as gdb. */
111 struct r_debug *_dl_debug_addr = NULL;
112
113 #include "../ldso/dl-array.c"
114 #include "../ldso/dl-debug.c"
115
116
117 # if defined(USE_TLS) && USE_TLS
118 /*
119  * Giving this initialized value preallocates some surplus bytes in the
120  * static TLS area, see __libc_setup_tls (libc-tls.c).
121  */
122 size_t _dl_tls_static_size = 2048;
123 # endif
124 #include LDSO_ELFINTERP
125 #include "../ldso/dl-hash.c"
126 #define _dl_trace_loaded_objects    0
127 #include "../ldso/dl-elf.c"
128 #endif /* SHARED */
129
130 #ifdef __SUPPORT_LD_DEBUG__
131 # define _dl_if_debug_print(fmt, args...) \
132         do { \
133         if (_dl_debug) \
134                 fprintf(stderr, "%s():%i: " fmt, __FUNCTION__, __LINE__, ## args); \
135         } while (0)
136 #else
137 # define _dl_if_debug_print(fmt, args...)
138 #endif
139
140 static int do_dlclose(void *, int need_fini);
141
142
143 static const char *const dl_error_names[] = {
144         "",
145         "File not found",
146         "Unable to open /dev/zero",
147         "Not an ELF file",
148 #if defined (__i386__)
149         "Not i386 binary",
150 #elif defined (__sparc__)
151         "Not sparc binary",
152 #elif defined (__mc68000__)
153         "Not m68k binary",
154 #else
155         "Unrecognized binary type",
156 #endif
157         "Not an ELF shared library",
158         "Unable to mmap file",
159         "No dynamic section",
160         "Library contains unsupported TLS",
161 #ifdef ELF_USES_RELOCA
162         "Unable to process REL relocs",
163 #else
164         "Unable to process RELA relocs",
165 #endif
166         "Bad handle",
167         "Unable to resolve symbol"
168 };
169
170
171 #if defined(USE_TLS) && USE_TLS
172 #ifdef SHARED
173 /*
174  * Systems which do not have tls_index also probably have to define
175  * DONT_USE_TLS_INDEX.
176  */
177
178 # ifndef __TLS_GET_ADDR
179 #  define __TLS_GET_ADDR __tls_get_addr
180 # endif
181
182 /*
183  * Return the symbol address given the map of the module it is in and
184  *  the symbol record.  This is used in dl-sym.c.
185  */
186 static void *
187 internal_function
188 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
189 {
190 # ifndef DONT_USE_TLS_INDEX
191         tls_index tmp =
192         {
193                 .ti_module = map->l_tls_modid,
194                 .ti_offset = st_value
195         };
196
197         return __TLS_GET_ADDR (&tmp);
198 # else
199         return __TLS_GET_ADDR (map->l_tls_modid, st_value);
200 # endif
201 }
202 #endif
203
204 /* Returns true when a non-empty entry was found.  */
205 static bool
206 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
207          bool should_be_there)
208 {
209         if (idx - disp >= listp->len) {
210                 if (listp->next == NULL) {
211                         /*
212                          * The index is not actually valid in the slotinfo list,
213                          * because this object was closed before it was fully set
214                          * up due to some error.
215                          */
216                         _dl_assert(!should_be_there);
217                 } else {
218                         if (remove_slotinfo(idx, listp->next, disp + listp->len,
219                                         should_be_there))
220                                 return true;
221
222                         /*
223                          * No non-empty entry. Search from the end of this element's
224                          * slotinfo array.
225                          */
226                         idx = disp + listp->len;
227                 }
228         } else {
229                 struct link_map *old_map = listp->slotinfo[idx - disp].map;
230
231                 /*
232                  * The entry might still be in its unused state if we are
233                  * closing an object that wasn't fully set up.
234                  */
235                 if (__builtin_expect(old_map != NULL, 1)) {
236                         _dl_assert(old_map->l_tls_modid == idx);
237
238                         /* Mark the entry as unused. */
239                         listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
240                         listp->slotinfo[idx - disp].map = NULL;
241                 }
242
243                 /*
244                  * If this is not the last currently used entry no need to
245                  * look further.
246                  */
247                 if (idx != _dl_tls_max_dtv_idx)
248                         return true;
249         }
250
251         while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
252                 --idx;
253
254                 if (listp->slotinfo[idx - disp].map != NULL) {
255                         /* Found a new last used index.  */
256                         _dl_tls_max_dtv_idx = idx;
257                         return true;
258                 }
259         }
260
261         /* No non-entry in this list element.  */
262         return false;
263 }
264 #endif
265
266 #ifndef __LDSO_NO_CLEANUP__
267 void dl_cleanup(void) __attribute__ ((destructor));
268 void dl_cleanup(void)
269 {
270         struct dyn_elf *h, *n;
271
272         for (h = _dl_handles; h; h = n) {
273                 n = h->next_handle;
274                 do_dlclose(h, 1);
275         }
276 }
277 #endif
278
279 static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
280         struct elf_resolve *map)
281 {
282         struct elf_resolve **p = list;
283         struct init_fini_list *q;
284
285         *p++ = map;
286         map->init_flag |= DL_RESERVED;
287         if (map->init_fini)
288                 for (q = map->init_fini; q; q = q->next)
289                         if (! (q->tpnt->init_flag & DL_RESERVED))
290                                 p += _dl_build_local_scope (p, q->tpnt);
291         return p - list;
292 }
293
294 void *dlopen(const char *libname, int flag)
295 {
296         struct elf_resolve *tpnt, *tfrom;
297         struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
298         ElfW(Addr) from;
299         struct elf_resolve *tpnt1;
300         void (*dl_brk) (void);
301         int now_flag;
302         struct init_fini_list *tmp, *runp, *runp2, *dep_list;
303         unsigned int nlist, i;
304         struct elf_resolve **init_fini_list;
305         static bool _dl_init;
306         struct elf_resolve **local_scope;
307         struct r_scope_elem *ls;
308 #if defined(USE_TLS) && USE_TLS
309         bool any_tls = false;
310 #endif
311
312         /* A bit of sanity checking... */
313         if (!(flag & (RTLD_LAZY|RTLD_NOW|RTLD_NOLOAD))) {
314                 _dl_error_number = LD_BAD_HANDLE;
315                 return NULL;
316         }
317
318         from = (ElfW(Addr)) __builtin_return_address(0);
319
320         if (!_dl_init) {
321                 _dl_init = true;
322                 _dl_malloc_function = malloc;
323                 _dl_free_function = free;
324         }
325         /* Cover the trivial case first */
326         if (!libname)
327                 return _dl_symbol_tables;
328
329 #ifndef SHARED
330 # ifdef __SUPPORT_LD_DEBUG__
331         _dl_debug = getenv("LD_DEBUG");
332         if (_dl_debug) {
333                 if (_dl_strstr(_dl_debug, "all")) {
334                         _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
335                                 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
336                 } else {
337                         _dl_debug_detail   = strstr(_dl_debug, "detail");
338                         _dl_debug_move     = strstr(_dl_debug, "move");
339                         _dl_debug_symbols  = strstr(_dl_debug, "sym");
340                         _dl_debug_reloc    = strstr(_dl_debug, "reloc");
341                         _dl_debug_nofixups = strstr(_dl_debug, "nofix");
342                         _dl_debug_bindings = strstr(_dl_debug, "bind");
343                 }
344         }
345 # endif
346 #endif
347
348         _dl_map_cache();
349
350         /*
351          * Try and locate the module we were called from - we
352          * need this so that we get the correct RPATH/RUNPATH.  Note that
353          * this is the current behavior under Solaris, but the
354          * ABI+ specifies that we should only use the RPATH from
355          * the application.  Thus this may go away at some time
356          * in the future.
357          */
358         {
359                 struct dyn_elf *dpnt;
360                 tfrom = NULL;
361                 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
362                         tpnt = dpnt->dyn;
363                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
364                                 tfrom = tpnt;
365                 }
366         }
367         for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
368                 continue;
369
370         relro_ptr = rpnt;
371         now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
372         if (getenv("LD_BIND_NOW"))
373                 now_flag = RTLD_NOW;
374
375 #if !defined SHARED && defined __LDSO_LIBRARY_PATH__
376         /* When statically linked, the _dl_library_path is not yet initialized */
377         _dl_library_path = getenv("LD_LIBRARY_PATH");
378 #endif
379
380         /* Try to load the specified library */
381         _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
382                         (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
383
384         tpnt = _dl_load_shared_library((flag & RTLD_NOLOAD) ? DL_RESOLVE_NOLOAD : 0,
385                                         &rpnt, tfrom, (char*)libname, 0);
386         if (tpnt == NULL) {
387                 _dl_unmap_cache();
388                 return NULL;
389         }
390         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
391         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
392         dyn_chain->dyn = tpnt;
393         tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
394
395         dyn_chain->next_handle = _dl_handles;
396         _dl_handles = dyn_ptr = dyn_chain;
397
398         if (tpnt->usage_count > 1) {
399                 _dl_if_debug_print("Lib: %s already opened\n", libname);
400                 /* see if there is a handle from a earlier dlopen */
401                 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
402                         if (handle->dyn == tpnt) {
403                                 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
404                                 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
405                                 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
406                                         dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
407                                 dyn_chain->next = handle->next;
408                                 break;
409                         }
410                 }
411                 return dyn_chain;
412         }
413
414         tpnt->init_flag |= DL_OPENED;
415
416         _dl_if_debug_print("Looking for needed libraries\n");
417         nlist = 0;
418         runp = alloca(sizeof(*runp));
419         runp->tpnt = tpnt;
420         runp->next = NULL;
421         dep_list = runp2 = runp;
422         for (; runp; runp = runp->next) {
423                 ElfW(Dyn) *dpnt;
424                 char *lpntstr;
425
426                 nlist++;
427                 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
428                 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
429                         if (dpnt->d_tag == DT_NEEDED) {
430                                 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
431                                                 dpnt->d_un.d_val);
432                                 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
433                                                 lpntstr, runp->tpnt->libname);
434                                 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
435                                 if (!tpnt1)
436                                         goto oops;
437
438                                 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
439
440                                 /* This list is for dlsym() and relocation */
441                                 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
442                                 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
443                                 dyn_ptr = dyn_ptr->next;
444                                 dyn_ptr->dyn = tpnt1;
445                                 /* Used to record RTLD_LOCAL scope */
446                                 tmp = alloca(sizeof(struct init_fini_list));
447                                 tmp->tpnt = tpnt1;
448                                 tmp->next = runp->tpnt->init_fini;
449                                 runp->tpnt->init_fini = tmp;
450
451                                 for (tmp=dep_list; tmp; tmp = tmp->next) {
452                                         if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
453                                                 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
454                                                                    tmp->tpnt->libname);
455                                                 tpnt1->usage_count--;
456                                                 break;
457                                         }
458                                 }
459                                 if (!tmp) { /* Don't add if circular dependency detected */
460                                         runp2->next = alloca(sizeof(*runp));
461                                         runp2 = runp2->next;
462                                         runp2->tpnt = tpnt1;
463                                         runp2->next = NULL;
464                                 }
465                         }
466                 }
467         }
468         init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
469         dyn_chain->init_fini.init_fini = init_fini_list;
470         dyn_chain->init_fini.nlist = nlist;
471         i = 0;
472         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
473                 init_fini_list[i++] = runp2->tpnt;
474                 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
475                         if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
476                                 tmp = malloc(sizeof(struct init_fini_list));
477                                 tmp->tpnt = runp->tpnt;
478                                 tmp->next = runp2->tpnt->rtld_local;
479                                 runp2->tpnt->rtld_local = tmp;
480                         }
481                 }
482
483         }
484         /* Build the local scope for the dynamically loaded modules. */
485         local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
486         for (i = 0; i < nlist; i++)
487                 if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
488                         int k, cnt;
489                         cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
490                         init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
491                         init_fini_list[i]->symbol_scope.r_nlist = cnt;
492                         _dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
493                                         cnt * sizeof (struct elf_resolve *));
494                         /* Restoring the init_flag.*/
495                         for (k = 0; k < nlist; k++)
496                                 init_fini_list[k]->init_flag &= ~DL_RESERVED;
497                 }
498
499         _dl_free(local_scope);
500
501         /* Sort the INIT/FINI list in dependency order. */
502         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
503                 unsigned int j, k;
504                 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
505                         /* Empty */;
506                 for (k = j + 1; k < nlist; ++k) {
507                         struct init_fini_list *ele = init_fini_list[k]->init_fini;
508
509                         for (; ele; ele = ele->next) {
510                                 if (ele->tpnt == runp2->tpnt) {
511                                         struct elf_resolve *here = init_fini_list[k];
512                                         _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
513                                         for (i = (k - j); i; --i)
514                                                 init_fini_list[i+j] = init_fini_list[i+j-1];
515                                         init_fini_list[j] = here;
516                                         ++j;
517                                         break;
518                                 }
519                         }
520                 }
521         }
522 #ifdef __SUPPORT_LD_DEBUG__
523         if (_dl_debug) {
524                 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
525                 for (i = 0; i < nlist; i++) {
526                         fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
527                         runp = init_fini_list[i]->init_fini;
528                         for (; runp; runp = runp->next)
529                                 fprintf(stderr, " %s ", runp->tpnt->libname);
530                         fprintf(stderr, "\n");
531                 }
532         }
533 #endif
534
535         _dl_if_debug_print("Beginning dlopen relocation fixups\n");
536         /*
537          * OK, now all of the kids are tucked into bed in their proper addresses.
538          * Now we go through and look for REL and RELA records that indicate fixups
539          * to the GOT tables.  We need to do this in reverse order so that COPY
540          * directives work correctly */
541 #ifdef __mips__
542         /*
543          * Relocation of the GOT entries for MIPS have to be done
544          * after all the libraries have been loaded.
545          */
546         _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
547 #endif
548         /* Get the tail of the list */
549         for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
550
551         /* Extend the global scope by adding the local scope of the dlopened DSO. */
552         ls->next = &dyn_chain->dyn->symbol_scope;
553
554         if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
555                 goto oops;
556
557         if (relro_ptr) {
558                 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
559                         if (rpnt->dyn->relro_size)
560                                 _dl_protect_relro(rpnt->dyn);
561                 }
562         }
563         /* TODO:  Should we set the protections of all pages back to R/O now ? */
564
565
566 #if defined(USE_TLS) && USE_TLS
567
568         for (i=0; i < nlist; i++) {
569                 struct elf_resolve *tmp_tpnt = init_fini_list[i];
570                 /* Only add TLS memory if this object is loaded now and
571                    therefore is not yet initialized.  */
572
573                 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
574                 /* Only if the module defines thread local data. */
575                         && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
576
577                         /* Now that we know the object is loaded successfully add
578                         modules containing TLS data to the slot info table.  We
579                         might have to increase its size.  */
580                         _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
581
582                         /* It is the case in which we couldn't perform TLS static
583                            initialization at relocation time, and we delayed it until
584                            the relocation has been completed. */
585
586                         if (tmp_tpnt->l_need_tls_init) {
587                                 tmp_tpnt->l_need_tls_init = 0;
588 # ifdef SHARED
589                                 /* Update the slot information data for at least the
590                                 generation of the DSO we are allocating data for.  */
591                                 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
592 # endif
593
594                                 _dl_init_static_tls((struct link_map*)tmp_tpnt);
595                                 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
596                 }
597
598                 /* We have to bump the generation counter. */
599                 any_tls = true;
600                 }
601         }
602
603         /* Bump the generation number if necessary.  */
604         if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
605                 _dl_debug_early("TLS generation counter wrapped! Please report this.");
606                 _dl_exit(30);
607         }
608
609 #endif
610
611         /* Notify the debugger we have added some objects. */
612         if (_dl_debug_addr) {
613                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
614                 if (dl_brk != NULL) {
615                         _dl_debug_addr->r_state = RT_ADD;
616                         (*dl_brk) ();
617
618                         _dl_debug_addr->r_state = RT_CONSISTENT;
619                         (*dl_brk) ();
620                 }
621         }
622
623         /* Run the ctors and setup the dtors */
624         for (i = nlist; i; --i) {
625                 tpnt = init_fini_list[i-1];
626                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
627                         continue;
628                 tpnt->init_flag |= INIT_FUNCS_CALLED;
629
630                 if (tpnt->dynamic_info[DT_INIT]) {
631                         void (*dl_elf_func) (void);
632                         dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
633                         if (dl_elf_func) {
634                                 _dl_if_debug_print("running ctors for library %s at '%p'\n",
635                                                 tpnt->libname, dl_elf_func);
636                                 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
637                         }
638                 }
639
640                 _dl_run_init_array(tpnt);
641         }
642
643         _dl_unmap_cache();
644         return (void *) dyn_chain;
645
646 oops:
647         /* Something went wrong.  Clean up and return NULL. */
648         _dl_unmap_cache();
649         do_dlclose(dyn_chain, 0);
650         return NULL;
651 }
652
653 void *dlsym(void *vhandle, const char *name)
654 {
655         struct elf_resolve *tpnt, *tfrom;
656         struct dyn_elf *handle;
657         ElfW(Addr) from;
658         struct dyn_elf *rpnt;
659         void *ret;
660         struct symbol_ref sym_ref = { NULL, NULL };
661         /* Nastiness to support underscore prefixes.  */
662 #ifdef __UCLIBC_UNDERSCORES__
663         char tmp_buf[80];
664         char *name2 = tmp_buf;
665         size_t nlen = strlen (name) + 1;
666         if (nlen + 1 > sizeof (tmp_buf))
667                 name2 = malloc (nlen + 1);
668         if (name2 == 0) {
669                 _dl_error_number = LD_ERROR_MMAP_FAILED;
670                 return 0;
671         }
672         name2[0] = '_';
673         memcpy (name2 + 1, name, nlen);
674 #else
675         const char *name2 = name;
676 #endif
677         handle = (struct dyn_elf *) vhandle;
678
679         /* First of all verify that we have a real handle
680            of some kind.  Return NULL if not a valid handle. */
681
682         if (handle == NULL)
683                 handle = _dl_symbol_tables;
684         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
685                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
686                         if (rpnt == handle)
687                                 break;
688                 if (!rpnt) {
689                         _dl_error_number = LD_BAD_HANDLE;
690                         ret = NULL;
691                         goto out;
692                 }
693         } else if (handle == RTLD_NEXT) {
694                 /*
695                  * Try and locate the module we were called from - we
696                  * need this so that we know where to start searching
697                  * from.  We never pass RTLD_NEXT down into the actual
698                  * dynamic loader itself, as it doesn't know
699                  * how to properly treat it.
700                  */
701                 from = (ElfW(Addr)) __builtin_return_address(0);
702
703                 tfrom = NULL;
704                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
705                         tpnt = rpnt->dyn;
706                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
707                                 tfrom = tpnt;
708                                 handle = rpnt->next;
709                         }
710                 }
711         }
712         tpnt = NULL;
713         if (handle == _dl_symbol_tables)
714                 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
715         ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, tpnt, ELF_RTYPE_CLASS_DLSYM, &sym_ref);
716
717 #if defined(USE_TLS) && USE_TLS && defined SHARED
718         if (sym_ref.sym && (ELF_ST_TYPE(sym_ref.sym->st_info) == STT_TLS) && (sym_ref.tpnt)) {
719                 /* The found symbol is a thread-local storage variable.
720                 Return its address for the current thread.  */
721                 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
722         }
723 #endif
724
725         /*
726          * Nothing found.
727          */
728         if (!ret)
729                 _dl_error_number = LD_NO_SYMBOL;
730 out:
731 #ifdef __UCLIBC_UNDERSCORES__
732         if (name2 != tmp_buf)
733                 free (name2);
734 #endif
735         return ret;
736 }
737
738 #if 0
739 void *dlvsym(void *vhandle, const char *name, const char *version)
740 {
741         return dlsym(vhandle, name);
742 }
743 #endif
744
745 static int do_dlclose(void *vhandle, int need_fini)
746 {
747         struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
748         struct init_fini_list *runp, *tmp;
749         ElfW(Phdr) *ppnt;
750         struct elf_resolve *tpnt, *run_tpnt;
751         int (*dl_elf_fini) (void);
752         void (*dl_brk) (void);
753         struct dyn_elf *handle;
754         unsigned int end;
755         unsigned int i, j;
756         struct r_scope_elem *ls;
757 #if defined(USE_TLS) && USE_TLS
758         bool any_tls = false;
759         size_t tls_free_start = NO_TLS_OFFSET;
760         size_t tls_free_end = NO_TLS_OFFSET;
761         struct link_map *tls_lmap;
762 #endif
763
764         handle = (struct dyn_elf *) vhandle;
765         if (handle == _dl_symbol_tables)
766                 return 0;
767         rpnt1 = NULL;
768         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
769                 if (rpnt == handle)
770                         break;
771                 rpnt1 = rpnt;
772         }
773
774         if (!rpnt) {
775                 _dl_error_number = LD_BAD_HANDLE;
776                 return 1;
777         }
778         if (rpnt1)
779                 rpnt1->next_handle = rpnt->next_handle;
780         else
781                 _dl_handles = rpnt->next_handle;
782         _dl_if_debug_print("%s: usage count: %d\n",
783                         handle->dyn->libname, handle->dyn->usage_count);
784         if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
785                 handle->dyn->usage_count--;
786                 free(handle);
787                 return 0;
788         }
789         /* OK, this is a valid handle - now close out the file */
790         for (j = 0; j < handle->init_fini.nlist; ++j) {
791                 tpnt = handle->init_fini.init_fini[j];
792                 tpnt->usage_count--;
793                 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
794                         if ((tpnt->dynamic_info[DT_FINI]
795                              || tpnt->dynamic_info[DT_FINI_ARRAY])
796                          && need_fini
797                          && !(tpnt->init_flag & FINI_FUNCS_CALLED)
798                         ) {
799                                 tpnt->init_flag |= FINI_FUNCS_CALLED;
800                                 _dl_run_fini_array(tpnt);
801
802                                 if (tpnt->dynamic_info[DT_FINI]) {
803                                         dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
804                                         _dl_if_debug_print("running dtors for library %s at '%p'\n",
805                                                         tpnt->libname, dl_elf_fini);
806                                         DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
807                                 }
808                         }
809
810                         _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
811                         end = 0;
812                         for (i = 0, ppnt = tpnt->ppnt;
813                                         i < tpnt->n_phent; ppnt++, i++) {
814                                 if (ppnt->p_type != PT_LOAD)
815                                         continue;
816                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
817                                         end = ppnt->p_vaddr + ppnt->p_memsz;
818                         }
819
820 #if defined(USE_TLS) && USE_TLS
821                         /* Do the cast to make things easy. */
822                         tls_lmap = (struct link_map *) tpnt;
823
824                         /* Remove the object from the dtv slotinfo array if it uses TLS. */
825                         if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
826                                 any_tls = true;
827
828                                 if (_dl_tls_dtv_slotinfo_list != NULL
829                                                 && ! remove_slotinfo (tls_lmap->l_tls_modid,
830                                                 _dl_tls_dtv_slotinfo_list, 0,
831                                                 (tpnt->init_flag & INIT_FUNCS_CALLED)))
832                                         /* All dynamically loaded modules with TLS are unloaded. */
833                                         _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
834
835                                 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
836                                         /*
837                                          * Collect a contiguous chunk built from the objects in
838                                          * this search list, going in either direction.  When the
839                                          * whole chunk is at the end of the used area then we can
840                                          * reclaim it.
841                                          */
842 # if defined(TLS_TCB_AT_TP)
843                                         if (tls_free_start == NO_TLS_OFFSET
844                                                 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
845                                                 /* Extend the contiguous chunk being reclaimed. */
846                                                 tls_free_start
847                                                         = tls_lmap->l_tls_offset -
848                                                           tls_lmap->l_tls_blocksize;
849
850                                                 if (tls_free_end == NO_TLS_OFFSET)
851                                                         tls_free_end = tls_lmap->l_tls_offset;
852                                         } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
853                                                         == tls_free_end)
854                                                 /* Extend the chunk backwards.  */
855                                                 tls_free_end = tls_lmap->l_tls_offset;
856                                         else {
857                                                 /*
858                                                  * This isn't contiguous with the last chunk freed.
859                                                  * One of them will be leaked unless we can free
860                                                  * one block right away.
861                                                  */
862                                                 if (tls_free_end == _dl_tls_static_used) {
863                                                         _dl_tls_static_used = tls_free_start;
864                                                         tls_free_end = tls_lmap->l_tls_offset;
865                                                         tls_free_start
866                                                                 = tls_free_end - tls_lmap->l_tls_blocksize;
867                                                 } else if ((size_t) tls_lmap->l_tls_offset
868                                                                 == _dl_tls_static_used)
869                                                         _dl_tls_static_used = tls_lmap->l_tls_offset -
870                                                                 tls_lmap->l_tls_blocksize;
871                                                 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
872                                                         /*
873                                                          * We pick the later block. It has a chance
874                                                          * to be freed.
875                                                          */
876                                                         tls_free_end = tls_lmap->l_tls_offset;
877                                                         tls_free_start = tls_free_end -
878                                                                 tls_lmap->l_tls_blocksize;
879                                                 }
880                                         }
881 # elif defined(TLS_DTV_AT_TP)
882                                         if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
883                                                 /* Extend the contiguous chunk being reclaimed. */
884                                                 tls_free_end -= tls_lmap->l_tls_blocksize;
885                                         else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
886                                                         == tls_free_start)
887                                                 /* Extend the chunk backwards. */
888                                                 tls_free_start = tls_lmap->l_tls_offset;
889                                         else {
890                                                 /*
891                                                  * This isn't contiguous with the last chunk
892                                                  * freed. One of them will be leaked.
893                                                  */
894                                                 if (tls_free_end == _dl_tls_static_used)
895                                                         _dl_tls_static_used = tls_free_start;
896                                                 tls_free_start = tls_lmap->l_tls_offset;
897                                                 tls_free_end = tls_free_start +
898                                                         tls_lmap->l_tls_blocksize;
899                                         }
900 # else
901 #  error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
902 # endif
903                                 } else {
904
905 #define TLS_DTV_UNALLOCATED     ((void *) -1l)
906
907                                         dtv_t *dtv = THREAD_DTV ();
908
909                                         _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
910                                         if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
911                                                 /* Note that free is called for NULL is well.  We
912                                                 deallocate even if it is this dtv entry we are
913                                                 supposed to load.  The reason is that we call
914                                                 memalign and not malloc.  */
915                                                 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
916                                                 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
917                                         }
918                                 }
919                         }
920 #endif
921
922                         DL_LIB_UNMAP (tpnt, end - tpnt->mapaddr);
923                         /* Free elements in RTLD_LOCAL scope list */
924                         for (runp = tpnt->rtld_local; runp; runp = tmp) {
925                                 tmp = runp->next;
926                                 free(runp);
927                         }
928
929                         /* Next, remove tpnt from the loaded_module list */
930                         if (_dl_loaded_modules == tpnt) {
931                                 _dl_loaded_modules = tpnt->next;
932                                 if (_dl_loaded_modules)
933                                         _dl_loaded_modules->prev = 0;
934                         } else {
935                                 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
936                                         if (run_tpnt->next == tpnt) {
937                                                 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
938                                                 run_tpnt->next = run_tpnt->next->next;
939                                                 if (run_tpnt->next)
940                                                         run_tpnt->next->prev = run_tpnt;
941                                                 break;
942                                         }
943                                 }
944                         }
945
946                         if (handle->dyn == tpnt) {
947                                 /* Unlink the local scope from global one */
948                                 for (ls = &_dl_loaded_modules->symbol_scope; ls; ls = ls->next)
949                                         if (ls->next->r_list[0] == tpnt) {
950                                                 _dl_if_debug_print("removing symbol_scope: %s\n", tpnt->libname);
951                                                 break;
952                                         }
953                                 ls->next = ls->next->next;
954                         }
955
956                         /* Next, remove tpnt from the global symbol table list */
957                         if (_dl_symbol_tables) {
958                                 if (_dl_symbol_tables->dyn == tpnt) {
959                                         _dl_symbol_tables = _dl_symbol_tables->next;
960                                         if (_dl_symbol_tables)
961                                                 _dl_symbol_tables->prev = 0;
962                                 } else {
963                                         for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
964                                                 if (rpnt1->next->dyn == tpnt) {
965                                                         _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
966                                                         rpnt1_tmp = rpnt1->next->next;
967                                                         free(rpnt1->next);
968                                                         rpnt1->next = rpnt1_tmp;
969                                                         if (rpnt1->next)
970                                                                 rpnt1->next->prev = rpnt1;
971                                                         break;
972                                                 }
973                                         }
974                                 }
975                         }
976                         free(tpnt->libname);
977                         free(tpnt->symbol_scope.r_list);
978                         free(tpnt);
979                 }
980         }
981         for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
982                 rpnt1_tmp = rpnt1->next;
983                 free(rpnt1);
984         }
985         free(handle->init_fini.init_fini);
986         free(handle);
987
988 #if defined(USE_TLS) && USE_TLS
989         /* If we removed any object which uses TLS bump the generation counter.  */
990         if (any_tls) {
991                 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
992                         _dl_debug_early("TLS generation counter wrapped!  Please report to the uClibc mailing list.\n");
993                         _dl_exit(30);
994                 }
995
996                 if (tls_free_end == _dl_tls_static_used)
997                         _dl_tls_static_used = tls_free_start;
998         }
999 #endif
1000
1001         if (_dl_debug_addr) {
1002                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
1003                 if (dl_brk != NULL) {
1004                         _dl_debug_addr->r_state = RT_DELETE;
1005                         (*dl_brk) ();
1006
1007                         _dl_debug_addr->r_state = RT_CONSISTENT;
1008                         (*dl_brk) ();
1009                 }
1010         }
1011
1012         return 0;
1013 }
1014
1015 int dlclose(void *vhandle)
1016 {
1017         return do_dlclose(vhandle, 1);
1018 }
1019
1020 char *dlerror(void)
1021 {
1022         const char *retval;
1023
1024         if (!_dl_error_number)
1025                 return NULL;
1026         retval = dl_error_names[_dl_error_number];
1027         _dl_error_number = 0;
1028         return (char *)retval;
1029 }
1030
1031 /*
1032  * Dump information to stderr about the current loaded modules
1033  */
1034 #ifdef __USE_GNU
1035 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
1036
1037 int dlinfo(void)
1038 {
1039         struct elf_resolve *tpnt;
1040         struct dyn_elf *rpnt, *hpnt;
1041
1042         fprintf(stderr, "List of loaded modules\n");
1043         /* First start with a complete list of all of the loaded files. */
1044         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1045                 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1046                         DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1047                         type[tpnt->libtype],
1048                         tpnt->usage_count, tpnt->libname);
1049         }
1050
1051         /* Next dump the module list for the application itself */
1052         fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1053         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1054                 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1055
1056         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1057                 fprintf(stderr, "Modules for handle %p\n", hpnt);
1058                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1059                         fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1060         }
1061         return 0;
1062 }
1063
1064 int dladdr(const void *__address, Dl_info * __info)
1065 {
1066         struct elf_resolve *pelf;
1067         struct elf_resolve *rpnt;
1068
1069         _dl_map_cache();
1070
1071         /*
1072          * Try and locate the module address is in
1073          */
1074         pelf = NULL;
1075
1076         _dl_if_debug_print("__address: %p  __info: %p\n", __address, __info);
1077
1078         __address = DL_LOOKUP_ADDRESS (__address);
1079
1080         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1081                 struct elf_resolve *tpnt;
1082
1083                 tpnt = rpnt;
1084
1085                 _dl_if_debug_print("Module \"%s\" at %p\n",
1086                                    tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1087
1088                 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1089                         pelf = tpnt;
1090         }
1091
1092         if (!pelf) {
1093                 return 0;
1094         }
1095
1096         /*
1097          * Try and locate the symbol of address
1098          */
1099
1100         {
1101                 char *strtab;
1102                 ElfW(Sym) *symtab;
1103                 unsigned int hn, si, sn, sf;
1104                 ElfW(Addr) sa = 0;
1105
1106                 /* Set the info for the object the address lies in */
1107                 __info->dli_fname = pelf->libname;
1108                 __info->dli_fbase = (void *)pelf->mapaddr;
1109
1110                 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1111                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1112
1113                 sf = sn = 0;
1114
1115 #ifdef __LDSO_GNU_HASH_SUPPORT__
1116                 if (pelf->l_gnu_bitmask) {
1117                         for (hn = 0; hn < pelf->nbucket; hn++) {
1118                                 si = pelf->l_gnu_buckets[hn];
1119                                 if (!si)
1120                                         continue;
1121
1122                                 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1123                                 do {
1124                                         ElfW(Addr) symbol_addr;
1125
1126                                         symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1127                                         if ((symtab[si].st_shndx != SHN_UNDEF
1128                                                  || symtab[si].st_value != 0)
1129                                                 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1130                                                 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1131                                                                                          (ElfW(Addr)) __address)) {
1132                                                 sa = symbol_addr;
1133                                                 sn = si;
1134                                                 sf = 1;
1135                                         }
1136                                         _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1137                                         ++si;
1138                                 } while ((*hasharr++ & 1u) == 0);
1139                         }
1140                 } else
1141 #endif
1142                 for (hn = 0; hn < pelf->nbucket; hn++) {
1143                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1144                                 ElfW(Addr) symbol_addr;
1145
1146                                 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1147                                 if ((symtab[si].st_shndx != SHN_UNDEF
1148                                          || symtab[si].st_value != 0)
1149                                         && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1150                                         && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1151                                                                                  (ElfW(Addr)) __address)) {
1152                                         sa = symbol_addr;
1153                                         sn = si;
1154                                         sf = 1;
1155                                 }
1156
1157                                 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1158                                                    strtab + symtab[si].st_name, symbol_addr);
1159                         }
1160                 }
1161
1162                 if (sf) {
1163                         /* A nearest symbol has been found; fill the entries */
1164                         __info->dli_sname = strtab + symtab[sn].st_name;
1165                         __info->dli_saddr = (void *)sa;
1166                 } else {
1167                         /* No symbol found, fill entries with NULL value,
1168                         only the containing object will be returned. */
1169                         __info->dli_sname = NULL;
1170                         __info->dli_saddr = NULL;
1171                 }
1172                 return 1;
1173         }
1174 }
1175 #endif