|
@@ -1,3 +1,4 @@
|
|
|
+#define _GNU_SOURCE
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
@@ -584,6 +585,22 @@ static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p)
|
|
|
+{
|
|
|
+ size_t min_addr = -1, max_addr = 0;
|
|
|
+ for (; cnt--; ph = (void *)((char *)ph + stride)) {
|
|
|
+ if (ph->p_type != PT_LOAD) continue;
|
|
|
+ if (ph->p_vaddr < min_addr)
|
|
|
+ min_addr = ph->p_vaddr;
|
|
|
+ if (ph->p_vaddr+ph->p_memsz > max_addr)
|
|
|
+ max_addr = ph->p_vaddr+ph->p_memsz;
|
|
|
+ }
|
|
|
+ min_addr &= -PAGE_SIZE;
|
|
|
+ max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE;
|
|
|
+ p->map = p->base + min_addr;
|
|
|
+ p->map_len = max_addr - min_addr;
|
|
|
+}
|
|
|
+
|
|
|
static void do_init_fini(struct dso *p)
|
|
|
{
|
|
|
size_t dyn[DYN_CNT] = {0};
|
|
@@ -647,6 +664,8 @@ void *__dynlink(int argc, char **argv)
|
|
|
lib->name = lib->shortname = "libc.so";
|
|
|
lib->global = 1;
|
|
|
ehdr = (void *)lib->base;
|
|
|
+ find_map_range((void *)(aux[AT_BASE]+ehdr->e_phoff),
|
|
|
+ ehdr->e_phnum, ehdr->e_phentsize, lib);
|
|
|
lib->dynv = (void *)(lib->base + find_dyn(
|
|
|
(void *)(aux[AT_BASE]+ehdr->e_phoff),
|
|
|
ehdr->e_phnum, ehdr->e_phentsize));
|
|
@@ -666,6 +685,8 @@ void *__dynlink(int argc, char **argv)
|
|
|
app->name = argv[0];
|
|
|
app->dynv = (void *)(app->base + find_dyn(
|
|
|
(void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
|
|
|
+ find_map_range((void *)aux[AT_PHDR],
|
|
|
+ aux[AT_PHNUM], aux[AT_PHENT], app);
|
|
|
} else {
|
|
|
int fd;
|
|
|
char *ldname = argv[0];
|
|
@@ -891,6 +912,67 @@ failed:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int __dladdr(void *addr, Dl_info *info)
|
|
|
+{
|
|
|
+ struct dso *p;
|
|
|
+ Sym *sym;
|
|
|
+ uint32_t nsym;
|
|
|
+ char *strings;
|
|
|
+ size_t i;
|
|
|
+ void *best = 0;
|
|
|
+ char *bestname;
|
|
|
+
|
|
|
+ pthread_rwlock_rdlock(&lock);
|
|
|
+ for (p=head; p && (unsigned char *)addr-p->map>p->map_len; p=p->next);
|
|
|
+ pthread_rwlock_unlock(&lock);
|
|
|
+
|
|
|
+ if (!p) return 0;
|
|
|
+
|
|
|
+ sym = p->syms;
|
|
|
+ strings = p->strings;
|
|
|
+ if (p->hashtab) {
|
|
|
+ nsym = p->hashtab[1];
|
|
|
+ } else {
|
|
|
+ uint32_t *buckets;
|
|
|
+ uint32_t *hashval;
|
|
|
+ buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
|
|
|
+ sym += p->ghashtab[1];
|
|
|
+ for (i = 0; i < p->ghashtab[0]; i++) {
|
|
|
+ if (buckets[i] > nsym)
|
|
|
+ nsym = buckets[i];
|
|
|
+ }
|
|
|
+ if (nsym) {
|
|
|
+ nsym -= p->ghashtab[1];
|
|
|
+ hashval = buckets + p->ghashtab[0] + nsym;
|
|
|
+ do nsym++;
|
|
|
+ while (!(*hashval++ & 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (; nsym; nsym--, sym++) {
|
|
|
+ if (sym->st_shndx && sym->st_value
|
|
|
+ && (1<<(sym->st_info&0xf) & OK_TYPES)
|
|
|
+ && (1<<(sym->st_info>>4) & OK_BINDS)) {
|
|
|
+ void *symaddr = p->base + sym->st_value;
|
|
|
+ if (symaddr > addr || symaddr < best)
|
|
|
+ continue;
|
|
|
+ best = symaddr;
|
|
|
+ bestname = strings + sym->st_name;
|
|
|
+ if (addr == symaddr)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!best) return 0;
|
|
|
+
|
|
|
+ info->dli_fname = p->name;
|
|
|
+ info->dli_fbase = p->base;
|
|
|
+ info->dli_sname = bestname;
|
|
|
+ info->dli_saddr = best;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
void *__dlsym(void *p, const char *s, void *ra)
|
|
|
{
|
|
|
void *res;
|
|
@@ -908,6 +990,10 @@ void *__dlsym(void *p, const char *s, void *ra)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
+int __dladdr (void *addr, Dl_info *info)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
#endif
|
|
|
|
|
|
char *dlerror()
|