Mike Frysinger wrote:
On Wednesday 12 December 2007, Carmelo AMOROSO wrote:
while running more tests on this (indeed never used dladdr in the past),

which tests ? our dl tests certainly dont have the coverage anywhere close to what i wish they did ...
-mike
Hello,
based on the patch from Nickolai, here you can find a comprehensive patch to fix
dladdr function.

With the current implementation, the invocation of dladdr((void *) 1, &dlinfo)
will fill dlinfo.dli_fname with the name of the application itself and
dlinfo.dli_fbase with 0 (the current value of tpnt->loadaddr for the main app).

The patch solves this adding a new field into the struct elf_resolve
named  DL_LOADADDR_TYPE mapaddr.
For shared objects, mapaddr has exactly the same value as loadaddr, while for the
main app it contains the address of the first PT_LOAD segmented loaded.

loadaddr will keep it's value and will used exactly as is (as a in memory offset
with respect to relative addresses from ELF sections).
While in the DL_ADDR_IN_LOADADDR macro, the new field mapaddr needs to be used.

I hope I was clear enough in my explanation ;-)
Any comments are welcome.

Cheers,
Carmelo
This patch solves a problem in dladdr caused by the wrong value
of elf_resolve.loadaddr for the main application.

Signed-off-by: Filippo Arcidiacono <[EMAIL PROTECTED]>
Signed-off-by: Carmelo Amoroso <[EMAIL PROTECTED]>

Index: ldso/ldso/ldso.c
===================================================================
--- ldso/ldso/ldso.c    (revision 20834)
+++ ldso/ldso/ldso.c    (working copy)
@@ -135,6 +135,7 @@
                          char **argv
                          DL_GET_READY_TO_RUN_EXTRA_PARMS)
 {
+       DL_LOADADDR_TYPE app_loadaddr = NULL;
        ElfW(Phdr) *ppnt;
        ElfW(Dyn) *dpnt;
        char *lpntstr;
@@ -276,6 +277,9 @@
                        relro_addr = ppnt->p_vaddr;
                        relro_size = ppnt->p_memsz;
                }
+               if (!app_loadaddr && (ppnt->p_type == PT_LOAD)) {
+                       app_loadaddr = ppnt->p_vaddr;
+               }
                if (ppnt->p_type == PT_DYNAMIC) {
                        dpnt = (ElfW(Dyn) *) DL_RELOC_ADDR(app_tpnt->loadaddr, 
ppnt->p_vaddr);
                        _dl_parse_dynamic_info(dpnt, app_tpnt->dynamic_info, 
debug_addr, app_tpnt->loadaddr);
@@ -322,6 +326,7 @@
                        _dl_symbol_tables = rpnt = (struct dyn_elf *) 
_dl_malloc(sizeof(struct dyn_elf));
                        _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
                        rpnt->dyn = _dl_loaded_modules;
+                       app_tpnt->mapaddr = app_loadaddr;
                        app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL;
                        app_tpnt->usage_count++;
                        app_tpnt->symbol_scope = _dl_symbol_tables;
Index: ldso/include/dl-defs.h
===================================================================
--- ldso/include/dl-defs.h      (revision 20834)
+++ ldso/include/dl-defs.h      (working copy)
@@ -168,8 +168,8 @@
  */
 #ifndef DL_ADDR_IN_LOADADDR
 # define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \
-       ((void*)(TPNT)->loadaddr < (void*)(ADDR) \
-        && (!(TFROM) || (TFROM)->loadaddr < (TPNT)->loadaddr))
+       ((void*)(TPNT)->mapaddr < (void*)(ADDR) \
+        && (!(TFROM) || (TFROM)->mapaddr < (TPNT)->mapaddr))
 #endif
 
 /* This is called from dladdr() to give targets that use function descriptors
Index: ldso/include/dl-hash.h
===================================================================
--- ldso/include/dl-hash.h      (revision 20834)
+++ ldso/include/dl-hash.h      (working copy)
@@ -34,6 +34,8 @@
   struct elf_resolve * next;
   struct elf_resolve * prev;
   /* Nothing after this address is used by gdb. */
+
+  DL_LOADADDR_TYPE mapaddr;    /* Address at which ELF segments (either main 
app and DSO) are mapped into */
   enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
   struct dyn_elf * symbol_scope;
   unsigned short usage_count;
Index: ldso/libdl/libdl.c
===================================================================
--- ldso/libdl/libdl.c  (revision 20834)
+++ ldso/libdl/libdl.c  (working copy)
@@ -739,13 +739,40 @@
                char *strtab;
                ElfW(Sym) *symtab;
                unsigned int hn, si, sn, sf;
-               ElfW(Addr) sa;
+               ElfW(Addr) sa = 0;
 
-               sa = 0;
+               /* Set the info for the object the address lies in */
+               __info->dli_fname = pelf->libname;
+               __info->dli_fbase = (void *)(pelf->mapaddr);
+
                symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
                strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
 
                sf = sn = 0;
+#ifdef __LDSO_GNU_HASH_SUPPORT__
+               if (pelf->l_gnu_bitmask) {
+                       for (hn = 0; hn < pelf->nbucket; hn++) {
+                               si = pelf->l_gnu_buckets[hn];
+                               if (!si)
+                                       continue;
+
+                               const Elf32_Word *hasharr = 
&pelf->l_gnu_chain_zero[si];
+                               do {
+                                       ElfW(Addr) symbol_addr;
+
+                                       symbol_addr = (ElfW(Addr)) 
pelf->loadaddr + symtab[si].st_value;
+                                       if (symbol_addr <= 
(ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
+                                               sa = symbol_addr;
+                                               sn = si;
+                                               sf = 1;
+                                       }
+                                       _dl_if_debug_print("Symbol \"%s\" at 
%p\n",
+                                                                       strtab 
+ symtab[si].st_name, symbol_addr);
+                                       ++si;
+                               } while ((*hasharr++ & 1u) == 0);
+                       }
+               } else
+#endif
                for (hn = 0; hn < pelf->nbucket; hn++) {
                        for (si = pelf->elf_buckets[hn]; si; si = 
pelf->chains[si]) {
                                ElfW(Addr) symbol_addr;
@@ -763,10 +790,14 @@
                }
 
                if (sf) {
-                       __info->dli_fname = pelf->libname;
-                       __info->dli_fbase = (void *) 
DL_LOADADDR_BASE(pelf->loadaddr);
+                       /* A nearest symbol has been found; fill the entries */
                        __info->dli_sname = strtab + symtab[sn].st_name;
                        __info->dli_saddr = (void *)sa;
+               } else {
+                       /* No symbol found, fill entries with NULL value,
+                       only the containing object will be returned. */
+                       __info->dli_sname = NULL;
+                       __info->dli_saddr = NULL;
                }
                return 1;
        }
_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://busybox.net/cgi-bin/mailman/listinfo/uclibc

Reply via email to