OSDN Git Service

Based on a patch from Alexandre Oliva, make sure _dl_malloc returns a nicely
[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-2004 by Erik Andersen <andersen@codpoet.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
35
36 #if defined (__LIBDL_SHARED__)
37
38 /* When libdl is loaded as a shared library, we need to load in
39  * and use a pile of symbols from ldso... */
40
41 extern void _dl_dprintf(int, const char *, ...) __attribute__ ((__weak__));
42 extern char *_dl_find_hash(const char *, struct dyn_elf *, int)
43         __attribute__ ((__weak__));
44 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
45         struct elf_resolve *, char *, int) __attribute__ ((__weak__));
46 extern struct elf_resolve * _dl_check_if_named_library_is_loaded(const char *, int)
47         __attribute__ ((__weak__));
48 extern int _dl_fixup(struct dyn_elf *rpnt, int lazy)
49          __attribute__ ((__weak__));
50 extern int _dl_errno __attribute__ ((__weak__));
51 extern struct dyn_elf *_dl_symbol_tables __attribute__ ((__weak__));
52 extern struct dyn_elf *_dl_handles __attribute__ ((__weak__));
53 extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__));
54 extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__));
55 extern unsigned long _dl_error_number __attribute__ ((__weak__));
56 extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__));
57 extern void (*_dl_free_function) (void *p) __attribute__ ((__weak__));
58 #ifdef USE_CACHE
59 int _dl_map_cache(void) __attribute__ ((__weak__));
60 int _dl_unmap_cache(void) __attribute__ ((__weak__));
61 #endif
62 #ifdef __mips__
63 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
64         __attribute__ ((__weak__));
65 #endif
66 #ifdef __SUPPORT_LD_DEBUG__
67 extern char *_dl_debug __attribute__ ((__weak__));
68 extern char *_dl_debug_symbols __attribute__ ((__weak__));
69 extern char *_dl_debug_move __attribute__ ((__weak__));
70 extern char *_dl_debug_reloc __attribute__ ((__weak__));
71 extern char *_dl_debug_detail __attribute__ ((__weak__));
72 extern char *_dl_debug_nofixups __attribute__ ((__weak__));
73 extern char *_dl_debug_bindings __attribute__ ((__weak__));
74 extern int   _dl_debug_file __attribute__ ((__weak__));
75 #endif
76
77
78 #else /* __LIBDL_SHARED__ */
79
80 /* When libdl is linked as a static library, we need to replace all
81  * the symbols that otherwise would have been loaded in from ldso... */
82
83 #ifdef __SUPPORT_LD_DEBUG__
84 char *_dl_debug  = 0;
85 char *_dl_debug_symbols = 0;
86 char *_dl_debug_move    = 0;
87 char *_dl_debug_reloc   = 0;
88 char *_dl_debug_detail  = 0;
89 char *_dl_debug_nofixups  = 0;
90 char *_dl_debug_bindings  = 0;
91 int   _dl_debug_file = 2;
92 #endif
93 char *_dl_library_path = 0;
94 char *_dl_ldsopath = 0;
95 struct r_debug *_dl_debug_addr = NULL;
96 static unsigned char *_dl_malloc_addr, *_dl_mmap_zero;
97 void *(*_dl_malloc_function) (size_t size);
98 int _dl_errno = 0;
99 void (*_dl_free_function) (void *p);
100 int _dl_fixup(struct dyn_elf *rpnt, int lazy);
101 #include "../ldso/dl-progname.h"               /* Pull in the name of ld.so */
102 #include "../ldso/dl-hash.c"
103 #define _dl_trace_loaded_objects    0
104 #include "../ldso/dl-elf.c"
105 #endif
106
107 static int do_dlclose(void *, int need_fini);
108
109
110 static const char *dl_error_names[] = {
111         "",
112         "File not found",
113         "Unable to open /dev/zero",
114         "Not an ELF file",
115 #if defined (__i386__)
116         "Not i386 binary",
117 #elif defined (__sparc__)
118         "Not sparc binary",
119 #elif defined (__mc68000__)
120         "Not m68k binary",
121 #else
122         "Unrecognized binary type",
123 #endif
124         "Not an ELF shared library",
125         "Unable to mmap file",
126         "No dynamic section",
127 #ifdef ELF_USES_RELOCA
128         "Unable to process REL relocs",
129 #else
130         "Unable to process RELA relocs",
131 #endif
132         "Bad handle",
133         "Unable to resolve symbol"
134 };
135
136 static void __attribute__ ((destructor)) dl_cleanup(void)
137 {
138         struct dyn_elf *d;
139
140         for (d = _dl_handles; d; d = d->next_handle)
141                 if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI]) {
142                         (* ((int (*)(void)) (d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI]))) ();
143                         d->dyn->dynamic_info[DT_FINI] = 0;
144                 }
145 }
146
147 void *_dlopen(const char *libname, int flag)
148 {
149         struct elf_resolve *tpnt, *tfrom, *tcurr;
150         struct dyn_elf *dyn_chain, *rpnt = NULL;
151         struct dyn_elf *dpnt;
152         static int dl_init = 0;
153         ElfW(Addr) from;
154         struct elf_resolve *tpnt1;
155         void (*dl_brk) (void);
156
157         /* A bit of sanity checking... */
158         if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
159                 _dl_error_number = LD_BAD_HANDLE;
160                 return NULL;
161         }
162
163         from = (ElfW(Addr)) __builtin_return_address(0);
164
165         /* Have the dynamic linker use the regular malloc function now */
166         if (!dl_init) {
167                 dl_init++;
168                 _dl_malloc_function = malloc;
169                 _dl_free_function = free;
170         }
171
172         /* Cover the trivial case first */
173         if (!libname)
174                 return _dl_symbol_tables;
175
176         _dl_map_cache();
177
178         /*
179          * Try and locate the module we were called from - we
180          * need this so that we get the correct RPATH.  Note that
181          * this is the current behavior under Solaris, but the
182          * ABI+ specifies that we should only use the RPATH from
183          * the application.  Thus this may go away at some time
184          * in the future.
185          */
186         tfrom = NULL;
187         for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
188                 tpnt = dpnt->dyn;
189                 if (tpnt->loadaddr < from
190                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
191                         tfrom = tpnt;
192         }
193
194         /* Try to load the specified library */
195 #ifdef __SUPPORT_LD_DEBUG__
196         if(_dl_debug)
197         _dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
198 #endif
199         if (!(tpnt = _dl_check_if_named_library_is_loaded((char *)libname, 0)))
200         tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
201         if (tpnt == NULL) {
202                 _dl_unmap_cache();
203                 return NULL;
204         }
205
206         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
207         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
208         dyn_chain->dyn = tpnt;
209         dyn_chain->flags = flag;
210         if (!tpnt->symbol_scope)
211                 tpnt->symbol_scope = dyn_chain;
212
213         dyn_chain->next_handle = _dl_handles;
214         _dl_handles = rpnt = dyn_chain;
215
216         if (tpnt->init_flag & INIT_FUNCS_CALLED) {
217             /* If the init and fini stuff has already been run, that means
218              * the dlopen'd library has already been loaded, and nothing
219              * further needs to be done. */
220             return (void *) dyn_chain;
221         }
222
223
224 #ifdef __SUPPORT_LD_DEBUG__
225         if(_dl_debug)
226         _dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
227 #endif
228
229         for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
230         {
231                 Elf32_Dyn *dpnt;
232                 char *lpntstr;
233                 for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
234                         if (dpnt->d_tag == DT_NEEDED) {
235
236                                 char *name;
237                                 lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
238                                         dpnt->d_un.d_val);
239                                 name = _dl_get_last_path_component(lpntstr);
240
241                                 if ((tpnt1 = _dl_check_if_named_library_is_loaded(name, 0)))
242                                         continue;
243
244 #ifdef __SUPPORT_LD_DEBUG__
245                                 if(_dl_debug)
246                                 _dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n",
247                                                 lpntstr, tcurr->libname);
248 #endif
249
250                                 if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, 0))) {
251                                         goto oops;
252                                 }
253
254                                 rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
255                                 _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
256                                 rpnt = rpnt->next;
257                                 if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
258                                 rpnt->dyn = tpnt1;
259
260                         }
261                 }
262         }
263
264         /*
265          * OK, now attach the entire chain at the end
266          */
267         rpnt->next = _dl_symbol_tables;
268
269 #ifdef __mips__
270         /*
271          * Relocation of the GOT entries for MIPS have to be done
272          * after all the libraries have been loaded.
273          */
274         _dl_perform_mips_global_got_relocations(tpnt);
275 #endif
276
277 #ifdef __SUPPORT_LD_DEBUG__
278         if(_dl_debug)
279         _dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
280 #endif
281         /*
282          * OK, now all of the kids are tucked into bed in their proper addresses.
283          * Now we go through and look for REL and RELA records that indicate fixups
284          * to the GOT tables.  We need to do this in reverse order so that COPY
285          * directives work correctly */
286         if (_dl_fixup(dyn_chain, dyn_chain->flags))
287                 goto oops;
288
289         /* TODO:  Should we set the protections of all pages back to R/O now ? */
290
291
292         /* Notify the debugger we have added some objects. */
293         if (_dl_debug_addr) {
294                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
295                 if (dl_brk != NULL) {
296                         _dl_debug_addr->r_state = RT_ADD;
297                         (*dl_brk) ();
298
299                         _dl_debug_addr->r_state = RT_CONSISTENT;
300                         (*dl_brk) ();
301                 }
302         }
303
304 #if 0 //def __SUPPORT_LD_DEBUG__
305         if(_dl_debug)
306         _dlinfo();
307 #endif
308
309 #if defined (__LIBDL_SHARED__)
310         /* Find the last library so we can run things in the right order */
311         for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
312             ;
313
314         /* Run the ctors and set up the dtors */
315         for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
316         {
317                 /* Apparently crt1 for the application is responsible for handling this.
318                  * We only need to run the init/fini for shared libraries
319                  */
320                 if (tpnt->libtype == program_interpreter)
321                         continue;
322                 if (tpnt->libtype == elf_executable)
323                         continue;
324                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
325                         continue;
326                 tpnt->init_flag |= INIT_FUNCS_CALLED;
327
328                 if (tpnt->dynamic_info[DT_INIT]) {
329                     void (*dl_elf_func) (void);
330                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
331                     if (dl_elf_func && *dl_elf_func != NULL) {
332 #ifdef __SUPPORT_LD_DEBUG__
333                         if(_dl_debug)
334                         _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
335 #endif
336                         (*dl_elf_func) ();
337                     }
338                 }
339                 if (tpnt->dynamic_info[DT_FINI]) {
340                     void (*dl_elf_func) (void);
341                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
342                     if (dl_elf_func && *dl_elf_func != NULL) {
343 #ifdef __SUPPORT_LD_DEBUG__
344                         if(_dl_debug)
345                         _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
346 #endif
347                         atexit(dl_elf_func);
348                     }
349                 }
350         }
351 #endif
352         return (void *) dyn_chain;
353
354 oops:
355         /* Something went wrong.  Clean up and return NULL. */
356         _dl_unmap_cache();
357         do_dlclose(dyn_chain, 0);
358         return NULL;
359 }
360 weak_alias(_dlopen, dlopen);
361
362 void *_dlsym(void *vhandle, const char *name)
363 {
364         struct elf_resolve *tpnt, *tfrom;
365         struct dyn_elf *handle;
366         ElfW(Addr) from;
367         struct dyn_elf *rpnt;
368         void *ret;
369
370         handle = (struct dyn_elf *) vhandle;
371
372         /* First of all verify that we have a real handle
373            of some kind.  Return NULL if not a valid handle. */
374
375         if (handle == NULL)
376                 handle = _dl_symbol_tables;
377         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
378                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
379                         if (rpnt == handle)
380                                 break;
381                 if (!rpnt) {
382                         _dl_error_number = LD_BAD_HANDLE;
383                         return NULL;
384                 }
385         } else if (handle == RTLD_NEXT) {
386                 /*
387                  * Try and locate the module we were called from - we
388                  * need this so that we know where to start searching
389                  * from.  We never pass RTLD_NEXT down into the actual
390                  * dynamic loader itself, as it doesn't know
391                  * how to properly treat it.
392                  */
393                 from = (ElfW(Addr)) __builtin_return_address(0);
394
395                 tfrom = NULL;
396                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
397                         tpnt = rpnt->dyn;
398                         if (tpnt->loadaddr < from
399                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
400                                 tfrom = tpnt;
401                                 handle = rpnt->next;
402                         }
403                 }
404         }
405
406         ret = _dl_find_hash((char*)name, handle, 0);
407
408         /*
409          * Nothing found.
410          */
411         if (!ret)
412                 _dl_error_number = LD_NO_SYMBOL;
413         return ret;
414 }
415 weak_alias(_dlsym, dlsym);
416
417 static int do_dlclose(void *vhandle, int need_fini)
418 {
419         struct dyn_elf *rpnt, *rpnt1;
420         struct dyn_elf *spnt, *spnt1;
421         ElfW(Phdr) *ppnt;
422         struct elf_resolve *tpnt;
423         int (*dl_elf_fini) (void);
424         void (*dl_brk) (void);
425         struct dyn_elf *handle;
426         unsigned int end;
427         int i = 0;
428
429         handle = (struct dyn_elf *) vhandle;
430         rpnt1 = NULL;
431         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
432                 if (rpnt == handle) {
433                         break;
434                 }
435                 rpnt1 = rpnt;
436         }
437
438         if (!rpnt) {
439                 _dl_error_number = LD_BAD_HANDLE;
440                 return 1;
441         }
442
443         /* OK, this is a valid handle - now close out the file.
444          * We check if we need to call fini () on the handle. */
445         spnt = need_fini ? handle : handle->next;
446         for (; spnt; spnt = spnt1) {
447                 spnt1 = spnt->next;
448
449                 /* We appended the module list to the end - when we get back here,
450                    quit. The access counts were not adjusted to account for being here. */
451                 if (spnt == _dl_symbol_tables)
452                         break;
453                 if (spnt->dyn->usage_count == 1
454                         && spnt->dyn->libtype == loaded_file) {
455                         tpnt = spnt->dyn;
456                         /* Apparently crt1 for the application is responsible for handling this.
457                          * We only need to run the init/fini for shared libraries
458                          */
459
460                         if (tpnt->dynamic_info[DT_FINI]) {
461                                 dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
462                                         tpnt->dynamic_info[DT_FINI]);
463                                 (*dl_elf_fini) ();
464                         }
465                 }
466         }
467         if (rpnt1)
468                 rpnt1->next_handle = rpnt->next_handle;
469         else
470                 _dl_handles = rpnt->next_handle;
471
472         /* OK, this is a valid handle - now close out the file */
473         for (rpnt = handle; rpnt; rpnt = rpnt1) {
474                 rpnt1 = rpnt->next;
475
476                 /* We appended the module list to the end - when we get back here,
477                    quit. The access counts were not adjusted to account for being here. */
478                 if (rpnt == _dl_symbol_tables)
479                         break;
480
481                 rpnt->dyn->usage_count--;
482                 if (rpnt->dyn->usage_count == 0
483                         && rpnt->dyn->libtype == loaded_file) {
484                         tpnt = rpnt->dyn;
485                         /* Apparently crt1 for the application is responsible for handling this.
486                          * We only need to run the init/fini for shared libraries
487                          */
488 #if 0
489
490                         /* We have to do this above, before we start closing objects.
491                          * Otherwise when the needed symbols for _fini handling are
492                          * resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
493                         if (tpnt->dynamic_info[DT_FINI]) {
494                             dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
495                                 (*dl_elf_fini) ();
496                         }
497 #endif
498                         end = 0;
499                         for (i = 0, ppnt = rpnt->dyn->ppnt;
500                                  i < rpnt->dyn->n_phent; ppnt++, i++) {
501                                 if (ppnt->p_type != PT_LOAD)
502                                         continue;
503                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
504                                         end = ppnt->p_vaddr + ppnt->p_memsz;
505                         }
506                         _dl_munmap((void*)rpnt->dyn->loadaddr, end);
507                         /* Next, remove rpnt->dyn from the loaded_module list */
508                         if (_dl_loaded_modules == rpnt->dyn) {
509                                 _dl_loaded_modules = rpnt->dyn->next;
510                                 if (_dl_loaded_modules)
511                                         _dl_loaded_modules->prev = 0;
512                         } else
513                                 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
514                                         if (tpnt->next == rpnt->dyn) {
515                                                 tpnt->next = tpnt->next->next;
516                                                 if (tpnt->next)
517                                                         tpnt->next->prev = tpnt;
518                                                 break;
519                                         }
520                         free(rpnt->dyn->libname);
521                         free(rpnt->dyn);
522                 }
523                 free(rpnt);
524         }
525
526
527         if (_dl_debug_addr) {
528             dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
529             if (dl_brk != NULL) {
530                 _dl_debug_addr->r_state = RT_DELETE;
531                 (*dl_brk) ();
532
533                 _dl_debug_addr->r_state = RT_CONSISTENT;
534                 (*dl_brk) ();
535             }
536         }
537
538         return 0;
539 }
540
541 int _dlclose(void *vhandle)
542 {
543         return do_dlclose(vhandle, 1);
544 }
545 weak_alias(_dlclose, dlclose);
546
547 const char *_dlerror(void)
548 {
549         const char *retval;
550
551         if (!_dl_error_number)
552                 return NULL;
553         retval = dl_error_names[_dl_error_number];
554         _dl_error_number = 0;
555         return retval;
556 }
557 weak_alias(_dlerror, dlerror);
558
559 /*
560  * Dump information to stderrr about the current loaded modules
561  */
562 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
563
564 void _dlinfo(void)
565 {
566         struct elf_resolve *tpnt;
567         struct dyn_elf *rpnt, *hpnt;
568
569         _dl_dprintf(2, "List of loaded modules\n");
570         /* First start with a complete list of all of the loaded files. */
571         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
572                 _dl_dprintf(2, "\t%x %x %x %s %d %s\n",
573                         (unsigned) tpnt->loadaddr, (unsigned) tpnt,
574                         (unsigned) tpnt->symbol_scope,
575                         type[tpnt->libtype],
576                         tpnt->usage_count, tpnt->libname);
577         }
578
579         /* Next dump the module list for the application itself */
580         _dl_dprintf(2, "\nModules for application (%x):\n",
581                                  (unsigned) _dl_symbol_tables);
582         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
583                 _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
584
585         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
586                 _dl_dprintf(2, "Modules for handle %x\n", (unsigned) hpnt);
587                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
588                         _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn,
589                                 rpnt->dyn->libname);
590         }
591 }
592 weak_alias(_dlinfo, dlinfo);
593
594 int _dladdr(void *__address, Dl_info * __dlip)
595 {
596         struct elf_resolve *pelf;
597         struct elf_resolve *rpnt;
598
599         _dl_map_cache();
600
601         /*
602          * Try and locate the module address is in
603          */
604         pelf = NULL;
605
606 #if 0
607         _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
608 #endif
609
610         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
611                 struct elf_resolve *tpnt;
612
613                 tpnt = rpnt;
614 #if 0
615                 _dl_dprintf(2, "Module \"%s\" at %x\n",
616                         tpnt->libname, tpnt->loadaddr);
617 #endif
618                 if (tpnt->loadaddr < (ElfW(Addr)) __address
619                         && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
620                     pelf = tpnt;
621                 }
622         }
623
624         if (!pelf) {
625                 return 0;
626         }
627
628         /*
629          * Try and locate the symbol of address
630          */
631
632         {
633                 char *strtab;
634                 Elf32_Sym *symtab;
635                 int hn, si;
636                 int sf;
637                 int sn = 0;
638                 ElfW(Addr) sa;
639
640                 sa = 0;
641                 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
642                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
643
644                 sf = 0;
645                 for (hn = 0; hn < pelf->nbucket; hn++) {
646                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
647                                 ElfW(Addr) symbol_addr;
648
649                                 symbol_addr = pelf->loadaddr + symtab[si].st_value;
650                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
651                                         sa = symbol_addr;
652                                         sn = si;
653                                         sf = 1;
654                                 }
655 #if 0
656                                 _dl_dprintf(2, "Symbol \"%s\" at %x\n",
657                                         strtab + symtab[si].st_name, symbol_addr);
658 #endif
659                         }
660                 }
661
662                 if (sf) {
663                         __dlip->dli_fname = pelf->libname;
664                         __dlip->dli_fbase = (void *)pelf->loadaddr;
665                         __dlip->dli_sname = strtab + symtab[sn].st_name;
666                         __dlip->dli_saddr = (void *)sa;
667                 }
668                 return 1;
669         }
670 }
671 weak_alias(_dladdr, dladdr);