Merge "libc: arch-x86: implement kernel vdso time functions"
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index 698ab6b..de72cb2 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -27,6 +27,7 @@
*/
#include <ctype.h>
+#include <elf.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
@@ -35,14 +36,22 @@
#include "debug_mapinfo.h"
#include "malloc_debug_disable.h"
+#if defined(__LP64__)
+#define Elf_W(x) Elf64_##x
+#else
+#define Elf_W(x) Elf32_##x
+#endif
+
// Format of /proc/<PID>/maps:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
static mapinfo_t* parse_maps_line(char* line) {
uintptr_t start;
uintptr_t end;
+ uintptr_t offset;
+ char permissions[4];
int name_pos;
- if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
- &end, &name_pos) < 2) {
+ if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
+ &end, permissions, &offset, &name_pos) < 2) {
return NULL;
}
@@ -59,6 +68,14 @@
if (mi) {
mi->start = start;
mi->end = end;
+ mi->offset = offset;
+ if (permissions[0] != 'r') {
+ // Any unreadable map will just get a zero load base.
+ mi->load_base = 0;
+ mi->load_base_read = true;
+ } else {
+ mi->load_base_read = false;
+ }
memcpy(mi->name, name, name_len);
mi->name[name_len] = '\0';
}
@@ -95,11 +112,58 @@
}
}
+template<typename T>
+static inline bool get_val(mapinfo_t* mi, uintptr_t addr, T* store) {
+ if (addr < mi->start || addr + sizeof(T) > mi->end) {
+ return false;
+ }
+ // Make sure the address is aligned properly.
+ if (addr & (sizeof(T)-1)) {
+ return false;
+ }
+ *store = *reinterpret_cast<T*>(addr);
+ return true;
+}
+
+__LIBC_HIDDEN__ void mapinfo_read_loadbase(mapinfo_t* mi) {
+ mi->load_base = 0;
+ mi->load_base_read = true;
+ uintptr_t addr = mi->start;
+ Elf_W(Ehdr) ehdr;
+ if (!get_val<Elf_W(Half)>(mi, addr + offsetof(Elf_W(Ehdr), e_phnum), &ehdr.e_phnum)) {
+ return;
+ }
+ if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Ehdr), e_phoff), &ehdr.e_phoff)) {
+ return;
+ }
+ addr += ehdr.e_phoff;
+ for (size_t i = 0; i < ehdr.e_phnum; i++) {
+ Elf_W(Phdr) phdr;
+ if (!get_val<Elf_W(Word)>(mi, addr + offsetof(Elf_W(Phdr), p_type), &phdr.p_type)) {
+ return;
+ }
+ if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Phdr), p_offset), &phdr.p_offset)) {
+ return;
+ }
+ if (phdr.p_type == PT_LOAD && phdr.p_offset == mi->offset) {
+ if (!get_val<Elf_W(Addr)>(mi, addr + offsetof(Elf_W(Phdr), p_vaddr), &phdr.p_vaddr)) {
+ return;
+ }
+ mi->load_base = phdr.p_vaddr;
+ return;
+ }
+ addr += sizeof(phdr);
+ }
+}
+
// Find the containing map info for the PC.
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) {
for (; mi != NULL; mi = mi->next) {
if ((pc >= mi->start) && (pc < mi->end)) {
- *rel_pc = pc - mi->start;
+ if (!mi->load_base_read) {
+ mapinfo_read_loadbase(mi);
+ }
+ *rel_pc = pc - mi->start + mi->load_base;
return mi;
}
}
diff --git a/libc/bionic/debug_mapinfo.h b/libc/bionic/debug_mapinfo.h
index 926b377..af7d05d 100644
--- a/libc/bionic/debug_mapinfo.h
+++ b/libc/bionic/debug_mapinfo.h
@@ -35,6 +35,9 @@
struct mapinfo_t* next;
uintptr_t start;
uintptr_t end;
+ uintptr_t offset;
+ uintptr_t load_base;
+ bool load_base_read;
char name[];
};
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index bd71628..3ca6c0d 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -64,18 +64,15 @@
// Declared in "private/bionic_ssp.h".
uintptr_t __stack_chk_guard = 0;
-/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
- * in memory. Beware: all writes to libc globals from this function will
- * apply to linker-private copies and will not be visible from libc later on.
- *
- * Note: this function creates a pthread_internal_t for the initial thread and
- * stores the pointer in TLS, but does not add it to pthread's thread list. This
- * has to be done later from libc itself (see __libc_init_common).
- *
- * This function also stores a pointer to the kernel argument block in a TLS slot to be
- * picked up by the libc constructor.
- */
-void __libc_init_tls(KernelArgumentBlock& args) {
+// Setup for the main thread. For dynamic executables, this is called by the
+// linker _before_ libc is mapped in memory. This means that all writes to
+// globals from this function will apply to linker-private copies and will not
+// be visible from libc later on.
+//
+// Note: this function creates a pthread_internal_t for the initial thread and
+// stores the pointer in TLS, but does not add it to pthread's thread list. This
+// has to be done later from libc itself (see __libc_init_common).
+void __libc_init_main_thread(KernelArgumentBlock& args) {
__libc_auxv = args.auxv;
static pthread_internal_t main_thread;
@@ -99,6 +96,9 @@
__init_thread(&main_thread);
__init_tls(&main_thread);
__set_tls(main_thread.tls);
+
+ // Store a pointer to the kernel argument block in a TLS slot to be
+ // picked up by the libc constructor.
main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
__init_alternate_signal_stack(&main_thread);
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 7794fbe..ef57af6 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -90,7 +90,7 @@
int (*slingshot)(int, char**, char**),
structors_array_t const * const structors) {
KernelArgumentBlock args(raw_args);
- __libc_init_tls(args);
+ __libc_init_main_thread(args);
__libc_init_AT_SECURE(args);
__libc_init_common(args);
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 30dc0eb..d92d9d9 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -114,7 +114,7 @@
#if defined(__cplusplus)
class KernelArgumentBlock;
-extern __LIBC_HIDDEN__ void __libc_init_tls(KernelArgumentBlock& args);
+extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock& args);
#endif
#endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 73eeba1..0718efc 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3465,7 +3465,7 @@
_exit(EXIT_FAILURE);
}
- __libc_init_tls(args);
+ __libc_init_main_thread(args);
// Initialize the linker's own global variables
linker_so.call_constructors();
diff --git a/tests/Android.mk b/tests/Android.mk
index 4d9a136..21deb5c 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -408,7 +408,7 @@
LOCAL_CXX = $(LOCAL_PATH)/file-check-cxx \
$(HOST_OUT_EXECUTABLES)/FileCheck \
- $($(LOCAL_2ND_ARCH_VAR_PREFIX)CXX_BARE) \
+ $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CXX) \
GCC \
LOCAL_CLANG := false