diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ldso/dl_iterate_phdr.c | 43 | ||||
| -rw-r--r-- | src/ldso/dynlink.c | 51 | 
2 files changed, 87 insertions, 7 deletions
| 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 <elf.h> +#include <link.h> +#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]<AUX_CNT) aux[libc.auxv[i]] = libc.auxv[i+1]; + +	for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) { +		phdr = (void *)p; +		if (phdr->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 <errno.h>  #include <limits.h>  #include <elf.h> +#include <link.h>  #include <setjmp.h>  #include <pthread.h>  #include <ctype.h> @@ -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)  { | 
