diff options
author | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-01-18 13:14:19 +0000 |
---|---|---|
committer | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-01-18 13:14:19 +0000 |
commit | 341b678f45c22cdc60b1312416ad0440aae6685a (patch) | |
tree | e1838c397a8b04951b9d00ef5c0a920813f0c830 | |
parent | 1030faf587a2f4bea255bfd2db28b59e196493aa (diff) |
This patch solves a problem in dladdr caused by the wrong value
of elf_resolve's loadaddr field for the main application.
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
-rw-r--r-- | ldso/include/dl-defs.h | 4 | ||||
-rw-r--r-- | ldso/include/dl-hash.h | 1 | ||||
-rw-r--r-- | ldso/ldso/dl-hash.c | 2 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 5 | ||||
-rw-r--r-- | ldso/libdl/libdl.c | 39 |
5 files changed, 44 insertions, 7 deletions
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h index 21b9c28f0..791d068bb 100644 --- a/ldso/include/dl-defs.h +++ b/ldso/include/dl-defs.h @@ -168,8 +168,8 @@ typedef struct { */ #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 diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h index 5bb1f47e1..193ae2d59 100644 --- a/ldso/include/dl-hash.h +++ b/ldso/include/dl-hash.h @@ -34,6 +34,7 @@ struct elf_resolve { 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; diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index 8d2ae3e38..559996289 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -152,7 +152,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname, hash_addr += tpnt->nbucket; tpnt->chains = hash_addr; } - tpnt->loadaddr = loadaddr; + tpnt->loadaddr = tpnt->mapaddr = loadaddr; for (i = 0; i < DYNAMIC_SIZE; i++) tpnt->dynamic_info[i] = dynamic_info[i]; return tpnt; diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index d6aa0b17e..15e03f560 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -135,6 +135,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, 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 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, 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 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, _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; diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index edf336684..6dc60587b 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -739,13 +739,40 @@ int dladdr(const void *__address, Dl_info * __info) char *strtab; ElfW(Sym) *symtab; unsigned int hn, si, sn, sf; - ElfW(Addr) sa; + ElfW(Addr) sa = 0; + + /* Set the info for the object the address lies in */ + __info->dli_fname = pelf->libname; + __info->dli_fbase = (void *) DL_LOADADDR_BASE(pelf->mapaddr); - sa = 0; 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 @@ int dladdr(const void *__address, Dl_info * __info) } 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; } |