summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldso/include/dl-hash.h1
-rw-r--r--ldso/ldso/dl-hash.c2
-rw-r--r--ldso/ldso/ldso.c7
-rw-r--r--ldso/libdl/libdl.c59
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;
}