OSDN Git Service

Fix a problem with dtors/dtors.
[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         if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
185                 _dl_unmap_cache();
186                 return NULL;
187         }
188         //tpnt->libtype = loaded_file;
189
190
191         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
192         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
193         dyn_chain->dyn = tpnt;
194         dyn_chain->flags = flag;
195         if (!tpnt->symbol_scope)
196                 tpnt->symbol_scope = dyn_chain;
197
198         dyn_chain->next_handle = _dl_handles;
199         _dl_handles = rpnt = dyn_chain;
200
201
202 #ifdef __SUPPORT_LD_DEBUG__
203         if(_dl_debug) 
204         _dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
205 #endif
206         for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
207         {
208                 Elf32_Dyn *dpnt;
209                 char *lpntstr;
210                 for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
211                         if (dpnt->d_tag == DT_NEEDED) {
212
213                                 char *name;
214                                 lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
215                                         dpnt->d_un.d_val);
216                                 name = _dl_get_last_path_component(lpntstr);
217
218 #ifdef __SUPPORT_LD_DEBUG__
219                                 if(_dl_debug) 
220                                 _dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n", 
221                                                 lpntstr, tcurr->libname);
222 #endif
223 #if 0
224                                 if ((tpnt1 = _dl_check_if_named_library_is_loaded(name)))
225                                 {
226                                     /* If the needed library is already loaded, then we
227                                      * need to override all globals and weaks in the current
228                                      * chain...  Or something. */
229                                     continue;
230                                 }
231 #endif
232
233                                 if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
234                                         goto oops;
235                                 }
236                                 /* We need global symbol resolution for everything
237                                  * in the dependent chain */
238                                 dyn_chain->flags |= RTLD_GLOBAL;
239
240                                 rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
241                                 _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
242                                 rpnt = rpnt->next;
243                                 if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
244                                 rpnt->dyn = tpnt1;
245
246                         }
247                 }
248         }
249
250         /*
251          * OK, now attach the entire chain at the end
252          */
253         rpnt->next = _dl_symbol_tables;
254
255 #ifdef __mips__
256         /*
257          * Relocation of the GOT entries for MIPS have to be done
258          * after all the libraries have been loaded.
259          */
260         _dl_perform_mips_global_got_relocations(tpnt);
261 #endif
262
263 #ifdef __SUPPORT_LD_DEBUG__
264         if(_dl_debug) 
265         _dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
266 #endif
267         /*
268          * OK, now all of the kids are tucked into bed in their proper addresses.
269          * Now we go through and look for REL and RELA records that indicate fixups
270          * to the GOT tables.  We need to do this in reverse order so that COPY
271          * directives work correctly */
272         if (_dl_fixup(dyn_chain->dyn, (dyn_chain->flags & RTLD_LAZY)))
273                 goto oops;
274
275 #ifdef __SUPPORT_LD_DEBUG__
276         if(_dl_debug) 
277         _dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
278 #endif
279         if (_dl_symbol_tables) {
280                 if (_dl_copy_fixups(dyn_chain))
281                         goto oops;
282         }
283
284
285         /* TODO:  Should we set the protections of all pages back to R/O now ? */
286         
287
288         /* Notify the debugger we have added some objects. */
289         _dl_debug_addr->r_state = RT_ADD;
290         if (_dl_debug_addr) {
291                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
292                 if (dl_brk != NULL) {
293                         _dl_debug_addr->r_state = RT_ADD;
294                         (*dl_brk) ();
295
296                         _dl_debug_addr->r_state = RT_CONSISTENT;
297                         (*dl_brk) ();
298                 }
299         }
300
301 #if 0 //def __SUPPORT_LD_DEBUG__
302         if(_dl_debug) 
303         _dlinfo();
304 #endif
305
306 #ifdef __PIC__
307         /* Find the last library so we can run things in the right order */
308         for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
309             ;
310
311         /* Run the ctors and set up the dtors */
312         for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
313         {
314                 /* Apparently crt1 for the application is responsible for handling this.
315                  * We only need to run the init/fini for shared libraries
316                  */
317                 if (tpnt->libtype == program_interpreter)
318                         continue;
319                 if (tpnt->libtype == elf_executable)
320                         continue;
321                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
322                         continue;
323                 tpnt->init_flag |= INIT_FUNCS_CALLED;
324
325                 if (tpnt->dynamic_info[DT_INIT]) {
326                     void (*dl_elf_func) (void);
327                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
328                     if (dl_elf_func && *dl_elf_func != NULL) {
329 #ifdef __SUPPORT_LD_DEBUG__
330                         if(_dl_debug) 
331                         _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
332 #endif
333                         (*dl_elf_func) ();
334                     }
335                 }
336                 if (tpnt->dynamic_info[DT_FINI]) {
337                     void (*dl_elf_func) (void);
338                     dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
339                     if (dl_elf_func && *dl_elf_func != NULL) {
340 #ifdef __SUPPORT_LD_DEBUG__
341                         if(_dl_debug) 
342                         _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
343 #endif
344                         atexit(dl_elf_func);
345                     }
346                 }
347         }
348 #endif
349         return (void *) dyn_chain;
350
351 oops:
352         /* Something went wrong.  Clean up and return NULL. */
353         _dl_unmap_cache();
354         do_dlclose(dyn_chain, 0);
355         return NULL;
356 }
357
358 void *_dlsym(void *vhandle, const char *name)
359 {
360         struct elf_resolve *tpnt, *tfrom;
361         struct dyn_elf *handle;
362         ElfW(Addr) from;
363         struct dyn_elf *rpnt;
364         void *ret;
365
366         handle = (struct dyn_elf *) vhandle;
367
368         /* First of all verify that we have a real handle
369            of some kind.  Return NULL if not a valid handle. */
370
371         if (handle == NULL)
372                 handle = _dl_symbol_tables;
373         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
374                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
375                         if (rpnt == handle)
376                                 break;
377                 if (!rpnt) {
378                         _dl_error_number = LD_BAD_HANDLE;
379                         return NULL;
380                 }
381         } else if (handle == RTLD_NEXT) {
382                 /*
383                  * Try and locate the module we were called from - we
384                  * need this so that we know where to start searching
385                  * from.  We never pass RTLD_NEXT down into the actual
386                  * dynamic loader itself, as it doesn't know
387                  * how to properly treat it.
388                  */
389                 from = (ElfW(Addr)) __builtin_return_address(0);
390
391                 tfrom = NULL;
392                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
393                         tpnt = rpnt->dyn;
394                         if (tpnt->loadaddr < from
395                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
396                                 tfrom = tpnt;
397                                 handle = rpnt->next;
398                         }
399                 }
400         }
401
402         ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
403
404         /*
405          * Nothing found.
406          */
407         if (!ret)
408                 _dl_error_number = LD_NO_SYMBOL;
409         return ret;
410 }
411
412 int _dlclose(void *vhandle)
413 {
414         return do_dlclose(vhandle, 1);
415 }
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 const char *_dlerror(void)
542 {
543         const char *retval;
544
545         if (!_dl_error_number)
546                 return NULL;
547         retval = dl_error_names[_dl_error_number];
548         _dl_error_number = 0;
549         return retval;
550 }
551
552 /*
553  * Dump information to stderrr about the current loaded modules
554  */
555 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
556
557 void _dlinfo(void)
558 {
559         struct elf_resolve *tpnt;
560         struct dyn_elf *rpnt, *hpnt;
561
562         _dl_dprintf(2, "List of loaded modules\n");
563         /* First start with a complete list of all of the loaded files. */
564         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { 
565                 _dl_dprintf(2, "\t%x %x %x %s %d %s\n", 
566                         (unsigned) tpnt->loadaddr, (unsigned) tpnt,
567                         (unsigned) tpnt->symbol_scope,
568                         type[tpnt->libtype],
569                         tpnt->usage_count, tpnt->libname);
570         }
571
572         /* Next dump the module list for the application itself */
573         _dl_dprintf(2, "\nModules for application (%x):\n",
574                                  (unsigned) _dl_symbol_tables);
575         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
576                 _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
577
578         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
579                 _dl_dprintf(2, "Modules for handle %x\n", (unsigned) hpnt);
580                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
581                         _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, 
582                                 rpnt->dyn->libname);
583         }
584 }
585
586 int _dladdr(void *__address, Dl_info * __dlip)
587 {
588         struct elf_resolve *pelf;
589         struct elf_resolve *rpnt;
590
591         _dl_map_cache();
592
593         /*
594          * Try and locate the module address is in
595          */
596         pelf = NULL;
597
598 #if 0
599         _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
600 #endif
601
602         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
603                 struct elf_resolve *tpnt;
604
605                 tpnt = rpnt;
606 #if 0
607                 _dl_dprintf(2, "Module \"%s\" at %x\n", 
608                         tpnt->libname, tpnt->loadaddr);
609 #endif
610                 if (tpnt->loadaddr < (ElfW(Addr)) __address
611                         && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
612                     pelf = tpnt;
613                 }
614         }
615
616         if (!pelf) {
617                 return 0;
618         }
619
620         /*
621          * Try and locate the symbol of address
622          */
623
624         {
625                 char *strtab;
626                 Elf32_Sym *symtab;
627                 int hn, si;
628                 int sf;
629                 int sn = 0;
630                 ElfW(Addr) sa;
631
632                 sa = 0;
633                 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
634                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
635
636                 sf = 0;
637                 for (hn = 0; hn < pelf->nbucket; hn++) {
638                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
639                                 ElfW(Addr) symbol_addr;
640
641                                 symbol_addr = pelf->loadaddr + symtab[si].st_value;
642                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
643                                         sa = symbol_addr;
644                                         sn = si;
645                                         sf = 1;
646                                 }
647 #if 0
648                                 _dl_dprintf(2, "Symbol \"%s\" at %x\n", 
649                                         strtab + symtab[si].st_name, symbol_addr);
650 #endif
651                         }
652                 }
653
654                 if (sf) {
655                         __dlip->dli_fname = pelf->libname;
656                         __dlip->dli_fbase = (void *)pelf->loadaddr;
657                         __dlip->dli_sname = strtab + symtab[sn].st_name;
658                         __dlip->dli_saddr = (void *)sa;
659                 }
660                 return 1;
661         }
662 }