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