about summary refs log tree commit diff
path: root/src/ldso
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-10-31 21:27:48 -0400
committerRich Felker <dalias@aerifal.cx>2012-10-31 21:27:48 -0400
commit18c0e02e2bd53ceedbb843b06ff90890f1c734b0 (patch)
tree37c29715025d24e38415e72ac8ec896fb22a2dcf /src/ldso
parent76f28cfce59dfc499252c874f87c34567e6c86c6 (diff)
downloadmusl-18c0e02e2bd53ceedbb843b06ff90890f1c734b0.tar.gz
musl-18c0e02e2bd53ceedbb843b06ff90890f1c734b0.tar.xz
musl-18c0e02e2bd53ceedbb843b06ff90890f1c734b0.zip
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.
Diffstat (limited to 'src/ldso')
-rw-r--r--src/ldso/dl_iterate_phdr.c43
-rw-r--r--src/ldso/dynlink.c51
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)
 {