mailing list of musl libc
 help / color / mirror / code / Atom feed
* ldso : dladdr support
@ 2012-08-07  9:04 musl
  2012-08-07 11:46 ` Szabolcs Nagy
  0 siblings, 1 reply; 33+ messages in thread
From: musl @ 2012-08-07  9:04 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 120 bytes --]

Hi,

This patch adds support for dladdr function.
It is based on my previous patch (gnu hash support).

Regards,

Boris

[-- Attachment #2: ldso-dladdr-support.patch --]
[-- Type: text/x-patch, Size: 4844 bytes --]

From 1ac52fe3a7e934223ec887b6d95bb74ecc0477b1 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <b.brezillon@overkiz.com>
Date: Tue, 7 Aug 2012 10:57:26 +0200
Subject: [PATCH] ldso : dladdr support

---
 include/dlfcn.h    |   15 ++++++++
 src/ldso/dynlink.c |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/include/dlfcn.h b/include/dlfcn.h
index dea74c7..8c45822 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -18,6 +18,21 @@ char  *dlerror(void);
 void  *dlopen(const char *, int);
 void  *dlsym(void *, const char *);
 
+#ifdef _GNU_SOURCE
+typedef struct {
+    const char *dli_fname;  /* Pathname of shared object that
+                               contains address */
+    void       *dli_fbase;  /* Address at which shared object
+                               is loaded */
+    const char *dli_sname;  /* Name of nearest symbol with address
+                               lower than addr */
+    void       *dli_saddr;  /* Exact address of symbol named
+                               in dli_sname */
+} Dl_info;
+
+int dladdr (void *addr, Dl_info *info);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 0c8d75a..acf8e56 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -28,12 +29,14 @@ typedef Elf32_Phdr Phdr;
 typedef Elf32_Sym Sym;
 #define R_TYPE(x) ((x)&255)
 #define R_SYM(x) ((x)>>8)
+#define ELF_ST_TYPE ELF32_ST_TYPE
 #else
 typedef Elf64_Ehdr Ehdr;
 typedef Elf64_Phdr Phdr;
 typedef Elf64_Sym Sym;
 #define R_TYPE(x) ((x)&0xffffffff)
 #define R_SYM(x) ((x)>>32)
+#define ELF_ST_TYPE ELF64_ST_TYPE
 #endif
 
 struct debug {
@@ -69,7 +72,8 @@ struct dso {
 
 struct hash_algo {
 	uint32_t (*hash) (const char *);
-	Sym *(*lookup) (const char *s, uint32_t h, struct dso *dso);
+	Sym *(*lookup) (const char *, uint32_t, struct dso *);
+	void (*iterate) (struct dso *, int (*) (struct dso *, Sym *, void *), void *);
 };
 
 #define SYSV_HASH_ALG_IDX   0
@@ -178,14 +182,50 @@ static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
 	return 0;
 }
 
+static void sysv_iterate (struct dso *dso, int (*func) (struct dso *, Sym *, void *), void *data)
+{
+	size_t i;
+	Sym *syms = dso->syms;
+	uint32_t *hashtab = dso->hashtab;
+	uint32_t nbucket = hashtab[0];
+	uint32_t nchain = hashtab[1];
+	for (i = 0; i < hashtab[1]; i++) {
+		if (!func (dso, syms + i, data))
+			return;
+	}
+}
+
+static void gnu_iterate (struct dso *dso, int (*func) (struct dso *, Sym *, void *), void *data)
+{
+	uint32_t i;
+	Sym *syms = dso->syms;
+	uint32_t *hashtab = dso->hashtab;
+	uint32_t *buckets = hashtab + 4 + (hashtab[2] * (sizeof(size_t) / sizeof(uint32_t)));
+	uint32_t nbuckets = hashtab[0];
+	uint32_t *hashvals = buckets + nbuckets;
+	uint32_t symndx = hashtab[1];
+
+	for (i = 0; i < nbuckets; ++i) {
+		uint32_t n = buckets[i];
+		Sym *sym = syms + n;
+		uint32_t *hashval = hashvals + n - symndx;
+		do {
+			if (!func (dso, sym++, data))
+				return;
+		}while (!(*hashval++ & 1));
+  }
+}
+
 static struct hash_algo hashalgs[] = {
 	{
 		.hash = sysv_hash,
 		.lookup = sysv_lookup,
+		.iterate = sysv_iterate,
 	},
 	{
 		.hash = gnu_hash,
 		.lookup = gnu_lookup,
+		.iterate = gnu_iterate,
 	},
 };
 
@@ -918,6 +958,69 @@ failed:
 	return 0;
 }
 
+struct sym_search {
+	void *addr;
+	Dl_info *info;
+};
+
+static int find_closest_sym (struct dso *dso, Sym *sym, void *data)
+{
+	struct sym_search *search = data;
+	void *symaddr = dso->base + sym->st_value;
+	char *strings = dso->strings;
+	Dl_info *info = search->info;
+	void *addr = search->addr;
+	void *prevaddr = info->dli_saddr;
+
+	if (sym->st_value == 0 && sym->st_shndx == SHN_UNDEF)
+		return 1;
+
+	if (ELF_ST_TYPE(sym->st_info) == STT_TLS)
+		return 1;
+
+	if (addr < symaddr)
+		return 1;
+
+	if (prevaddr && (addr - symaddr) > (addr - prevaddr))
+		return 1;
+
+	info->dli_saddr = symaddr;
+	info->dli_sname = strings + sym->st_name;
+
+	if (addr == symaddr)
+		return 0;
+
+	return 1;
+
+}
+
+static int do_dladdr (void *addr, Dl_info *info)
+{
+	struct sym_search search;
+	struct dso *p;
+	memset (info, 0, sizeof (*info));
+	search.info = info;
+	search.addr = addr;
+	for (p=head; p; p=p->next) {
+		if ((unsigned char *)addr >= p->map && (unsigned char *)addr < p->map + p->map_len) {
+			info->dli_fname = p->name;
+			info->dli_fbase = p->base;
+			hashalgs[p->hashalg].iterate (p, find_closest_sym, &search);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int dladdr (void *addr, Dl_info *info)
+{
+	int res;
+	pthread_rwlock_rdlock(&lock);
+	res = do_dladdr (addr, info);
+	pthread_rwlock_unlock(&lock);
+	return res;
+}
+
 void *__dlsym(void *p, const char *s, void *ra)
 {
 	void *res;
-- 
1.7.9.5


[-- Attachment #3: gnu-hash-support.patch --]
[-- Type: text/x-patch, Size: 6101 bytes --]

From 28edcc77f5096d17be29da1be1c3972c2356d269 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <b.brezillon@overkiz.com>
Date: Mon, 6 Aug 2012 20:17:01 +0200
Subject: [PATCH] Add gnu hash support.

---
 src/ldso/dynlink.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 115 insertions(+), 10 deletions(-)

diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 31ef684..0c8d75a 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -52,6 +52,7 @@ struct dso {
 
 	int refcnt;
 	Sym *syms;
+	uint32_t hashalg;
 	uint32_t *hashtab;
 	char *strings;
 	unsigned char *map;
@@ -66,6 +67,15 @@ struct dso {
 	char buf[];
 };
 
+struct hash_algo {
+	uint32_t (*hash) (const char *);
+	Sym *(*lookup) (const char *s, uint32_t h, struct dso *dso);
+};
+
+#define SYSV_HASH_ALG_IDX   0
+#define GNU_HASH_ALG_IDX    1
+#define HASH_ALG_CNT        2
+
 #include "reloc.h"
 
 void __init_ssp(size_t *);
@@ -94,7 +104,7 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt)
 	}
 }
 
-static uint32_t hash(const char *s0)
+static uint32_t sysv_hash(const char *s0)
 {
 	const unsigned char *s = (void *)s0;
 	uint_fast32_t h = 0;
@@ -105,7 +115,16 @@ static uint32_t hash(const char *s0)
 	return h & 0xfffffff;
 }
 
-static Sym *lookup(const char *s, uint32_t h, struct dso *dso)
+static uint32_t gnu_hash (const char *s0)
+{
+	const unsigned char *s = (void *)s0;
+	uint_fast32_t h = 5381;
+	for (unsigned char c = *s; c != '\0'; c = *++s)
+		h = h * 33 + c;
+	return h & 0xffffffff;
+}
+
+static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
 {
 	size_t i;
 	Sym *syms = dso->syms;
@@ -118,20 +137,86 @@ static Sym *lookup(const char *s, uint32_t h, struct dso *dso)
 	return 0;
 }
 
+static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
+{
+	size_t i;
+	Sym *sym;
+	char *strings = dso->strings;
+	uint32_t *hashtab = dso->hashtab;
+	uint32_t nbuckets = hashtab[0];
+	size_t *maskwords = (size_t *)(hashtab + 4);
+	uint32_t *buckets = hashtab + 4 + (hashtab[2] * (sizeof(size_t) / sizeof(uint32_t)));
+	uint32_t symndx = hashtab[1];
+	Sym *syms = dso->syms;
+	uint32_t shift2 = hashtab[3];
+	uint32_t h2 = h1 >> shift2;
+	uint32_t *hashvals = buckets + nbuckets;
+	uint32_t *hashval;
+	size_t c = sizeof(size_t) * 8;
+	size_t n = (h1 / c) & (hashtab[2] - 1);
+	size_t bitmask = (1 << (h1 % c)) | (1 << (h2 % c));
+
+	if ((maskwords[n] & bitmask) != bitmask)
+		return 0;
+
+	n = buckets[h1 % nbuckets];
+	if (!n)
+		return 0;
+
+	sym = syms + n;
+	hashval = hashvals + n - symndx;
+
+	for (h1 &= ~1; 1; sym++) {
+		h2 = *hashval++;
+		if ((h1 == (h2 & ~1)) && !strcmp(s, strings + sym->st_name))
+			return sym;
+
+		if (h2 & 1)
+			break;
+	}
+
+	return 0;
+}
+
+static struct hash_algo hashalgs[] = {
+	{
+		.hash = sysv_hash,
+		.lookup = sysv_lookup,
+	},
+	{
+		.hash = gnu_hash,
+		.lookup = gnu_lookup,
+	},
+};
+
+
 #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
 #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
 
 static void *find_sym(struct dso *dso, const char *s, int need_def)
 {
-	uint32_t h = hash(s);
 	void *def = 0;
-	if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
-	if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
-	if (h==0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1;
+	uint32_t computed[HASH_ALG_CNT / 32 + 1];
+	uint32_t hashes[HASH_ALG_CNT];
+	memset (computed, 0, sizeof (computed));
+	if (!strcmp(s, "dlopen")) rtld_used = 1;
+	if (!strcmp(s, "dlsym")) rtld_used = 1;
+	if (!strcmp(s, "__stack_chk_fail")) ssp_used = 1;
 	for (; dso; dso=dso->next) {
 		Sym *sym;
+		uint32_t h;
 		if (!dso->global) continue;
-		sym = lookup(s, h, dso);
+
+		if (!(computed[dso->hashalg / 32] & (1 << (dso->hashalg % 32)))) {
+			h = hashalgs[dso->hashalg].hash(s);
+			hashes[dso->hashalg] = h;
+			computed[dso->hashalg / 32] |= (1 << (dso->hashalg % 32));
+		}
+		else {
+			h = hashes[dso->hashalg];
+		}
+
+		sym = hashalgs[dso->hashalg].lookup(s, h, dso);
 		if (sym && (!need_def || sym->st_shndx) && sym->st_value
 		 && (1<<(sym->st_info&0xf) & OK_TYPES)
 		 && (1<<(sym->st_info>>4) & OK_BINDS)) {
@@ -320,11 +405,17 @@ static int path_open(const char *name, const char *search, char *buf, size_t buf
 
 static void decode_dyn(struct dso *p)
 {
+	size_t *v = p->dynv;
 	size_t dyn[DYN_CNT] = {0};
 	decode_vec(p->dynv, dyn, DYN_CNT);
 	p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
 	p->hashtab = (void *)(p->base + dyn[DT_HASH]);
+	p->hashalg = SYSV_HASH_ALG_IDX;
 	p->strings = (void *)(p->base + dyn[DT_STRTAB]);
+	for (; v[0]; v+=2) if (v[0] == DT_GNU_HASH) {
+		p->hashtab = (void *)(p->base + v[1]);
+		p->hashalg = GNU_HASH_ALG_IDX;
+	}
 }
 
 static struct dso *load_library(const char *name)
@@ -786,6 +877,9 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
 	size_t i;
 	uint32_t h;
 	Sym *sym;
+	uint32_t computed[HASH_ALG_CNT / 32 + 1];
+	uint32_t hashes[HASH_ALG_CNT];
+
 	if (p == RTLD_NEXT) {
 		for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
 		if (!p) p=head;
@@ -798,12 +892,23 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
 		if (!res) goto failed;
 		return res;
 	}
-	h = hash(s);
-	sym = lookup(s, h, p);
+	memset (computed, 0, sizeof (computed));
+	h = hashalgs[p->hashalg].hash(s);
+	computed[p->hashalg / 32] |= (1 << (p->hashalg % 32));
+	hashes[p->hashalg] = h;
+	sym = hashalgs[p->hashalg].lookup(s, h, p);
 	if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
 		return p->base + sym->st_value;
 	if (p->deps) for (i=0; p->deps[i]; i++) {
-		sym = lookup(s, h, p);
+		if (!(computed[p->deps[i]->hashalg / 32] & (1 << (p->deps[i]->hashalg % 32)))) {
+			h = hashalgs[p->deps[i]->hashalg].hash(s);
+			hashes[p->deps[i]->hashalg] = h;
+			computed[p->deps[i]->hashalg / 32] |= (1 << (p->deps[i]->hashalg % 32));
+		}
+		else {
+			h = hashes[p->deps[i]->hashalg];
+		}
+		sym = hashalgs[p->deps[i]->hashalg].lookup(s, h, p->deps[i]);
 		if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
 			return p->deps[i]->base + sym->st_value;
 	}
-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2012-08-26  0:00 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-07  9:04 ldso : dladdr support musl
2012-08-07 11:46 ` Szabolcs Nagy
2012-08-07 14:15   ` musl
2012-08-07 14:53     ` Szabolcs Nagy
2012-08-07 23:09     ` Rich Felker
2012-08-08  9:55       ` musl
2012-08-08 11:52         ` Szabolcs Nagy
2012-08-08 12:54           ` Rich Felker
2012-08-08 13:57           ` musl
2012-08-11 23:05             ` Rich Felker
2012-08-15 22:41               ` boris brezillon
2012-08-17  5:39                 ` Rich Felker
2012-08-19 16:42                   ` musl
2012-08-20  2:06                     ` Rich Felker
2012-08-20 12:55                       ` musl
2012-08-20 14:32                         ` musl
2012-08-23 21:39                           ` Rich Felker
2012-08-23 22:21                             ` Rich Felker
2012-08-24  7:29                               ` musl
2012-08-24 18:38                                 ` Rich Felker
2012-08-25  7:42                                   ` boris brezillon
2012-08-25 12:35                                     ` Rich Felker
2012-08-25 22:13                                   ` musl
2012-08-25 22:37                                     ` musl
2012-08-26  0:00                                   ` musl
2012-08-24  8:12                               ` Szabolcs Nagy
2012-08-24  8:56                                 ` musl
2012-08-24  9:38                                   ` Szabolcs Nagy
2012-08-25 21:34                               ` musl
2012-08-25 21:42                                 ` Rich Felker
2012-08-16 18:03               ` musl
2012-08-17 16:35               ` musl
2012-08-08 12:49         ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).