OSDN Git Service

324b76aa5f1b6860f674e42d29442ec48c998a2a
[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 = 0, start = 0xffffffff;
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 (ppnt->p_vaddr < start)
817                                         start = ppnt->p_vaddr;
818                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
819                                         end = ppnt->p_vaddr + ppnt->p_memsz;
820                         }
821
822 #if defined(USE_TLS) && USE_TLS
823                         /* Do the cast to make things easy. */
824                         tls_lmap = (struct link_map *) tpnt;
825
826                         /* Remove the object from the dtv slotinfo array if it uses TLS. */
827                         if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
828                                 any_tls = true;
829
830                                 if (_dl_tls_dtv_slotinfo_list != NULL
831                                                 && ! remove_slotinfo (tls_lmap->l_tls_modid,
832                                                 _dl_tls_dtv_slotinfo_list, 0,
833                                                 (tpnt->init_flag & INIT_FUNCS_CALLED)))
834                                         /* All dynamically loaded modules with TLS are unloaded. */
835                                         _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
836
837                                 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
838                                         /*
839                                          * Collect a contiguous chunk built from the objects in
840                                          * this search list, going in either direction.  When the
841                                          * whole chunk is at the end of the used area then we can
842                                          * reclaim it.
843                                          */
844 # if defined(TLS_TCB_AT_TP)
845                                         if (tls_free_start == NO_TLS_OFFSET
846                                                 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
847                                                 /* Extend the contiguous chunk being reclaimed. */
848                                                 tls_free_start
849                                                         = tls_lmap->l_tls_offset -
850                                                           tls_lmap->l_tls_blocksize;
851
852                                                 if (tls_free_end == NO_TLS_OFFSET)
853                                                         tls_free_end = tls_lmap->l_tls_offset;
854                                         } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
855                                                         == tls_free_end)
856                                                 /* Extend the chunk backwards.  */
857                                                 tls_free_end = tls_lmap->l_tls_offset;
858                                         else {
859                                                 /*
860                                                  * This isn't contiguous with the last chunk freed.
861                                                  * One of them will be leaked unless we can free
862                                                  * one block right away.
863                                                  */
864                                                 if (tls_free_end == _dl_tls_static_used) {
865                                                         _dl_tls_static_used = tls_free_start;
866                                                         tls_free_end = tls_lmap->l_tls_offset;
867                                                         tls_free_start
868                                                                 = tls_free_end - tls_lmap->l_tls_blocksize;
869                                                 } else if ((size_t) tls_lmap->l_tls_offset
870                                                                 == _dl_tls_static_used)
871                                                         _dl_tls_static_used = tls_lmap->l_tls_offset -
872                                                                 tls_lmap->l_tls_blocksize;
873                                                 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
874                                                         /*
875                                                          * We pick the later block. It has a chance
876                                                          * to be freed.
877                                                          */
878                                                         tls_free_end = tls_lmap->l_tls_offset;
879                                                         tls_free_start = tls_free_end -
880                                                                 tls_lmap->l_tls_blocksize;
881                                                 }
882                                         }
883 # elif defined(TLS_DTV_AT_TP)
884                                         if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
885                                                 /* Extend the contiguous chunk being reclaimed. */
886                                                 tls_free_end -= tls_lmap->l_tls_blocksize;
887                                         else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
888                                                         == tls_free_start)
889                                                 /* Extend the chunk backwards. */
890                                                 tls_free_start = tls_lmap->l_tls_offset;
891                                         else {
892                                                 /*
893                                                  * This isn't contiguous with the last chunk
894                                                  * freed. One of them will be leaked.
895                                                  */
896                                                 if (tls_free_end == _dl_tls_static_used)
897                                                         _dl_tls_static_used = tls_free_start;
898                                                 tls_free_start = tls_lmap->l_tls_offset;
899                                                 tls_free_end = tls_free_start +
900                                                         tls_lmap->l_tls_blocksize;
901                                         }
902 # else
903 #  error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
904 # endif
905                                 } else {
906
907 #define TLS_DTV_UNALLOCATED     ((void *) -1l)
908
909                                         dtv_t *dtv = THREAD_DTV ();
910
911                                         _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
912                                         if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
913                                                 /* Note that free is called for NULL is well.  We
914                                                 deallocate even if it is this dtv entry we are
915                                                 supposed to load.  The reason is that we call
916                                                 memalign and not malloc.  */
917                                                 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
918                                                 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
919                                         }
920                                 }
921                         }
922 #endif
923
924                         end = (end + ADDR_ALIGN) & PAGE_ALIGN;
925                         start = start & ~ADDR_ALIGN;
926                         DL_LIB_UNMAP (tpnt, end - start);
927                         /* Free elements in RTLD_LOCAL scope list */
928                         for (runp = tpnt->rtld_local; runp; runp = tmp) {
929                                 tmp = runp->next;
930                                 free(runp);
931                         }
932
933                         /* Next, remove tpnt from the loaded_module list */
934                         if (_dl_loaded_modules == tpnt) {
935                                 _dl_loaded_modules = tpnt->next;
936                                 if (_dl_loaded_modules)
937                                         _dl_loaded_modules->prev = 0;
938                         } else {
939                                 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
940                                         if (run_tpnt->next == tpnt) {
941                                                 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
942                                                 run_tpnt->next = run_tpnt->next->next;
943                                                 if (run_tpnt->next)
944                                                         run_tpnt->next->prev = run_tpnt;
945                                                 break;
946                                         }
947                                 }
948                         }
949
950                         if (handle->dyn == tpnt) {
951                                 /* Unlink the local scope from global one */
952                                 for (ls = &_dl_loaded_modules->symbol_scope; ls; ls = ls->next)
953                                         if (ls->next->r_list[0] == tpnt) {
954                                                 _dl_if_debug_print("removing symbol_scope: %s\n", tpnt->libname);
955                                                 break;
956                                         }
957                                 ls->next = ls->next->next;
958                         }
959
960                         /* Next, remove tpnt from the global symbol table list */
961                         if (_dl_symbol_tables) {
962                                 if (_dl_symbol_tables->dyn == tpnt) {
963                                         _dl_symbol_tables = _dl_symbol_tables->next;
964                                         if (_dl_symbol_tables)
965                                                 _dl_symbol_tables->prev = 0;
966                                 } else {
967                                         for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
968                                                 if (rpnt1->next->dyn == tpnt) {
969                                                         _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
970                                                         rpnt1_tmp = rpnt1->next->next;
971                                                         free(rpnt1->next);
972                                                         rpnt1->next = rpnt1_tmp;
973                                                         if (rpnt1->next)
974                                                                 rpnt1->next->prev = rpnt1;
975                                                         break;
976                                                 }
977                                         }
978                                 }
979                         }
980                         free(tpnt->libname);
981                         free(tpnt->symbol_scope.r_list);
982                         free(tpnt);
983                 }
984         }
985         for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
986                 rpnt1_tmp = rpnt1->next;
987                 free(rpnt1);
988         }
989         free(handle->init_fini.init_fini);
990         free(handle);
991
992 #if defined(USE_TLS) && USE_TLS
993         /* If we removed any object which uses TLS bump the generation counter.  */
994         if (any_tls) {
995                 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
996                         _dl_debug_early("TLS generation counter wrapped!  Please report to the uClibc mailing list.\n");
997                         _dl_exit(30);
998                 }
999
1000                 if (tls_free_end == _dl_tls_static_used)
1001                         _dl_tls_static_used = tls_free_start;
1002         }
1003 #endif
1004
1005         if (_dl_debug_addr) {
1006                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
1007                 if (dl_brk != NULL) {
1008                         _dl_debug_addr->r_state = RT_DELETE;
1009                         (*dl_brk) ();
1010
1011                         _dl_debug_addr->r_state = RT_CONSISTENT;
1012                         (*dl_brk) ();
1013                 }
1014         }
1015
1016         return 0;
1017 }
1018
1019 int dlclose(void *vhandle)
1020 {
1021         return do_dlclose(vhandle, 1);
1022 }
1023
1024 char *dlerror(void)
1025 {
1026         const char *retval;
1027
1028         if (!_dl_error_number)
1029                 return NULL;
1030         retval = dl_error_names[_dl_error_number];
1031         _dl_error_number = 0;
1032         return (char *)retval;
1033 }
1034
1035 /*
1036  * Dump information to stderr about the current loaded modules
1037  */
1038 #ifdef __USE_GNU
1039 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
1040
1041 int dlinfo(void)
1042 {
1043         struct elf_resolve *tpnt;
1044         struct dyn_elf *rpnt, *hpnt;
1045
1046         fprintf(stderr, "List of loaded modules\n");
1047         /* First start with a complete list of all of the loaded files. */
1048         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1049                 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1050                         DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1051                         type[tpnt->libtype],
1052                         tpnt->usage_count, tpnt->libname);
1053         }
1054
1055         /* Next dump the module list for the application itself */
1056         fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1057         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1058                 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1059
1060         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1061                 fprintf(stderr, "Modules for handle %p\n", hpnt);
1062                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1063                         fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1064         }
1065         return 0;
1066 }
1067
1068 int dladdr(const void *__address, Dl_info * __info)
1069 {
1070         struct elf_resolve *pelf;
1071         struct elf_resolve *rpnt;
1072
1073         _dl_map_cache();
1074
1075         /*
1076          * Try and locate the module address is in
1077          */
1078         pelf = NULL;
1079
1080         _dl_if_debug_print("__address: %p  __info: %p\n", __address, __info);
1081
1082         __address = DL_LOOKUP_ADDRESS (__address);
1083
1084         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1085                 struct elf_resolve *tpnt;
1086
1087                 tpnt = rpnt;
1088
1089                 _dl_if_debug_print("Module \"%s\" at %p\n",
1090                                    tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1091
1092                 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1093                         pelf = tpnt;
1094         }
1095
1096         if (!pelf) {
1097                 return 0;
1098         }
1099
1100         /*
1101          * Try and locate the symbol of address
1102          */
1103
1104         {
1105                 char *strtab;
1106                 ElfW(Sym) *symtab;
1107                 unsigned int hn, si, sn, sf;
1108                 ElfW(Addr) sa = 0;
1109
1110                 /* Set the info for the object the address lies in */
1111                 __info->dli_fname = pelf->libname;
1112                 __info->dli_fbase = (void *)pelf->mapaddr;
1113
1114                 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1115                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1116
1117                 sf = sn = 0;
1118
1119 #ifdef __LDSO_GNU_HASH_SUPPORT__
1120                 if (pelf->l_gnu_bitmask) {
1121                         for (hn = 0; hn < pelf->nbucket; hn++) {
1122                                 si = pelf->l_gnu_buckets[hn];
1123                                 if (!si)
1124                                         continue;
1125
1126                                 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1127                                 do {
1128                                         ElfW(Addr) symbol_addr;
1129
1130                                         symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1131                                         if ((symtab[si].st_shndx != SHN_UNDEF
1132                                                  || symtab[si].st_value != 0)
1133                                                 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1134                                                 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1135                                                                                          (ElfW(Addr)) __address)) {
1136                                                 sa = symbol_addr;
1137                                                 sn = si;
1138                                                 sf = 1;
1139                                         }
1140                                         _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1141                                         ++si;
1142                                 } while ((*hasharr++ & 1u) == 0);
1143                         }
1144                 } else
1145 #endif
1146                 for (hn = 0; hn < pelf->nbucket; hn++) {
1147                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1148                                 ElfW(Addr) symbol_addr;
1149
1150                                 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1151                                 if ((symtab[si].st_shndx != SHN_UNDEF
1152                                          || symtab[si].st_value != 0)
1153                                         && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1154                                         && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1155                                                                                  (ElfW(Addr)) __address)) {
1156                                         sa = symbol_addr;
1157                                         sn = si;
1158                                         sf = 1;
1159                                 }
1160
1161                                 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1162                                                    strtab + symtab[si].st_name, symbol_addr);
1163                         }
1164                 }
1165
1166                 if (sf) {
1167                         /* A nearest symbol has been found; fill the entries */
1168                         __info->dli_sname = strtab + symtab[sn].st_name;
1169                         __info->dli_saddr = (void *)sa;
1170                 } else {
1171                         /* No symbol found, fill entries with NULL value,
1172                         only the containing object will be returned. */
1173                         __info->dli_sname = NULL;
1174                         __info->dli_saddr = NULL;
1175                 }
1176                 return 1;
1177         }
1178 }
1179 #endif