aboutsummaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2012-02-17 10:49:29 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2012-02-17 10:49:29 +0000
commita7d61fc17dc8db1da4b29862e85a0ff47d1aeb15 (patch)
tree4ac15d54cf734a144a3a7707224503456d970cbc /lib/libc
parent2a4106cfef327b046181ff683ebc803dbbddeaac (diff)
Notes
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/gen/aux.c31
-rw-r--r--lib/libc/gen/dlfcn.c53
-rw-r--r--lib/libc/include/libc_private.h10
3 files changed, 89 insertions, 5 deletions
diff --git a/lib/libc/gen/aux.c b/lib/libc/gen/aux.c
index b5c079bfde564..4bf8643af1664 100644
--- a/lib/libc/gen/aux.c
+++ b/lib/libc/gen/aux.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 2010 Konstantin Belousov <kib@FreeBSD.ORG>.
+ * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,34 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include "libc_private.h"
-Elf_Auxinfo *__elf_aux_vector;
+extern char **environ;
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
-static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
+void *__elf_aux_vector;
+static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
+
+static void
+init_aux_vector_once(void)
+{
+ Elf_Addr *sp;
+
+ sp = (Elf_Addr *)environ;
+ while (*sp++ != 0)
+ ;
+ __elf_aux_vector = (Elf_Auxinfo *)sp;
+}
+void
+__init_elf_aux_vector(void)
+{
+
+ if (&_DYNAMIC != NULL)
+ return;
+ _once(&aux_vector_once, init_aux_vector_once);
+}
+
+static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
static char *canary, *pagesizes;
@@ -86,6 +110,7 @@ _elf_aux_info(int aux, void *buf, int buflen)
{
int res;
+ __init_elf_aux_vector();
if (__elf_aux_vector == NULL)
return (ENOSYS);
_once(&aux_once, init_aux);
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index 7be9f8706f68a..ad24bb4914caf 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -34,6 +34,10 @@ __FBSDID("$FreeBSD$");
#include <dlfcn.h>
#include <link.h>
#include <stddef.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "libc_private.h"
static char sorry[] = "Service unavailable";
@@ -138,13 +142,58 @@ _rtld_thread_init(void * li)
_rtld_error(sorry);
}
+static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT;
+static struct dl_phdr_info phdr_info;
+
+static void
+dl_init_phdr_info(void)
+{
+ Elf_Auxinfo *auxp;
+ size_t phent;
+ unsigned int i;
+
+ phent = 0;
+ for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) {
+ switch (auxp->a_type) {
+ case AT_BASE:
+ phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr;
+ break;
+ case AT_EXECPATH:
+ phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr;
+ break;
+ case AT_PHDR:
+ phdr_info.dlpi_phdr =
+ (const Elf_Phdr *)auxp->a_un.a_ptr;
+ break;
+ case AT_PHENT:
+ phent = auxp->a_un.a_val;
+ break;
+ case AT_PHNUM:
+ phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val;
+ break;
+ }
+ }
+ for (i = 0; i < phdr_info.dlpi_phnum; i++) {
+ if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
+ phdr_info.dlpi_tls_modid = 1;
+ phdr_info.dlpi_tls_data =
+ (void*)phdr_info.dlpi_phdr[i].p_vaddr;
+ }
+ }
+ phdr_info.dlpi_adds = 1;
+}
+
#pragma weak dl_iterate_phdr
int
dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
void *data)
{
- _rtld_error(sorry);
- return 0;
+
+ __init_elf_aux_vector();
+ if (__elf_aux_vector == NULL)
+ return (1);
+ _once(&dl_phdr_info_once, dl_init_phdr_info);
+ return (callback(&phdr_info, sizeof(phdr_info), data));
}
#pragma weak fdlopen
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index c7284cc3afee1..d4b24a7c962eb 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -44,6 +44,15 @@
extern int __isthreaded;
/*
+ * Elf_Auxinfo *__elf_aux_vector, the pointer to the ELF aux vector
+ * provided by kernel. Either set for us by rtld, or found at runtime
+ * on stack for static binaries.
+ *
+ * Type is void to avoid polluting whole libc with ELF types.
+ */
+extern void *__elf_aux_vector;
+
+/*
* libc should use libc_dlopen internally, which respects a global
* flag where loading of new shared objects can be restricted.
*/
@@ -229,6 +238,7 @@ int _execvpe(const char *, char * const *, char * const *);
int _elf_aux_info(int aux, void *buf, int buflen);
struct dl_phdr_info;
int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
+void __init_elf_aux_vector(void);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);