From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/1440 Path: news.gmane.org!not-for-mail From: musl Newsgroups: gmane.linux.lib.musl.general Subject: ldso : dladdr support Date: Tue, 07 Aug 2012 11:04:19 +0200 Message-ID: <5020DA13.6080803@gmail.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------070702070704020807030806" X-Trace: dough.gmane.org 1344330283 21453 80.91.229.3 (7 Aug 2012 09:04:43 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Tue, 7 Aug 2012 09:04:43 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-1441-gllmg-musl=m.gmane.org@lists.openwall.com Tue Aug 07 11:04:42 2012 Return-path: Envelope-to: gllmg-musl@plane.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by plane.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1SyfiP-0005Nj-K8 for gllmg-musl@plane.gmane.org; Tue, 07 Aug 2012 11:04:37 +0200 Original-Received: (qmail 15409 invoked by uid 550); 7 Aug 2012 09:04:34 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 15401 invoked from network); 7 Aug 2012 09:04:34 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=Z483DaOKHN8mgaOu0WcZ2o2uzABgcQiPAm1yaCHe6vo=; b=L3+QqS1Q69UF2fAjJvFoHeGNR8QLTrSpbAa2wjlnvQdz1yjDLvemVftIy4Dv7J4zc+ r5yUJH+d5K24vCE6fMdoTHgF0f6sTevUEMxd4HBLXw8LD2TslK4Ei3CoynBX2t2CLIe9 N9WM8aNo7id3dCFnFd5rOdomhSifB+GHEG9c0PnaZdvAL45WmY+Vl4Rj/YYr+khU4DaZ 2/XAZd16bBUXrJZvXEHZpdpysh/uQnfPBcY+V+yNzovz4NM2UjayLG5bVJWEIrN6qZ1i XEpjMSWP+tdHKCFYvuORrXBva8qbDX5BYnKtH0jPYqAuzSzO6zvim05TlPOgQ5pM9dIR NnJg== User-Agent: Mozilla/5.0 (X11; Linux i686; rv:14.0) Gecko/20120714 Thunderbird/14.0 Xref: news.gmane.org gmane.linux.lib.musl.general:1440 Archived-At: This is a multi-part message in MIME format. --------------070702070704020807030806 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Hi, This patch adds support for dladdr function. It is based on my previous patch (gnu hash support). Regards, Boris --------------070702070704020807030806 Content-Type: text/x-patch; name="ldso-dladdr-support.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ldso-dladdr-support.patch" >From 1ac52fe3a7e934223ec887b6d95bb74ecc0477b1 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON 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 #include #include @@ -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 --------------070702070704020807030806 Content-Type: text/x-patch; name="gnu-hash-support.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="gnu-hash-support.patch" >From 28edcc77f5096d17be29da1be1c3972c2356d269 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON 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<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 --------------070702070704020807030806--