diff options
| -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 | 7 | ||||
| -rw-r--r-- | ldso/libdl/libdl.c | 59 |
4 files changed, 52 insertions, 17 deletions
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h index fb75c8611..758767f4d 100644 --- a/ldso/include/dl-hash.h +++ b/ldso/include/dl-hash.h @@ -59,6 +59,7 @@ struct elf_resolve { unsigned int l_need_tls_init:1; #endif + ElfW(Addr) mapaddr; 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 971b1842c..ff4f22a6f 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -153,7 +153,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname, hash_addr += tpnt->nbucket; tpnt->chains = hash_addr; } - tpnt->loadaddr = (ElfW(Addr))loadaddr; + tpnt->loadaddr = tpnt->mapaddr = (ElfW(Addr))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 738b970f4..39e56f8a7 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -181,6 +181,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr, ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv) { + ElfW(Addr) app_loadaddr = NULL; ElfW(Phdr) *ppnt; ElfW(Dyn) *dpnt; char *lpntstr; @@ -329,6 +330,9 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long 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) *) (ppnt->p_vaddr + app_tpnt->loadaddr); _dl_parse_dynamic_info(dpnt, app_tpnt->dynamic_info, debug_addr, app_tpnt->loadaddr); @@ -366,6 +370,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long 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; @@ -873,7 +878,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr, * ld.so.1, so we have to look up each symbol individually. */ - _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, NULL, 0, NULL); + _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, NULL, 0, NULL); if (_dl_envp) *_dl_envp = (unsigned long) envp; diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index e4f564bc2..c5033df2d 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -995,20 +995,18 @@ int dladdr(const void *__address, Dl_info * __info) */ pelf = NULL; -#if 0 - fprintf(stderr, "dladdr( %p, %p )\n", __address, __info); -#endif + _dl_if_debug_print("dladdr( %p, %p )\n", __address, __info); for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) { struct elf_resolve *tpnt; tpnt = rpnt; -#if 0 - fprintf(stderr, "Module \"%s\" at %p\n", + + _dl_if_debug_print("Module \"%s\" at %p\n", tpnt->libname, tpnt->loadaddr); -#endif - if (tpnt->loadaddr < (ElfW(Addr)) __address - && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) { + + if (tpnt->mapaddr < (ElfW(Addr)) __address + && (pelf == NULL || pelf->mapaddr < tpnt->mapaddr)) { pelf = tpnt; } } @@ -1025,13 +1023,41 @@ 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 *)(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; @@ -1042,18 +1068,21 @@ int dladdr(const void *__address, Dl_info * __info) sn = si; sf = 1; } -#if 0 - fprintf(stderr, "Symbol \"%s\" at %p\n", + + _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr); -#endif } } if (sf) { - __info->dli_fname = pelf->libname; - __info->dli_fbase = (void *)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; } |
