OSDN Git Service

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