OSDN Git Service

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