From 18c0e02e2bd53ceedbb843b06ff90890f1c734b0 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 31 Oct 2012 21:27:48 -0400 Subject: [PATCH] add dl_iterate_phdr interface patches by Alex Caudill (npx). the dynamic-linked version is almost identical to the final submitted patch; I just added a couple missing lines for saving the phdr address when the dynamic linker is invoked directly to run a program, and removed a couple to avoid introducing another unnecessary type. the static-linked version is based on npx's draft. it could use some improvements which are contingent on the startup code saving some additional information for later use. --- include/link.h | 27 ++++++++++++++++++++ src/ldso/dl_iterate_phdr.c | 43 ++++++++++++++++++++++++++++++++ src/ldso/dynlink.c | 51 ++++++++++++++++++++++++++++++++------ 3 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 include/link.h create mode 100644 src/ldso/dl_iterate_phdr.c diff --git a/include/link.h b/include/link.h new file mode 100644 index 00000000..d5160e7e --- /dev/null +++ b/include/link.h @@ -0,0 +1,27 @@ +#ifndef _LINK_H +#define _LINK_H + +#include +#define __NEED_size_t +#include + +#if UINTPTR_MAX > 0xffffffff +#define ElfW(type) Elf64_ ## type +#else +#define ElfW(type) Elf32_ ## type +#endif + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) *dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *); + +#endif diff --git a/src/ldso/dl_iterate_phdr.c b/src/ldso/dl_iterate_phdr.c new file mode 100644 index 00000000..49b321a0 --- /dev/null +++ b/src/ldso/dl_iterate_phdr.c @@ -0,0 +1,43 @@ +#ifndef SHARED + +#include +#include +#include "libc.h" + +#define AUX_CNT 38 + +int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data) +{ + unsigned char *p; + ElfW(Phdr) *phdr, *tls_phdr=0; + size_t base = 0; + size_t n; + struct dl_phdr_info info; + size_t i, aux[AUX_CNT]; + + for (i=0; libc.auxv[i]; i+=2) + if (libc.auxv[i]p_type == PT_PHDR) + base = aux[AT_PHDR] - phdr->p_vaddr; + if (phdr->p_type == PT_TLS) + tls_phdr = phdr; + } + info.dlpi_addr = base; + info.dlpi_name = "/proc/self/exe"; + info.dlpi_phdr = (void *)aux[AT_PHDR]; + info.dlpi_phnum = aux[AT_PHNUM]; + info.dlpi_adds = 0; + info.dlpi_subs = 0; + if (tls_phdr) { + info.dlpi_tls_modid = 1; + info.dlpi_tls_data = (void *)(base + tls_phdr->p_vaddr); + } else { + info.dlpi_tls_modid = 0; + info.dlpi_tls_data = 0; + } + return (callback)(&info, sizeof (info), data); +} +#endif diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index a6dbaf01..13bf16a5 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,8 @@ struct dso { size_t *dynv; struct dso *next, *prev; + Phdr *phdr; + int phnum; int refcnt; Sym *syms; uint32_t *hashtab; @@ -91,6 +94,7 @@ void *__install_initial_tls(void *); static struct dso *head, *tail, *ldso, *fini_head; static char *env_path, *sys_path, *r_path; +static unsigned long long gencnt; static int ssp_used; static int runtime; static int ldd_mode; @@ -323,6 +327,8 @@ static void *map_library(int fd, struct dso *dso) eh->e_phoff = sizeof *eh; } ph = (void *)((char *)buf + eh->e_phoff); + dso->phdr = ph; + dso->phnum = eh->e_phnum; for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { if (ph->p_type == PT_DYNAMIC) dyn = ph->p_vaddr; @@ -825,18 +831,19 @@ 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)); + lib->phnum = ehdr->e_phnum; + lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff); + find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib); + lib->dynv = (void *)(lib->base + find_dyn(lib->phdr, + ehdr->e_phnum, ehdr->e_phentsize)); decode_dyn(lib); if (aux[AT_PHDR]) { size_t interp_off = 0; size_t tls_image = 0; /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ - phdr = (void *)aux[AT_PHDR]; + app->phdr = phdr = (void *)aux[AT_PHDR]; + app->phnum = aux[AT_PHNUM]; for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { if (phdr->p_type == PT_PHDR) app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); @@ -884,6 +891,8 @@ void *__dynlink(int argc, char **argv) close(fd); lib->name = ldname; app->name = argv[0]; + app->phnum = ehdr->e_phnum; + app->phdr = (void *)(app->base + ehdr->e_phoff); aux[AT_ENTRY] = ehdr->e_entry; } if (app->tls_size) { @@ -907,7 +916,8 @@ void *__dynlink(int argc, char **argv) /* Attach to vdso, if provided by the kernel */ if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) { ehdr = (void *)vdso_base; - phdr = (void *)(vdso_base + ehdr->e_phoff); + vdso->phdr = phdr = (void *)(vdso_base + ehdr->e_phoff); + vdso->phnum = ehdr->e_phnum; for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) { if (phdr->p_type == PT_DYNAMIC) vdso->dynv = (void *)(vdso_base + phdr->p_offset); @@ -1068,6 +1078,7 @@ void *dlopen(const char *file, int mode) orig_tail = tail; end: __release_ptc(); + if (p) gencnt++; pthread_rwlock_unlock(&lock); if (p) do_init_fini(orig_tail); pthread_setcancelstate(cs, 0); @@ -1192,6 +1203,32 @@ void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra) pthread_rwlock_unlock(&lock); return res; } + +int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data) +{ + struct dso *current; + struct dl_phdr_info info; + int ret = 0; + for(current = head; current;) { + info.dlpi_addr = (uintptr_t)current->base; + info.dlpi_name = current->name; + info.dlpi_phdr = current->phdr; + info.dlpi_phnum = current->phnum; + info.dlpi_adds = gencnt; + info.dlpi_subs = 0; + info.dlpi_tls_modid = current->tls_id; + info.dlpi_tls_data = current->tls_image; + + ret = (callback)(&info, sizeof (info), data); + + if (ret != 0) break; + + pthread_rwlock_rdlock(&lock); + current = current->next; + pthread_rwlock_unlock(&lock); + } + return ret; +} #else void *dlopen(const char *file, int mode) {