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