OSDN Git Service

As noted by Doru Petrescu, there was a spurious line that was using
[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
190         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
191         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
192         dyn_chain->dyn = tpnt;
193         dyn_chain->flags = flag;
194         if (!tpnt->symbol_scope)
195                 tpnt->symbol_scope = dyn_chain;
196
197         dyn_chain->next_handle = _dl_handles;
198         _dl_handles = rpnt = dyn_chain;
199
200         if (tpnt->init_flag & INIT_FUNCS_CALLED) {
201             /* If the init and fini stuff has already been run, that means
202              * the dlopen'd library has already been loaded, and nothing
203              * further needs to be done. */
204             return (void *) dyn_chain;
205         }
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         if (_dl_debug_addr) {
292                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
293                 if (dl_brk != NULL) {
294                         _dl_debug_addr->r_state = RT_ADD;
295                         (*dl_brk) ();
296
297                         _dl_debug_addr->r_state = RT_CONSISTENT;
298                         (*dl_brk) ();
299                 }
300         }
301
302 #if 0 //def __SUPPORT_LD_DEBUG__
303         if(_dl_debug) 
304         _dlinfo();
305 #endif
306
307 #ifdef __PIC__
308         /* Find the last library so we can run things in the right order */
309         for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
310             ;
311
312         /* Run the ctors and set up the dtors */
313         for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
314         {
315                 /* Apparently crt1 for the application is responsible for handling this.
316                  * We only need to run the init/fini for shared libraries
317                  */
318                 if (tpnt->libtype == program_interpreter)
319                         continue;
320                 if (tpnt->libtype == elf_executable)
321                         continue;
322                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
323                         continue;
324                 tpnt->init_flag |= INIT_FUNCS_CALLED;
325
326                 if (tpnt->dynamic_info[DT_INIT]) {
327                     void (*dl_elf_func) (void);
328                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
329                     if (dl_elf_func && *dl_elf_func != NULL) {
330 #ifdef __SUPPORT_LD_DEBUG__
331                         if(_dl_debug) 
332                         _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
333 #endif
334                         (*dl_elf_func) ();
335                     }
336                 }
337                 if (tpnt->dynamic_info[DT_FINI]) {
338                     void (*dl_elf_func) (void);
339                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
340                     if (dl_elf_func && *dl_elf_func != NULL) {
341 #ifdef __SUPPORT_LD_DEBUG__
342                         if(_dl_debug) 
343                         _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
344 #endif
345                         atexit(dl_elf_func);
346                     }
347                 }
348         }
349 #endif
350         return (void *) dyn_chain;
351
352 oops:
353         /* Something went wrong.  Clean up and return NULL. */
354         _dl_unmap_cache();
355         do_dlclose(dyn_chain, 0);
356         return NULL;
357 }
358
359 void *_dlsym(void *vhandle, const char *name)
360 {
361         struct elf_resolve *tpnt, *tfrom;
362         struct dyn_elf *handle;
363         ElfW(Addr) from;
364         struct dyn_elf *rpnt;
365         void *ret;
366
367         handle = (struct dyn_elf *) vhandle;
368
369         /* First of all verify that we have a real handle
370            of some kind.  Return NULL if not a valid handle. */
371
372         if (handle == NULL)
373                 handle = _dl_symbol_tables;
374         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
375                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
376                         if (rpnt == handle)
377                                 break;
378                 if (!rpnt) {
379                         _dl_error_number = LD_BAD_HANDLE;
380                         return NULL;
381                 }
382         } else if (handle == RTLD_NEXT) {
383                 /*
384                  * Try and locate the module we were called from - we
385                  * need this so that we know where to start searching
386                  * from.  We never pass RTLD_NEXT down into the actual
387                  * dynamic loader itself, as it doesn't know
388                  * how to properly treat it.
389                  */
390                 from = (ElfW(Addr)) __builtin_return_address(0);
391
392                 tfrom = NULL;
393                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
394                         tpnt = rpnt->dyn;
395                         if (tpnt->loadaddr < from
396                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
397                                 tfrom = tpnt;
398                                 handle = rpnt->next;
399                         }
400                 }
401         }
402
403         ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
404
405         /*
406          * Nothing found.
407          */
408         if (!ret)
409                 _dl_error_number = LD_NO_SYMBOL;
410         return ret;
411 }
412
413 int _dlclose(void *vhandle)
414 {
415         return do_dlclose(vhandle, 1);
416 }
417
418 static int do_dlclose(void *vhandle, int need_fini)
419 {
420         struct dyn_elf *rpnt, *rpnt1;
421         struct dyn_elf *spnt, *spnt1;
422         ElfW(Phdr) *ppnt;
423         struct elf_resolve *tpnt;
424         int (*dl_elf_fini) (void);
425         void (*dl_brk) (void);
426         struct dyn_elf *handle;
427         unsigned int end;
428         int i = 0;
429
430         handle = (struct dyn_elf *) vhandle;
431         rpnt1 = NULL;
432         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
433                 if (rpnt == handle) {
434                         break;
435                 }
436                 rpnt1 = rpnt;
437         }
438
439         if (!rpnt) {
440                 _dl_error_number = LD_BAD_HANDLE;
441                 return 1;
442         }
443
444         /* OK, this is a valid handle - now close out the file.
445          * We check if we need to call fini () on the handle. */
446         spnt = need_fini ? handle : handle->next;
447         for (; spnt; spnt = spnt1) {
448                 spnt1 = spnt->next;
449
450                 /* We appended the module list to the end - when we get back here, 
451                    quit. The access counts were not adjusted to account for being here. */
452                 if (spnt == _dl_symbol_tables)
453                         break;
454                 if (spnt->dyn->usage_count == 1
455                         && spnt->dyn->libtype == loaded_file) {
456                         tpnt = spnt->dyn;
457                         /* Apparently crt1 for the application is responsible for handling this.
458                          * We only need to run the init/fini for shared libraries
459                          */
460
461                         if (tpnt->dynamic_info[DT_FINI]) {
462                                 dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
463                                         tpnt->dynamic_info[DT_FINI]);
464                                 (*dl_elf_fini) ();
465                         }
466                 }
467         }
468         if (rpnt1)
469                 rpnt1->next_handle = rpnt->next_handle;
470         else
471                 _dl_handles = rpnt->next_handle;
472
473         /* OK, this is a valid handle - now close out the file */
474         for (rpnt = handle; rpnt; rpnt = rpnt1) {
475                 rpnt1 = rpnt->next;
476
477                 /* We appended the module list to the end - when we get back here, 
478                    quit. The access counts were not adjusted to account for being here. */
479                 if (rpnt == _dl_symbol_tables)
480                         break;
481
482                 rpnt->dyn->usage_count--;
483                 if (rpnt->dyn->usage_count == 0
484                         && rpnt->dyn->libtype == loaded_file) {
485                         tpnt = rpnt->dyn;
486                         /* Apparently crt1 for the application is responsible for handling this.
487                          * We only need to run the init/fini for shared libraries
488                          */
489 #if 0
490
491                         /* We have to do this above, before we start closing objects.  
492                          * Otherwise when the needed symbols for _fini handling are 
493                          * resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/ 
494                         if (tpnt->dynamic_info[DT_FINI]) { 
495                             dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
496                                 (*dl_elf_fini) ();
497                         }
498 #endif
499                         end = 0;
500                         for (i = 0, ppnt = rpnt->dyn->ppnt;
501                                  i < rpnt->dyn->n_phent; ppnt++, i++) {
502                                 if (ppnt->p_type != PT_LOAD)
503                                         continue;
504                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
505                                         end = ppnt->p_vaddr + ppnt->p_memsz;
506                         }
507                         _dl_munmap((void*)rpnt->dyn->loadaddr, end);
508                         /* Next, remove rpnt->dyn from the loaded_module list */
509                         if (_dl_loaded_modules == rpnt->dyn) {
510                                 _dl_loaded_modules = rpnt->dyn->next;
511                                 if (_dl_loaded_modules)
512                                         _dl_loaded_modules->prev = 0;
513                         } else
514                                 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
515                                         if (tpnt->next == rpnt->dyn) {
516                                                 tpnt->next = tpnt->next->next;
517                                                 if (tpnt->next)
518                                                         tpnt->next->prev = tpnt;
519                                                 break;
520                                         }
521                         free(rpnt->dyn->libname);
522                         free(rpnt->dyn);
523                 }
524                 free(rpnt);
525         }
526
527
528         if (_dl_debug_addr) {
529             dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
530             if (dl_brk != NULL) {
531                 _dl_debug_addr->r_state = RT_DELETE;
532                 (*dl_brk) ();
533
534                 _dl_debug_addr->r_state = RT_CONSISTENT;
535                 (*dl_brk) ();
536             }
537         }
538
539         return 0;
540 }
541
542 const char *_dlerror(void)
543 {
544         const char *retval;
545
546         if (!_dl_error_number)
547                 return NULL;
548         retval = dl_error_names[_dl_error_number];
549         _dl_error_number = 0;
550         return retval;
551 }
552
553 /*
554  * Dump information to stderrr about the current loaded modules
555  */
556 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
557
558 void _dlinfo(void)
559 {
560         struct elf_resolve *tpnt;
561         struct dyn_elf *rpnt, *hpnt;
562
563         _dl_dprintf(2, "List of loaded modules\n");
564         /* First start with a complete list of all of the loaded files. */
565         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { 
566                 _dl_dprintf(2, "\t%x %x %x %s %d %s\n", 
567                         (unsigned) tpnt->loadaddr, (unsigned) tpnt,
568                         (unsigned) tpnt->symbol_scope,
569                         type[tpnt->libtype],
570                         tpnt->usage_count, tpnt->libname);
571         }
572
573         /* Next dump the module list for the application itself */
574         _dl_dprintf(2, "\nModules for application (%x):\n",
575                                  (unsigned) _dl_symbol_tables);
576         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
577                 _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
578
579         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
580                 _dl_dprintf(2, "Modules for handle %x\n", (unsigned) hpnt);
581                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
582                         _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, 
583                                 rpnt->dyn->libname);
584         }
585 }
586
587 int _dladdr(void *__address, Dl_info * __dlip)
588 {
589         struct elf_resolve *pelf;
590         struct elf_resolve *rpnt;
591
592         _dl_map_cache();
593
594         /*
595          * Try and locate the module address is in
596          */
597         pelf = NULL;
598
599 #if 0
600         _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
601 #endif
602
603         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
604                 struct elf_resolve *tpnt;
605
606                 tpnt = rpnt;
607 #if 0
608                 _dl_dprintf(2, "Module \"%s\" at %x\n", 
609                         tpnt->libname, tpnt->loadaddr);
610 #endif
611                 if (tpnt->loadaddr < (ElfW(Addr)) __address
612                         && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
613                     pelf = tpnt;
614                 }
615         }
616
617         if (!pelf) {
618                 return 0;
619         }
620
621         /*
622          * Try and locate the symbol of address
623          */
624
625         {
626                 char *strtab;
627                 Elf32_Sym *symtab;
628                 int hn, si;
629                 int sf;
630                 int sn = 0;
631                 ElfW(Addr) sa;
632
633                 sa = 0;
634                 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
635                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
636
637                 sf = 0;
638                 for (hn = 0; hn < pelf->nbucket; hn++) {
639                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
640                                 ElfW(Addr) symbol_addr;
641
642                                 symbol_addr = pelf->loadaddr + symtab[si].st_value;
643                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
644                                         sa = symbol_addr;
645                                         sn = si;
646                                         sf = 1;
647                                 }
648 #if 0
649                                 _dl_dprintf(2, "Symbol \"%s\" at %x\n", 
650                                         strtab + symtab[si].st_name, symbol_addr);
651 #endif
652                         }
653                 }
654
655                 if (sf) {
656                         __dlip->dli_fname = pelf->libname;
657                         __dlip->dli_fbase = (void *)pelf->loadaddr;
658                         __dlip->dli_sname = strtab + symtab[sn].st_name;
659                         __dlip->dli_saddr = (void *)sa;
660                 }
661                 return 1;
662         }
663 }