OSDN Git Service

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