aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/Android.mk92
-rw-r--r--libc/SYSCALLS.TXT2
-rw-r--r--libc/arch-arm/arm.mk1
-rw-r--r--libc/arch-arm/bionic/sigsetjmp.S2
-rw-r--r--libc/arch-arm/include/machine/asm.h4
-rw-r--r--libc/arch-arm64/arm64.mk1
-rw-r--r--libc/arch-arm64/include/machine/asm.h4
-rw-r--r--libc/arch-mips/include/machine/asm.h4
-rw-r--r--libc/arch-mips/mips.mk1
-rw-r--r--libc/arch-mips/string/mips_strlen.c5
-rw-r--r--libc/arch-mips64/bionic/__get_sp.S34
-rw-r--r--libc/arch-mips64/bionic/syscall.S2
-rw-r--r--libc/arch-mips64/include/machine/asm.h4
-rw-r--r--libc/arch-mips64/syscalls/_flush_cache.S27
-rw-r--r--libc/arch-x86/atom/string/sse2-wcslen-atom.S16
-rw-r--r--libc/arch-x86/bionic/__get_sp.S34
-rw-r--r--libc/arch-x86/include/machine/asm.h11
-rw-r--r--libc/arch-x86/x86.mk1
-rw-r--r--libc/arch-x86_64/bionic/__get_sp.S34
-rw-r--r--libc/arch-x86_64/include/machine/asm.h9
-rw-r--r--libc/arch-x86_64/x86_64.mk1
-rw-r--r--libc/bionic/__gnu_basename.cpp (renamed from libc/arch-arm64/bionic/__get_sp.S)13
-rw-r--r--libc/bionic/bionic_systrace.cpp2
-rw-r--r--libc/bionic/clone.cpp2
-rw-r--r--libc/bionic/daemon.c68
-rw-r--r--libc/bionic/debug_mapinfo.cpp2
-rw-r--r--libc/bionic/dirent.cpp2
-rw-r--r--libc/bionic/dlmalloc.c23
-rw-r--r--libc/bionic/libc_init_common.cpp24
-rw-r--r--libc/bionic/libc_logging.cpp19
-rw-r--r--libc/bionic/locale.cpp2
-rw-r--r--libc/bionic/malloc_debug_leak.cpp60
-rw-r--r--libc/bionic/malloc_debug_qemu.cpp2
-rw-r--r--libc/bionic/malloc_info.cpp94
-rw-r--r--libc/bionic/malloc_info.h32
-rw-r--r--libc/bionic/new.cpp8
-rw-r--r--libc/bionic/pthread_attr.cpp52
-rw-r--r--libc/bionic/pthread_setname_np.cpp2
-rw-r--r--libc/bionic/pututline.c4
-rw-r--r--libc/bionic/strerror_r.cpp13
-rw-r--r--libc/bionic/sysconf.cpp4
-rw-r--r--libc/bionic/system_properties.cpp35
-rw-r--r--libc/dns/gethnamaddr.c4
-rw-r--r--libc/dns/net/getaddrinfo.c4
-rw-r--r--libc/dns/net/services.h109
-rw-r--r--libc/dns/resolv/__dn_comp.c38
-rw-r--r--libc/dns/resolv/__res_close.c33
-rw-r--r--libc/dns/resolv/__res_send.c37
-rw-r--r--libc/dns/resolv/res_cache.c2
-rw-r--r--libc/dns/resolv/res_init.c43
-rw-r--r--libc/include/android/set_abort_message.h (renamed from libc/arch-arm/bionic/__get_sp.S)18
-rw-r--r--libc/include/arpa/inet.h3
-rw-r--r--libc/include/elf.h2
-rw-r--r--libc/include/fcntl.h4
-rw-r--r--libc/include/features.h29
-rw-r--r--libc/include/libgen.h12
-rw-r--r--libc/include/malloc.h22
-rw-r--r--libc/include/netinet/in.h4
-rw-r--r--libc/include/sched.h4
-rw-r--r--libc/include/stdatomic.h179
-rw-r--r--libc/include/stdio.h12
-rw-r--r--libc/include/stdio_ext.h (renamed from libc/arch-mips/bionic/__get_sp.S)32
-rw-r--r--libc/include/stdlib.h4
-rw-r--r--libc/include/string.h35
-rw-r--r--libc/include/sys/cachectl.h1
-rw-r--r--libc/include/sys/cdefs.h146
-rw-r--r--libc/include/sys/cdefs_elf.h94
-rw-r--r--libc/include/sys/socket.h3
-rw-r--r--libc/include/sys/stat.h3
-rw-r--r--libc/include/unistd.h8
-rw-r--r--libc/include/wchar.h1
-rwxr-xr-xlibc/kernel/tools/clean_header.py3
-rw-r--r--libc/kernel/tools/cpp.py17
-rw-r--r--libc/kernel/tools/utils.py89
-rw-r--r--libc/private/bionic_asm.h2
-rw-r--r--libc/private/bionic_string_utils.h (renamed from tests/libs/dlsym_local_symbol_private.cpp)21
-rw-r--r--libc/private/libc_logging.h2
-rw-r--r--libc/stdio/stdio_ext.cpp96
-rw-r--r--libc/tools/bionic_utils.py165
-rwxr-xr-xlibc/tools/check-symbols-glibc.py71
-rwxr-xr-xlibc/tools/gensyscalls.py148
-rw-r--r--libc/upstream-freebsd/android/include/freebsd-compat.h2
-rw-r--r--libc/upstream-netbsd/android/include/namespace.h5
-rw-r--r--libc/upstream-netbsd/android/include/netbsd-compat.h6
-rw-r--r--libc/upstream-openbsd/android/include/openbsd-compat.h15
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/daemon.c64
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/err.c47
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/errx.c47
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/verr.c (renamed from libc/bionic/err.c)90
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/verrx.c49
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/vwarn.c54
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/vwarnx.c47
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/warn.c47
-rw-r--r--libc/upstream-openbsd/lib/libc/gen/warnx.c47
-rw-r--r--libc/upstream-openbsd/lib/libc/net/res_random.c275
-rw-r--r--libc/upstream-openbsd/lib/libc/stdio/fmemopen.c183
-rw-r--r--libc/upstream-openbsd/lib/libc/stdio/open_memstream.c158
-rw-r--r--libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c169
-rw-r--r--libc/zoneinfo/tzdatabin568999 -> 566837 bytes
-rw-r--r--libm/include/math.h8
-rw-r--r--libm/sincos.c2
-rw-r--r--libstdc++/Android.mk15
-rw-r--r--libstdc++/include/new12
-rw-r--r--libstdc++/src/libstdc++.cpp1
-rw-r--r--linker/Android.mk5
-rw-r--r--linker/debugger.cpp30
-rw-r--r--linker/dlfcn.cpp76
-rw-r--r--linker/linked_list.h58
-rw-r--r--linker/linker.cpp767
-rw-r--r--linker/linker.h29
-rw-r--r--linker/linker_environ.cpp30
-rw-r--r--linker/linker_environ.h2
-rw-r--r--linker/linker_libc_support.c (renamed from tests/libs/dlsym_local_symbol.map)9
-rw-r--r--linker/linker_phdr.cpp32
-rw-r--r--linker/linker_phdr.h2
-rw-r--r--linker/tests/linked_list_test.cpp113
-rw-r--r--tests/Android.mk31
-rw-r--r--tests/atexit_test.cpp23
-rw-r--r--tests/dlext_test.cpp14
-rw-r--r--tests/dlfcn_test.cpp55
-rw-r--r--tests/getauxval_test.cpp1
-rw-r--r--tests/libc_logging_test.cpp12
-rw-r--r--tests/libgen_test.cpp5
-rw-r--r--tests/libs/Android.mk16
-rw-r--r--tests/libs/atexit_testlib.cpp37
-rw-r--r--tests/libs/dlopen_testlib_ifunc.c21
-rw-r--r--tests/libs/dlsym_local_symbol_public.cpp47
-rw-r--r--tests/locale_test.cpp3
-rw-r--r--tests/malloc_test.cpp50
-rw-r--r--tests/math_cos_test.cpp3
-rw-r--r--tests/math_cosf_test.cpp3
-rw-r--r--tests/math_exp_test.cpp3
-rw-r--r--tests/math_expf_test.cpp3
-rw-r--r--tests/math_log_test.cpp3
-rw-r--r--tests/math_logf_test.cpp3
-rw-r--r--tests/math_pow_test.cpp3
-rw-r--r--tests/math_powf_test.cpp3
-rw-r--r--tests/math_sin_test.cpp3
-rw-r--r--tests/math_sincos_test.cpp5
-rw-r--r--tests/math_sincosf_test.cpp3
-rw-r--r--tests/math_sinf_test.cpp3
-rw-r--r--tests/math_tan_test.cpp3
-rw-r--r--tests/math_tanf_test.cpp3
-rw-r--r--tests/pthread_test.cpp81
-rw-r--r--tests/stdatomic_test.cpp90
-rw-r--r--tests/stdio_ext_test.cpp133
-rw-r--r--tests/stdio_test.cpp82
-rw-r--r--tests/string_posix_strerror_r_test.cpp57
-rw-r--r--tests/string_test.cpp53
-rw-r--r--tests/sys_socket_test.cpp17
-rw-r--r--tests/time_test.cpp1
-rw-r--r--tests/uchar_test.cpp1
-rw-r--r--tests/unistd_test.cpp4
-rw-r--r--tests/wchar_test.cpp31
154 files changed, 3819 insertions, 1838 deletions
diff --git a/libc/Android.mk b/libc/Android.mk
index 3b6e3cbec..31807ddc3 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -38,8 +38,6 @@ endif
# =========================================================
libc_common_src_files := \
bionic/bindresvport.c \
- bionic/daemon.c \
- bionic/err.c \
bionic/ether_aton.c \
bionic/ether_ntoa.c \
bionic/fts.c \
@@ -62,6 +60,7 @@ libc_common_src_files := \
bionic/system_properties_compat.c \
stdio/snprintf.c\
stdio/sprintf.c \
+ stdio/stdio_ext.cpp \
# Fortify implementations of libc functions.
libc_common_src_files += \
@@ -103,8 +102,6 @@ libc_bionic_src_files := \
bionic/__cmsg_nxthdr.cpp \
bionic/connect.cpp \
bionic/ctype.cpp \
- bionic/__cxa_guard.cpp \
- bionic/__cxa_pure_virtual.cpp \
bionic/dirent.cpp \
bionic/dup2.cpp \
bionic/epoll_create.cpp \
@@ -124,6 +121,7 @@ libc_bionic_src_files := \
bionic/getpgrp.cpp \
bionic/getpid.cpp \
bionic/gettid.cpp \
+ bionic/__gnu_basename.cpp \
bionic/inotify_init.cpp \
bionic/lchown.cpp \
bionic/lfs64_support.cpp \
@@ -135,6 +133,7 @@ libc_bionic_src_files := \
bionic/link.cpp \
bionic/locale.cpp \
bionic/lstat.cpp \
+ bionic/malloc_info.cpp \
bionic/mbrtoc16.cpp \
bionic/mbrtoc32.cpp \
bionic/mbstate.cpp \
@@ -143,7 +142,6 @@ libc_bionic_src_files := \
bionic/mknod.cpp \
bionic/mntent.cpp \
bionic/NetdClientDispatch.cpp \
- bionic/new.cpp \
bionic/open.cpp \
bionic/pause.cpp \
bionic/pipe.cpp \
@@ -231,6 +229,11 @@ libc_bionic_src_files := \
bionic/wchar.cpp \
bionic/wctype.cpp \
+libc_cxa_src_files := \
+ bionic/__cxa_guard.cpp \
+ bionic/__cxa_pure_virtual.cpp \
+ bionic/new.cpp \
+
libc_upstream_freebsd_src_files := \
upstream-freebsd/lib/libc/gen/ldexp.c \
upstream-freebsd/lib/libc/gen/sleep.c \
@@ -279,7 +282,6 @@ libc_upstream_netbsd_src_files := \
upstream-netbsd/lib/libc/regex/regerror.c \
upstream-netbsd/lib/libc/regex/regexec.c \
upstream-netbsd/lib/libc/regex/regfree.c \
- upstream-netbsd/lib/libc/resolv/mtctxres.c \
upstream-netbsd/lib/libc/stdlib/bsearch.c \
upstream-netbsd/lib/libc/stdlib/div.c \
upstream-netbsd/lib/libc/stdlib/drand48.c \
@@ -334,6 +336,9 @@ libc_upstream_openbsd_src_files := \
upstream-openbsd/lib/libc/crypt/arc4random_uniform.c \
upstream-openbsd/lib/libc/gen/alarm.c \
upstream-openbsd/lib/libc/gen/ctype_.c \
+ upstream-openbsd/lib/libc/gen/daemon.c \
+ upstream-openbsd/lib/libc/gen/err.c \
+ upstream-openbsd/lib/libc/gen/errx.c \
upstream-openbsd/lib/libc/gen/exec.c \
upstream-openbsd/lib/libc/gen/fnmatch.c \
upstream-openbsd/lib/libc/gen/ftok.c \
@@ -343,6 +348,12 @@ libc_upstream_openbsd_src_files := \
upstream-openbsd/lib/libc/gen/time.c \
upstream-openbsd/lib/libc/gen/tolower_.c \
upstream-openbsd/lib/libc/gen/toupper_.c \
+ upstream-openbsd/lib/libc/gen/verr.c \
+ upstream-openbsd/lib/libc/gen/verrx.c \
+ upstream-openbsd/lib/libc/gen/vwarn.c \
+ upstream-openbsd/lib/libc/gen/vwarnx.c \
+ upstream-openbsd/lib/libc/gen/warn.c \
+ upstream-openbsd/lib/libc/gen/warnx.c \
upstream-openbsd/lib/libc/locale/btowc.c \
upstream-openbsd/lib/libc/locale/mbrlen.c \
upstream-openbsd/lib/libc/locale/mbstowcs.c \
@@ -388,6 +399,7 @@ libc_upstream_openbsd_src_files := \
upstream-openbsd/lib/libc/stdio/fgetws.c \
upstream-openbsd/lib/libc/stdio/fileno.c \
upstream-openbsd/lib/libc/stdio/findfp.c \
+ upstream-openbsd/lib/libc/stdio/fmemopen.c \
upstream-openbsd/lib/libc/stdio/fprintf.c \
upstream-openbsd/lib/libc/stdio/fpurge.c \
upstream-openbsd/lib/libc/stdio/fputc.c \
@@ -416,6 +428,8 @@ libc_upstream_openbsd_src_files := \
upstream-openbsd/lib/libc/stdio/getwchar.c \
upstream-openbsd/lib/libc/stdio/makebuf.c \
upstream-openbsd/lib/libc/stdio/mktemp.c \
+ upstream-openbsd/lib/libc/stdio/open_memstream.c \
+ upstream-openbsd/lib/libc/stdio/open_wmemstream.c \
upstream-openbsd/lib/libc/stdio/perror.c \
upstream-openbsd/lib/libc/stdio/printf.c \
upstream-openbsd/lib/libc/stdio/putc.c \
@@ -635,8 +649,15 @@ LOCAL_SRC_FILES := \
$(call all-c-files-under,dns) \
upstream-netbsd/lib/libc/isc/ev_streams.c \
upstream-netbsd/lib/libc/isc/ev_timers.c \
+ upstream-netbsd/lib/libc/resolv/mtctxres.c \
-LOCAL_CFLAGS := \
+# We use the OpenBSD res_random.
+LOCAL_CFLAGS += \
+ -Dres_randomid=__res_randomid
+LOCAL_SRC_FILES += \
+ upstream-openbsd/lib/libc/net/res_random.c \
+
+LOCAL_CFLAGS += \
$(libc_common_cflags) \
-DANDROID_CHANGES \
-DINET6 \
@@ -807,6 +828,27 @@ include $(BUILD_STATIC_LIBRARY)
# ========================================================
+# libc_cxa.a - Things traditionally in libstdc++
+# ========================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(libc_cxa_src_files)
+LOCAL_CFLAGS := $(libc_common_cflags) \
+ -fvisibility=hidden \
+
+LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
+LOCAL_CPPFLAGS := $(libc_common_cppflags)
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+LOCAL_MODULE := libc_cxa
+LOCAL_CLANG := true # GCC refuses to hide new/delete
+LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
+LOCAL_SYSTEM_SHARED_LIBRARIES :=
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+# ========================================================
# libc_syscalls.a
# ========================================================
@@ -858,6 +900,7 @@ LOCAL_CLANG := $(use_clang)
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_WHOLE_STATIC_LIBRARIES := \
libc_bionic \
+ libc_cxa \
libc_dns \
libc_freebsd \
libc_gdtoa \
@@ -1046,7 +1089,6 @@ LOCAL_CPPFLAGS := $(libc_common_cppflags)
# Make sure that unwind.h comes from libunwind.
LOCAL_C_INCLUDES := \
- external/libunwind/include \
$(libc_common_c_includes) \
LOCAL_SRC_FILES := \
@@ -1062,7 +1104,9 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
LOCAL_SHARED_LIBRARIES := libc libdl
LOCAL_SYSTEM_SHARED_LIBRARIES :=
-LOCAL_WHOLE_STATIC_LIBRARIES := libunwindbacktrace
+# Only need this for arm since libc++ uses its own unwind code that
+# doesn't mix with the other default unwind code.
+LOCAL_STATIC_LIBRARIES_arm := libc++
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
# Don't install on release build
@@ -1105,6 +1149,36 @@ include $(BUILD_SHARED_LIBRARY)
endif #!user
+# ========================================================
+# libstdc++.so
+# ========================================================
+libstdcxx_common_src_files := \
+ bionic/__cxa_guard.cpp \
+ bionic/__cxa_pure_virtual.cpp \
+ bionic/new.cpp \
+ bionic/libc_logging.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+LOCAL_CFLAGS := $(libc_common_cflags)
+LOCAL_SRC_FILES := $(libstdcxx_common_src_files)
+LOCAL_MODULE:= libstdc++
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
+include $(BUILD_SHARED_LIBRARY)
+
+# ========================================================
+# libstdc++.a
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+LOCAL_CFLAGS := $(libc_common_cflags)
+LOCAL_SRC_FILES := $(libstdcxx_common_src_files)
+LOCAL_MODULE:= libstdc++
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
+include $(BUILD_STATIC_LIBRARY)
+
# ========================================================
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 38ae8310a..bfa13b701 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -315,7 +315,7 @@ int __set_tls:__ARM_NR_set_tls(void*) arm
int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm
# MIPS-specific
-int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips,mips64
+int _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
int __set_tls:set_thread_area(void*) mips,mips64
# x86-specific
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index 00be4aed5..70cc8eba6 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -53,7 +53,6 @@ libc_bionic_src_files_arm += \
arch-arm/bionic/atomics_arm.c \
arch-arm/bionic/__bionic_clone.S \
arch-arm/bionic/_exit_with_stack_teardown.S \
- arch-arm/bionic/__get_sp.S \
arch-arm/bionic/libgcc_compat.c \
arch-arm/bionic/memcmp.S \
arch-arm/bionic/_setjmp.S \
diff --git a/libc/arch-arm/bionic/sigsetjmp.S b/libc/arch-arm/bionic/sigsetjmp.S
index f9e30eed8..6a25a1216 100644
--- a/libc/arch-arm/bionic/sigsetjmp.S
+++ b/libc/arch-arm/bionic/sigsetjmp.S
@@ -33,8 +33,6 @@
* SUCH DAMAGE.
*/
-#define _ALIGN_TEXT .align 0
-
#include <private/bionic_asm.h>
#include <machine/setjmp.h>
diff --git a/libc/arch-arm/include/machine/asm.h b/libc/arch-arm/include/machine/asm.h
index 88d16f950..70dbe67f2 100644
--- a/libc/arch-arm/include/machine/asm.h
+++ b/libc/arch-arm/include/machine/asm.h
@@ -38,9 +38,7 @@
#ifndef _ARM32_ASM_H_
#define _ARM32_ASM_H_
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 0
-#endif
+#define __bionic_asm_align 0
#undef __bionic_asm_custom_entry
#undef __bionic_asm_custom_end
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index ed991ce60..6c4f6a6e8 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -29,7 +29,6 @@ libc_common_src_files_arm64 += \
libc_bionic_src_files_arm64 := \
arch-arm64/bionic/__bionic_clone.S \
arch-arm64/bionic/_exit_with_stack_teardown.S \
- arch-arm64/bionic/__get_sp.S \
arch-arm64/bionic/__rt_sigreturn.S \
arch-arm64/bionic/_setjmp.S \
arch-arm64/bionic/setjmp.S \
diff --git a/libc/arch-arm64/include/machine/asm.h b/libc/arch-arm64/include/machine/asm.h
index 31b5c63ea..2bea043e9 100644
--- a/libc/arch-arm64/include/machine/asm.h
+++ b/libc/arch-arm64/include/machine/asm.h
@@ -38,9 +38,7 @@
#ifndef _AARCH64_ASM_H_
#define _AARCH64_ASM_H_
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 0
-#endif
+#define __bionic_asm_align 0
#undef __bionic_asm_function_type
#define __bionic_asm_function_type %function
diff --git a/libc/arch-mips/include/machine/asm.h b/libc/arch-mips/include/machine/asm.h
index 5eacde3df..cdc79143a 100644
--- a/libc/arch-mips/include/machine/asm.h
+++ b/libc/arch-mips/include/machine/asm.h
@@ -28,9 +28,7 @@
#ifndef _MIPS64_ASM_H
#define _MIPS64_ASM_H
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 4
-#endif
+#define __bionic_asm_align 4
#undef __bionic_asm_custom_entry
#undef __bionic_asm_custom_end
diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk
index 8e415f957..31a1f32fd 100644
--- a/libc/arch-mips/mips.mk
+++ b/libc/arch-mips/mips.mk
@@ -54,7 +54,6 @@ libc_bionic_src_files_mips += \
arch-mips/bionic/bzero.S \
arch-mips/bionic/cacheflush.cpp \
arch-mips/bionic/_exit_with_stack_teardown.S \
- arch-mips/bionic/__get_sp.S \
arch-mips/bionic/_setjmp.S \
arch-mips/bionic/setjmp.S \
arch-mips/bionic/sigsetjmp.S \
diff --git a/libc/arch-mips/string/mips_strlen.c b/libc/arch-mips/string/mips_strlen.c
index 9fb7e6a85..45fc4b4bd 100644
--- a/libc/arch-mips/string/mips_strlen.c
+++ b/libc/arch-mips/string/mips_strlen.c
@@ -30,6 +30,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <string.h>
#include "mips-string-ops.h"
#define do_strlen_word(__av) {\
@@ -47,8 +48,8 @@
#define strlen my_strlen
#endif
-int
-strlen (const void *_a)
+size_t
+strlen (const char *_a)
{
int cnt = 0;
unsigned x;
diff --git a/libc/arch-mips64/bionic/__get_sp.S b/libc/arch-mips64/bionic/__get_sp.S
deleted file mode 100644
index 5f5d32ef7..000000000
--- a/libc/arch-mips64/bionic/__get_sp.S
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY_PRIVATE(__get_sp)
- move v0, sp
- j ra
-END(__get_sp)
diff --git a/libc/arch-mips64/bionic/syscall.S b/libc/arch-mips64/bionic/syscall.S
index c4fd00995..e3710f8ce 100644
--- a/libc/arch-mips64/bionic/syscall.S
+++ b/libc/arch-mips64/bionic/syscall.S
@@ -52,7 +52,7 @@ LEAF(syscall,FRAMESZ)
#else
move a3, a4
move a4, a5
- REG_L a5, FRAMESZ(sp)
+ move a5, a6
#endif
syscall
move a0, v0
diff --git a/libc/arch-mips64/include/machine/asm.h b/libc/arch-mips64/include/machine/asm.h
index 5eacde3df..cdc79143a 100644
--- a/libc/arch-mips64/include/machine/asm.h
+++ b/libc/arch-mips64/include/machine/asm.h
@@ -28,9 +28,7 @@
#ifndef _MIPS64_ASM_H
#define _MIPS64_ASM_H
-#ifndef _ALIGN_TEXT
-# define _ALIGN_TEXT .align 4
-#endif
+#define __bionic_asm_align 4
#undef __bionic_asm_custom_entry
#undef __bionic_asm_custom_end
diff --git a/libc/arch-mips64/syscalls/_flush_cache.S b/libc/arch-mips64/syscalls/_flush_cache.S
deleted file mode 100644
index 997ccecb0..000000000
--- a/libc/arch-mips64/syscalls/_flush_cache.S
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
- .hidden __set_errno
-
-ENTRY(_flush_cache)
- .set push
- .set noreorder
- li v0, __NR_cacheflush
- syscall
- bnez a3, 1f
- move a0, v0
- j ra
- nop
-1:
- move t0, ra
- bal 2f
- nop
-2:
- .cpsetup ra, t1, 2b
- LA t9,__set_errno
- .cpreturn
- j t9
- move ra, t0
- .set pop
-END(_flush_cache)
diff --git a/libc/arch-x86/atom/string/sse2-wcslen-atom.S b/libc/arch-x86/atom/string/sse2-wcslen-atom.S
index 6a6ad519e..2f10db450 100644
--- a/libc/arch-x86/atom/string/sse2-wcslen-atom.S
+++ b/libc/arch-x86/atom/string/sse2-wcslen-atom.S
@@ -65,21 +65,21 @@ name: \
ENTRY (wcslen)
mov STR(%esp), %edx
#endif
- cmp $0, (%edx)
+ cmpl $0, (%edx)
jz L(exit_tail0)
- cmp $0, 4(%edx)
+ cmpl $0, 4(%edx)
jz L(exit_tail1)
- cmp $0, 8(%edx)
+ cmpl $0, 8(%edx)
jz L(exit_tail2)
- cmp $0, 12(%edx)
+ cmpl $0, 12(%edx)
jz L(exit_tail3)
- cmp $0, 16(%edx)
+ cmpl $0, 16(%edx)
jz L(exit_tail4)
- cmp $0, 20(%edx)
+ cmpl $0, 20(%edx)
jz L(exit_tail5)
- cmp $0, 24(%edx)
+ cmpl $0, 24(%edx)
jz L(exit_tail6)
- cmp $0, 28(%edx)
+ cmpl $0, 28(%edx)
jz L(exit_tail7)
pxor %xmm0, %xmm0
diff --git a/libc/arch-x86/bionic/__get_sp.S b/libc/arch-x86/bionic/__get_sp.S
deleted file mode 100644
index aea6ac62c..000000000
--- a/libc/arch-x86/bionic/__get_sp.S
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY_PRIVATE(__get_sp)
- mov %esp, %eax
- ret
-END(__get_sp)
diff --git a/libc/arch-x86/include/machine/asm.h b/libc/arch-x86/include/machine/asm.h
index 672493d5d..943f9dd54 100644
--- a/libc/arch-x86/include/machine/asm.h
+++ b/libc/arch-x86/include/machine/asm.h
@@ -49,15 +49,6 @@
#define PIC_GOT(x) x@GOT(%ebx)
#define PIC_GOTOFF(x) x@GOTOFF(%ebx)
-/* let kernels and others override entrypoint alignment */
-#if !defined(_ALIGN_TEXT) && !defined(_KERNEL)
-# ifdef _STANDALONE
-# define _ALIGN_TEXT .align 1
-# elif defined __ELF__
-# define _ALIGN_TEXT .align 16
-# else
-# define _ALIGN_TEXT .align 4
-# endif
-#endif
+#define __bionic_asm_align 16
#endif /* !_I386_ASM_H_ */
diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk
index 019dc8e81..a14154866 100644
--- a/libc/arch-x86/x86.mk
+++ b/libc/arch-x86/x86.mk
@@ -25,7 +25,6 @@ libc_bionic_src_files_x86 := \
libc_bionic_src_files_x86 += \
arch-x86/bionic/__bionic_clone.S \
arch-x86/bionic/_exit_with_stack_teardown.S \
- arch-x86/bionic/__get_sp.S \
arch-x86/bionic/_setjmp.S \
arch-x86/bionic/setjmp.S \
arch-x86/bionic/__set_tls.c \
diff --git a/libc/arch-x86_64/bionic/__get_sp.S b/libc/arch-x86_64/bionic/__get_sp.S
deleted file mode 100644
index 49a2406e7..000000000
--- a/libc/arch-x86_64/bionic/__get_sp.S
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY_PRIVATE(__get_sp)
- mov %rsp, %rax
- ret
-END(__get_sp)
diff --git a/libc/arch-x86_64/include/machine/asm.h b/libc/arch-x86_64/include/machine/asm.h
index 06da39aae..28cd08f93 100644
--- a/libc/arch-x86_64/include/machine/asm.h
+++ b/libc/arch-x86_64/include/machine/asm.h
@@ -40,13 +40,6 @@
#define PIC_PLT(x) x@PLT
#define PIC_GOT(x) x@GOTPCREL(%rip)
-/* let kernels and others override entrypoint alignment */
-#ifndef _ALIGN_TEXT
-# ifdef _STANDALONE
-# define _ALIGN_TEXT .align 4
-# else
-# define _ALIGN_TEXT .align 16
-# endif
-#endif
+#define __bionic_asm_align 16
#endif /* !_AMD64_ASM_H_ */
diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk
index 7887c519e..b001b5e98 100644
--- a/libc/arch-x86_64/x86_64.mk
+++ b/libc/arch-x86_64/x86_64.mk
@@ -30,7 +30,6 @@ libc_common_src_files_x86_64 += \
libc_bionic_src_files_x86_64 := \
arch-x86_64/bionic/__bionic_clone.S \
arch-x86_64/bionic/_exit_with_stack_teardown.S \
- arch-x86_64/bionic/__get_sp.S \
arch-x86_64/bionic/__rt_sigreturn.S \
arch-x86_64/bionic/_setjmp.S \
arch-x86_64/bionic/setjmp.S \
diff --git a/libc/arch-arm64/bionic/__get_sp.S b/libc/bionic/__gnu_basename.cpp
index d5e88e973..1eb3f6594 100644
--- a/libc/arch-arm64/bionic/__get_sp.S
+++ b/libc/bionic/__gnu_basename.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,10 @@
* SUCH DAMAGE.
*/
-#include <private/bionic_asm.h>
+#define _GNU_SOURCE 1
+#include <string.h>
-ENTRY_PRIVATE(__get_sp)
- mov x0, sp
- ret
-END(__get_sp)
+extern "C" const char* __gnu_basename(const char* path) {
+ const char* last_slash = strrchr(path, '/');
+ return (last_slash != NULL) ? last_slash + 1 : path;
+}
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index b8e892e72..f5be41553 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -74,7 +74,7 @@ ScopedTrace::ScopedTrace(const char* message) {
}
if (g_trace_marker_fd == -1) {
- g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+ g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
if (g_trace_marker_fd == -1) {
__libc_fatal("Could not open kernel trace file: %s\n", strerror(errno));
}
diff --git a/libc/bionic/clone.cpp b/libc/bionic/clone.cpp
index 0a0fdd526..9b5c9e7ae 100644
--- a/libc/bionic/clone.cpp
+++ b/libc/bionic/clone.cpp
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-#define __GNU_SOURCE 1
+#define _GNU_SOURCE 1
#include <sched.h>
#include <stdlib.h>
#include <stdarg.h>
diff --git a/libc/bionic/daemon.c b/libc/bionic/daemon.c
deleted file mode 100644
index 8181d169b..000000000
--- a/libc/bionic/daemon.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int daemon( int nochdir, int noclose )
-{
- pid_t pid;
-
- if ( !nochdir && chdir("/") != 0 )
- return -1;
-
- if ( !noclose )
- {
- int fd = open("/dev/null", O_RDWR);
-
- if ( fd < 0 )
- return -1;
-
- if ( dup2( fd, 0 ) < 0 ||
- dup2( fd, 1 ) < 0 ||
- dup2( fd, 2 ) < 0 )
- {
- close(fd);
- return -1;
- }
- close(fd);
- }
-
- pid = fork();
- if (pid < 0)
- return -1;
-
- if (pid > 0)
- _exit(0);
-
- if ( setsid() < 0 )
- return -1;
-
- return 0;
-}
-
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index d83799afa..698ab6b87 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -71,7 +71,7 @@ __LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) {
struct mapinfo_t* milist = NULL;
char data[1024]; // Used to read lines as well as to construct the filename.
snprintf(data, sizeof(data), "/proc/%d/maps", pid);
- FILE* fp = fopen(data, "r");
+ FILE* fp = fopen(data, "re");
if (fp != NULL) {
while (fgets(data, sizeof(data), fp) != NULL) {
mapinfo_t* mi = parse_maps_line(data);
diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp
index 7abc7f3ec..5e1c7a565 100644
--- a/libc/bionic/dirent.cpp
+++ b/libc/bionic/dirent.cpp
@@ -78,7 +78,7 @@ DIR* fdopendir(int fd) {
}
DIR* opendir(const char* path) {
- int fd = open(path, O_RDONLY | O_DIRECTORY);
+ int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
return (fd != -1) ? __allocate_DIR(fd) : NULL;
}
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index e89c5d1ff..5853e7c1b 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -16,6 +16,7 @@
#include "dlmalloc.h"
+#include "malloc.h"
#include "private/bionic_prctl.h"
#include "private/libc_logging.h"
@@ -54,3 +55,25 @@ static void* named_anonymous_mmap(size_t length) {
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, length, "libc_malloc");
return map;
}
+
+// Since dlmalloc isn't the default, we'll leave this unimplemented for now. If
+// we decide we need it later, we can fill it in.
+size_t __mallinfo_narenas() {
+ return 0;
+}
+
+size_t __mallinfo_nbins() {
+ return 0;
+}
+
+struct mallinfo __mallinfo_arena_info(size_t aidx __unused) {
+ struct mallinfo mi;
+ memset(&mi, 0, sizeof(mi));
+ return mi;
+}
+
+struct mallinfo __mallinfo_bin_info(size_t aidx __unused, size_t bidx __unused) {
+ struct mallinfo mi;
+ memset(&mi, 0, sizeof(mi));
+ return mi;
+}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index ff9940ef7..2a6a03b5d 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -36,7 +36,6 @@
#include <stdlib.h>
#include <sys/auxv.h>
#include <sys/time.h>
-#include <sys/resource.h>
#include <unistd.h>
#include "private/bionic_auxv.h"
@@ -46,7 +45,6 @@
#include "pthread_internal.h"
extern "C" abort_msg_t** __abort_message_ptr;
-extern "C" uintptr_t __get_sp(void);
extern "C" int __system_properties_init(void);
extern "C" int __set_tls(void* ptr);
extern "C" int __set_tid_address(int* tid_address);
@@ -62,17 +60,6 @@ char** environ;
// Declared in "private/bionic_ssp.h".
uintptr_t __stack_chk_guard = 0;
-static size_t get_main_thread_stack_size() {
- rlimit stack_limit;
- int rlimit_result = getrlimit(RLIMIT_STACK, &stack_limit);
- if ((rlimit_result == 0) &&
- (stack_limit.rlim_cur != RLIM_INFINITY) &&
- (stack_limit.rlim_cur > PTHREAD_STACK_MIN)) {
- return (stack_limit.rlim_cur & ~(PAGE_SIZE - 1));
- }
- return PTHREAD_STACK_SIZE_DEFAULT;
-}
-
/* 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.
@@ -96,16 +83,15 @@ void __libc_init_tls(KernelArgumentBlock& args) {
main_thread.tid = __set_tid_address(&main_thread.tid);
main_thread.set_cached_pid(main_thread.tid);
- // Work out the extent of the main thread's stack.
- uintptr_t stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
- size_t stack_size = get_main_thread_stack_size();
- void* stack_bottom = reinterpret_cast<void*>(stack_top - stack_size);
-
// We don't want to free the main thread's stack even when the main thread exits
// because things like environment variables with global scope live on it.
+ // We also can't free the pthread_internal_t itself, since that lives on the main
+ // thread's stack rather than on the heap.
pthread_attr_init(&main_thread.attr);
- pthread_attr_setstack(&main_thread.attr, stack_bottom, stack_size);
main_thread.attr.flags = PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK | PTHREAD_ATTR_FLAG_MAIN_THREAD;
+ main_thread.attr.guard_size = 0; // The main thread has no guard page.
+ main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked.
+ // TODO: the main thread's sched_policy and sched_priority need to be queried.
__init_thread(&main_thread, false);
__init_tls(&main_thread);
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index d0172edaa..49a37628f 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -29,6 +29,7 @@
#include "../private/libc_logging.h" // Relative path so we can #include this .cpp file for testing.
#include "../private/ScopedPthreadMutexLocker.h"
+#include <android/set_abort_message.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -74,10 +75,12 @@ struct BufferOutputStream {
len = strlen(data);
}
+ total += len;
+
while (len > 0) {
int avail = end_ - pos_;
if (avail == 0) {
- break;
+ return;
}
if (avail > len) {
avail = len;
@@ -86,11 +89,10 @@ struct BufferOutputStream {
pos_ += avail;
pos_[0] = '\0';
len -= avail;
- total += avail;
}
}
- int total;
+ size_t total;
private:
char* buffer_;
@@ -108,18 +110,19 @@ struct FdOutputStream {
len = strlen(data);
}
+ total += len;
+
while (len > 0) {
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
if (rc == -1) {
- break;
+ return;
}
data += rc;
len -= rc;
- total += rc;
}
}
- int total;
+ size_t total;
private:
int fd_;
@@ -629,7 +632,7 @@ static void __libc_fatal(const char* format, va_list args) {
// Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
__libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
- __android_set_abort_message(msg);
+ android_set_abort_message(msg);
}
void __libc_fatal_no_abort(const char* format, ...) {
@@ -647,7 +650,7 @@ void __libc_fatal(const char* format, ...) {
abort();
}
-void __android_set_abort_message(const char* msg) {
+void android_set_abort_message(const char* msg) {
ScopedPthreadMutexLocker locker(&g_abort_msg_lock);
if (__abort_message_ptr == NULL) {
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 4c3fd7f31..ddb49ce6f 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -92,7 +92,7 @@ static void __locale_init() {
g_locale.int_n_sign_posn = CHAR_MAX;
}
-size_t __mb_cur_max() {
+size_t __ctype_get_mb_cur_max() {
locale_t l = reinterpret_cast<locale_t>(pthread_getspecific(g_uselocale_key));
if (l == nullptr || l == LC_GLOBAL_LOCALE) {
return __bionic_current_locale_is_utf8 ? 4 : 1;
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 837dccc5a..df0f997e5 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -385,6 +385,36 @@ extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
return ptr;
}
+extern "C" size_t leak_malloc_usable_size(const void* mem) {
+ if (DebugCallsDisabled()) {
+ return g_malloc_dispatch->malloc_usable_size(mem);
+ }
+
+ if (mem == NULL) {
+ return 0;
+ }
+
+ // Check the guard to make sure it is valid.
+ const AllocationEntry* header = const_to_header(mem);
+
+ if (header->guard == MEMALIGN_GUARD) {
+ // If this is a memalign'd pointer, then grab the header from
+ // entry.
+ header = const_to_header(header->entry);
+ } else if (header->guard != GUARD) {
+ debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
+ header->guard, header->entry);
+ return 0;
+ }
+
+ size_t ret = g_malloc_dispatch->malloc_usable_size(header);
+ if (ret != 0) {
+ // The usable area starts at 'mem' and stops at 'header+ret'.
+ return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem);
+ }
+ return 0;
+}
+
extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
if (DebugCallsDisabled()) {
return g_malloc_dispatch->realloc(oldMem, bytes);
@@ -408,7 +438,7 @@ extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
newMem = leak_malloc(bytes);
if (newMem != NULL) {
- size_t oldSize = header->entry->size & ~SIZE_FLAG_MASK;
+ size_t oldSize = leak_malloc_usable_size(oldMem);
size_t copySize = (oldSize <= bytes) ? oldSize : bytes;
memcpy(newMem, oldMem, copySize);
leak_free(oldMem);
@@ -462,34 +492,6 @@ extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
return base;
}
-extern "C" size_t leak_malloc_usable_size(const void* mem) {
- if (DebugCallsDisabled()) {
- return g_malloc_dispatch->malloc_usable_size(mem);
- }
-
- if (mem != NULL) {
- // Check the guard to make sure it is valid.
- const AllocationEntry* header = const_to_header((void*)mem);
-
- if (header->guard == MEMALIGN_GUARD) {
- // If this is a memalign'd pointer, then grab the header from
- // entry.
- header = const_to_header(header->entry);
- } else if (header->guard != GUARD) {
- debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
- header->guard, header->entry);
- return 0;
- }
-
- size_t ret = g_malloc_dispatch->malloc_usable_size(header);
- if (ret != 0) {
- // The usable area starts at 'mem' and stops at 'header+ret'.
- return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem);
- }
- }
- return 0;
-}
-
extern "C" struct mallinfo leak_mallinfo() {
return g_malloc_dispatch->mallinfo();
}
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index b3b604d86..2f4949b12 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -606,7 +606,7 @@ extern "C" bool malloc_debug_initialize(HashTable*, const MallocDebug* malloc_di
* the memory mapped spaces into writes to an I/O port that emulator
* "listens to" on the other end. Note that until we open and map that
* device, logging to emulator's stdout will not be available. */
- int fd = open("/dev/qemu_trace", O_RDWR);
+ int fd = open("/dev/qemu_trace", O_CLOEXEC | O_RDWR);
if (fd < 0) {
error_log("Unable to open /dev/qemu_trace");
return false;
diff --git a/libc/bionic/malloc_info.cpp b/libc/bionic/malloc_info.cpp
new file mode 100644
index 000000000..99caedbad
--- /dev/null
+++ b/libc/bionic/malloc_info.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "malloc_info.h"
+
+#include <errno.h>
+#include "private/bionic_macros.h"
+
+class __LIBC_HIDDEN__ Elem {
+public:
+ // name must be valid throughout lifetime of the object.
+ explicit Elem(FILE* fp, const char* name,
+ const char* attr_fmt = nullptr, ...) {
+ this->fp = fp;
+ this->name = name;
+
+ fprintf(fp, "<%s", name);
+ if (attr_fmt != nullptr) {
+ va_list args;
+ va_start(args, attr_fmt);
+ fputc(' ', fp);
+ vfprintf(fp, attr_fmt, args);
+ va_end(args);
+ }
+ fputc('>', fp);
+ }
+
+ ~Elem() noexcept {
+ fprintf(fp, "</%s>", name);
+ }
+
+ void contents(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(fp, fmt, args);
+ va_end(args);
+ }
+
+private:
+ FILE* fp;
+ const char* name;
+
+ DISALLOW_COPY_AND_ASSIGN(Elem);
+};
+
+int malloc_info(int options, FILE* fp) {
+ if (options != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ Elem root(fp, "malloc", "version=\"jemalloc-1\"");
+
+ // Dump all of the large allocations in the arenas.
+ for (size_t i = 0; i < __mallinfo_narenas(); i++) {
+ struct mallinfo mi = __mallinfo_arena_info(i);
+ if (mi.hblkhd != 0) {
+ Elem arena_elem(fp, "heap", "nr=\"%d\"", i);
+ {
+ Elem(fp, "allocated-large").contents("%zu", mi.ordblks);
+ Elem(fp, "allocated-huge").contents("%zu", mi.uordblks);
+ Elem(fp, "allocated-bins").contents("%zu", mi.fsmblks);
+
+ size_t total = 0;
+ for (size_t j = 0; j < __mallinfo_nbins(); j++) {
+ struct mallinfo mi = __mallinfo_bin_info(i, j);
+ if (mi.ordblks != 0) {
+ Elem bin_elem(fp, "bin", "nr=\"%d\"", j);
+ Elem(fp, "allocated").contents("%zu", mi.ordblks);
+ Elem(fp, "nmalloc").contents("%zu", mi.uordblks);
+ Elem(fp, "ndalloc").contents("%zu", mi.fordblks);
+ total += mi.ordblks;
+ }
+ }
+ Elem(fp, "bins-total").contents("%zu", total);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/libc/bionic/malloc_info.h b/libc/bionic/malloc_info.h
new file mode 100644
index 000000000..5fffae980
--- /dev/null
+++ b/libc/bionic/malloc_info.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBC_BIONIC_MALLOC_INFO_H_
+#define LIBC_BIONIC_MALLOC_INFO_H_
+
+#include <malloc.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+__LIBC_HIDDEN__ size_t __mallinfo_narenas();
+__LIBC_HIDDEN__ size_t __mallinfo_nbins();
+__LIBC_HIDDEN__ struct mallinfo __mallinfo_arena_info(size_t);
+__LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t);
+
+__END_DECLS
+
+#endif // LIBC_BIONIC_MALLOC_INFO_H_
diff --git a/libc/bionic/new.cpp b/libc/bionic/new.cpp
index fcfd1bdf5..cd84c2e30 100644
--- a/libc/bionic/new.cpp
+++ b/libc/bionic/new.cpp
@@ -38,11 +38,11 @@ void* operator new[](std::size_t size) {
return p;
}
-void operator delete(void* ptr) {
+void operator delete(void* ptr) throw() {
free(ptr);
}
-void operator delete[](void* ptr) {
+void operator delete[](void* ptr) throw() {
free(ptr);
}
@@ -54,10 +54,10 @@ void* operator new[](std::size_t size, const std::nothrow_t&) {
return malloc(size);
}
-void operator delete(void* ptr, const std::nothrow_t&) {
+void operator delete(void* ptr, const std::nothrow_t&) throw() {
free(ptr);
}
-void operator delete[](void* ptr, const std::nothrow_t&) {
+void operator delete[](void* ptr, const std::nothrow_t&) throw() {
free(ptr);
}
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index e1cd85365..c93970a19 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -28,6 +28,13 @@
#include <pthread.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/resource.h>
+
+#include "private/bionic_string_utils.h"
+#include "private/ErrnoRestorer.h"
+#include "private/libc_logging.h"
#include "pthread_internal.h"
int pthread_attr_init(pthread_attr_t* attr) {
@@ -90,8 +97,8 @@ int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) {
}
int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) {
- *stack_size = attr->stack_size;
- return 0;
+ void* unused;
+ return pthread_attr_getstack(attr, &unused, stack_size);
}
int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_size) {
@@ -106,7 +113,43 @@ int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_s
return 0;
}
+static int __pthread_attr_getstack_main_thread(void** stack_base, size_t* stack_size) {
+ ErrnoRestorer errno_restorer;
+
+ rlimit stack_limit;
+ if (getrlimit(RLIMIT_STACK, &stack_limit) == -1) {
+ return errno;
+ }
+
+ // If the current RLIMIT_STACK is RLIM_INFINITY, only admit to an 8MiB stack for sanity's sake.
+ if (stack_limit.rlim_cur == RLIM_INFINITY) {
+ stack_limit.rlim_cur = 8 * 1024 * 1024;
+ }
+
+ // It doesn't matter which thread we are; we're just looking for "[stack]".
+ FILE* fp = fopen("/proc/self/maps", "re");
+ if (fp == NULL) {
+ return errno;
+ }
+ char line[BUFSIZ];
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (ends_with(line, " [stack]\n")) {
+ uintptr_t lo, hi;
+ if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) {
+ *stack_size = stack_limit.rlim_cur;
+ *stack_base = reinterpret_cast<void*>(hi - *stack_size);
+ fclose(fp);
+ return 0;
+ }
+ }
+ }
+ __libc_fatal("No [stack] line found in /proc/self/maps!");
+}
+
int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) {
+ if ((attr->flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) != 0) {
+ return __pthread_attr_getstack_main_thread(stack_base, stack_size);
+ }
*stack_base = attr->stack_base;
*stack_size = attr->stack_size;
return 0;
@@ -122,9 +165,8 @@ int pthread_attr_getguardsize(const pthread_attr_t* attr, size_t* guard_size) {
return 0;
}
-int pthread_getattr_np(pthread_t thid, pthread_attr_t* attr) {
- pthread_internal_t* thread = (pthread_internal_t*) thid;
- *attr = thread->attr;
+int pthread_getattr_np(pthread_t t, pthread_attr_t* attr) {
+ *attr = reinterpret_cast<pthread_internal_t*>(t)->attr;
return 0;
}
diff --git a/libc/bionic/pthread_setname_np.cpp b/libc/bionic/pthread_setname_np.cpp
index 1ddf81044..7b2fa6b0a 100644
--- a/libc/bionic/pthread_setname_np.cpp
+++ b/libc/bionic/pthread_setname_np.cpp
@@ -67,7 +67,7 @@ int pthread_setname_np(pthread_t t, const char* thread_name) {
}
char comm_name[sizeof(TASK_COMM_FMT) + 8];
snprintf(comm_name, sizeof(comm_name), TASK_COMM_FMT, tid);
- int fd = open(comm_name, O_WRONLY);
+ int fd = open(comm_name, O_CLOEXEC | O_WRONLY);
if (fd == -1) {
return errno;
}
diff --git a/libc/bionic/pututline.c b/libc/bionic/pututline.c
index c8427f720..8cbf47057 100644
--- a/libc/bionic/pututline.c
+++ b/libc/bionic/pututline.c
@@ -36,7 +36,7 @@ void pututline(struct utmp* utmp)
struct utmp u;
long i;
- if (!(f = fopen(_PATH_UTMP, "w+")))
+ if (!(f = fopen(_PATH_UTMP, "w+e")))
return;
while (fread(&u, sizeof(struct utmp), 1, f) == 1)
@@ -55,7 +55,7 @@ void pututline(struct utmp* utmp)
fclose(f);
- if (!(f = fopen(_PATH_UTMP, "w+")))
+ if (!(f = fopen(_PATH_UTMP, "w+e")))
return;
fwrite(utmp, sizeof(struct utmp), 1, f);
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 1e57cc0b3..d419fb109 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -1,11 +1,16 @@
/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
/* Public Domain <marc@snafu.org> */
+// G++ automatically defines _GNU_SOURCE, which then means that <string.h>
+// gives us the GNU variant.
+#undef _GNU_SOURCE
+
+#include <string.h>
+
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
-#include <string.h>
#include "private/ErrnoRestorer.h"
#include "private/libc_logging.h"
@@ -62,6 +67,12 @@ int strerror_r(int error_number, char* buf, size_t buf_len) {
return 0;
}
+extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) {
+ ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates...
+ strerror_r(error_number, buf, buf_len);
+ return buf; // ...and just returns whatever fit.
+}
+
extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
const char* signal_name = __strsignal_lookup(signal_number);
if (signal_name != NULL) {
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 8309f087a..d8aac4fe0 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -95,7 +95,7 @@ static int __sysconf_nprocessors_conf() {
}
static int __sysconf_nprocessors_onln() {
- FILE* fp = fopen("/proc/stat", "r");
+ FILE* fp = fopen("/proc/stat", "re");
if (fp == NULL) {
return 1;
}
@@ -118,7 +118,7 @@ static int __sysconf_nprocessors_onln() {
}
static int __get_meminfo(const char* pattern) {
- FILE* fp = fopen("/proc/meminfo", "r");
+ FILE* fp = fopen("/proc/meminfo", "re");
if (fp == NULL) {
return -1;
}
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 30081a59d..411d6bf34 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -201,14 +201,6 @@ static int map_prop_area_rw()
return -1;
}
- // TODO: Is this really required ? Does android run on any kernels that
- // don't support O_CLOEXEC ?
- const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
- if (ret < 0) {
- close(fd);
- return -1;
- }
-
if (ftruncate(fd, PA_SIZE) < 0) {
close(fd);
return -1;
@@ -271,18 +263,9 @@ static int map_fd_ro(const int fd) {
static int map_prop_area()
{
- int fd(open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
- if (fd >= 0) {
- /* For old kernels that don't support O_CLOEXEC */
- const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
- if (ret < 0) {
- close(fd);
- return -1;
- }
- }
-
+ int fd = open(property_filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
bool close_fd = true;
- if ((fd < 0) && (errno == ENOENT)) {
+ if (fd == -1 && errno == ENOENT) {
/*
* For backwards compatibility, if the file doesn't
* exist, we use the environment to get the file descriptor.
@@ -611,6 +594,14 @@ const prop_info *__system_property_find(const char *name)
return find_property(root_node(), name, strlen(name), NULL, 0, false);
}
+// The C11 standard doesn't allow atomic loads from const fields,
+// though C++11 does. Fudge it until standards get straightened out.
+static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s,
+ memory_order mo) {
+ atomic_uint_least32_t* non_const_s = const_cast<atomic_uint_least32_t*>(s);
+ return atomic_load_explicit(non_const_s, mo);
+}
+
int __system_property_read(const prop_info *pi, char *name, char *value)
{
if (__predict_false(compat_mode)) {
@@ -631,7 +622,7 @@ int __system_property_read(const prop_info *pi, char *name, char *value)
// would be any different, so this should be OK.
atomic_thread_fence(memory_order_acquire);
if (serial ==
- atomic_load_explicit(&(pi->serial), memory_order_relaxed)) {
+ load_const_atomic(&(pi->serial), memory_order_relaxed)) {
if (name != 0) {
strcpy(name, pi->name);
}
@@ -733,12 +724,12 @@ int __system_property_add(const char *name, unsigned int namelen,
// Wait for non-locked serial, and retrieve it with acquire semantics.
unsigned int __system_property_serial(const prop_info *pi)
{
- uint32_t serial = atomic_load_explicit(&pi->serial, memory_order_acquire);
+ uint32_t serial = load_const_atomic(&pi->serial, memory_order_acquire);
while (SERIAL_DIRTY(serial)) {
__futex_wait(const_cast<volatile void *>(
reinterpret_cast<const void *>(&pi->serial)),
serial, NULL);
- serial = atomic_load_explicit(&pi->serial, memory_order_acquire);
+ serial = load_const_atomic(&pi->serial, memory_order_acquire);
}
return serial;
}
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
index 80fdcbee1..cc33c612c 100644
--- a/libc/dns/gethnamaddr.c
+++ b/libc/dns/gethnamaddr.c
@@ -899,7 +899,7 @@ _sethtent(int f)
res_static rs = __res_get_static();
if (rs == NULL) return;
if (!rs->hostf)
- rs->hostf = fopen(_PATH_HOSTS, "r" );
+ rs->hostf = fopen(_PATH_HOSTS, "re" );
else
rewind(rs->hostf);
rs->stayopen = f;
@@ -925,7 +925,7 @@ _gethtent(void)
int af, len;
res_static rs = __res_get_static();
- if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
+ if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) {
h_errno = NETDB_INTERNAL;
return NULL;
}
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index 65fd1c197..a4923187e 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -2017,7 +2017,7 @@ _sethtent(FILE **hostf)
{
if (!*hostf)
- *hostf = fopen(_PATH_HOSTS, "r" );
+ *hostf = fopen(_PATH_HOSTS, "re");
else
rewind(*hostf);
}
@@ -2046,7 +2046,7 @@ _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
assert(name != NULL);
assert(pai != NULL);
- if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
+ if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
return (NULL);
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
diff --git a/libc/dns/net/services.h b/libc/dns/net/services.h
index fa199d084..7f748f79f 100644
--- a/libc/dns/net/services.h
+++ b/libc/dns/net/services.h
@@ -30,8 +30,8 @@ static const char _services[] = "\
\6tacacs\0\61u\0\
\12re-mail-ck\0\62t\0\
\12re-mail-ck\0\62u\0\
-\6domain\0\65t\1\12nameserver\
-\6domain\0\65u\1\12nameserver\
+\6domain\0\65t\0\
+\6domain\0\65u\0\
\3mtp\0\71t\0\
\11tacacs-ds\0\101t\0\
\11tacacs-ds\0\101u\0\
@@ -44,8 +44,8 @@ static const char _services[] = "\
\6gopher\0\106u\0\
\3rje\0\115t\1\6netrjs\
\6finger\0\117t\0\
-\3www\0\120t\1\4http\
-\3www\0\120u\0\
+\4http\0\120t\1\3www\
+\4http\0\120u\0\
\4link\0\127t\1\7ttylink\
\10kerberos\0\130t\3\11kerberos5\4krb5\14kerberos-sec\
\10kerberos\0\130u\3\11kerberos5\4krb5\14kerberos-sec\
@@ -138,12 +138,16 @@ static const char _services[] = "\
\4ldap\1\205u\0\
\4imsp\1\226t\0\
\4imsp\1\226u\0\
+\6svrloc\1\253t\0\
+\6svrloc\1\253u\0\
\5https\1\273t\0\
\5https\1\273u\0\
\4snpp\1\274t\0\
\4snpp\1\274u\0\
\14microsoft-ds\1\275t\0\
\14microsoft-ds\1\275u\0\
+\7kpasswd\1\320t\0\
+\7kpasswd\1\320u\0\
\4saft\1\347t\0\
\4saft\1\347u\0\
\6isakmp\1\364t\0\
@@ -158,6 +162,8 @@ static const char _services[] = "\
\10npmp-gui\2\143u\1\14dqs313_execd\
\10hmmp-ind\2\144t\1\20dqs313_intercell\
\10hmmp-ind\2\144u\1\20dqs313_intercell\
+\4qmqp\2\164t\0\
+\4qmqp\2\164u\0\
\3ipp\2\167t\0\
\3ipp\2\167u\0\
\4exec\2\0t\0\
@@ -181,8 +187,14 @@ static const char _services[] = "\
\4uucp\2\34t\1\5uucpd\
\6klogin\2\37t\0\
\6kshell\2\40t\1\5krcmd\
+\15dhcpv6-client\2\42t\0\
+\15dhcpv6-client\2\42u\0\
+\15dhcpv6-server\2\43t\0\
+\15dhcpv6-server\2\43u\0\
\12afpovertcp\2\44t\0\
\12afpovertcp\2\44u\0\
+\4idfp\2\45t\0\
+\4idfp\2\45u\0\
\10remotefs\2\54t\2\12rfs_server\3rfs\
\5nntps\2\63t\1\5snntp\
\5nntps\2\63u\1\5snntp\
@@ -239,19 +251,33 @@ static const char _services[] = "\
\13sa-msg-port\6\156u\1\13old-radacct\
\6kermit\6\161t\0\
\6kermit\6\161u\0\
+\11groupwise\6\215t\0\
+\11groupwise\6\215u\0\
\3l2f\6\245t\1\4l2tp\
\3l2f\6\245u\1\4l2tp\
\6radius\7\24t\0\
\6radius\7\24u\0\
\13radius-acct\7\25t\1\7radacct\
\13radius-acct\7\25u\1\7radacct\
+\4msnp\7\107t\0\
+\4msnp\7\107u\0\
\13unix-status\7\245t\0\
\12log-server\7\246t\0\
\12remoteping\7\247t\0\
+\12cisco-sccp\7\320t\0\
+\12cisco-sccp\7\320u\0\
+\6search\7\332t\1\4ndtp\
+\13pipe-server\7\332t\1\13pipe_server\
\3nfs\10\1t\0\
\3nfs\10\1u\0\
+\6gnunet\10\46t\0\
+\6gnunet\10\46u\0\
\12rtcm-sc104\10\65t\0\
\12rtcm-sc104\10\65u\0\
+\15gsigatekeeper\10\107t\0\
+\15gsigatekeeper\10\107u\0\
+\4gris\10\127t\0\
+\4gris\10\127u\0\
\12cvspserver\11\141t\0\
\12cvspserver\11\141u\0\
\5venus\11\176t\0\
@@ -266,10 +292,14 @@ static const char _services[] = "\
\3mon\12\27u\0\
\4dict\12\104t\0\
\4dict\12\104u\0\
+\15f5-globalsite\12\350t\0\
+\15f5-globalsite\12\350u\0\
+\6gsiftp\12\373t\0\
+\6gsiftp\12\373u\0\
\4gpsd\13\203t\0\
\4gpsd\13\203u\0\
-\6gds_db\13\352t\0\
-\6gds_db\13\352u\0\
+\6gds-db\13\352t\1\6gds_db\
+\6gds-db\13\352u\1\6gds_db\
\5icpv2\14\72t\1\3icp\
\5icpv2\14\72u\1\3icp\
\5mysql\14\352t\0\
@@ -282,24 +312,49 @@ static const char _services[] = "\
\4daap\16\151u\0\
\3svn\16\152t\1\12subversion\
\3svn\16\152u\1\12subversion\
+\5suucp\17\277t\0\
+\5suucp\17\277u\0\
+\6sysrqd\17\376t\0\
+\6sysrqd\17\376u\0\
+\5sieve\20\136t\0\
+\4epmd\21\21t\0\
+\4epmd\21\21u\0\
+\6remctl\21\25t\0\
+\6remctl\21\25u\0\
+\11f5-iquery\21\1t\0\
+\11f5-iquery\21\1u\0\
\3iax\21\331t\0\
\3iax\21\331u\0\
+\3mtn\22\123t\0\
+\3mtn\22\123u\0\
\13radmin-port\23\43t\0\
\13radmin-port\23\43u\0\
\3rfe\23\212u\0\
\3rfe\23\212t\0\
+\4mmcc\23\272t\0\
+\4mmcc\23\272u\0\
\3sip\23\304t\0\
\3sip\23\304u\0\
\7sip-tls\23\305t\0\
\7sip-tls\23\305u\0\
+\3aol\24\106t\0\
+\3aol\24\106u\0\
\13xmpp-client\24\146t\1\15jabber-client\
\13xmpp-client\24\146u\1\15jabber-client\
\13xmpp-server\24\225t\1\15jabber-server\
\13xmpp-server\24\225u\1\15jabber-server\
\10cfengine\24\274t\0\
\10cfengine\24\274u\0\
+\4mdns\24\351t\0\
+\4mdns\24\351u\0\
\12postgresql\25\70t\1\10postgres\
\12postgresql\25\70u\1\10postgres\
+\7freeciv\25\264t\1\4rptp\
+\7freeciv\25\264u\0\
+\4amqp\26\50t\0\
+\4amqp\26\50u\0\
+\3ggz\26\70t\0\
+\3ggz\26\70u\0\
\3x11\27\160t\1\5x11-0\
\3x11\27\160u\1\5x11-0\
\5x11-1\27\161t\0\
@@ -320,6 +375,12 @@ static const char _services[] = "\
\14gnutella-svc\30\312u\0\
\14gnutella-rtr\30\313t\0\
\14gnutella-rtr\30\313u\0\
+\13sge-qmaster\31\54t\1\13sge_qmaster\
+\13sge-qmaster\31\54u\1\13sge_qmaster\
+\11sge-execd\31\55t\1\11sge_execd\
+\11sge-execd\31\55u\1\11sge_execd\
+\13mysql-proxy\31\56t\0\
+\13mysql-proxy\31\56u\0\
\17afs3-fileserver\33\130t\1\3bbs\
\17afs3-fileserver\33\130u\1\3bbs\
\15afs3-callback\33\131t\0\
@@ -342,12 +403,21 @@ static const char _services[] = "\
\13afs3-rmtsys\33\141u\0\
\14font-service\33\274t\1\3xfs\
\14font-service\33\274u\1\3xfs\
+\10http-alt\37\220t\1\10webcache\
+\10http-alt\37\220u\0\
\12bacula-dir\43\215t\0\
\12bacula-dir\43\215u\0\
\11bacula-fd\43\216t\0\
\11bacula-fd\43\216u\0\
\11bacula-sd\43\217t\0\
\11bacula-sd\43\217u\0\
+\5xmms2\45\303t\0\
+\5xmms2\45\303u\0\
+\3nbd\52\71t\0\
+\14zabbix-agent\47\102t\0\
+\14zabbix-agent\47\102u\0\
+\16zabbix-trapper\47\103t\0\
+\16zabbix-trapper\47\103u\0\
\6amanda\47\140t\0\
\6amanda\47\140u\0\
\3hkp\54\153t\0\
@@ -364,16 +434,17 @@ static const char _services[] = "\
\4bpcd\65\326u\0\
\6vopied\65\327t\0\
\6vopied\65\327u\0\
+\4dcap\126\155t\0\
+\7gsidcap\126\160t\0\
\4wnn6\127\1t\0\
\4wnn6\127\1u\0\
\11kerberos4\2\356u\2\13kerberos-iv\3kdc\
\11kerberos4\2\356t\2\13kerberos-iv\3kdc\
-\17kerberos_master\2\357u\0\
-\17kerberos_master\2\357t\0\
-\15passwd_server\2\360u\0\
-\10krb_prop\2\362t\2\11krb5_prop\5hprop\
+\17kerberos-master\2\357u\1\17kerberos_master\
+\17kerberos-master\2\357t\0\
+\15passwd-server\2\360u\1\15passwd_server\
+\10krb-prop\2\362t\3\10krb_prop\11krb5_prop\5hprop\
\11krbupdate\2\370t\1\4kreg\
-\7kpasswd\2\371t\1\4kpwd\
\4swat\3\205t\0\
\4kpop\4\125t\0\
\5knetd\10\5t\0\
@@ -389,9 +460,9 @@ static const char _services[] = "\
\10poppassd\0\152t\0\
\10poppassd\0\152u\0\
\5ssmtp\1\321t\1\5smtps\
-\10moira_db\3\7t\0\
-\14moira_update\3\11t\0\
-\12moira_ureg\3\13u\0\
+\10moira-db\3\7t\1\10moira_db\
+\14moira-update\3\11t\1\14moira_update\
+\12moira-ureg\3\13u\1\12moira_ureg\
\5spamd\3\17t\0\
\5omirr\3\50t\1\6omirrd\
\5omirr\3\50u\1\6omirrd\
@@ -404,9 +475,7 @@ static const char _services[] = "\
\4xtel\5\41t\0\
\5xtelw\5\42t\0\
\7support\5\371t\0\
-\5sieve\7\320t\0\
\7cfinger\7\323t\0\
-\4ndtp\7\332t\0\
\4frox\10\111t\0\
\10ninstall\10\146t\0\
\10ninstall\10\146u\0\
@@ -436,9 +505,7 @@ static const char _services[] = "\
\7hostmon\24\353t\0\
\7hostmon\24\353u\0\
\5rplay\25\263u\0\
-\5rplay\25\263t\0\
-\4rptp\25\264u\0\
-\4rptp\25\264t\0\
+\4nrpe\26\42t\0\
\4nsca\26\43t\0\
\4mrtd\26\52t\0\
\6bgpsim\26\53t\0\
@@ -446,14 +513,15 @@ static const char _services[] = "\
\11sane-port\31\246t\2\4sane\5saned\
\4ircd\32\13t\0\
\10zope-ftp\37\125t\0\
-\10webcache\37\220t\0\
\6tproxy\37\221t\0\
\7omniorb\37\230t\0\
\7omniorb\37\230u\0\
\20clc-build-daemon\43\36t\0\
\6xinetd\43\212t\0\
\13mandelspawn\44\217u\1\12mandelbrot\
+\3git\44\312t\0\
\4zope\45\311t\0\
+\6webmin\47\20t\0\
\7kamanda\47\141t\0\
\7kamanda\47\141u\0\
\11amandaidx\47\142t\0\
@@ -473,6 +541,7 @@ static const char _services[] = "\
\5binkp\137\352t\0\
\3asp\152\356t\0\
\3asp\152\356u\0\
+\6csync2\170\221t\0\
\11dircproxy\336\250t\0\
\5tfido\353\21t\0\
\4fido\353\23t\0\
diff --git a/libc/dns/resolv/__dn_comp.c b/libc/dns/resolv/__dn_comp.c
deleted file mode 100644
index 93d3f1988..000000000
--- a/libc/dns/resolv/__dn_comp.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* $NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#if defined(__indr_reference)
-__indr_reference(__dn_comp,dn_comp)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
-#include <resolv.h>
-#endif
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef dn_comp
-int dn_comp(const char *, u_char *, int, u_char **, u_char **);
-
-int
-dn_comp(const char *exp_dn, u_char *comp_dn, u_char **dnptrs,
- u_char **lastdnptr, int length)
-{
-
- return __dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr);
-}
-
-#endif
diff --git a/libc/dns/resolv/__res_close.c b/libc/dns/resolv/__res_close.c
deleted file mode 100644
index 3af50b06b..000000000
--- a/libc/dns/resolv/__res_close.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* $NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif /* LIBC_SCCS and not lint */
-
-#if defined(__indr_reference)
-__indr_reference(__res_close, res_close)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include "resolv_private.h"
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef res_close
-void res_close(void);
-
-void
-res_close(void)
-{
-
- __res_close();
-}
-
-#endif
diff --git a/libc/dns/resolv/__res_send.c b/libc/dns/resolv/__res_send.c
deleted file mode 100644
index 198b05c12..000000000
--- a/libc/dns/resolv/__res_send.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */
-
-/*
- * written by matthew green, 22/04/97.
- * public domain.
- */
-
-#include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $");
-#endif
-
-#if defined(__indr_reference)
-__indr_reference(__res_send, res_send)
-#else
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#ifdef ANDROID_CHANGES
-#include "resolv_private.h"
-#else
-#include <resolv.h>
-#endif
-
-/* XXX THIS IS A MESS! SEE <resolv.h> XXX */
-
-#undef res_send
-int res_send(const u_char *, int, u_char *, int);
-
-int
-res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
-{
-
- return __res_send(buf, buflen, ans, anssiz);
-}
-
-#endif
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 77a1b4d19..0201aa8f1 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1436,7 +1436,7 @@ _dump_answer(const void* answer, int answerlen)
char* buf;
int fileLen;
- fp = fopen("/data/reslog.txt", "w+");
+ fp = fopen("/data/reslog.txt", "w+e");
if (fp != NULL) {
statep = __res_get_state();
diff --git a/libc/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c
index f1cbed8ac..713b6e015 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -289,7 +289,7 @@ __res_vinit(res_state statp, int preinit) {
line[sizeof(name) - 1] == '\t'))
nserv = 0;
- if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+ if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
/* read the config file */
while (fgets(buf, sizeof(buf), fp) != NULL) {
/* skip comments */
@@ -616,47 +616,6 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of thi
}
#endif
-#ifdef ANDROID_CHANGES
-static int
-real_randomid(u_int *random_value) {
- /* open the nonblocking random device, returning -1 on failure */
- int random_device = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
- if (random_device < 0) {
- return -1;
- }
-
- /* read from the random device, returning -1 on failure (or too many retries)*/
- for (u_int retry = 5; retry > 0; retry--) {
- int retval = read(random_device, random_value, sizeof(u_int));
- if (retval == sizeof(u_int)) {
- *random_value &= 0xffff;
- close(random_device);
- return 0;
- } else if ((retval < 0) && (errno != EINTR)) {
- break;
- }
- }
-
- close(random_device);
- return -1;
-}
-#endif /* ANDROID_CHANGES */
-
-u_int
-res_randomid(void) {
-#ifdef ANDROID_CHANGES
- int status = 0;
- u_int output = 0;
- status = real_randomid(&output);
- if (status != -1) {
- return output;
- }
-#endif /* ANDROID_CHANGES */
- struct timeval now;
- gettimeofday(&now, NULL);
- return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
-}
-
/*%
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it. This provides support for endhostent()
diff --git a/libc/arch-arm/bionic/__get_sp.S b/libc/include/android/set_abort_message.h
index 9ae6f247f..4b3d82b37 100644
--- a/libc/arch-arm/bionic/__get_sp.S
+++ b/libc/include/android/set_abort_message.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,15 @@
* SUCH DAMAGE.
*/
-#include <private/bionic_asm.h>
+#ifndef _SET_ABORT_MESSAGE_H
+#define _SET_ABORT_MESSAGE_H
-ENTRY_PRIVATE(__get_sp)
- mov r0, sp
- bx lr
-END(__get_sp)
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void android_set_abort_message(const char* msg);
+
+__END_DECLS
+
+#endif // _SET_ABORT_MESSAGE_H
diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h
index 067be1fe9..86265bf24 100644
--- a/libc/include/arpa/inet.h
+++ b/libc/include/arpa/inet.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _ARPA_INET_H_
#define _ARPA_INET_H_
@@ -34,8 +35,6 @@
__BEGIN_DECLS
-typedef uint32_t in_addr_t;
-
in_addr_t inet_addr(const char*);
int inet_aton(const char*, struct in_addr*);
in_addr_t inet_lnaof(struct in_addr);
diff --git a/libc/include/elf.h b/libc/include/elf.h
index faae73e92..7a9485aea 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -80,6 +80,4 @@ typedef struct {
#define STT_LOPROC 13
#define STT_HIPROC 15
-#define R_386_IRELATIVE 42
-
#endif /* _ELF_H */
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 4450bb65f..32557d958 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -82,9 +82,9 @@ extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);
#if defined(__BIONIC_FORTIFY)
extern int __open_2(const char*, int);
-extern int __open_real(const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "open");
+extern int __open_real(const char*, int, ...) __RENAME(open);
extern int __openat_2(int, const char*, int);
-extern int __openat_real(int, const char*, int, ...) __asm__(__USER_LABEL_PREFIX__ "openat");
+extern int __openat_real(int, const char*, int, ...) __RENAME(openat);
__errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
__errordecl(__creat_too_many_args, "too many arguments");
diff --git a/libc/include/features.h b/libc/include/features.h
index 343c84d2b..a279c7f0e 100644
--- a/libc/include/features.h
+++ b/libc/include/features.h
@@ -25,34 +25,11 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _FEATURES_H_
#define _FEATURES_H_
-/* certain Linux-specific programs expect a <features.h> header file
- * that defines various features macros
- */
-
-/* we do include a number of BSD extensions */
-#define _BSD_SOURCE 1
-
-/* we do include a number of GNU extensions */
-#define _GNU_SOURCE 1
-
-/* C95 support */
-#undef __USE_ISOC95
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L
-# define __USE_ISOC95 1
-#endif
-
-/* C99 support */
-#undef __USE_ISOC99
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
-# define __USE_ISOC99 1
-#endif
-
-/* Posix support */
-#define __USE_POSIX 1
-#define __USE_POSIX2 1
-#define __USE_XPG 1
+/* Our <features.h> macro fun is all in <sys/cdefs.h>. */
+#include <sys/cdefs.h>
#endif /* _FEATURES_H_ */
diff --git a/libc/include/libgen.h b/libc/include/libgen.h
index c5fc76a79..4caf8b9c5 100644
--- a/libc/include/libgen.h
+++ b/libc/include/libgen.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _LIBGEN_H
#define _LIBGEN_H
@@ -33,9 +34,18 @@
__BEGIN_DECLS
+#if !defined(__bionic_using_gnu_basename)
+/*
+ * <string.h> gets you the GNU basename.
+ * <libgen.h> the POSIX one.
+ * Note that our "POSIX" one has the wrong argument cv-qualifiers.
+ */
+extern char* basename(const char*);
+#define __bionic_using_posix_basename
+#endif
+
/* our version of dirname/basename don't modify the input path */
extern char* dirname (const char* path);
-extern char* basename(const char* path);
/* special thread-safe Bionic versions
*
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index e6ea27606..cb1dd3bcf 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -24,6 +24,7 @@
*/
#include <sys/cdefs.h>
#include <stddef.h>
+#include <stdio.h>
__BEGIN_DECLS
@@ -53,6 +54,27 @@ struct mallinfo {
extern struct mallinfo mallinfo(void);
+/*
+ * XML structure for malloc_info(3) is in the following format:
+ *
+ * <malloc version="jemalloc-1">
+ * <heap nr="INT">
+ * <allocated-large>INT</allocated-large>
+ * <allocated-huge>INT</allocated-huge>
+ * <allocated-bins>INT</allocated-bins>
+ * <bins-total>INT</bins-total>
+ * <bin nr="INT">
+ * <allocated>INT</allocated>
+ * <nmalloc>INT</nmalloc>
+ * <ndalloc>INT</ndalloc>
+ * </bin>
+ * <!-- more bins -->
+ * </heap>
+ * <!-- more heaps -->
+ * </malloc>
+ */
+extern int malloc_info(int, FILE *);
+
__END_DECLS
#endif /* LIBC_INCLUDE_MALLOC_H_ */
diff --git a/libc/include/netinet/in.h b/libc/include/netinet/in.h
index bf3b498c4..44c7fc1a6 100644
--- a/libc/include/netinet/in.h
+++ b/libc/include/netinet/in.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _NETINET_IN_H_
#define _NETINET_IN_H_
@@ -43,6 +44,9 @@ __BEGIN_DECLS
#define INET_ADDRSTRLEN 16
+typedef uint16_t in_port_t;
+typedef uint32_t in_addr_t;
+
extern int bindresvport (int sd, struct sockaddr_in *sin);
static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
diff --git a/libc/include/sched.h b/libc/include/sched.h
index e43b6ccaa..6155ab7ca 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -52,7 +52,7 @@ extern int sched_setparam(pid_t, const struct sched_param*);
extern int sched_getparam(pid_t, struct sched_param*);
extern int sched_rr_get_interval(pid_t, struct timespec*);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int clone(int (*)(void*), void*, int, void*, ...);
extern int unshare(int);
@@ -146,7 +146,7 @@ extern void __sched_cpufree(cpu_set_t* set);
extern int __sched_cpucount(size_t setsize, cpu_set_t* set);
-#endif /* _GNU_SOURCE */
+#endif /* __USE_GNU */
__END_DECLS
diff --git a/libc/include/stdatomic.h b/libc/include/stdatomic.h
index 669cefd66..3db25a78e 100644
--- a/libc/include/stdatomic.h
+++ b/libc/include/stdatomic.h
@@ -31,17 +31,142 @@
#define _STDATOMIC_H_
#include <sys/cdefs.h>
+
+
+#if defined(__cplusplus) && defined(_USING_LIBCXX)
+# ifdef __clang__
+# if __has_feature(cxx_atomic)
+# define _STDATOMIC_HAVE_ATOMIC
+# endif
+# else /* gcc */
+# if __GNUC_PREREQ(4, 7)
+# define _STDATOMIC_HAVE_ATOMIC
+# endif
+# endif
+#endif
+
+#ifdef _STDATOMIC_HAVE_ATOMIC
+
+/* We have a usable C++ <atomic>; use it instead. */
+
+#include <atomic>
+
+#undef _Atomic
+ /* Also defined by <atomic> for gcc. But not used in macros. */
+ /* Also a clang intrinsic. */
+ /* Should not be used by client code before this file is */
+ /* included. The definitions in <atomic> themselves see */
+ /* the old definition, as they should. */
+ /* Client code sees the following definition. */
+
+#define _Atomic(t) std::atomic<t>
+
+using std::atomic_is_lock_free;
+using std::atomic_init;
+using std::atomic_store;
+using std::atomic_store_explicit;
+using std::atomic_load;
+using std::atomic_load_explicit;
+using std::atomic_exchange;
+using std::atomic_exchange_explicit;
+using std::atomic_compare_exchange_strong;
+using std::atomic_compare_exchange_strong_explicit;
+using std::atomic_compare_exchange_weak;
+using std::atomic_compare_exchange_weak_explicit;
+using std::atomic_fetch_add;
+using std::atomic_fetch_add_explicit;
+using std::atomic_fetch_sub;
+using std::atomic_fetch_sub_explicit;
+using std::atomic_fetch_or;
+using std::atomic_fetch_or_explicit;
+using std::atomic_fetch_xor;
+using std::atomic_fetch_xor_explicit;
+using std::atomic_fetch_and;
+using std::atomic_fetch_and_explicit;
+using std::atomic_thread_fence;
+using std::atomic_signal_fence;
+
+using std::memory_order;
+using std::memory_order_relaxed;
+using std::memory_order_consume;
+using std::memory_order_release;
+using std::memory_order_acq_rel;
+using std::memory_order_seq_cst;
+
+using std::atomic_bool;
+using std::atomic_char;
+using std::atomic_schar;
+using std::atomic_uchar;
+using std::atomic_short;
+using std::atomic_ushort;
+using std::atomic_int;
+using std::atomic_uint;
+using std::atomic_long;
+using std::atomic_ulong;
+using std::atomic_llong;
+using std::atomic_ullong;
+using std::atomic_char16_t;
+using std::atomic_char32_t;
+using std::atomic_wchar_t;
+using std::atomic_int_least8_t;
+using std::atomic_uint_least8_t;
+using std::atomic_int_least16_t;
+using std::atomic_uint_least16_t;
+using std::atomic_int_least32_t;
+using std::atomic_uint_least32_t;
+using std::atomic_int_least64_t;
+using std::atomic_uint_least64_t;
+using std::atomic_int_fast8_t;
+using std::atomic_uint_fast8_t;
+using std::atomic_int_fast16_t;
+using std::atomic_uint_fast16_t;
+using std::atomic_int_fast32_t;
+using std::atomic_uint_fast32_t;
+using std::atomic_int_fast64_t;
+using std::atomic_uint_fast64_t;
+using std::atomic_intptr_t;
+using std::atomic_uintptr_t;
+using std::atomic_size_t;
+using std::atomic_ptrdiff_t;
+using std::atomic_intmax_t;
+using std::atomic_uintmax_t;
+
+#else /* <atomic> unavailable, possibly because this is C, not C++ */
+
#include <sys/types.h>
#include <stdbool.h>
-#if __has_extension(c_atomic) || __has_extension(cxx_atomic)
-#define __CLANG_ATOMICS
-#elif __GNUC_PREREQ__(4, 7)
-#define __GNUC_ATOMICS
-#elif defined(__GNUC__)
-#define __SYNC_ATOMICS
+/*
+ * C: Do it ourselves.
+ * Note that the runtime representation defined here should be compatible
+ * with the C++ one, i.e. an _Atomic(T) needs to contain the same
+ * bits as a T.
+ */
+
+#include <stddef.h> /* For ptrdiff_t. */
+#include <stdint.h> /* TODO: Should pollute namespace less. */
+#if __STDC_VERSION__ >= 201112L
+# include <uchar.h> /* For char16_t and char32_t. */
+#endif
+
+#ifdef __clang__
+# if __has_extension(c_atomic) || __has_extension(cxx_atomic)
+# define __CLANG_ATOMICS
+# else
+# error "stdatomic.h does not support your compiler"
+# endif
+# if __has_builtin(__sync_swap)
+# define __HAS_BUILTIN_SYNC_SWAP
+# endif
#else
-#error "stdatomic.h does not support your compiler"
+# if __GNUC_PREREQ(4, 7)
+# define __GNUC_ATOMICS
+# else
+# define __SYNC_ATOMICS
+# ifdef __cplusplus
+# define __ATOMICS_AVOID_DOT_INIT
+# endif
+# endif
#endif
/*
@@ -50,33 +175,53 @@
#ifdef __GCC_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_BOOL_LOCK_FREE 2 /* For all modern platforms */
#endif
#ifdef __GCC_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_CHAR_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_CHAR16_T_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_CHAR32_T_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_WCHAR_T_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_SHORT_LOCK_FREE
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_SHORT_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_INT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_INT_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_LONG_LOCK_FREE
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_LONG_LOCK_FREE 2
#endif
#ifdef __GCC_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_LLONG_LOCK_FREE 1 /* maybe */
#endif
#ifdef __GCC_ATOMIC_POINTER_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
+#elif defined(__SYNC_ATOMICS)
+#define ATOMIC_POINTER_LOCK_FREE 2
#endif
/*
@@ -87,7 +232,11 @@
#define ATOMIC_VAR_INIT(value) (value)
#define atomic_init(obj, value) __c11_atomic_init(obj, value)
#else
+#ifdef __ATOMICS_AVOID_DOT_INIT
+#define ATOMIC_VAR_INIT(value) { value }
+#else
#define ATOMIC_VAR_INIT(value) { .__val = (value) }
+#endif
#define atomic_init(obj, value) ((void)((obj)->__val = (value)))
#endif
@@ -121,6 +270,8 @@
*
* The memory_order_* constants that denote the barrier behaviour of the
* atomic operations.
+ * The enum values must be identical to those used by the
+ * C++ <atomic> header.
*/
typedef enum {
@@ -137,7 +288,7 @@ typedef enum {
*/
static __inline void
-atomic_thread_fence(memory_order __order __unused)
+atomic_thread_fence(memory_order __order __attribute__((unused)))
{
#ifdef __CLANG_ATOMICS
@@ -150,7 +301,7 @@ atomic_thread_fence(memory_order __order __unused)
}
static __inline void
-atomic_signal_fence(memory_order __order __unused)
+atomic_signal_fence(memory_order __order __attribute__((unused)))
{
#ifdef __CLANG_ATOMICS
@@ -172,7 +323,7 @@ atomic_signal_fence(memory_order __order __unused)
((void)(obj), (_Bool)1)
#elif defined(__CLANG_ATOMICS)
#define atomic_is_lock_free(obj) \
- __atomic_is_lock_free(sizeof(*(obj)), obj)
+ __c11_atomic_is_lock_free(sizeof(*(obj)))
#elif defined(__GNUC_ATOMICS)
#define atomic_is_lock_free(obj) \
__atomic_is_lock_free(sizeof((obj)->__val), &(obj)->__val)
@@ -185,7 +336,7 @@ atomic_signal_fence(memory_order __order __unused)
* 7.17.6 Atomic integer types.
*/
-#if !__has_extension(c_atomic) && !__has_extension(cxx_atomic)
+#ifndef __CLANG_ATOMICS
/*
* No native support for _Atomic(). Place object in structure to prevent
* most forms of direct non-atomic access.
@@ -306,7 +457,7 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
desired, success, failure) \
atomic_compare_exchange_strong_explicit(object, expected, \
desired, success, failure)
-#if __has_builtin(__sync_swap)
+#ifdef __HAS_BUILTIN_SYNC_SWAP
/* Clang provides a full-barrier atomic exchange - use it if available. */
#define atomic_exchange_explicit(object, desired, order) \
((void)(order), __sync_swap(&(object)->__val, desired))
@@ -386,7 +537,7 @@ typedef struct {
atomic_bool __flag;
} atomic_flag;
-#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(0) }
+#define ATOMIC_FLAG_INIT { ATOMIC_VAR_INIT(false) }
static __inline bool
atomic_flag_test_and_set_explicit(volatile atomic_flag *__object,
@@ -419,4 +570,6 @@ atomic_flag_clear(volatile atomic_flag *__object)
}
#endif /* !_KERNEL */
+#endif /* <atomic> unavailable */
+
#endif /* !_STDATOMIC_H_ */
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 74e573294..ce60fd70e 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -325,6 +325,11 @@ int putc_unlocked(int, FILE *);
int putchar_unlocked(int);
#endif /* __POSIX_VISIBLE >= 199506 */
+#if __POSIX_VISIBLE >= 200809
+FILE* fmemopen(void*, size_t, const char*);
+FILE* open_memstream(char**, size_t*);
+#endif /* __POSIX_VISIBLE >= 200809 */
+
__END_DECLS
#endif /* __BSD_VISIBLE || __POSIX_VISIBLE || __XPG_VISIBLE */
@@ -343,6 +348,11 @@ int setlinebuf(FILE *);
int vasprintf(char ** __restrict, const char * __restrict,
__va_list)
__printflike(2, 0);
+
+void clearerr_unlocked(FILE*);
+int feof_unlocked(FILE*);
+int ferror_unlocked(FILE*);
+
__END_DECLS
/*
@@ -408,7 +418,7 @@ int sprintf(char *dest, const char *format, ...)
#endif
extern char* __fgets_chk(char*, int, FILE*, size_t);
-extern char* __fgets_real(char*, int, FILE*) __asm__(__USER_LABEL_PREFIX__ "fgets");
+extern char* __fgets_real(char*, int, FILE*) __RENAME(fgets);
__errordecl(__fgets_too_big_error, "fgets called with size bigger than buffer");
__errordecl(__fgets_too_small_error, "fgets called with size less than zero");
diff --git a/libc/arch-mips/bionic/__get_sp.S b/libc/include/stdio_ext.h
index 5f5d32ef7..f299e54e2 100644
--- a/libc/arch-mips/bionic/__get_sp.S
+++ b/libc/include/stdio_ext.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,9 +26,29 @@
* SUCH DAMAGE.
*/
-#include <private/bionic_asm.h>
+#ifndef _STDIO_EXT_H
+#define _STDIO_EXT_H
-ENTRY_PRIVATE(__get_sp)
- move v0, sp
- j ra
-END(__get_sp)
+#include <sys/cdefs.h>
+#include <stdio.h>
+
+#define FSETLOCKING_QUERY 0
+#define FSETLOCKING_INTERNAL 1
+#define FSETLOCKING_BYCALLER 2
+
+__BEGIN_DECLS
+
+size_t __fbufsize(FILE*);
+int __freading(FILE*);
+int __fwriting(FILE*);
+int __freadable(FILE*);
+int __fwritable(FILE*);
+int __flbf(FILE*);
+void __fpurge(FILE*);
+size_t __fpending(FILE*);
+void _flushlbf(void);
+int __fsetlocking(FILE*, int);
+
+__END_DECLS
+
+#endif /* _STDIO_EXT_H */
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index a5eb3d15b..52f71dd47 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -161,8 +161,8 @@ extern int mbtowc(wchar_t *, const char *, size_t);
extern int wctomb(char *, wchar_t);
extern size_t wcstombs(char *, const wchar_t *, size_t);
-extern size_t __mb_cur_max(void);
-#define MB_CUR_MAX __mb_cur_max()
+extern size_t __ctype_get_mb_cur_max(void);
+#define MB_CUR_MAX __ctype_get_mb_cur_max()
__END_DECLS
diff --git a/libc/include/string.h b/libc/include/string.h
index 8df68e38d..b0643af6c 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -25,8 +25,9 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#ifndef _STRING_H_
-#define _STRING_H_
+
+#ifndef _STRING_H
+#define _STRING_H
#include <sys/cdefs.h>
#include <stddef.h>
@@ -66,8 +67,12 @@ extern char* strcasestr(const char *haystack, const char *needle) __purefunc;
extern char* strtok(char* __restrict, const char* __restrict);
extern char* strtok_r(char* __restrict, const char* __restrict, char** __restrict);
-extern char* strerror(int);
-extern int strerror_r(int errnum, char *buf, size_t n);
+extern char* strerror(int);
+#if defined(__USE_GNU)
+extern char* strerror_r(int, char*, size_t) __RENAME(__gnu_strerror_r);
+#else /* POSIX */
+extern int strerror_r(int, char*, size_t);
+#endif
extern size_t strnlen(const char *, size_t) __purefunc;
extern char* strncat(char* __restrict, const char* __restrict, size_t);
@@ -92,6 +97,20 @@ extern size_t strxfrm(char* __restrict, const char* __restrict, size_t);
extern int strcoll_l(const char *, const char *, locale_t) __purefunc;
extern size_t strxfrm_l(char* __restrict, const char* __restrict, size_t, locale_t);
+#if defined(__USE_GNU) && !defined(__bionic_using_posix_basename)
+/*
+ * glibc has a basename in <string.h> that's different to the POSIX one in <libgen.h>.
+ * It doesn't modify its argument, and in C++ it's const-correct.
+ */
+#if defined(__cplusplus)
+extern "C++" char* basename(char*) __RENAME(__gnu_basename) __nonnull((1));
+extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
+#else
+extern char* basename(const char*) __RENAME(__gnu_basename) __nonnull((1));
+#endif
+#define __bionic_using_gnu_basename
+#endif
+
#if defined(__BIONIC_FORTIFY)
__BIONIC_FORTIFY_INLINE
@@ -180,8 +199,7 @@ void* memset(void *s, int c, size_t n) {
return __builtin___memset_chk(s, c, n, __bos0(s));
}
-extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t)
- __asm__(__USER_LABEL_PREFIX__ "strlcpy");
+extern size_t __strlcpy_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcpy);
extern size_t __strlcpy_chk(char *, const char *, size_t, size_t);
__BIONIC_FORTIFY_INLINE
@@ -204,8 +222,7 @@ size_t strlcpy(char* __restrict dest, const char* __restrict src, size_t size) {
return __strlcpy_chk(dest, src, size, bos);
}
-extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t)
- __asm__(__USER_LABEL_PREFIX__ "strlcat");
+extern size_t __strlcat_real(char* __restrict, const char* __restrict, size_t) __RENAME(strlcat);
extern size_t __strlcat_chk(char* __restrict, const char* __restrict, size_t, size_t);
@@ -291,4 +308,4 @@ char* strrchr(const char *s, int c) {
__END_DECLS
-#endif /* _STRING_H_ */
+#endif /* _STRING_H */
diff --git a/libc/include/sys/cachectl.h b/libc/include/sys/cachectl.h
index 57e6ae787..a302ff806 100644
--- a/libc/include/sys/cachectl.h
+++ b/libc/include/sys/cachectl.h
@@ -31,6 +31,5 @@
#ifdef __mips__
#include <asm/cachectl.h>
extern int __cachectl (void *addr, __const int nbytes, __const int op);
-extern int _flush_cache (char *addr, __const int nbytes, __const int op);
#endif
#endif /* sys/cachectl.h */
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 028661628..b223afd05 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -60,18 +60,18 @@
* or later, for e.g. features that appeared in a particular version
* of GNU C. Usage:
*
- * #if __GNUC_PREREQ__(major, minor)
+ * #if __GNUC_PREREQ(major, minor)
* ...cool feature...
* #else
* ...delete feature...
* #endif
*/
#ifdef __GNUC__
-#define __GNUC_PREREQ__(x, y) \
+#define __GNUC_PREREQ(x, y) \
((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
(__GNUC__ > (x)))
#else
-#define __GNUC_PREREQ__(x, y) 0
+#define __GNUC_PREREQ(x, y) 0
#endif
#include <sys/cdefs_elf.h>
@@ -163,7 +163,7 @@
* GCC2 provides __extension__ to suppress warnings for various GNU C
* language extensions under "-ansi -pedantic".
*/
-#if !__GNUC_PREREQ__(2, 0)
+#if !__GNUC_PREREQ(2, 0)
#define __extension__ /* delete __extension__ if non-gcc or gcc1 */
#endif
@@ -175,7 +175,7 @@
* these work for GNU C++ (modulo a slight glitch in the C++ grammar
* in the distribution version of 2.5.5).
*/
-#if !__GNUC_PREREQ__(2, 5)
+#if !__GNUC_PREREQ(2, 5)
#define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define __dead __volatile
@@ -189,7 +189,7 @@
#define __pure
#endif
-#if __GNUC_PREREQ__(2, 7)
+#if __GNUC_PREREQ(2, 7)
#define __unused __attribute__((__unused__))
#else
#define __unused /* delete */
@@ -197,13 +197,13 @@
#define __pure2 __attribute__((__const__)) /* Android-added: used by FreeBSD libm */
-#if __GNUC_PREREQ__(3, 1)
+#if __GNUC_PREREQ(3, 1)
#define __used __attribute__((__used__))
#else
#define __used /* delete */
#endif
-#if __GNUC_PREREQ__(2, 7)
+#if __GNUC_PREREQ(2, 7)
#define __packed __attribute__((__packed__))
#define __aligned(x) __attribute__((__aligned__(x)))
#define __section(x) __attribute__((__section__(x)))
@@ -217,11 +217,11 @@
#define __section(x) error: no __section for this compiler
#endif
-#if !__GNUC_PREREQ__(2, 8)
+#if !__GNUC_PREREQ(2, 8)
#define __extension__
#endif
-#if __GNUC_PREREQ__(2, 8)
+#if __GNUC_PREREQ(2, 8)
#define __statement(x) __extension__(x)
#elif defined(lint)
#define __statement(x) (0)
@@ -241,7 +241,7 @@
#if defined(__STDC__VERSION__) && __STDC_VERSION__ >= 199901L
#define __restrict restrict
#else
-#if !__GNUC_PREREQ__(2, 92)
+#if !__GNUC_PREREQ(2, 92)
#define __restrict /* delete __restrict when not supported */
#endif
#endif
@@ -251,9 +251,9 @@
* in GCC 2.95.
*/
#if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L)
-#if __GNUC_PREREQ__(2, 6)
+#if __GNUC_PREREQ(2, 6)
#define __func__ __PRETTY_FUNCTION__
-#elif __GNUC_PREREQ__(2, 4)
+#elif __GNUC_PREREQ(2, 4)
#define __func__ __FUNCTION__
#else
#define __func__ ""
@@ -267,26 +267,12 @@
#endif /* NO_KERNEL_RCSIDS */
#endif /* _KERNEL */
-#if !defined(_STANDALONE) && !defined(_KERNEL)
-#ifdef __GNUC__
-#define __RENAME(x) ___RENAME(x)
-#else
-#ifdef __lint__
-#define __RENAME(x) __symbolrename(x)
-#else
-#error "No function renaming possible"
-#endif /* __lint__ */
-#endif /* __GNUC__ */
-#else /* _STANDALONE || _KERNEL */
-#define __RENAME(x) no renaming in kernel or standalone environment
-#endif
-
/*
* A barrier to stop the optimizer from moving code or assume live
* register values. This is gcc specific, the version is more or less
* arbitrary, might work with older compilers.
*/
-#if __GNUC_PREREQ__(2, 95)
+#if __GNUC_PREREQ(2, 95)
#define __insn_barrier() __asm __volatile("":::"memory")
#else
#define __insn_barrier() /* */
@@ -320,7 +306,7 @@
* basic block reordering that this affects can often generate
* larger code.
*/
-#if __GNUC_PREREQ__(2, 96)
+#if __GNUC_PREREQ(2, 96)
#define __predict_true(exp) __builtin_expect((exp) != 0, 1)
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#else
@@ -328,7 +314,7 @@
#define __predict_false(exp) (exp)
#endif
-#if __GNUC_PREREQ__(2, 96)
+#if __GNUC_PREREQ(2, 96)
#define __noreturn __attribute__((__noreturn__))
#define __mallocfunc __attribute__((malloc))
#define __purefunc __attribute__((pure))
@@ -338,19 +324,19 @@
#define __purefunc
#endif
-#if __GNUC_PREREQ__(3, 1)
+#if __GNUC_PREREQ(3, 1)
#define __always_inline __attribute__((__always_inline__))
#else
#define __always_inline
#endif
-#if __GNUC_PREREQ__(3, 4)
+#if __GNUC_PREREQ(3, 4)
#define __wur __attribute__((__warn_unused_result__))
#else
#define __wur
#endif
-#if __GNUC_PREREQ__(4, 3)
+#if __GNUC_PREREQ(4, 3)
#define __errordecl(name, msg) extern void name(void) __attribute__((__error__(msg)))
#define __warnattr(msg) __attribute__((__warning__(msg)))
#else
@@ -359,64 +345,33 @@
#endif
/*
- * Macros for manipulating "link sets". Link sets are arrays of pointers
- * to objects, which are gathered up by the linker.
- *
- * Object format-specific code has provided us with the following macros:
- *
- * __link_set_add_text(set, sym)
- * Add a reference to the .text symbol `sym' to `set'.
- *
- * __link_set_add_rodata(set, sym)
- * Add a reference to the .rodata symbol `sym' to `set'.
- *
- * __link_set_add_data(set, sym)
- * Add a reference to the .data symbol `sym' to `set'.
- *
- * __link_set_add_bss(set, sym)
- * Add a reference to the .bss symbol `sym' to `set'.
- *
- * __link_set_decl(set, ptype)
- * Provide an extern declaration of the set `set', which
- * contains an array of the pointer type `ptype'. This
- * macro must be used by any code which wishes to reference
- * the elements of a link set.
- *
- * __link_set_start(set)
- * This points to the first slot in the link set.
- *
- * __link_set_end(set)
- * This points to the (non-existent) slot after the last
- * entry in the link set.
- *
- * __link_set_count(set)
- * Count the number of entries in link set `set'.
- *
- * In addition, we provide the following macros for accessing link sets:
- *
- * __link_set_foreach(pvar, set)
- * Iterate over the link set `set'. Because a link set is
- * an array of pointers, pvar must be declared as "type **pvar",
- * and the actual entry accessed as "*pvar".
- *
- * __link_set_entry(set, idx)
- * Access the link set entry at index `idx' from set `set'.
+ * Some BSD source needs these macros.
+ * Originally they embedded the rcs versions of each source file
+ * in the generated binary. We strip strings during build anyway,.
*/
-#define __link_set_foreach(pvar, set) \
- for (pvar = __link_set_start(set); pvar < __link_set_end(set); pvar++)
-
-#define __link_set_entry(set, idx) (__link_set_begin(set)[idx])
+#define __IDSTRING(_prefix,_s) /* nothing */
+#define __COPYRIGHT(_s) /* nothing */
+#define __FBSDID(_s) /* nothing */
+#define __RCSID(_s) /* nothing */
+#define __SCCSID(_s) /* nothing */
/*
- * Some of the FreeBSD sources used in Bionic need this.
- * Originally, this is used to embed the rcs versions of each source file
- * in the generated binary. We certainly don't want this in Bionic.
+ * _BSD_SOURCE and _GNU_SOURCE are expected to be defined by callers before
+ * any standard header file is included. In those header files we test
+ * against __USE_BSD and __USE_GNU. glibc does this in <features.h> but we
+ * do it in <sys/cdefs.h> instead because that's where our existing
+ * _POSIX_C_SOURCE tests were, and we're already confident that <sys/cdefs.h>
+ * is included everywhere it should be.
*/
-#define __FBSDID(s) /* nothing */
+#if defined(_BSD_SOURCE)
+# define __USE_BSD 1
+#endif
+
+#if defined(_GNU_SOURCE)
+# define __USE_GNU 1
+#endif
/*-
- * The following definitions are an extension of the behavior originally
- * implemented in <sys/_posix.h>, but with a different level of granularity.
* POSIX.1 requires that the macros we test be defined before any standard
* header file is included.
*
@@ -570,11 +525,24 @@
#endif
#define __bos0(s) __builtin_object_size((s), 0)
-#define __BIONIC_FORTIFY_INLINE \
- extern __inline__ \
- __attribute__ ((always_inline)) \
- __attribute__ ((gnu_inline))
+#define __BIONIC_FORTIFY_INLINE extern __inline__ __always_inline __attribute__((gnu_inline))
#endif
#define __BIONIC_FORTIFY_UNKNOWN_SIZE ((size_t) -1)
+/* Used to tag non-static symbols that are private and never exposed by the shared library. */
+#define __LIBC_HIDDEN__ __attribute__((visibility("hidden")))
+
+/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */
+#ifdef __LP64__
+#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__
+#else
+#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__
+#endif
+
+/* Used to tag non-static symbols that are public and exposed by the shared library. */
+#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default")))
+
+/* Used to rename functions so that the compiler emits a call to 'x' rather than the function this was applied to. */
+#define __RENAME(x) __asm__(#x)
+
#endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/include/sys/cdefs_elf.h b/libc/include/sys/cdefs_elf.h
index 4dd7dc347..a40a867b8 100644
--- a/libc/include/sys/cdefs_elf.h
+++ b/libc/include/sys/cdefs_elf.h
@@ -30,27 +30,9 @@
#ifndef _SYS_CDEFS_ELF_H_
#define _SYS_CDEFS_ELF_H_
-#ifdef __LEADING_UNDERSCORE
-#define _C_LABEL(x) __CONCAT(_,x)
-#define _C_LABEL_STRING(x) "_"x
-#else
-#define _C_LABEL(x) x
-#define _C_LABEL_STRING(x) x
-#endif
-
-#define ___RENAME(x) __asm__(___STRING(_C_LABEL(x)))
-
-#define __indr_reference(sym,alias) /* nada, since we do weak refs */
-
-#define __strong_alias(alias,sym) \
- __asm__(".global " _C_LABEL_STRING(#alias) "\n" \
- _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
-
-#define __weak_alias(alias,sym) \
- __asm__(".weak " _C_LABEL_STRING(#alias) "\n" \
- _C_LABEL_STRING(#alias) " = " _C_LABEL_STRING(#sym));
-#define __weak_extern(sym) \
- __asm__(".weak " _C_LABEL_STRING(#sym));
+#define __strong_alias(alias, sym) \
+ __asm__(".global " #alias "\n" \
+ #alias " = " #sym);
/* We use __warnattr instead of __warn_references.
* TODO: remove this and put an empty definition in one of the upstream-* compatibility headers.
@@ -58,74 +40,4 @@
#define __warn_references(sym,msg) \
/*__asm__(".section .gnu.warning." #sym "\n\t.ascii \"" msg "\"\n\t.text");*/
-#define __SECTIONSTRING(_sec, _str) \
- __asm__(".section " #_sec "\n\t.asciz \"" _str "\"\n\t.previous")
-
-/* Used to tag non-static symbols that are private and never exposed by the shared library. */
-#define __LIBC_HIDDEN__ __attribute__((visibility ("hidden")))
-
-/* Like __LIBC_HIDDEN__, but preserves binary compatibility for LP32. */
-#ifdef __LP64__
-#define __LIBC64_HIDDEN__ __LIBC_HIDDEN__
-#else
-#define __LIBC64_HIDDEN__ __LIBC_ABI_PUBLIC__
-#endif
-
-/* Used to tag non-static symbols that are public and exposed by the shared library. */
-#define __LIBC_ABI_PUBLIC__ __attribute__((visibility ("default")))
-
-#define __IDSTRING(_n,_s) __SECTIONSTRING(.ident,_s)
-
-#define __RCSID(_s) __IDSTRING(rcsid,_s)
-#define __SCCSID(_s)
-#define __SCCSID2(_s)
-#if 0 /* XXX userland __COPYRIGHTs have \ns in them */
-#define __COPYRIGHT(_s) __SECTIONSTRING(.copyright,_s)
-#else
-#define __COPYRIGHT(_s) \
- static const char copyright[] \
- __attribute__((__unused__,__section__(".copyright"))) = _s
-#endif
-
-#define __KERNEL_RCSID(_n, _s) __RCSID(_s)
-#define __KERNEL_SCCSID(_n, _s)
-#if 0 /* XXX see above */
-#define __KERNEL_COPYRIGHT(_n, _s) __COPYRIGHT(_s)
-#else
-#define __KERNEL_COPYRIGHT(_n, _s) __SECTIONSTRING(.copyright, _s)
-#endif
-
-#ifndef __lint__
-#define __link_set_make_entry(set, sym) \
- static void const * const __link_set_##set##_sym_##sym \
- __section("link_set_" #set) __used = &sym
-#define __link_set_make_entry2(set, sym, n) \
- static void const * const __link_set_##set##_sym_##sym##_##n \
- __section("link_set_" #set) __used = &sym[n]
-#else
-#define __link_set_make_entry(set, sym) \
- extern void const * const __link_set_##set##_sym_##sym
-#define __link_set_make_entry2(set, sym, n) \
- extern void const * const __link_set_##set##_sym_##sym##_##n
-#endif /* __lint__ */
-
-#define __link_set_add_text(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_data(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_bss(set, sym) __link_set_make_entry(set, sym)
-#define __link_set_add_text2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_rodata2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_data2(set, sym, n) __link_set_make_entry2(set, sym, n)
-#define __link_set_add_bss2(set, sym, n) __link_set_make_entry2(set, sym, n)
-
-#define __link_set_decl(set, ptype) \
- extern ptype * const __start_link_set_##set[]; \
- extern ptype * const __stop_link_set_##set[] \
-
-#define __link_set_start(set) (__start_link_set_##set)
-#define __link_set_end(set) (__stop_link_set_##set)
-
-#define __link_set_count(set) \
- (__link_set_end(set) - __link_set_start(set))
-
#endif /* !_SYS_CDEFS_ELF_H_ */
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index ae2f2381e..a8840ff46 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -294,8 +294,7 @@ __socketcall ssize_t recvfrom(int, void*, size_t, int, const struct sockaddr*, s
#if defined(__BIONIC_FORTIFY)
__errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, int, const struct sockaddr*, socklen_t*);
-extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*)
- __asm__(__USER_LABEL_PREFIX__ "recvfrom");
+extern ssize_t __recvfrom_real(int, void*, size_t, int, const struct sockaddr*, socklen_t*) __RENAME(recvfrom);
__BIONIC_FORTIFY_INLINE
ssize_t recvfrom(int fd, void* buf, size_t len, int flags, const struct sockaddr* src_addr, socklen_t* addr_len) {
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index c0c168b2e..b56ffa423 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
@@ -162,7 +163,7 @@ extern mode_t umask(mode_t);
#if defined(__BIONIC_FORTIFY)
extern mode_t __umask_chk(mode_t);
-extern mode_t __umask_real(mode_t) __asm__(__USER_LABEL_PREFIX__ "umask");
+extern mode_t __umask_real(mode_t) __RENAME(umask);
__errordecl(__umask_invalid_mode, "umask called with invalid mode");
__BIONIC_FORTIFY_INLINE
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 7fbafdf27..34ae2bcd1 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _UNISTD_H_
#define _UNISTD_H_
@@ -112,7 +113,7 @@ extern int chdir(const char *);
extern int fchdir(int);
extern int rmdir(const char *);
extern int pipe(int *);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int pipe2(int *, int);
#endif
extern int chroot(const char *);
@@ -143,7 +144,7 @@ extern ssize_t pwrite64(int, const void *, size_t, off64_t);
extern int dup(int);
extern int dup2(int, int);
-#ifdef _GNU_SOURCE
+#if defined(__USE_GNU)
extern int dup3(int, int, int);
#endif
extern int fcntl(int, int, ...);
@@ -201,8 +202,7 @@ extern int tcsetpgrp(int fd, pid_t _pid);
extern ssize_t __read_chk(int, void*, size_t, size_t);
__errordecl(__read_dest_size_error, "read called with size bigger than destination");
__errordecl(__read_count_toobig_error, "read called with count > SSIZE_MAX");
-extern ssize_t __read_real(int, void*, size_t)
- __asm__(__USER_LABEL_PREFIX__ "read");
+extern ssize_t __read_real(int, void*, size_t) __RENAME(read);
__BIONIC_FORTIFY_INLINE
ssize_t read(int fd, void* buf, size_t count) {
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index 1898c7e93..ae10d93e6 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -166,6 +166,7 @@ extern wint_t towctrans(wint_t, wctrans_t);
extern wctrans_t wctrans(const char*);
#if __POSIX_VISIBLE >= 200809
+FILE* open_wmemstream(wchar_t**, size_t*);
wchar_t* wcsdup(const wchar_t*);
size_t wcsnlen(const wchar_t*, size_t);
#endif
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 660181772..ebebe80f9 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -199,8 +199,7 @@ if __name__ == "__main__":
if opt == '-u':
noUpdate = 0
elif opt == '-v':
- verbose = 1
- D_setlevel(1)
+ logging.basicConfig(level=logging.DEBUG)
elif opt == '-k':
kernel_original_path = arg
elif opt == '-d':
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 2be95320c..0c098de26 100644
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1711,7 +1711,7 @@ def optimize_if01( blocks ):
while j < n and not blocks[j].isIf():
j += 1
if j > i:
- D2("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno))
+ logging.debug("appending lines %d to %d" % (blocks[i].lineno, blocks[j-1].lineno))
result += blocks[i:j]
if j >= n:
break
@@ -1730,17 +1730,17 @@ def optimize_if01( blocks ):
break
dir = blocks[j].directive
if dir == "endif":
- D2("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno))
+ logging.debug("remove 'if 0' .. 'endif' (lines %d to %d)" % (blocks[i].lineno, blocks[j].lineno))
i = j + 1
elif dir == "else":
# convert 'else' into 'if 1'
- D2("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno))
+ logging.debug("convert 'if 0' .. 'else' into 'if 1' (lines %d to %d)" % (blocks[i].lineno, blocks[j-1].lineno))
blocks[j].directive = "if"
blocks[j].expr = CppExpr( CppLineTokenizer("1").toTokenList() )
i = j
elif dir == "elif":
# convert 'elif' into 'if'
- D2("convert 'if 0' .. 'elif' into 'if'")
+ logging.debug("convert 'if 0' .. 'elif' into 'if'")
blocks[j].directive = "if"
i = j
continue
@@ -1749,25 +1749,25 @@ def optimize_if01( blocks ):
k = find_matching_endif( blocks, j+1 )
if k >= n:
# unterminated #if 1, finish here
- D2("unterminated 'if 1'")
+ logging.debug("unterminated 'if 1'")
result += blocks[j+1:k]
break
dir = blocks[k].directive
if dir == "endif":
- D2("convert 'if 1' .. 'endif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
+ logging.debug("convert 'if 1' .. 'endif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
result += optimize_if01(blocks[j+1:k])
i = k+1
elif dir == "else":
# convert 'else' into 'if 0'
- D2("convert 'if 1' .. 'else' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
+ logging.debug("convert 'if 1' .. 'else' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
result += optimize_if01(blocks[j+1:k])
blocks[k].directive = "if"
blocks[k].expr = CppExpr( CppLineTokenizer("0").toTokenList() )
i = k
elif dir == "elif":
# convert 'elif' into 'if 0'
- D2("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
+ logging.debug("convert 'if 1' .. 'elif' (lines %d to %d)" % (blocks[j].lineno, blocks[k].lineno))
result += optimize_if01(blocks[j+1:k])
blocks[k].expr = CppExpr( CppLineTokenizer("0").toTokenList() )
i = k
@@ -1835,7 +1835,6 @@ def test_optimizeAll():
out = StringOutput()
lines = string.split(text, '\n')
list = BlockParser().parse( CppLinesTokenizer(lines) )
- #D_setlevel(2)
list.replaceTokens( kernel_token_replacements )
list.optimizeAll( {"__KERNEL__":kCppUndefinedMacro} )
list.write(out)
diff --git a/libc/kernel/tools/utils.py b/libc/kernel/tools/utils.py
index 0478e93e6..e5a310e03 100644
--- a/libc/kernel/tools/utils.py
+++ b/libc/kernel/tools/utils.py
@@ -1,59 +1,29 @@
# common python utility routines for the Bionic tool scripts
-import sys, os, commands, string, commands
+import commands
+import logging
+import os
+import string
+import sys
-# basic debugging trace support
-# call D_setlevel to set the verbosity level
-# and D(), D2(), D3(), D4() to add traces
-#
-verbose = 0
def panic(msg):
- sys.stderr.write( find_program_name() + ": error: " )
- sys.stderr.write( msg )
+ sys.stderr.write(os.path.basename(sys.argv[0]) + ": error: ")
+ sys.stderr.write(msg)
sys.exit(1)
-def D(msg):
- global verbose
- if verbose > 0:
- print msg
-
-def D2(msg):
- global verbose
- if verbose >= 2:
- print msg
-
-def D3(msg):
- global verbose
- if verbose >= 3:
- print msg
-
-def D4(msg):
- global verbose
- if verbose >= 4:
- print msg
-
-def D_setlevel(level):
- global verbose
- verbose = level
-
-
-# other stuff
-#
-#
-def find_program_name():
- return os.path.basename(sys.argv[0])
def find_program_dir():
return os.path.dirname(sys.argv[0])
+
class StringOutput:
def __init__(self):
self.line = ""
def write(self,msg):
self.line += msg
- D2("write '%s'" % msg)
+ logging.debug("write '%s'" % msg)
def get(self):
return self.line
@@ -76,47 +46,6 @@ def create_file_path(path):
continue
os.mkdir(dir)
-def walk_source_files(paths,callback,args,excludes=[]):
- """recursively walk a list of paths and files, only keeping the source files in directories"""
- for path in paths:
- if len(path) > 0 and path[0] == '@':
- # this is the name of another file, include it and parse it
- path = path[1:]
- if os.path.exists(path):
- for line in open(path):
- if len(line) > 0 and line[-1] == '\n':
- line = line[:-1]
- walk_source_files([line],callback,args,excludes)
- continue
- if not os.path.isdir(path):
- callback(path,args)
- else:
- for root, dirs, files in os.walk(path):
- #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
- if len(excludes):
- for d in dirs[:]:
- if os.path.join(root,d) in excludes:
- dirs.remove(d)
- for f in files:
- r, ext = os.path.splitext(f)
- if ext in [ ".h", ".c", ".cpp", ".S" ]:
- callback( "%s/%s" % (root,f), args )
-
-def cleanup_dir(path):
- """create a directory if needed, and ensure that it is totally empty
- by removing any existing content in it"""
- if not os.path.exists(path):
- os.mkdir(path)
- else:
- for root, dirs, files in os.walk(path, topdown=False):
- if root.endswith("kernel_headers/"):
- # skip 'kernel_headers'
- continue
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
-
class BatchFileUpdater:
"""a class used to edit several files at once"""
diff --git a/libc/private/bionic_asm.h b/libc/private/bionic_asm.h
index 7c2686f38..d53ebbae1 100644
--- a/libc/private/bionic_asm.h
+++ b/libc/private/bionic_asm.h
@@ -41,7 +41,7 @@
#define ENTRY(f) \
.text; \
.globl f; \
- _ALIGN_TEXT; \
+ .align __bionic_asm_align; \
.type f, __bionic_asm_function_type; \
f: \
__bionic_asm_custom_entry(f); \
diff --git a/tests/libs/dlsym_local_symbol_private.cpp b/libc/private/bionic_string_utils.h
index 2587508e9..ab0eccf02 100644
--- a/tests/libs/dlsym_local_symbol_private.cpp
+++ b/libc/private/bionic_string_utils.h
@@ -14,11 +14,18 @@
* limitations under the License.
*/
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <stdio.h>
+#ifndef _BIONIC_STRING_UTILS_H_
+#define _BIONIC_STRING_UTILS_H_
-// This symbol is declared local in
-// the linker version map: libdlsym_local_symbol.map.
-// It should not be visible from the outside.
-extern "C" const uint32_t __attribute__ ((visibility ("protected"))) private_taxicab_number = 1729;
+#include <string.h>
+
+static inline bool ends_with(const char* s1, const char* s2) {
+ size_t s1_length = strlen(s1);
+ size_t s2_length = strlen(s2);
+ if (s2_length > s1_length) {
+ return false;
+ }
+ return memcmp(s1 + (s1_length - s2_length), s2, s2_length) == 0;
+}
+
+#endif // _BIONIC_STRING_UTILS_H_
diff --git a/libc/private/libc_logging.h b/libc/private/libc_logging.h
index 35c756bb9..da2192bba 100644
--- a/libc/private/libc_logging.h
+++ b/libc/private/libc_logging.h
@@ -69,8 +69,6 @@ struct abort_msg_t {
char msg[0];
};
-void __android_set_abort_message(const char* msg);
-
//
// Formats a message to the log (priority 'fatal'), then aborts.
//
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
new file mode 100644
index 000000000..bfdecb81c
--- /dev/null
+++ b/libc/stdio/stdio_ext.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio_ext.h>
+
+#include <stdio.h>
+#include "local.h"
+
+#define FSETLOCKING_QUERY 0
+#define FSETLOCKING_INTERNAL 1
+#define FSETLOCKING_BYCALLER 2
+
+size_t __fbufsize(FILE* fp) {
+ return fp->_bf._size;
+}
+
+/* For a _SRW stream, we don't know whether we last read or wrote.
+int __freading(FILE* fp) {
+ return (fp->_flags & _SRD) != 0 || ...;
+}
+*/
+
+/* For a _SRW stream, we don't know whether we last read or wrote.
+int __fwriting(FILE*) {
+ return (fp->_flags & _SWR) != 0 || ...;
+}
+*/
+
+int __freadable(FILE* fp) {
+ return (fp->_flags & (__SRD|__SRW)) != 0;
+}
+
+int __fwritable(FILE* fp) {
+ return (fp->_flags & (__SWR|__SRW)) != 0;
+}
+
+int __flbf(FILE* fp) {
+ return (fp->_flags & __SLBF) != 0;
+}
+
+void __fpurge(FILE* fp) {
+ fpurge(fp);
+}
+
+size_t __fpending(FILE* fp) {
+ return fp->_p - fp->_bf._base;
+}
+
+void _flushlbf() {
+ // If we flush all streams, we know we've flushed all the line-buffered streams.
+ fflush(NULL);
+}
+
+int __fsetlocking(FILE*, int) {
+ // We don't currently have an implementation that would obey this,
+ // so make setting the state a no-op and always return "we handle locking for you".
+ // http://b/17154740 suggests ways we could fix this.
+ return FSETLOCKING_INTERNAL;
+}
+
+void clearerr_unlocked(FILE* fp) {
+ return __sclearerr(fp);
+}
+
+int feof_unlocked(FILE* fp) {
+ return __sfeof(fp);
+}
+
+int ferror_unlocked(FILE* fp) {
+ return __sferror(fp);
+}
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
deleted file mode 100644
index c38efb503..000000000
--- a/libc/tools/bionic_utils.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# common python utility routines for the Bionic tool scripts
-
-import sys, os, commands, string
-
-all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ]
-
-# basic debugging trace support
-# call D_setlevel to set the verbosity level
-# and D(), D2(), D3(), D4() to add traces
-#
-verbose = 0
-
-def D(msg):
- global verbose
- if verbose > 0:
- print msg
-
-def D2(msg):
- global verbose
- if verbose >= 2:
- print msg
-
-def D3(msg):
- global verbose
- if verbose >= 3:
- print msg
-
-def D4(msg):
- global verbose
- if verbose >= 4:
- print msg
-
-def D_setlevel(level):
- global verbose
- verbose = level
-
-
-# parser for the SYSCALLS.TXT file
-#
-class SysCallsTxtParser:
- def __init__(self):
- self.syscalls = []
- self.lineno = 0
-
- def E(self, msg):
- print "%d: %s" % (self.lineno, msg)
-
- def parse_line(self, line):
- """ parse a syscall spec line.
-
- line processing, format is
- return type func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list
- """
- pos_lparen = line.find('(')
- E = self.E
- if pos_lparen < 0:
- E("missing left parenthesis in '%s'" % line)
- return
-
- pos_rparen = line.rfind(')')
- if pos_rparen < 0 or pos_rparen <= pos_lparen:
- E("missing or misplaced right parenthesis in '%s'" % line)
- return
-
- return_type = line[:pos_lparen].strip().split()
- if len(return_type) < 2:
- E("missing return type in '%s'" % line)
- return
-
- syscall_func = return_type[-1]
- return_type = string.join(return_type[:-1],' ')
- socketcall_id = -1
-
- pos_colon = syscall_func.find(':')
- if pos_colon < 0:
- syscall_name = syscall_func
- else:
- if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
- E("misplaced colon in '%s'" % line)
- return
-
- # now find if there is a socketcall_id for a dispatch-type syscall
- # after the optional 2nd colon
- pos_colon2 = syscall_func.find(':', pos_colon + 1)
- if pos_colon2 < 0:
- syscall_name = syscall_func[pos_colon+1:]
- syscall_func = syscall_func[:pos_colon]
- else:
- if pos_colon2+1 >= len(syscall_func):
- E("misplaced colon2 in '%s'" % line)
- return
- syscall_name = syscall_func[(pos_colon+1):pos_colon2]
- socketcall_id = int(syscall_func[pos_colon2+1:])
- syscall_func = syscall_func[:pos_colon]
-
- alias_delim = syscall_func.find('|')
- if alias_delim > 0:
- alias_list = syscall_func[alias_delim+1:].strip()
- syscall_func = syscall_func[:alias_delim]
- alias_delim = syscall_name.find('|')
- if alias_delim > 0:
- syscall_name = syscall_name[:alias_delim]
- syscall_aliases = string.split(alias_list, ',')
- else:
- syscall_aliases = []
-
- if pos_rparen > pos_lparen+1:
- syscall_params = line[pos_lparen+1:pos_rparen].split(',')
- params = string.join(syscall_params,',')
- else:
- syscall_params = []
- params = "void"
-
- t = {
- "name" : syscall_name,
- "func" : syscall_func,
- "aliases" : syscall_aliases,
- "params" : syscall_params,
- "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params),
- "socketcall_id" : socketcall_id
- }
-
- # Parse the architecture list.
- arch_list = line[pos_rparen+1:].strip()
- if arch_list == "all":
- for arch in all_arches:
- t[arch] = True
- else:
- for arch in string.split(arch_list, ','):
- if arch in all_arches:
- t[arch] = True
- else:
- E("invalid syscall architecture '%s' in '%s'" % (arch, line))
- return
-
- self.syscalls.append(t)
-
- global verbose
- if verbose >= 2:
- print t
-
-
- def parse_file(self, file_path):
- D2("parse_file: %s" % file_path)
- fp = open(file_path)
- for line in fp.xreadlines():
- self.lineno += 1
- line = line.strip()
- if not line: continue
- if line[0] == '#': continue
- self.parse_line(line)
-
- fp.close()
-
-
-class StringOutput:
- def __init__(self):
- self.line = ""
-
- def write(self,msg):
- self.line += msg
- D2("write '%s'" % msg)
-
- def get(self):
- return self.line
diff --git a/libc/tools/check-symbols-glibc.py b/libc/tools/check-symbols-glibc.py
index 58a10e060..8bcf7fcc5 100755
--- a/libc/tools/check-symbols-glibc.py
+++ b/libc/tools/check-symbols-glibc.py
@@ -3,12 +3,18 @@
import glob
import os
import re
-import string
import subprocess
import sys
+only_unwanted = False
+if len(sys.argv) > 1:
+ if sys.argv[1] in ('-u', '--unwanted'):
+ only_unwanted = True
+
toolchain = os.environ['ANDROID_TOOLCHAIN']
arch = re.sub(r'.*/linux-x86/([^/]+)/.*', r'\1', toolchain)
+if arch == 'aarch64':
+ arch = 'arm64'
def GetSymbolsFromSo(so_file):
# Example readelf output:
@@ -50,15 +56,26 @@ def MangleGlibcNameToBionic(name):
return glibc_to_bionic_names[name]
return name
+def GetNdkIgnored():
+ global arch
+ symbols = set()
+ files = glob.glob('%s/ndk/build/tools/unwanted-symbols/%s/*' %
+ (os.getenv('ANDROID_BUILD_TOP'), arch))
+ for f in files:
+ symbols |= set(open(f, 'r').read().splitlines())
+ return symbols
+
glibc_to_bionic_names = {
'__res_init': 'res_init',
'__res_mkquery': 'res_mkquery',
'__res_query': 'res_query',
'__res_search': 'res_search',
+ '__xpg_basename': '__gnu_basename',
}
glibc = GetSymbolsFromSystemSo('libc.so.*', 'librt.so.*', 'libpthread.so.*', 'libresolv.so.*', 'libm.so.*')
bionic = GetSymbolsFromAndroidSo('libc.so', 'libm.so')
+ndk_ignored = GetNdkIgnored()
glibc = map(MangleGlibcNameToBionic, glibc)
@@ -100,6 +117,16 @@ macro_stuff = set([
'__errno',
'__fe_dfl_env',
'__get_h_errno',
+ '__fpclassifyd',
+ '__isfinite',
+ '__isfinitef',
+ '__isfinitel',
+ '__isnormal',
+ '__isnormalf',
+ '__isnormall',
+ '__sF',
+ '__pthread_cleanup_pop',
+ '__pthread_cleanup_push',
])
# bionic exposes various Linux features that glibc doesn't.
linux_stuff = set([
@@ -133,21 +160,43 @@ weird_stuff = set([
'mknodat',
'stat',
'stat64',
+ 'optreset',
+ 'sigsetjmp',
+])
+# These exist in glibc, but under slightly different names (generally one extra
+# or one fewer _). TODO: check against glibc names.
+libresolv_stuff = set([
+ '__res_send_setqhook',
+ '__res_send_setrhook',
+ '_resolv_flush_cache_for_net',
+ '_resolv_set_nameservers_for_net',
+ 'dn_expand',
+ 'nsdispatch',
+])
+# Implementation details we know we export (and can't get away from).
+known = set([
+ '_ctype_',
+ '__libc_init',
])
-print 'glibc:'
-for symbol in sorted(glibc):
- print symbol
+if not only_unwanted:
+ print 'glibc:'
+ for symbol in sorted(glibc):
+ print symbol
-print
-print 'bionic:'
-for symbol in sorted(bionic):
- print symbol
+ print
+ print 'bionic:'
+ for symbol in sorted(bionic):
+ print symbol
+
+ print
+ print 'in bionic but not glibc:'
-print
-print 'in bionic but not glibc:'
-allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff | std_stuff | weird_stuff)
+allowed_stuff = (bsd_stuff | FORTIFY_stuff | linux_stuff | macro_stuff |
+ std_stuff | weird_stuff | libresolv_stuff | known)
for symbol in sorted((bionic - allowed_stuff).difference(glibc)):
+ if symbol in ndk_ignored:
+ symbol += '*'
print symbol
sys.exit(0)
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 4619ec690..929bec47e 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -8,14 +8,18 @@ import atexit
import commands
import filecmp
import glob
+import logging
import os.path
import re
import shutil
import stat
+import string
import sys
import tempfile
-from bionic_utils import *
+
+all_arches = [ "arm", "arm64", "mips", "mips64", "x86", "x86_64" ]
+
# temp directory where we store all intermediate files
bionic_temp = tempfile.mkdtemp(prefix="bionic_gensyscalls");
@@ -387,6 +391,120 @@ def x86_64_genstub(syscall):
return result
+class SysCallsTxtParser:
+ def __init__(self):
+ self.syscalls = []
+ self.lineno = 0
+
+ def E(self, msg):
+ print "%d: %s" % (self.lineno, msg)
+
+ def parse_line(self, line):
+ """ parse a syscall spec line.
+
+ line processing, format is
+ return type func_name[|alias_list][:syscall_name[:socketcall_id]] ( [paramlist] ) architecture_list
+ """
+ pos_lparen = line.find('(')
+ E = self.E
+ if pos_lparen < 0:
+ E("missing left parenthesis in '%s'" % line)
+ return
+
+ pos_rparen = line.rfind(')')
+ if pos_rparen < 0 or pos_rparen <= pos_lparen:
+ E("missing or misplaced right parenthesis in '%s'" % line)
+ return
+
+ return_type = line[:pos_lparen].strip().split()
+ if len(return_type) < 2:
+ E("missing return type in '%s'" % line)
+ return
+
+ syscall_func = return_type[-1]
+ return_type = string.join(return_type[:-1],' ')
+ socketcall_id = -1
+
+ pos_colon = syscall_func.find(':')
+ if pos_colon < 0:
+ syscall_name = syscall_func
+ else:
+ if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
+ E("misplaced colon in '%s'" % line)
+ return
+
+ # now find if there is a socketcall_id for a dispatch-type syscall
+ # after the optional 2nd colon
+ pos_colon2 = syscall_func.find(':', pos_colon + 1)
+ if pos_colon2 < 0:
+ syscall_name = syscall_func[pos_colon+1:]
+ syscall_func = syscall_func[:pos_colon]
+ else:
+ if pos_colon2+1 >= len(syscall_func):
+ E("misplaced colon2 in '%s'" % line)
+ return
+ syscall_name = syscall_func[(pos_colon+1):pos_colon2]
+ socketcall_id = int(syscall_func[pos_colon2+1:])
+ syscall_func = syscall_func[:pos_colon]
+
+ alias_delim = syscall_func.find('|')
+ if alias_delim > 0:
+ alias_list = syscall_func[alias_delim+1:].strip()
+ syscall_func = syscall_func[:alias_delim]
+ alias_delim = syscall_name.find('|')
+ if alias_delim > 0:
+ syscall_name = syscall_name[:alias_delim]
+ syscall_aliases = string.split(alias_list, ',')
+ else:
+ syscall_aliases = []
+
+ if pos_rparen > pos_lparen+1:
+ syscall_params = line[pos_lparen+1:pos_rparen].split(',')
+ params = string.join(syscall_params,',')
+ else:
+ syscall_params = []
+ params = "void"
+
+ t = {
+ "name" : syscall_name,
+ "func" : syscall_func,
+ "aliases" : syscall_aliases,
+ "params" : syscall_params,
+ "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params),
+ "socketcall_id" : socketcall_id
+ }
+
+ # Parse the architecture list.
+ arch_list = line[pos_rparen+1:].strip()
+ if arch_list == "all":
+ for arch in all_arches:
+ t[arch] = True
+ else:
+ for arch in string.split(arch_list, ','):
+ if arch in all_arches:
+ t[arch] = True
+ else:
+ E("invalid syscall architecture '%s' in '%s'" % (arch, line))
+ return
+
+ self.syscalls.append(t)
+
+ logging.debug(t)
+
+
+ def parse_file(self, file_path):
+ logging.debug("parse_file: %s" % file_path)
+ fp = open(file_path)
+ for line in fp.xreadlines():
+ self.lineno += 1
+ line = line.strip()
+ if not line: continue
+ if line[0] == '#': continue
+ self.parse_line(line)
+
+ fp.close()
+
+
class State:
def __init__(self):
self.old_stubs = []
@@ -444,7 +562,7 @@ class State:
def gen_glibc_syscalls_h(self):
# TODO: generate a separate file for each architecture, like glibc's bits/syscall.h.
glibc_syscalls_h_path = "include/sys/glibc-syscalls.h"
- D("generating " + glibc_syscalls_h_path)
+ logging.info("generating " + glibc_syscalls_h_path)
glibc_fp = create_file(glibc_syscalls_h_path)
glibc_fp.write("/* %s */\n" % warning)
glibc_fp.write("#ifndef _BIONIC_GLIBC_SYSCALLS_H_\n")
@@ -473,7 +591,7 @@ class State:
for arch in all_arches:
if syscall.has_key("asm-%s" % arch):
filename = "arch-%s/syscalls/%s.S" % (arch, syscall["func"])
- D2(">>> generating " + filename)
+ logging.info(">>> generating " + filename)
fp = create_file(filename)
fp.write(syscall["asm-%s" % arch])
fp.close()
@@ -481,28 +599,28 @@ class State:
def regenerate(self):
- D("scanning for existing architecture-specific stub files...")
+ logging.info("scanning for existing architecture-specific stub files...")
for arch in all_arches:
arch_dir = "arch-" + arch
- D("scanning " + os.path.join(bionic_libc_root, arch_dir))
+ logging.info("scanning " + os.path.join(bionic_libc_root, arch_dir))
rel_path = os.path.join(arch_dir, "syscalls")
for file in os.listdir(os.path.join(bionic_libc_root, rel_path)):
if file.endswith(".S"):
self.old_stubs.append(os.path.join(rel_path, file))
- D("found %d stub files" % len(self.old_stubs))
+ logging.info("found %d stub files" % len(self.old_stubs))
if not os.path.exists(bionic_temp):
- D("creating %s..." % bionic_temp)
+ logging.info("creating %s..." % bionic_temp)
make_dir(bionic_temp)
- D("re-generating stubs and support files...")
+ logging.info("re-generating stubs and support files...")
self.gen_glibc_syscalls_h()
self.gen_syscall_stubs()
- D("comparing files...")
+ logging.info("comparing files...")
adds = []
edits = []
@@ -511,18 +629,18 @@ class State:
libc_file = os.path.join(bionic_libc_root, stub)
if not os.path.exists(libc_file):
# new file, git add it
- D("new file: " + stub)
+ logging.info("new file: " + stub)
adds.append(libc_file)
shutil.copyfile(tmp_file, libc_file)
elif not filecmp.cmp(tmp_file, libc_file):
- D("changed file: " + stub)
+ logging.info("changed file: " + stub)
edits.append(stub)
deletes = []
for stub in self.old_stubs:
if not stub in self.new_stubs:
- D("deleted file: " + stub)
+ logging.info("deleted file: " + stub)
deletes.append(os.path.join(bionic_libc_root, stub))
if not DRY_RUN:
@@ -539,11 +657,11 @@ class State:
commands.getoutput("git add %s" % (os.path.join(bionic_libc_root, "SYSCALLS.TXT")))
if (not adds) and (not deletes) and (not edits):
- D("no changes detected!")
+ logging.info("no changes detected!")
else:
- D("ready to go!!")
+ logging.info("ready to go!!")
-D_setlevel(1)
+logging.basicConfig(level=logging.INFO)
state = State()
state.process_file(os.path.join(bionic_libc_root, "SYSCALLS.TXT"))
diff --git a/libc/upstream-freebsd/android/include/freebsd-compat.h b/libc/upstream-freebsd/android/include/freebsd-compat.h
index d5f14258e..b44b94a8a 100644
--- a/libc/upstream-freebsd/android/include/freebsd-compat.h
+++ b/libc/upstream-freebsd/android/include/freebsd-compat.h
@@ -17,7 +17,7 @@
#ifndef _BIONIC_FREEBSD_COMPAT_H_included
#define _BIONIC_FREEBSD_COMPAT_H_included
-#define __USE_BSD
+#define _BSD_SOURCE
#define REPLACE_GETOPT
/*
diff --git a/libc/upstream-netbsd/android/include/namespace.h b/libc/upstream-netbsd/android/include/namespace.h
index 5df543cfc..630ea9b06 100644
--- a/libc/upstream-netbsd/android/include/namespace.h
+++ b/libc/upstream-netbsd/android/include/namespace.h
@@ -17,11 +17,6 @@
#ifndef _BIONIC_NETBSD_NAMESPACE_H_included
#define _BIONIC_NETBSD_NAMESPACE_H_included
-// NetBSD uses __weak_alias on a lot of functions. We don't want that.
-#if defined(__weak_alias)
-#undef __weak_alias
-#endif
-
__LIBC_HIDDEN__ int __res_enable_mt(void);
__LIBC_HIDDEN__ int __res_disable_mt(void);
diff --git a/libc/upstream-netbsd/android/include/netbsd-compat.h b/libc/upstream-netbsd/android/include/netbsd-compat.h
index 84be93194..04bc728b5 100644
--- a/libc/upstream-netbsd/android/include/netbsd-compat.h
+++ b/libc/upstream-netbsd/android/include/netbsd-compat.h
@@ -17,6 +17,9 @@
#ifndef _BIONIC_NETBSD_COMPAT_H_included
#define _BIONIC_NETBSD_COMPAT_H_included
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
// NetBSD uses _DIAGASSERT to null-check arguments and the like.
#include <assert.h>
#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
@@ -24,9 +27,6 @@
// TODO: update our <sys/cdefs.h> to support this properly.
#define __type_fit(t, a) (0 == 0)
-#define _GNU_SOURCE
-#define __USE_BSD
-
// TODO: we don't yet have thread-safe environment variables.
#define __readlockenv() 0
#define __unlockenv() 0
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 34ad2c5c8..630094d99 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -17,10 +17,23 @@
#ifndef _BIONIC_OPENBSD_COMPAT_H_included
#define _BIONIC_OPENBSD_COMPAT_H_included
+#define _BSD_SOURCE
+
#include <sys/cdefs.h>
#include <stddef.h> // For size_t.
-#define __USE_BSD
+/* Redirect internal C library calls to the public function. */
+#define _err err
+#define _errx errx
+#define _verr verr
+#define _verrx verrx
+#define _vwarn vwarn
+#define _vwarnx vwarnx
+#define _warn warn
+#define _warnx warnx
+
+/* Ignore all __weak_alias in OpenBSD. */
+#define __weak_alias(alias,sym)
/* OpenBSD's <ctype.h> uses these names, which conflicted with stlport.
* Additionally, we changed the numeric/digit type from N to D for libcxx.
diff --git a/libc/upstream-openbsd/lib/libc/gen/daemon.c b/libc/upstream-openbsd/lib/libc/gen/daemon.c
new file mode 100644
index 000000000..79f426473
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/daemon.c
@@ -0,0 +1,64 @@
+/* $OpenBSD: daemon.c,v 1.7 2010/07/27 22:29:09 marco Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int
+daemon(int nochdir, int noclose)
+{
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(0);
+ }
+
+ if (setsid() == -1)
+ return (-1);
+
+ if (!nochdir)
+ (void)chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)dup2(fd, STDIN_FILENO);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close(fd);
+ }
+ return (0);
+}
diff --git a/libc/upstream-openbsd/lib/libc/gen/err.c b/libc/upstream-openbsd/lib/libc/gen/err.c
new file mode 100644
index 000000000..e7ec29de4
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/err.c
@@ -0,0 +1,47 @@
+/* $OpenBSD: err.c,v 1.11 2012/12/05 23:19:59 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE2 */
+__dead void
+_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _verr(eval, fmt, ap);
+ va_end(ap);
+}
+
+/* PRINTFLIKE2 */
+__weak_alias(err, _err);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/errx.c b/libc/upstream-openbsd/lib/libc/gen/errx.c
new file mode 100644
index 000000000..d213435db
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/errx.c
@@ -0,0 +1,47 @@
+/* $OpenBSD: errx.c,v 1.10 2012/12/05 23:19:59 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE2 */
+__dead void
+_errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _verrx(eval, fmt, ap);
+ va_end(ap);
+}
+
+/* PRINTFLIKE2 */
+__weak_alias(errx, _errx);
+
diff --git a/libc/bionic/err.c b/libc/upstream-openbsd/lib/libc/gen/verr.c
index 84a3d85c3..dcd8edcd0 100644
--- a/libc/bionic/err.c
+++ b/libc/upstream-openbsd/lib/libc/gen/verr.c
@@ -1,6 +1,7 @@
+/* $OpenBSD: verr.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
/*-
* Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,83 +28,17 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <stdarg.h>
-#include <errno.h>
-
-extern const char* __progname;
-
-__noreturn void
-err(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- verr(eval, fmt, ap);
- va_end(ap);
-}
-
-__noreturn void
-errx(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- verrx(eval, fmt, ap);
- va_end(ap);
-}
-
-__noreturn void
-verr(int eval, const char *fmt, va_list ap)
-{
- int sverrno;
-
- sverrno = errno;
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL) {
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, ": ");
- }
- (void)fprintf(stderr, "%s\n", strerror(sverrno));
- exit(eval);
-}
+extern char *__progname; /* Program name, from crt0. */
-__noreturn void
-verrx(int eval, const char *fmt, va_list ap)
-{
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- exit(eval);
-}
-
-void
-warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vwarn(fmt, ap);
- va_end(ap);
-}
-
-void
-warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vwarnx(fmt, ap);
- va_end(ap);
-}
-
-void
-vwarn(const char *fmt, va_list ap)
+__dead void
+_verr(int eval, const char *fmt, va_list ap)
{
int sverrno;
@@ -114,13 +49,8 @@ vwarn(const char *fmt, va_list ap)
(void)fprintf(stderr, ": ");
}
(void)fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(eval);
}
-void
-vwarnx(const char *fmt, va_list ap)
-{
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
-}
+__weak_alias(verr, _verr);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/verrx.c b/libc/upstream-openbsd/lib/libc/gen/verrx.c
new file mode 100644
index 000000000..60da062f5
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/verrx.c
@@ -0,0 +1,49 @@
+/* $OpenBSD: verrx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+extern char *__progname; /* Program name, from crt0. */
+
+__dead void
+_verrx(int eval, const char *fmt, va_list ap)
+{
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, "\n");
+ exit(eval);
+}
+
+__weak_alias(verrx, _verrx);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarn.c b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
new file mode 100644
index 000000000..26b60f336
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
@@ -0,0 +1,54 @@
+/* $OpenBSD: vwarn.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern char *__progname; /* Program name, from crt0. */
+
+void
+_vwarn(const char *fmt, va_list ap)
+{
+ int sverrno;
+
+ sverrno = errno;
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL) {
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, ": ");
+ }
+ (void)fprintf(stderr, "%s\n", strerror(sverrno));
+}
+
+__weak_alias(vwarn, _vwarn);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarnx.c b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
new file mode 100644
index 000000000..e6b1957d4
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
@@ -0,0 +1,47 @@
+/* $OpenBSD: vwarnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+extern char *__progname; /* Program name, from crt0. */
+
+void
+_vwarnx(const char *fmt, va_list ap)
+{
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, "\n");
+}
+
+__weak_alias(vwarnx, _vwarnx);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/warn.c b/libc/upstream-openbsd/lib/libc/gen/warn.c
new file mode 100644
index 000000000..c1b47a65f
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/warn.c
@@ -0,0 +1,47 @@
+/* $OpenBSD: warn.c,v 1.10 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE1 */
+void
+_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _vwarn(fmt, ap);
+ va_end(ap);
+}
+
+/* PRINTFLIKE1 */
+__weak_alias(warn, _warn);
+
diff --git a/libc/upstream-openbsd/lib/libc/gen/warnx.c b/libc/upstream-openbsd/lib/libc/gen/warnx.c
new file mode 100644
index 000000000..af2ab669c
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/gen/warnx.c
@@ -0,0 +1,47 @@
+/* $OpenBSD: warnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+
+/* PRINTFLIKE1 */
+void
+_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+/* PRINTFLIKE1 */
+__weak_alias(warnx, _warnx);
+
diff --git a/libc/upstream-openbsd/lib/libc/net/res_random.c b/libc/upstream-openbsd/lib/libc/net/res_random.c
new file mode 100644
index 000000000..f28692f7c
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/net/res_random.c
@@ -0,0 +1,275 @@
+/* $OpenBSD: res_random.c,v 1.21 2014/07/20 04:22:34 guenther Exp $ */
+
+/*
+ * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+ * Copyright 2008 Damien Miller <djm@openbsd.org>
+ * All rights reserved.
+ *
+ * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
+ * such a mathematical system to generate more random (yet non-repeating)
+ * ids to solve the resolver/named problem. But Niels designed the
+ * actual system based on the constraints.
+ *
+ * Later modified by Damien Miller to wrap the LCG output in a 15-bit
+ * permutation generator based on a Luby-Rackoff block cipher. This
+ * ensures the output is non-repeating and preserves the MSB twiddle
+ * trick, but makes it more resistant to LCG prediction.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * seed = random 15bit
+ * n = prime, g0 = generator to n,
+ * j = random so that gcd(j,n-1) == 1
+ * g = g0^j mod n will be a generator again.
+ *
+ * X[0] = random seed.
+ * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
+ * with a = 7^(even random) mod m,
+ * b = random with gcd(b,m) == 1
+ * m = 31104 and a maximal period of m-1.
+ *
+ * The transaction id is determined by:
+ * id[n] = seed xor (g^X[n] mod n)
+ *
+ * Effectivly the id is restricted to the lower 15 bits, thus
+ * yielding two different cycles by toggling the msb on and off.
+ * This avoids reuse issues caused by reseeding.
+ *
+ * The output of this generator is then randomly permuted though a
+ * custom 15 bit Luby-Rackoff block cipher.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <resolv.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "thread_private.h"
+
+#define RU_OUT 180 /* Time after wich will be reseeded */
+#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */
+#define RU_GEN 2 /* Starting generator */
+#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */
+#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */
+#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */
+#define RU_ROUNDS 11 /* Number of rounds for permute (odd) */
+
+struct prf_ctx {
+ /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */
+ u_char prf7[(RU_ROUNDS / 2) * (1 << 7)];
+
+ /* PRF lookup table for even rounds (8 bits input to 7 bits output) */
+ u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)];
+};
+
+#define PFAC_N 3
+static const u_int16_t pfacts[PFAC_N] = {
+ 2,
+ 3,
+ 2729
+};
+
+static u_int16_t ru_x;
+static u_int16_t ru_seed, ru_seed2;
+static u_int16_t ru_a, ru_b;
+static u_int16_t ru_g;
+static u_int16_t ru_counter = 0;
+static u_int16_t ru_msb = 0;
+static struct prf_ctx *ru_prf = NULL;
+static time_t ru_reseed;
+
+static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t);
+static void res_initid(void);
+
+/*
+ * Do a fast modular exponation, returned value will be in the range
+ * of 0 - (mod-1)
+ */
+static u_int16_t
+pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod)
+{
+ u_int16_t s, t, u;
+
+ s = 1;
+ t = gen;
+ u = exp;
+
+ while (u) {
+ if (u & 1)
+ s = (s * t) % mod;
+ u >>= 1;
+ t = (t * t) % mod;
+ }
+ return (s);
+}
+
+/*
+ * 15-bit permutation based on Luby-Rackoff block cipher
+ */
+static u_int
+permute15(u_int in)
+{
+ int i;
+ u_int left, right, tmp;
+
+ if (ru_prf == NULL)
+ return in;
+
+ left = (in >> 8) & 0x7f;
+ right = in & 0xff;
+
+ /*
+ * Each round swaps the width of left and right. Even rounds have
+ * a 7-bit left, odd rounds have an 8-bit left. Since this uses an
+ * odd number of rounds, left is always 8 bits wide at the end.
+ */
+ for (i = 0; i < RU_ROUNDS; i++) {
+ if ((i & 1) == 0)
+ tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f;
+ else
+ tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right];
+ tmp ^= left;
+ left = right;
+ right = tmp;
+ }
+
+ return (right << 8) | left;
+}
+
+/*
+ * Initializes the seed and chooses a suitable generator. Also toggles
+ * the msb flag. The msb flag is used to generate two distinct
+ * cycles of random numbers and thus avoiding reuse of ids.
+ *
+ * This function is called from res_randomid() when needed, an
+ * application does not have to worry about it.
+ */
+static void
+res_initid(void)
+{
+ u_int16_t j, i;
+ u_int32_t tmp;
+ int noprime = 1;
+ struct timespec ts;
+
+ ru_x = arc4random_uniform(RU_M);
+
+ /* 15 bits of random seed */
+ tmp = arc4random();
+ ru_seed = (tmp >> 16) & 0x7FFF;
+ ru_seed2 = tmp & 0x7FFF;
+
+ /* Determine the LCG we use */
+ tmp = arc4random();
+ ru_b = (tmp & 0xfffe) | 1;
+ ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M);
+ while (ru_b % 3 == 0)
+ ru_b += 2;
+
+ j = arc4random_uniform(RU_N);
+
+ /*
+ * Do a fast gcd(j,RU_N-1), so we can find a j with
+ * gcd(j, RU_N-1) == 1, giving a new generator for
+ * RU_GEN^j mod RU_N
+ */
+
+ while (noprime) {
+ for (i = 0; i < PFAC_N; i++)
+ if (j % pfacts[i] == 0)
+ break;
+
+ if (i >= PFAC_N)
+ noprime = 0;
+ else
+ j = (j + 1) % RU_N;
+ }
+
+ ru_g = pmod(RU_GEN, j, RU_N);
+ ru_counter = 0;
+
+ /* Initialise PRF for Luby-Rackoff permutation */
+ if (ru_prf == NULL)
+ ru_prf = malloc(sizeof(*ru_prf));
+ if (ru_prf != NULL)
+ arc4random_buf(ru_prf, sizeof(*ru_prf));
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ ru_reseed = ts.tv_sec + RU_OUT;
+ ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
+}
+
+u_int
+res_randomid(void)
+{
+ struct timespec ts;
+ u_int r;
+ _THREAD_PRIVATE_MUTEX(random);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ _THREAD_PRIVATE_MUTEX_LOCK(random);
+
+ if (ru_counter >= RU_MAX || ts.tv_sec > ru_reseed)
+ res_initid();
+
+ /* Linear Congruential Generator */
+ ru_x = (ru_a * ru_x + ru_b) % RU_M;
+ ru_counter++;
+
+ r = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb;
+
+ _THREAD_PRIVATE_MUTEX_UNLOCK(random);
+
+ return (r);
+}
+
+#if 0
+int
+main(int argc, char **argv)
+{
+ int i, n;
+ u_int16_t wert;
+
+ res_initid();
+
+ printf("Generator: %u\n", ru_g);
+ printf("Seed: %u\n", ru_seed);
+ printf("Reseed at %ld\n", ru_reseed);
+ printf("Ru_X: %u\n", ru_x);
+ printf("Ru_A: %u\n", ru_a);
+ printf("Ru_B: %u\n", ru_b);
+
+ n = argc > 1 ? atoi(argv[1]) : 60001;
+ for (i=0;i<n;i++) {
+ wert = res_randomid();
+ printf("%u\n", wert);
+ }
+ return 0;
+}
+#endif
+
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
new file mode 100644
index 000000000..8cda04763
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: fmemopen.c,v 1.2 2013/03/27 15:06:25 mpi Exp $ */
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright (c) 2009 Ted Unangst
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+struct state {
+ char *string; /* actual stream */
+ size_t pos; /* current position */
+ size_t size; /* allocated size */
+ size_t len; /* length of the data */
+ int update; /* open for update */
+};
+
+static int
+fmemopen_read(void *v, char *b, int l)
+{
+ struct state *st = v;
+ int i;
+
+ for (i = 0; i < l && i + st->pos < st->len; i++)
+ b[i] = st->string[st->pos + i];
+ st->pos += i;
+
+ return (i);
+}
+
+static int
+fmemopen_write(void *v, const char *b, int l)
+{
+ struct state *st = v;
+ int i;
+
+ for (i = 0; i < l && i + st->pos < st->size; i++)
+ st->string[st->pos + i] = b[i];
+ st->pos += i;
+
+ if (st->pos >= st->len) {
+ st->len = st->pos;
+
+ if (st->len < st->size)
+ st->string[st->len] = '\0';
+ else if (!st->update)
+ st->string[st->size - 1] = '\0';
+ }
+
+ return (i);
+}
+
+static fpos_t
+fmemopen_seek(void *v, fpos_t off, int whence)
+{
+ struct state *st = v;
+ ssize_t base = 0;
+
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ base = st->pos;
+ break;
+ case SEEK_END:
+ base = st->len;
+ break;
+ }
+
+ if (off > st->size - base || off < -base) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ st->pos = base + off;
+
+ return (st->pos);
+}
+
+static int
+fmemopen_close(void *v)
+{
+ free(v);
+
+ return (0);
+}
+
+static int
+fmemopen_close_free(void *v)
+{
+ struct state *st = v;
+
+ free(st->string);
+ free(st);
+
+ return (0);
+}
+
+FILE *
+fmemopen(void *buf, size_t size, const char *mode)
+{
+ struct state *st;
+ FILE *fp;
+ int flags, oflags;
+
+ if (size == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((flags = __sflags(mode, &oflags)) == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (buf == NULL && ((oflags & O_RDWR) == 0)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((st = malloc(sizeof(*st))) == NULL)
+ return (NULL);
+
+ if ((fp = __sfp()) == NULL) {
+ free(st);
+ return (NULL);
+ }
+
+ st->pos = 0;
+ st->len = (oflags & O_WRONLY) ? 0 : size;
+ st->size = size;
+ st->update = oflags & O_RDWR;
+
+ if (buf == NULL) {
+ if ((st->string = malloc(size)) == NULL) {
+ free(st);
+ fp->_flags = 0;
+ return (NULL);
+ }
+ *st->string = '\0';
+ } else {
+ st->string = (char *)buf;
+
+ if (oflags & O_TRUNC)
+ *st->string = '\0';
+
+ if (oflags & O_APPEND) {
+ char *p;
+
+ if ((p = memchr(st->string, '\0', size)) != NULL)
+ st->pos = st->len = (p - st->string);
+ else
+ st->pos = st->len = size;
+ }
+ }
+
+ fp->_flags = (short)flags;
+ fp->_file = -1;
+ fp->_cookie = (void *)st;
+ fp->_read = (flags & __SWR) ? NULL : fmemopen_read;
+ fp->_write = (flags & __SRD) ? NULL : fmemopen_write;
+ fp->_seek = fmemopen_seek;
+ fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close;
+
+ return (fp);
+}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
new file mode 100644
index 000000000..46105358d
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c
@@ -0,0 +1,158 @@
+/* $OpenBSD: open_memstream.c,v 1.3 2013/04/03 03:11:53 guenther Exp $ */
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+struct state {
+ char *string; /* actual stream */
+ char **pbuf; /* point to the stream */
+ size_t *psize; /* point to min(pos, len) */
+ size_t pos; /* current position */
+ size_t size; /* number of allocated char */
+ size_t len; /* length of the data */
+};
+
+static int
+memstream_write(void *v, const char *b, int l)
+{
+ struct state *st = v;
+ char *p;
+ size_t i, end;
+
+ end = (st->pos + l);
+
+ if (end >= st->size) {
+ /* 1.6 is (very) close to the golden ratio. */
+ size_t sz = st->size * 8 / 5;
+
+ if (sz < end + 1)
+ sz = end + 1;
+ p = realloc(st->string, sz);
+ if (!p)
+ return (-1);
+ bzero(p + st->size, sz - st->size);
+ *st->pbuf = st->string = p;
+ st->size = sz;
+ }
+
+ for (i = 0; i < l; i++)
+ st->string[st->pos + i] = b[i];
+ st->pos += l;
+
+ if (st->pos > st->len) {
+ st->len = st->pos;
+ st->string[st->len] = '\0';
+ }
+
+ *st->psize = st->pos;
+
+ return (i);
+}
+
+static fpos_t
+memstream_seek(void *v, fpos_t off, int whence)
+{
+ struct state *st = v;
+ ssize_t base = 0;
+
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ base = st->pos;
+ break;
+ case SEEK_END:
+ base = st->len;
+ break;
+ }
+
+ if (off > SIZE_MAX - base || off < -base) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ st->pos = base + off;
+ *st->psize = MIN(st->pos, st->len);
+
+ return (st->pos);
+}
+
+static int
+memstream_close(void *v)
+{
+ struct state *st = v;
+
+ free(st);
+
+ return (0);
+}
+
+FILE *
+open_memstream(char **pbuf, size_t *psize)
+{
+ struct state *st;
+ FILE *fp;
+
+ if (pbuf == NULL || psize == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((st = malloc(sizeof(*st))) == NULL)
+ return (NULL);
+
+ if ((fp = __sfp()) == NULL) {
+ free(st);
+ return (NULL);
+ }
+
+ st->size = BUFSIZ;
+ if ((st->string = calloc(1, st->size)) == NULL) {
+ free(st);
+ fp->_flags = 0;
+ return (NULL);
+ }
+
+ *st->string = '\0';
+ st->pos = 0;
+ st->len = 0;
+ st->pbuf = pbuf;
+ st->psize = psize;
+
+ *pbuf = st->string;
+ *psize = st->len;
+
+ fp->_flags = __SWR;
+ fp->_file = -1;
+ fp->_cookie = st;
+ fp->_read = NULL;
+ fp->_write = memstream_write;
+ fp->_seek = memstream_seek;
+ fp->_close = memstream_close;
+ _SET_ORIENTATION(fp, -1);
+
+ return (fp);
+}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
new file mode 100644
index 000000000..94141878f
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c
@@ -0,0 +1,169 @@
+/* $OpenBSD: open_wmemstream.c,v 1.3 2014/03/06 07:28:21 gerhard Exp $ */
+
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "local.h"
+
+struct state {
+ wchar_t *string; /* actual stream */
+ wchar_t **pbuf; /* point to the stream */
+ size_t *psize; /* point to min(pos, len) */
+ size_t pos; /* current position */
+ size_t size; /* number of allocated wchar_t */
+ size_t len; /* length of the data */
+ mbstate_t mbs; /* conversion state of the stream */
+};
+
+static int
+wmemstream_write(void *v, const char *b, int l)
+{
+ struct state *st = v;
+ wchar_t *p;
+ size_t nmc, len, end;
+
+ end = (st->pos + l);
+
+ if (end >= st->size) {
+ /* 1.6 is (very) close to the golden ratio. */
+ size_t sz = st->size * 8 / 5;
+
+ if (sz < end + 1)
+ sz = end + 1;
+ p = realloc(st->string, sz * sizeof(wchar_t));
+ if (!p)
+ return (-1);
+ bzero(p + st->size, (sz - st->size) * sizeof(wchar_t));
+ *st->pbuf = st->string = p;
+ st->size = sz;
+ }
+
+ nmc = (st->size - st->pos) * sizeof(wchar_t);
+ len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs);
+ if (len == (size_t)-1)
+ return (-1);
+ st->pos += len;
+
+ if (st->pos > st->len) {
+ st->len = st->pos;
+ st->string[st->len] = L'\0';
+ }
+
+ *st->psize = st->pos;
+
+ return (len);
+}
+
+static fpos_t
+wmemstream_seek(void *v, fpos_t off, int whence)
+{
+ struct state *st = v;
+ ssize_t base = 0;
+
+ switch (whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ base = st->pos;
+ break;
+ case SEEK_END:
+ base = st->len;
+ break;
+ }
+
+ if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ /*
+ * XXX Clearing mbs here invalidates shift state for state-
+ * dependent encodings, but they are not (yet) supported.
+ */
+ bzero(&st->mbs, sizeof(st->mbs));
+
+ st->pos = base + off;
+ *st->psize = MIN(st->pos, st->len);
+
+ return (st->pos);
+}
+
+static int
+wmemstream_close(void *v)
+{
+ struct state *st = v;
+
+ free(st);
+
+ return (0);
+}
+
+FILE *
+open_wmemstream(wchar_t **pbuf, size_t *psize)
+{
+ struct state *st;
+ FILE *fp;
+
+ if (pbuf == NULL || psize == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((st = malloc(sizeof(*st))) == NULL)
+ return (NULL);
+
+ if ((fp = __sfp()) == NULL) {
+ free(st);
+ return (NULL);
+ }
+
+ st->size = BUFSIZ * sizeof(wchar_t);
+ if ((st->string = calloc(1, st->size)) == NULL) {
+ free(st);
+ fp->_flags = 0;
+ return (NULL);
+ }
+
+ *st->string = L'\0';
+ st->pos = 0;
+ st->len = 0;
+ st->pbuf = pbuf;
+ st->psize = psize;
+ bzero(&st->mbs, sizeof(st->mbs));
+
+ *pbuf = st->string;
+ *psize = st->len;
+
+ fp->_flags = __SWR;
+ fp->_file = -1;
+ fp->_cookie = st;
+ fp->_read = NULL;
+ fp->_write = wmemstream_write;
+ fp->_seek = wmemstream_seek;
+ fp->_close = wmemstream_close;
+ _SET_ORIENTATION(fp, 1);
+
+ return (fp);
+}
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index 9547f584c..8d574f561 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libm/include/math.h b/libm/include/math.h
index 4faec333f..1fcc578dc 100644
--- a/libm/include/math.h
+++ b/libm/include/math.h
@@ -36,11 +36,11 @@ extern const union __nan_un {
float __uf;
} __nan;
-#if __GNUC_PREREQ__(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
+#if __GNUC_PREREQ(3, 3) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800)
#define __MATH_BUILTIN_CONSTANTS
#endif
-#if __GNUC_PREREQ__(3, 0) && !defined(__INTEL_COMPILER)
+#if __GNUC_PREREQ(3, 0) && !defined(__INTEL_COMPILER)
#define __MATH_BUILTIN_RELOPS
#endif
@@ -462,11 +462,11 @@ long double truncl(long double);
#endif /* __ISO_C_VISIBLE >= 1999 */
-#if defined(_GNU_SOURCE)
+#if defined(__USE_GNU)
void sincos(double, double*, double*);
void sincosf(float, float*, float*);
void sincosl(long double, long double*, long double*);
-#endif /* _GNU_SOURCE */
+#endif /* __USE_GNU */
#pragma GCC visibility pop
__END_DECLS
diff --git a/libm/sincos.c b/libm/sincos.c
index ad755490f..a5608cfed 100644
--- a/libm/sincos.c
+++ b/libm/sincos.c
@@ -22,8 +22,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
*/
+
#define _GNU_SOURCE 1
#include <math.h>
diff --git a/libstdc++/Android.mk b/libstdc++/Android.mk
deleted file mode 100644
index ff9609aca..000000000
--- a/libstdc++/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := src/libstdc++.cpp
-LOCAL_MODULE:= libstdc++
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= src/libstdc++.cpp
-LOCAL_MODULE:= libstdc++
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libstdc++/include/new b/libstdc++/include/new
index 0253e8b68..c5a43de43 100644
--- a/libstdc++/include/new
+++ b/libstdc++/include/new
@@ -13,19 +13,19 @@ namespace std {
void* operator new(std::size_t);
void* operator new[](std::size_t);
-void operator delete(void*);
-void operator delete[](void*);
+void operator delete(void*) throw();
+void operator delete[](void*) throw();
void* operator new(std::size_t, const std::nothrow_t&);
void* operator new[](std::size_t, const std::nothrow_t&);
-void operator delete(void*, const std::nothrow_t&);
-void operator delete[](void*, const std::nothrow_t&);
+void operator delete(void*, const std::nothrow_t&) throw();
+void operator delete[](void*, const std::nothrow_t&) throw();
inline void* operator new(std::size_t, void* p) { return p; }
inline void* operator new[](std::size_t, void* p) { return p; }
// these next two are not really required, since exceptions are off
-inline void operator delete(void*, void*) { }
-inline void operator delete[](void*, void*) { }
+inline void operator delete(void*, void*) throw() { }
+inline void operator delete[](void*, void*) throw() { }
} // extern C++
diff --git a/libstdc++/src/libstdc++.cpp b/libstdc++/src/libstdc++.cpp
deleted file mode 100644
index 3676aa19f..000000000
--- a/libstdc++/src/libstdc++.cpp
+++ /dev/null
@@ -1 +0,0 @@
-extern "C" void __this_library_is_now_part_of_libc() {}
diff --git a/linker/Android.mk b/linker/Android.mk
index 68e801da2..4298032a4 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \
linker.cpp \
linker_allocator.cpp \
linker_environ.cpp \
+ linker_libc_support.c \
linker_phdr.cpp \
rt.cpp \
@@ -57,6 +58,10 @@ LOCAL_MODULE_STEM_32 := linker
LOCAL_MODULE_STEM_64 := linker64
LOCAL_MULTILIB := both
+# Leave the symbols in the shared library so that stack unwinders can produce
+# meaningful name resolution.
+LOCAL_STRIP_MODULE := keep_symbols
+
include $(LOCAL_PATH)/linker_executable.mk
ifdef TARGET_2ND_ARCH
LOCAL_2ND_ARCH_VAR_PREFIX := $(TARGET_2ND_ARCH_VAR_PREFIX)
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 079682cab..6565985b5 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -162,17 +162,17 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
thread_name[MAX_TASK_NAME_LEN] = 0;
}
- // "info" will be NULL if the siginfo_t information was not available.
+ // "info" will be null if the siginfo_t information was not available.
// Many signals don't have an address or a code.
char code_desc[32]; // ", code -6"
char addr_desc[32]; // ", fault addr 0x1234"
addr_desc[0] = code_desc[0] = 0;
- if (info != NULL) {
+ if (info != nullptr) {
// For a rethrown signal, this si_code will be right and the one debuggerd shows will
// always be SI_TKILL.
- snprintf(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+ __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
if (has_address) {
- snprintf(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+ __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
}
__libc_format_log(ANDROID_LOG_FATAL, "libc",
@@ -198,7 +198,7 @@ static bool have_siginfo(int signum) {
}
bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
- if (sigaction(signum, &old_action, NULL) == -1) {
+ if (sigaction(signum, &old_action, nullptr) == -1) {
__libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
strerror(errno));
}
@@ -230,7 +230,7 @@ static void send_debuggerd_packet(siginfo_t* info) {
msg.action = DEBUGGER_ACTION_CRASH;
msg.tid = gettid();
msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message);
- msg.original_si_code = (info != NULL) ? info->si_code : 0;
+ msg.original_si_code = (info != nullptr) ? info->si_code : 0;
int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
if (ret == sizeof(msg)) {
char debuggerd_ack;
@@ -255,7 +255,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*)
// It's possible somebody cleared the SA_SIGINFO flag, which would mean
// our "info" arg holds an undefined value.
if (!have_siginfo(signal_number)) {
- info = NULL;
+ info = nullptr;
}
log_signal_summary(signal_number, info);
@@ -296,14 +296,14 @@ __LIBC_HIDDEN__ void debuggerd_init() {
// Use the alternate signal stack if available so we can catch stack overflows.
action.sa_flags |= SA_ONSTACK;
- sigaction(SIGABRT, &action, NULL);
- sigaction(SIGBUS, &action, NULL);
- sigaction(SIGFPE, &action, NULL);
- sigaction(SIGILL, &action, NULL);
- sigaction(SIGPIPE, &action, NULL);
- sigaction(SIGSEGV, &action, NULL);
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGPIPE, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, &action, NULL);
+ sigaction(SIGSTKFLT, &action, nullptr);
#endif
- sigaction(SIGTRAP, &action, NULL);
+ sigaction(SIGTRAP, &action, nullptr);
}
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 8ebf3576b..38484d995 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -42,7 +42,7 @@ static const char* __bionic_set_dlerror(char* new_value) {
static void __bionic_format_dlerror(const char* msg, const char* detail) {
char* buffer = __get_thread()->dlerror_buffer;
strlcpy(buffer, msg, __BIONIC_DLERROR_BUFFER_SIZE);
- if (detail != NULL) {
+ if (detail != nullptr) {
strlcat(buffer, ": ", __BIONIC_DLERROR_BUFFER_SIZE);
strlcat(buffer, detail, __BIONIC_DLERROR_BUFFER_SIZE);
}
@@ -51,7 +51,7 @@ static void __bionic_format_dlerror(const char* msg, const char* detail) {
}
const char* dlerror() {
- const char* old_value = __bionic_set_dlerror(NULL);
+ const char* old_value = __bionic_set_dlerror(nullptr);
return old_value;
}
@@ -68,9 +68,9 @@ void android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
static void* dlopen_ext(const char* filename, int flags, const android_dlextinfo* extinfo) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
soinfo* result = do_dlopen(filename, flags, extinfo);
- if (result == NULL) {
+ if (result == nullptr) {
__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
- return NULL;
+ return nullptr;
}
return result;
}
@@ -80,45 +80,52 @@ void* android_dlopen_ext(const char* filename, int flags, const android_dlextinf
}
void* dlopen(const char* filename, int flags) {
- return dlopen_ext(filename, flags, NULL);
+ return dlopen_ext(filename, flags, nullptr);
}
void* dlsym(void* handle, const char* symbol) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
#if !defined(__LP64__)
- if (handle == NULL) {
- __bionic_format_dlerror("dlsym library handle is null", NULL);
- return NULL;
+ if (handle == nullptr) {
+ __bionic_format_dlerror("dlsym library handle is null", nullptr);
+ return nullptr;
}
#endif
- if (symbol == NULL) {
- __bionic_format_dlerror("dlsym symbol name is null", NULL);
- return NULL;
+ if (symbol == nullptr) {
+ __bionic_format_dlerror("dlsym symbol name is null", nullptr);
+ return nullptr;
}
- soinfo* found = NULL;
- ElfW(Sym)* sym = NULL;
- void* caller_addr = __builtin_return_address(0);
- soinfo* caller_si = find_containing_library(caller_addr);
-
+ soinfo* found = nullptr;
+ ElfW(Sym)* sym = nullptr;
if (handle == RTLD_DEFAULT) {
- sym = dlsym_linear_lookup(symbol, &found, NULL, caller_si);
+ sym = dlsym_linear_lookup(symbol, &found, nullptr);
} else if (handle == RTLD_NEXT) {
- sym = NULL;
- if (caller_si && caller_si->next) {
- sym = dlsym_linear_lookup(symbol, &found, caller_si->next, caller_si);
+ void* caller_addr = __builtin_return_address(0);
+ soinfo* si = find_containing_library(caller_addr);
+
+ sym = nullptr;
+ if (si && si->next) {
+ sym = dlsym_linear_lookup(symbol, &found, si->next);
}
} else {
- sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol, caller_si);
+ sym = dlsym_handle_lookup(reinterpret_cast<soinfo*>(handle), &found, symbol);
}
- if (sym != NULL && sym->st_shndx != 0) {
- return reinterpret_cast<void*>(sym->st_value + found->load_bias);
+ if (sym != nullptr) {
+ unsigned bind = ELF_ST_BIND(sym->st_info);
+
+ if ((bind == STB_GLOBAL || bind == STB_WEAK) && sym->st_shndx != 0) {
+ return reinterpret_cast<void*>(sym->st_value + found->load_bias);
+ }
+
+ __bionic_format_dlerror("symbol found but not global", symbol);
+ return nullptr;
} else {
__bionic_format_dlerror("undefined symbol", symbol);
- return NULL;
+ return nullptr;
}
}
@@ -127,7 +134,7 @@ int dladdr(const void* addr, Dl_info* info) {
// Determine if this address can be found in any library currently mapped.
soinfo* si = find_containing_library(addr);
- if (si == NULL) {
+ if (si == nullptr) {
return 0;
}
@@ -139,7 +146,7 @@ int dladdr(const void* addr, Dl_info* info) {
// Determine if any symbol in the library contains the specified address.
ElfW(Sym)* sym = dladdr_find_symbol(si, addr);
- if (sym != NULL) {
+ if (sym != nullptr) {
info->dli_sname = si->strtab + sym->st_name;
info->dli_saddr = reinterpret_cast<void*>(si->load_bias + sym->st_value);
}
@@ -157,7 +164,7 @@ int dlclose(void* handle) {
// name_offset: starting index of the name in libdl_info.strtab
#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
{ name_offset, \
- reinterpret_cast<Elf32_Addr>(reinterpret_cast<void*>(value)), \
+ reinterpret_cast<Elf32_Addr>(value), \
/* st_size */ 0, \
(shndx == 0) ? 0 : (STB_GLOBAL << 4), \
/* st_other */ 0, \
@@ -169,7 +176,7 @@ int dlclose(void* handle) {
(shndx == 0) ? 0 : (STB_GLOBAL << 4), \
/* st_other */ 0, \
shndx, \
- reinterpret_cast<Elf64_Addr>(reinterpret_cast<void*>(value)), \
+ reinterpret_cast<Elf64_Addr>(value), \
/* st_size */ 0, \
}
@@ -192,7 +199,7 @@ static ElfW(Sym) g_libdl_symtab[] = {
// This is actually the STH_UNDEF entry. Technically, it's
// supposed to have st_name == 0, but instead, it points to an index
// in the strtab with a \0 to make iterating through the symtab easier.
- ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, NULL, 0),
+ ELFW(SYM_INITIALIZER)(sizeof(ANDROID_LIBDL_STRTAB) - 1, nullptr, 0),
ELFW(SYM_INITIALIZER)( 0, &dlopen, 1),
ELFW(SYM_INITIALIZER)( 7, &dlclose, 1),
ELFW(SYM_INITIALIZER)( 15, &dlsym, 1),
@@ -225,17 +232,12 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
#endif
-// Defined as global because we do not yet have access
-// to synchronization functions __cxa_guard_* needed
-// to define statics inside functions.
-static soinfo __libdl_info;
+static soinfo __libdl_info("libdl.so", nullptr);
// This is used by the dynamic linker. Every process gets these symbols for free.
soinfo* get_libdl_info() {
- if (__libdl_info.name[0] == '\0') {
- // initialize
- strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name));
- __libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO;
+ if ((__libdl_info.flags & FLAG_LINKED) == 0) {
+ __libdl_info.flags |= FLAG_LINKED;
__libdl_info.strtab = ANDROID_LIBDL_STRTAB;
__libdl_info.symtab = g_libdl_symtab;
__libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned);
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 8096e623d..5fbdc8ffb 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -32,6 +32,9 @@ template<typename T, typename Allocator>
class LinkedList {
public:
LinkedList() : head_(nullptr), tail_(nullptr) {}
+ ~LinkedList() {
+ clear();
+ }
void push_front(T* const element) {
LinkedListEntry<T>* new_entry = Allocator::alloc();
@@ -83,26 +86,63 @@ class LinkedList {
}
template<typename F>
- void for_each(F&& action) {
+ void for_each(F action) {
+ visit([&] (T* si) {
+ action(si);
+ return true;
+ });
+ }
+
+ template<typename F>
+ bool visit(F action) {
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
- if (e->element != nullptr) {
- action(e->element);
+ if (!action(e->element)) {
+ return false;
}
}
+ return true;
}
template<typename F>
- void remove_if(F&& predicate) {
- for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
- if (e->element != nullptr && predicate(e->element)) {
- e->element = nullptr;
+ void remove_if(F predicate) {
+ for (LinkedListEntry<T>* e = head_, *p = nullptr; e != nullptr;) {
+ if (predicate(e->element)) {
+ LinkedListEntry<T>* next = e->next;
+ if (p == nullptr) {
+ head_ = next;
+ } else {
+ p->next = next;
+ }
+ Allocator::free(e);
+ e = next;
+ } else {
+ p = e;
+ e = e->next;
}
}
}
- bool contains(const T* el) {
+ size_t size() const {
+ size_t sz = 0;
+ for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
+ ++sz;
+ }
+
+ return sz;
+ }
+
+ size_t copy_to_array(T* array[], size_t array_length) const {
+ size_t sz = 0;
+ for (LinkedListEntry<T>* e = head_; sz < array_length && e != nullptr; e = e->next) {
+ array[sz++] = e->element;
+ }
+
+ return sz;
+ }
+
+ bool contains(const T* el) const {
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
- if (e->element != nullptr && e->element == el) {
+ if (e->element == el) {
return true;
}
}
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 9ab4e6108..9eb74403c 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -35,9 +35,10 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
-#include <sys/stat.h>
#include <unistd.h>
+#include <new>
+
// Private C library headers.
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
@@ -78,7 +79,6 @@ static const char* get_base_name(const char* name) {
#define SEARCH_NAME(x) get_base_name(x)
#endif
-static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo);
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
static LinkerAllocator<soinfo> g_soinfo_allocator;
@@ -96,7 +96,7 @@ static const char* const kDefaultLdPaths[] = {
"/vendor/lib",
"/system/lib",
#endif
- NULL
+ nullptr
};
#define LDPATH_BUFSIZE (LDPATH_MAX*64)
@@ -115,7 +115,7 @@ static soinfo* g_ld_preloads[LDPRELOAD_MAX + 1];
__LIBC_HIDDEN__ int g_ld_debug_verbosity;
-__LIBC_HIDDEN__ abort_msg_t* g_abort_message = NULL; // For debuggerd.
+__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
enum RelocationKind {
kRelocAbsolute = 0,
@@ -125,11 +125,6 @@ enum RelocationKind {
kRelocMax
};
-enum class SymbolLookupScope {
- kAllowLocal,
- kExcludeLocal,
-};
-
#if STATS
struct linker_stats_t {
int count[kRelocMax];
@@ -193,7 +188,7 @@ size_t linker_get_error_buffer_size() {
extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
-static r_debug _r_debug = {1, NULL, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
+static r_debug _r_debug = {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
static link_map* r_debug_tail = 0;
static void insert_soinfo_into_debug_map(soinfo* info) {
@@ -292,20 +287,10 @@ static void protect_data(int protection) {
static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) {
if (strlen(name) >= SOINFO_NAME_LEN) {
DL_ERR("library name \"%s\" too long", name);
- return NULL;
+ return nullptr;
}
- soinfo* si = g_soinfo_allocator.alloc();
-
- // Initialize the new element.
- memset(si, 0, sizeof(soinfo));
- strlcpy(si->name, name, sizeof(si->name));
- si->flags = FLAG_NEW_SOINFO;
-
- if (file_stat != NULL) {
- si->set_st_dev(file_stat->st_dev);
- si->set_st_ino(file_stat->st_ino);
- }
+ soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat);
sonext->next = si;
sonext = si;
@@ -315,7 +300,7 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) {
}
static void soinfo_free(soinfo* si) {
- if (si == NULL) {
+ if (si == nullptr) {
return;
}
@@ -323,16 +308,16 @@ static void soinfo_free(soinfo* si) {
munmap(reinterpret_cast<void*>(si->base), si->size);
}
- soinfo *prev = NULL, *trav;
+ soinfo *prev = nullptr, *trav;
TRACE("name %s: freeing soinfo @ %p", si->name, si);
- for (trav = solist; trav != NULL; trav = trav->next) {
+ for (trav = solist; trav != nullptr; trav = trav->next) {
if (trav == si)
break;
prev = trav;
}
- if (trav == NULL) {
+ if (trav == nullptr) {
/* si was not in solist */
DL_ERR("name \"%s\" is not in solist!", si->name);
return;
@@ -341,7 +326,7 @@ static void soinfo_free(soinfo* si) {
// clear links to/from si
si->remove_all_links();
- /* prev will never be NULL, because the first entry in solist is
+ /* prev will never be null, because the first entry in solist is
always the static libdl_info.
*/
prev->next = si->next;
@@ -355,7 +340,7 @@ static void soinfo_free(soinfo* si) {
static void parse_path(const char* path, const char* delimiters,
const char** array, char* buf, size_t buf_size, size_t max_count) {
- if (path == NULL) {
+ if (path == nullptr) {
return;
}
@@ -372,9 +357,9 @@ static void parse_path(const char* path, const char* delimiters,
// Forget the last path if we had to truncate; this occurs if the 2nd to
// last char isn't '\0' (i.e. wasn't originally a delimiter).
if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
- array[i - 1] = NULL;
+ array[i - 1] = nullptr;
} else {
- array[i] = NULL;
+ array[i] = nullptr;
}
}
@@ -410,7 +395,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
}
}
*pcount = 0;
- return NULL;
+ return nullptr;
}
#endif
@@ -419,7 +404,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
* loaded libraries. gcc_eh does the rest. */
int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
int rv = 0;
- for (soinfo* si = solist; si != NULL; si = si->next) {
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
dl_phdr_info dl_info;
dl_info.dlpi_addr = si->link_map_head.l_addr;
dl_info.dlpi_name = si->link_map_head.l_name;
@@ -433,7 +418,7 @@ int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void
return rv;
}
-static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name, const SymbolLookupScope& lookup_scope) {
+static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
ElfW(Sym)* symtab = si->symtab;
const char* strtab = si->strtab;
@@ -444,6 +429,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name,
ElfW(Sym)* s = symtab + n;
if (strcmp(strtab + s->st_name, name)) continue;
+ /* only concern ourselves with global and weak symbol definitions */
switch (ELF_ST_BIND(s->st_info)) {
case STB_GLOBAL:
case STB_WEAK:
@@ -456,13 +442,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name,
static_cast<size_t>(s->st_size));
return s;
case STB_LOCAL:
- if (lookup_scope != SymbolLookupScope::kAllowLocal) {
- continue;
- }
- TRACE_TYPE(LOOKUP, "FOUND LOCAL %s in %s (%p) %zd",
- name, si->name, reinterpret_cast<void*>(s->st_value),
- static_cast<size_t>(s->st_size));
- return s;
+ continue;
default:
__libc_fatal("ERROR: Unexpected ST_BIND value: %d for '%s' in '%s'",
ELF_ST_BIND(s->st_info), name, si->name);
@@ -473,17 +453,33 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name,
name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
- return NULL;
+ return nullptr;
+}
+
+soinfo::soinfo(const char* name, const struct stat* file_stat) {
+ memset(this, 0, sizeof(*this));
+
+ strlcpy(this->name, name, sizeof(this->name));
+ flags = FLAG_NEW_SOINFO;
+ version = SOINFO_VERSION;
+
+ if (file_stat != nullptr) {
+ set_st_dev(file_stat->st_dev);
+ set_st_ino(file_stat->st_ino);
+ }
}
-static void resolve_ifunc_symbols(soinfo* si) {
+void soinfo::resolve_ifunc_symbols() {
+ if (!get_has_ifuncs()) {
+ return;
+ }
- phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias);
+ phdr_table_unprotect_segments(phdr, phnum, load_bias);
TRACE_TYPE(IFUNC, "CHECKING FOR IFUNCS AND PERFORMING SYMBOL UPDATES");
- for (size_t i = 0; i < si->nchain; ++i) {
- ElfW(Sym)* s = &si->symtab[i];
+ for (size_t i = 0; i < nchain; ++i) {
+ ElfW(Sym)* s = &symtab[i];
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
// The address of the ifunc in the symbol table is the address of the
// function that chooses the function to which the ifunc will refer.
@@ -491,12 +487,12 @@ static void resolve_ifunc_symbols(soinfo* si) {
// in the linker and then return its result (minus the base offset).
TRACE_TYPE(IFUNC, "FOUND IFUNC");
ElfW(Addr) (*ifunc_ptr)();
- ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + si->base);
- s->st_value = (ifunc_ptr() - si->base);
+ ifunc_ptr = reinterpret_cast<ElfW(Addr)(*)()>(s->st_value + base);
+ s->st_value = (ifunc_ptr() - base);
TRACE_TYPE(IFUNC, "NEW VALUE IS %p", (void*)s->st_value);
}
}
- phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias);
+ phdr_table_protect_segments(phdr, phnum, load_bias);
}
static unsigned elfhash(const char* _name) {
@@ -512,22 +508,31 @@ static unsigned elfhash(const char* _name) {
return h;
}
-static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, soinfo* needed[]) {
+static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi) {
unsigned elf_hash = elfhash(name);
- ElfW(Sym)* s = NULL;
+ ElfW(Sym)* s = nullptr;
- if (si != NULL && somain != NULL) {
+ if (si != nullptr && somain != nullptr) {
/*
* Local scope is executable scope. Just start looking into it right away
* for the shortcut.
*/
if (si == somain) {
- s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
- if (s != NULL) {
+ s = soinfo_elf_lookup(si, elf_hash, name);
+ if (s != nullptr) {
*lsi = si;
goto done;
}
+
+ /* Next, look for it in the preloads list */
+ for (int i = 0; g_ld_preloads[i] != NULL; i++) {
+ s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
+ if (s != NULL) {
+ *lsi = g_ld_preloads[i];
+ goto done;
+ }
+ }
} else {
/* Order of symbol lookup is controlled by DT_SYMBOLIC flag */
@@ -540,11 +545,20 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
if (!si->has_DT_SYMBOLIC) {
DEBUG("%s: looking up %s in executable %s",
si->name, name, somain->name);
- s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
- if (s != NULL) {
+ s = soinfo_elf_lookup(somain, elf_hash, name);
+ if (s != nullptr) {
*lsi = somain;
goto done;
}
+
+ /* Next, look for it in the preloads list */
+ for (int i = 0; g_ld_preloads[i] != NULL; i++) {
+ s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
+ if (s != NULL) {
+ *lsi = g_ld_preloads[i];
+ goto done;
+ }
+ }
}
/* Look for symbols in the local scope (the object who is
@@ -557,8 +571,8 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
* and some the first non-weak definition. This is system dependent.
* Here we return the first definition found for simplicity. */
- s = soinfo_elf_lookup(si, elf_hash, name, SymbolLookupScope::kAllowLocal);
- if (s != NULL) {
+ s = soinfo_elf_lookup(si, elf_hash, name);
+ if (s != nullptr) {
*lsi = si;
goto done;
}
@@ -571,36 +585,36 @@ static ElfW(Sym)* soinfo_do_lookup(soinfo* si, const char* name, soinfo** lsi, s
if (si->has_DT_SYMBOLIC) {
DEBUG("%s: looking up %s in executable %s after local scope",
si->name, name, somain->name);
- s = soinfo_elf_lookup(somain, elf_hash, name, SymbolLookupScope::kExcludeLocal);
- if (s != NULL) {
+ s = soinfo_elf_lookup(somain, elf_hash, name);
+ if (s != nullptr) {
*lsi = somain;
goto done;
}
- }
- }
- }
- /* Next, look for it in the preloads list */
- for (int i = 0; g_ld_preloads[i] != NULL; i++) {
- s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
- if (s != NULL) {
- *lsi = g_ld_preloads[i];
- goto done;
+ /* Next, look for it in the preloads list */
+ for (int i = 0; g_ld_preloads[i] != NULL; i++) {
+ s = soinfo_elf_lookup(g_ld_preloads[i], elf_hash, name);
+ if (s != NULL) {
+ *lsi = g_ld_preloads[i];
+ goto done;
+ }
+ }
+ }
}
}
- for (int i = 0; needed[i] != NULL; i++) {
- DEBUG("%s: looking up %s in %s",
- si->name, name, needed[i]->name);
- s = soinfo_elf_lookup(needed[i], elf_hash, name, SymbolLookupScope::kExcludeLocal);
- if (s != NULL) {
- *lsi = needed[i];
- goto done;
+ si->get_children().visit([&](soinfo* child) {
+ DEBUG("%s: looking up %s in %s", si->name, name, child->name);
+ s = soinfo_elf_lookup(child, elf_hash, name);
+ if (s != nullptr) {
+ *lsi = child;
+ return false;
}
- }
+ return true;
+ });
done:
- if (s != NULL) {
+ if (s != nullptr) {
TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
"found in %s, base = %p, load bias = %p",
si->name, name, reinterpret_cast<void*>(s->st_value),
@@ -609,11 +623,45 @@ done:
return s;
}
- return NULL;
+ return nullptr;
}
-// Another soinfo list allocator to use in dlsym. We don't reuse
-// SoinfoListAllocator because it is write-protected most of the time.
+// Each size has it's own allocator.
+template<size_t size>
+class SizeBasedAllocator {
+ public:
+ static void* alloc() {
+ return allocator_.alloc();
+ }
+
+ static void free(void* ptr) {
+ allocator_.free(ptr);
+ }
+
+ private:
+ static LinkerBlockAllocator allocator_;
+};
+
+template<size_t size>
+LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
+
+template<typename T>
+class TypeBasedAllocator {
+ public:
+ static T* alloc() {
+ return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
+ }
+
+ static void free(T* ptr) {
+ SizeBasedAllocator<sizeof(T)>::free(ptr);
+ }
+};
+
+template <typename T>
+using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
+
+typedef linked_list_t<soinfo> SoinfoLinkedList;
+
static LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_list_allocator_rw;
class SoinfoListAllocatorRW {
public:
@@ -628,9 +676,10 @@ class SoinfoListAllocatorRW {
// This is used by dlsym(3). It performs symbol lookup only within the
// specified soinfo object and its dependencies in breadth first order.
-ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soinfo* caller) {
- LinkedList<soinfo, SoinfoListAllocatorRW> visit_list;
- LinkedList<soinfo, SoinfoListAllocatorRW> visited;
+ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+ SoinfoLinkedList visit_list;
+ SoinfoLinkedList visited;
+
visit_list.push_back(si);
soinfo* current_soinfo;
while ((current_soinfo = visit_list.pop_front()) != nullptr) {
@@ -638,13 +687,10 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi
continue;
}
- ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name,
- caller == current_soinfo ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
+ ElfW(Sym)* result = soinfo_elf_lookup(current_soinfo, elfhash(name), name);
if (result != nullptr) {
*found = current_soinfo;
- visit_list.clear();
- visited.clear();
return result;
}
visited.push_back(current_soinfo);
@@ -654,8 +700,6 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi
});
}
- visit_list.clear();
- visited.clear();
return nullptr;
}
@@ -664,24 +708,23 @@ ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soi
beginning of the global solist. Otherwise the search starts at the
specified soinfo (for RTLD_NEXT).
*/
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller) {
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start) {
unsigned elf_hash = elfhash(name);
- if (start == NULL) {
+ if (start == nullptr) {
start = solist;
}
- ElfW(Sym)* s = NULL;
- for (soinfo* si = start; (s == NULL) && (si != NULL); si = si->next) {
- s = soinfo_elf_lookup(si, elf_hash, name,
- caller == si ? SymbolLookupScope::kAllowLocal : SymbolLookupScope::kExcludeLocal);
- if (s != NULL) {
+ ElfW(Sym)* s = nullptr;
+ for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
+ s = soinfo_elf_lookup(si, elf_hash, name);
+ if (s != nullptr) {
*found = si;
break;
}
}
- if (s != NULL) {
+ if (s != nullptr) {
TRACE_TYPE(LOOKUP, "%s s->st_value = %p, found->base = %p",
name, reinterpret_cast<void*>(s->st_value), reinterpret_cast<void*>((*found)->base));
}
@@ -691,12 +734,12 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start,
soinfo* find_containing_library(const void* p) {
ElfW(Addr) address = reinterpret_cast<ElfW(Addr)>(p);
- for (soinfo* si = solist; si != NULL; si = si->next) {
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
if (address >= si->base && address - si->base < si->size) {
return si;
}
}
- return NULL;
+ return nullptr;
}
ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) {
@@ -713,12 +756,12 @@ ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr) {
}
}
- return NULL;
+ return nullptr;
}
static int open_library_on_path(const char* name, const char* const paths[]) {
char buf[512];
- for (size_t i = 0; paths[i] != NULL; ++i) {
+ for (size_t i = 0; paths[i] != nullptr; ++i) {
int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name);
@@ -736,7 +779,7 @@ static int open_library(const char* name) {
TRACE("[ opening %s ]", name);
// If the name contains a slash, we should attempt to open it directly and not search the paths.
- if (strchr(name, '/') != NULL) {
+ if (strchr(name, '/') != nullptr) {
int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
if (fd != -1) {
return fd;
@@ -759,14 +802,14 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin
int fd = -1;
ScopedFd file_guard(-1);
- if (extinfo != NULL && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+ if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
fd = extinfo->library_fd;
} else {
// Open the file.
fd = open_library(name);
if (fd == -1) {
DL_ERR("library \"%s\" not found", name);
- return NULL;
+ return nullptr;
}
file_guard.reset(fd);
@@ -777,12 +820,12 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin
struct stat file_stat;
if (TEMP_FAILURE_RETRY(fstat(fd, &file_stat)) != 0) {
DL_ERR("unable to stat file for the library %s: %s", name, strerror(errno));
- return NULL;
+ return nullptr;
}
// Check for symlink and other situations where
// file can have different names.
- for (soinfo* si = solist; si != NULL; si = si->next) {
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
if (si->get_st_dev() != 0 &&
si->get_st_ino() != 0 &&
si->get_st_dev() == file_stat.st_dev &&
@@ -793,17 +836,17 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin
}
if ((dlflags & RTLD_NOLOAD) != 0) {
- return NULL;
+ return nullptr;
}
// Read the ELF header and load the segments.
if (!elf_reader.Load(extinfo)) {
- return NULL;
+ return nullptr;
}
soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat);
- if (si == NULL) {
- return NULL;
+ if (si == nullptr) {
+ return nullptr;
}
si->base = elf_reader.load_start();
si->size = elf_reader.load_size();
@@ -816,30 +859,26 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin
TRACE("[ load_library base=%p size=%zu name='%s' ]",
reinterpret_cast<void*>(si->base), si->size, si->name);
- if (!soinfo_link_image(si, extinfo)) {
+ if (!si->LinkImage(extinfo)) {
soinfo_free(si);
- return NULL;
+ return nullptr;
}
- // if the library has any ifuncs, we will need to resolve them so that dlsym
- // can handle them properly
- resolve_ifunc_symbols(si);
-
return si;
}
static soinfo *find_loaded_library_by_name(const char* name) {
const char* search_name = SEARCH_NAME(name);
- for (soinfo* si = solist; si != NULL; si = si->next) {
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
if (!strcmp(search_name, si->name)) {
return si;
}
}
- return NULL;
+ return nullptr;
}
static soinfo* find_library_internal(const char* name, int dlflags, const android_dlextinfo* extinfo) {
- if (name == NULL) {
+ if (name == nullptr) {
return somain;
}
@@ -847,14 +886,14 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi
// Library might still be loaded, the accurate detection
// of this fact is done by load_library
- if (si == NULL) {
+ if (si == nullptr) {
TRACE("[ '%s' has not been found by name. Trying harder...]", name);
si = load_library(name, dlflags, extinfo);
}
- if (si != NULL && (si->flags & FLAG_LINKED) == 0) {
+ if (si != nullptr && (si->flags & FLAG_LINKED) == 0) {
DL_ERR("recursive link to \"%s\"", si->name);
- return NULL;
+ return nullptr;
}
return si;
@@ -862,7 +901,7 @@ static soinfo* find_library_internal(const char* name, int dlflags, const androi
static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
soinfo* si = find_library_internal(name, dlflags, extinfo);
- if (si != NULL) {
+ if (si != nullptr) {
si->ref_count++;
}
return si;
@@ -873,18 +912,25 @@ static void soinfo_unload(soinfo* si) {
TRACE("unloading '%s'", si->name);
si->CallDestructors();
- if ((si->flags | FLAG_NEW_SOINFO) != 0) {
- si->get_children().for_each([&] (soinfo* child) {
- TRACE("%s needs to unload %s", si->name, child->name);
- soinfo_unload(child);
- });
+ if (si->has_min_version(0)) {
+ // It is not safe to do si->get_children().for_each, because
+ // during soinfo_free the child will concurrently modify the si->children
+ // list, therefore we create a copy and use it to unload children.
+ size_t children_count = si->get_children().size();
+ soinfo* children[children_count];
+ si->get_children().copy_to_array(children, children_count);
+
+ for (size_t i = 0; i < children_count; ++i) {
+ TRACE("%s needs to unload %s", si->name, children[i]->name);
+ soinfo_unload(children[i]);
+ }
} else {
for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
const char* library_name = si->strtab + d->d_un.d_val;
TRACE("%s needs to unload %s", si->name, library_name);
- soinfo* needed = find_library(library_name, RTLD_NOLOAD, NULL);
- if (needed != NULL) {
+ soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
+ if (needed != nullptr) {
soinfo_unload(needed);
} else {
// Not found: for example if symlink was deleted between dlopen and dlclose
@@ -905,7 +951,21 @@ static void soinfo_unload(soinfo* si) {
}
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
- snprintf(buffer, buffer_size, "%s:%s", kDefaultLdPaths[0], kDefaultLdPaths[1]);
+ // Use basic string manipulation calls to avoid snprintf.
+ // snprintf indirectly calls pthread_getspecific to get the size of a buffer.
+ // When debug malloc is enabled, this call returns 0. This in turn causes
+ // snprintf to do nothing, which causes libraries to fail to load.
+ // See b/17302493 for further details.
+ // Once the above bug is fixed, this code can be modified to use
+ // snprintf again.
+ size_t required_len = strlen(kDefaultLdPaths[0]) + strlen(kDefaultLdPaths[1]) + 2;
+ if (buffer_size < required_len) {
+ __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: buffer len %zu, required len %zu",
+ buffer_size, required_len);
+ }
+ char* end = stpcpy(buffer, kDefaultLdPaths[0]);
+ *end = ':';
+ strcpy(end + 1, kDefaultLdPaths[1]);
}
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
@@ -917,15 +977,15 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path) {
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo) {
if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NOLOAD)) != 0) {
DL_ERR("invalid flags to dlopen: %x", flags);
- return NULL;
+ return nullptr;
}
- if (extinfo != NULL && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
+ if (extinfo != nullptr && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
DL_ERR("invalid extended flags to android_dlopen_ext: %" PRIx64, extinfo->flags);
- return NULL;
+ return nullptr;
}
protect_data(PROT_READ | PROT_WRITE);
soinfo* si = find_library(name, flags, extinfo);
- if (si != NULL) {
+ if (si != nullptr) {
si->CallConstructors();
}
protect_data(PROT_READ);
@@ -940,7 +1000,7 @@ void do_dlclose(soinfo* si) {
// ifuncs are only defined for x86
#if defined(__i386__)
-static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) {
+static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count) {
for (size_t idx = 0; idx < count; ++idx, ++rel) {
ElfW(Sym)* s;
soinfo* lsi;
@@ -948,9 +1008,9 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so
unsigned sym = ELFW(R_SYM)(rel->r_info);
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias);
ElfW(Addr) sym_addr = 0;
- const char* sym_name = NULL;
+ const char* sym_name = nullptr;
sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
- s = soinfo_do_lookup(si, sym_name, &lsi, needed);
+ s = soinfo_do_lookup(si, sym_name, &lsi);
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_386_JMP_SLOT) {
TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr));
@@ -963,7 +1023,7 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, so
#endif
#if defined(__x86_64__)
-static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) {
+static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count) {
for (size_t idx = 0; idx < count; ++idx, ++rela) {
ElfW(Sym)* s;
soinfo* lsi;
@@ -971,9 +1031,9 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count,
unsigned sym = ELFW(R_SYM)(rela->r_info);
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + si->load_bias);
ElfW(Addr) sym_addr = 0;
- const char* sym_name = NULL;
+ const char* sym_name = nullptr;
sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
- s = soinfo_do_lookup(si, sym_name, &lsi, needed);
+ s = soinfo_do_lookup(si, sym_name, &lsi);
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC && type == R_X86_64_JUMP_SLOT) {
TRACE("IFUNC RELOCATION, PASS 2: %p", (void*)(sym_addr + rela->r_addend));
@@ -986,29 +1046,29 @@ static void soinfo_ifunc_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count,
#endif
#if defined(USE_RELA)
-static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo* needed[]) {
+int soinfo::Relocate(ElfW(Rela)* rela, unsigned count) {
ElfW(Sym)* s;
soinfo* lsi;
for (size_t idx = 0; idx < count; ++idx, ++rela) {
unsigned type = ELFW(R_TYPE)(rela->r_info);
unsigned sym = ELFW(R_SYM)(rela->r_info);
- ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + si->load_bias);
+ ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rela->r_offset + load_bias);
ElfW(Addr) sym_addr = 0;
- const char* sym_name = NULL;
+ const char* sym_name = nullptr;
- DEBUG("Processing '%s' relocation at index %zd", si->name, idx);
+ DEBUG("Processing '%s' relocation at index %zd", name, idx);
if (type == 0) { // R_*_NONE
continue;
}
if (sym != 0) {
- sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
- s = soinfo_do_lookup(si, sym_name, &lsi, needed);
- if (s == NULL) {
+ sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+ s = soinfo_do_lookup(this, sym_name, &lsi);
+ if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
- s = &si->symtab[sym];
+ s = &symtab[sym];
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
- DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
+ DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
return -1;
}
@@ -1060,7 +1120,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
}
count_relocation(kRelocSymbol);
} else {
- s = NULL;
+ s = nullptr;
}
switch (type) {
@@ -1166,8 +1226,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
return -1;
}
TRACE_TYPE(RELO, "RELO RELATIVE %16llx <- %16llx\n",
- reloc, (si->base + rela->r_addend));
- *reinterpret_cast<ElfW(Addr)*>(reloc) = (si->base + rela->r_addend);
+ reloc, (base + rela->r_addend));
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = (base + rela->r_addend);
break;
case R_AARCH64_COPY:
@@ -1180,7 +1240,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
* R_AARCH64_COPY may only appear in executable objects where e_type is
* set to ET_EXEC.
*/
- DL_ERR("%s R_AARCH64_COPY relocations are not supported", si->name);
+ DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
return -1;
case R_AARCH64_TLS_TPREL64:
TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
@@ -1197,7 +1257,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
TRACE_TYPE(RELO, "RELO JMP_SLOT %08zx <- %08zx %s", static_cast<size_t>(reloc),
static_cast<size_t>(sym_addr + rela->r_addend), sym_name);
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
- si->set_has_ifuncs(true);
+ set_has_ifuncs(true);
} else {
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr + rela->r_addend;
}
@@ -1217,8 +1277,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
return -1;
}
TRACE_TYPE(RELO, "RELO RELATIVE %08zx <- +%08zx", static_cast<size_t>(reloc),
- static_cast<size_t>(si->base));
- *reinterpret_cast<ElfW(Addr)*>(reloc) = si->base + rela->r_addend;
+ static_cast<size_t>(base));
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = base + rela->r_addend;
break;
case R_X86_64_32:
count_relocation(kRelocRelative);
@@ -1253,8 +1313,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rela)* rela, unsigned count, soinfo*
}
#else // REL, not RELA.
-
-static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* needed[]) {
+int soinfo::Relocate(ElfW(Rel)* rel, unsigned count) {
ElfW(Sym)* s;
soinfo* lsi;
@@ -1262,22 +1321,22 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
unsigned type = ELFW(R_TYPE)(rel->r_info);
// TODO: don't use unsigned for 'sym'. Use uint32_t or ElfW(Addr) instead.
unsigned sym = ELFW(R_SYM)(rel->r_info);
- ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + si->load_bias);
+ ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
ElfW(Addr) sym_addr = 0;
- const char* sym_name = NULL;
+ const char* sym_name = nullptr;
- DEBUG("Processing '%s' relocation at index %zd", si->name, idx);
+ DEBUG("Processing '%s' relocation at index %zd", name, idx);
if (type == 0) { // R_*_NONE
continue;
}
if (sym != 0) {
- sym_name = reinterpret_cast<const char*>(si->strtab + si->symtab[sym].st_name);
- s = soinfo_do_lookup(si, sym_name, &lsi, needed);
- if (s == NULL) {
+ sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+ s = soinfo_do_lookup(this, sym_name, &lsi);
+ if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
- s = &si->symtab[sym];
+ s = &symtab[sym];
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
- DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
+ DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
return -1;
}
@@ -1332,7 +1391,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
}
count_relocation(kRelocSymbol);
} else {
- s = NULL;
+ s = nullptr;
}
switch (type) {
@@ -1372,7 +1431,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
* R_ARM_COPY may only appear in executable objects where e_type is
* set to ET_EXEC.
*/
- DL_ERR("%s R_ARM_COPY relocations are not supported", si->name);
+ DL_ERR("%s R_ARM_COPY relocations are not supported", name);
return -1;
#elif defined(__i386__)
case R_386_JMP_SLOT:
@@ -1380,7 +1439,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
MARK(rel->r_offset);
TRACE_TYPE(RELO, "RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
- si->set_has_ifuncs(true);
+ set_has_ifuncs(true);
} else {
*reinterpret_cast<ElfW(Addr)*>(reloc) = sym_addr;
}
@@ -1424,7 +1483,7 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
if (s) {
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
} else {
- *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base;
+ *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
}
break;
#endif
@@ -1441,8 +1500,8 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
return -1;
}
TRACE_TYPE(RELO, "RELO RELATIVE %p <- +%p",
- reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(si->base));
- *reinterpret_cast<ElfW(Addr)*>(reloc) += si->base;
+ reinterpret_cast<void*>(reloc), reinterpret_cast<void*>(base));
+ *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
break;
default:
@@ -1455,9 +1514,9 @@ static int soinfo_relocate(soinfo* si, ElfW(Rel)* rel, unsigned count, soinfo* n
#endif
#if defined(__mips__)
-static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
+static bool mips_relocate_got(soinfo* si) {
ElfW(Addr)** got = si->plt_got;
- if (got == NULL) {
+ if (got == nullptr) {
return true;
}
unsigned local_gotno = si->mips_local_gotno;
@@ -1488,8 +1547,8 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
// This is an undefined reference... try to locate it.
const char* sym_name = si->strtab + sym->st_name;
soinfo* lsi;
- ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi, needed);
- if (s == NULL) {
+ ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
+ if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference.
s = &symtab[g];
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
@@ -1509,7 +1568,7 @@ static bool mips_relocate_got(soinfo* si, soinfo* needed[]) {
#endif
void soinfo::CallArray(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
- if (functions == NULL) {
+ if (functions == nullptr) {
return;
}
@@ -1528,7 +1587,7 @@ void soinfo::CallArray(const char* array_name __unused, linker_function_t* funct
}
void soinfo::CallFunction(const char* function_name __unused, linker_function_t function) {
- if (function == NULL || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
+ if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
return;
}
@@ -1564,7 +1623,7 @@ void soinfo::CallConstructors() {
// out above, the libc constructor will be called again (recursively!).
constructors_called = true;
- if ((flags & FLAG_EXE) == 0 && preinit_array != NULL) {
+ if ((flags & FLAG_EXE) == 0 && preinit_array != nullptr) {
// The GNU dynamic linker silently ignores these, but we warn the developer.
PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
name, preinit_array_count);
@@ -1579,6 +1638,8 @@ void soinfo::CallConstructors() {
// DT_INIT should be called before DT_INIT_ARRAY if both are present.
CallFunction("DT_INIT", init_func);
CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);
+
+ resolve_ifunc_symbols();
}
void soinfo::CallDestructors() {
@@ -1596,16 +1657,14 @@ void soinfo::CallDestructors() {
}
void soinfo::add_child(soinfo* child) {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return;
+ if (has_min_version(0)) {
+ this->children.push_front(child);
+ child->parents.push_front(this);
}
-
- this->children.push_front(child);
- child->parents.push_front(this);
}
void soinfo::remove_all_links() {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
+ if (!has_min_version(0)) {
return;
}
@@ -1617,7 +1676,7 @@ void soinfo::remove_all_links() {
});
parents.for_each([&] (soinfo* parent) {
- parent->children.for_each([&] (const soinfo* child) {
+ parent->children.remove_if([&] (const soinfo* child) {
return child == this;
});
});
@@ -1628,51 +1687,45 @@ void soinfo::remove_all_links() {
}
void soinfo::set_st_dev(dev_t dev) {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return;
+ if (has_min_version(0)) {
+ st_dev = dev;
}
-
- st_dev = dev;
}
void soinfo::set_st_ino(ino_t ino) {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return;
+ if (has_min_version(0)) {
+ st_ino = ino;
}
-
- st_ino = ino;
}
void soinfo::set_has_ifuncs(bool ifuncs) {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return;
+ if (has_min_version(1)) {
+ has_ifuncs = ifuncs;
}
-
- has_ifuncs = ifuncs;
}
dev_t soinfo::get_st_dev() {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return 0;
+ if (has_min_version(0)) {
+ return st_dev;
}
- return st_dev;
+ return 0;
};
ino_t soinfo::get_st_ino() {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return 0;
+ if (has_min_version(0)) {
+ return st_ino;
}
- return st_ino;
+ return 0;
}
bool soinfo::get_has_ifuncs() {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return false;
+ if (has_min_version(1)) {
+ return has_ifuncs;
}
- return has_ifuncs;
+ return false;
}
// This is a return on get_children() in case
@@ -1680,11 +1733,11 @@ bool soinfo::get_has_ifuncs() {
static soinfo::soinfo_list_t g_empty_list;
soinfo::soinfo_list_t& soinfo::get_children() {
- if ((this->flags & FLAG_NEW_SOINFO) == 0) {
- return g_empty_list;
+ if (has_min_version(0)) {
+ return this->children;
}
- return this->children;
+ return g_empty_list;
}
/* Force any of the closed stdin, stdout and stderr to be associated with
@@ -1748,84 +1801,80 @@ static int nullify_closed_stdio() {
return return_value;
}
-static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
- /* "base" might wrap around UINT32_MAX. */
- ElfW(Addr) base = si->load_bias;
- const ElfW(Phdr)* phdr = si->phdr;
- int phnum = si->phnum;
- bool relocating_linker = (si->flags & FLAG_LINKER) != 0;
+bool soinfo::LinkImage(const android_dlextinfo* extinfo) {
+ bool relocating_linker = (flags & FLAG_LINKER) != 0;
/* We can't debug anything until the linker is relocated */
if (!relocating_linker) {
- INFO("[ linking %s ]", si->name);
- DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(si->base), si->flags);
+ INFO("[ linking %s ]", name);
+ DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags);
}
/* Extract dynamic section */
size_t dynamic_count;
ElfW(Word) dynamic_flags;
- phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
+ phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic,
&dynamic_count, &dynamic_flags);
- if (si->dynamic == NULL) {
+ if (dynamic == nullptr) {
if (!relocating_linker) {
- DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name);
+ DL_ERR("missing PT_DYNAMIC in \"%s\"", name);
}
return false;
} else {
if (!relocating_linker) {
- DEBUG("dynamic = %p", si->dynamic);
+ DEBUG("dynamic = %p", dynamic);
}
}
#if defined(__arm__)
- (void) phdr_table_get_arm_exidx(phdr, phnum, base,
- &si->ARM_exidx, &si->ARM_exidx_count);
+ (void) phdr_table_get_arm_exidx(phdr, phnum, load_bias,
+ &ARM_exidx, &ARM_exidx_count);
#endif
// Extract useful information from dynamic section.
uint32_t needed_count = 0;
- for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+ for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
switch (d->d_tag) {
case DT_HASH:
- si->nbucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[0];
- si->nchain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr)[1];
- si->bucket = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8);
- si->chain = reinterpret_cast<uint32_t*>(base + d->d_un.d_ptr + 8 + si->nbucket * 4);
+ nbucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[0];
+ nchain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr)[1];
+ bucket = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8);
+ chain = reinterpret_cast<uint32_t*>(load_bias + d->d_un.d_ptr + 8 + nbucket * 4);
break;
case DT_STRTAB:
- si->strtab = reinterpret_cast<const char*>(base + d->d_un.d_ptr);
+ strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
break;
case DT_SYMTAB:
- si->symtab = reinterpret_cast<ElfW(Sym)*>(base + d->d_un.d_ptr);
+ symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
break;
#if !defined(__LP64__)
case DT_PLTREL:
if (d->d_un.d_val != DT_REL) {
- DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
+ DL_ERR("unsupported DT_RELA in \"%s\"", name);
return false;
}
break;
#endif
case DT_JMPREL:
#if defined(USE_RELA)
- si->plt_rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr);
+ plt_rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
#else
- si->plt_rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr);
+ plt_rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
#endif
break;
case DT_PLTRELSZ:
#if defined(USE_RELA)
- si->plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
+ plt_rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
#else
- si->plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
+ plt_rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
#endif
break;
#if defined(__mips__)
case DT_PLTGOT:
// Used by mips and mips64.
- si->plt_got = reinterpret_cast<ElfW(Addr)**>(base + d->d_un.d_ptr);
+ plt_got = reinterpret_cast<ElfW(Addr)**>(load_bias + d->d_un.d_ptr);
break;
#endif
case DT_DEBUG:
@@ -1843,67 +1892,67 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
#endif
#if defined(USE_RELA)
case DT_RELA:
- si->rela = reinterpret_cast<ElfW(Rela)*>(base + d->d_un.d_ptr);
+ rela = reinterpret_cast<ElfW(Rela)*>(load_bias + d->d_un.d_ptr);
break;
case DT_RELASZ:
- si->rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
+ rela_count = d->d_un.d_val / sizeof(ElfW(Rela));
break;
case DT_REL:
- DL_ERR("unsupported DT_REL in \"%s\"", si->name);
+ DL_ERR("unsupported DT_REL in \"%s\"", name);
return false;
case DT_RELSZ:
- DL_ERR("unsupported DT_RELSZ in \"%s\"", si->name);
+ DL_ERR("unsupported DT_RELSZ in \"%s\"", name);
return false;
#else
case DT_REL:
- si->rel = reinterpret_cast<ElfW(Rel)*>(base + d->d_un.d_ptr);
+ rel = reinterpret_cast<ElfW(Rel)*>(load_bias + d->d_un.d_ptr);
break;
case DT_RELSZ:
- si->rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
+ rel_count = d->d_un.d_val / sizeof(ElfW(Rel));
break;
case DT_RELA:
- DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
+ DL_ERR("unsupported DT_RELA in \"%s\"", name);
return false;
#endif
case DT_INIT:
- si->init_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
+ init_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+ DEBUG("%s constructors (DT_INIT) found at %p", name, init_func);
break;
case DT_FINI:
- si->fini_func = reinterpret_cast<linker_function_t>(base + d->d_un.d_ptr);
- DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
+ fini_func = reinterpret_cast<linker_function_t>(load_bias + d->d_un.d_ptr);
+ DEBUG("%s destructors (DT_FINI) found at %p", name, fini_func);
break;
case DT_INIT_ARRAY:
- si->init_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
+ init_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+ DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", name, init_array);
break;
case DT_INIT_ARRAYSZ:
- si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+ init_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
break;
case DT_FINI_ARRAY:
- si->fini_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
+ fini_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+ DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", name, fini_array);
break;
case DT_FINI_ARRAYSZ:
- si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+ fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
break;
case DT_PREINIT_ARRAY:
- si->preinit_array = reinterpret_cast<linker_function_t*>(base + d->d_un.d_ptr);
- DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
+ preinit_array = reinterpret_cast<linker_function_t*>(load_bias + d->d_un.d_ptr);
+ DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", name, preinit_array);
break;
case DT_PREINIT_ARRAYSZ:
- si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
+ preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(ElfW(Addr));
break;
case DT_TEXTREL:
#if defined(__LP64__)
- DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", si->name);
+ DL_ERR("text relocations (DT_TEXTREL) found in 64-bit ELF file \"%s\"", name);
return false;
#else
- si->has_text_relocations = true;
+ has_text_relocations = true;
break;
#endif
case DT_SYMBOLIC:
- si->has_DT_SYMBOLIC = true;
+ has_DT_SYMBOLIC = true;
break;
case DT_NEEDED:
++needed_count;
@@ -1911,14 +1960,14 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
case DT_FLAGS:
if (d->d_un.d_val & DF_TEXTREL) {
#if defined(__LP64__)
- DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", si->name);
+ DL_ERR("text relocations (DF_TEXTREL) found in 64-bit ELF file \"%s\"", name);
return false;
#else
- si->has_text_relocations = true;
+ has_text_relocations = true;
#endif
}
if (d->d_un.d_val & DF_SYMBOLIC) {
- si->has_DT_SYMBOLIC = true;
+ has_DT_SYMBOLIC = true;
}
break;
#if defined(__mips__)
@@ -1929,7 +1978,7 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
case DT_MIPS_RLD_MAP:
// Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
{
- r_debug** dp = reinterpret_cast<r_debug**>(base + d->d_un.d_ptr);
+ r_debug** dp = reinterpret_cast<r_debug**>(load_bias + d->d_un.d_ptr);
*dp = &_r_debug;
}
break;
@@ -1940,15 +1989,15 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
break;
case DT_MIPS_SYMTABNO:
- si->mips_symtabno = d->d_un.d_val;
+ mips_symtabno = d->d_un.d_val;
break;
case DT_MIPS_LOCAL_GOTNO:
- si->mips_local_gotno = d->d_un.d_val;
+ mips_local_gotno = d->d_un.d_val;
break;
case DT_MIPS_GOTSYM:
- si->mips_gotsym = d->d_un.d_val;
+ mips_gotsym = d->d_un.d_val;
break;
#endif
@@ -1960,100 +2009,95 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
}
DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
- reinterpret_cast<void*>(si->base), si->strtab, si->symtab);
+ reinterpret_cast<void*>(base), strtab, symtab);
// Sanity checks.
if (relocating_linker && needed_count != 0) {
DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
return false;
}
- if (si->nbucket == 0) {
- DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
+ if (nbucket == 0) {
+ DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", name);
return false;
}
- if (si->strtab == 0) {
- DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name);
+ if (strtab == 0) {
+ DL_ERR("empty/missing DT_STRTAB in \"%s\"", name);
return false;
}
- if (si->symtab == 0) {
- DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name);
+ if (symtab == 0) {
+ DL_ERR("empty/missing DT_SYMTAB in \"%s\"", name);
return false;
}
// If this is the main executable, then load all of the libraries from LD_PRELOAD now.
- if (si->flags & FLAG_EXE) {
+ if (flags & FLAG_EXE) {
memset(g_ld_preloads, 0, sizeof(g_ld_preloads));
size_t preload_count = 0;
- for (size_t i = 0; g_ld_preload_names[i] != NULL; i++) {
- soinfo* lsi = find_library(g_ld_preload_names[i], 0, NULL);
- if (lsi != NULL) {
+ for (size_t i = 0; g_ld_preload_names[i] != nullptr; i++) {
+ soinfo* lsi = find_library(g_ld_preload_names[i], 0, nullptr);
+ if (lsi != nullptr) {
g_ld_preloads[preload_count++] = lsi;
} else {
// As with glibc, failure to load an LD_PRELOAD library is just a warning.
DL_WARN("could not load library \"%s\" from LD_PRELOAD for \"%s\"; caused by %s",
- g_ld_preload_names[i], si->name, linker_get_error_buffer());
+ g_ld_preload_names[i], name, linker_get_error_buffer());
}
}
}
- soinfo** needed = reinterpret_cast<soinfo**>(alloca((1 + needed_count) * sizeof(soinfo*)));
- soinfo** pneeded = needed;
-
- for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
+ for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
- const char* library_name = si->strtab + d->d_un.d_val;
- DEBUG("%s needs %s", si->name, library_name);
- soinfo* lsi = find_library(library_name, 0, NULL);
- if (lsi == NULL) {
+ const char* library_name = strtab + d->d_un.d_val;
+ DEBUG("%s needs %s", name, library_name);
+ soinfo* lsi = find_library(library_name, 0, nullptr);
+ if (lsi == nullptr) {
strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
- library_name, si->name, tmp_err_buf);
+ library_name, name, tmp_err_buf);
return false;
}
- si->add_child(lsi);
- *pneeded++ = lsi;
+ add_child(lsi);
}
}
- *pneeded = NULL;
#if !defined(__LP64__)
- if (si->has_text_relocations) {
+ if (has_text_relocations) {
// Make segments writable to allow text relocations to work properly. We will later call
// phdr_table_protect_segments() after all of them are applied and all constructors are run.
DL_WARN("%s has text relocations. This is wasting memory and prevents "
- "security hardening. Please fix.", si->name);
- if (phdr_table_unprotect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
+ "security hardening. Please fix.", name);
+ if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- si->name, strerror(errno));
+ name, strerror(errno));
return false;
}
}
#endif
#if defined(USE_RELA)
- if (si->plt_rela != NULL) {
- DEBUG("[ relocating %s plt ]\n", si->name);
- if (soinfo_relocate(si, si->plt_rela, si->plt_rela_count, needed)) {
+ if (plt_rela != nullptr) {
+ DEBUG("[ relocating %s plt ]\n", name);
+ if (Relocate(plt_rela, plt_rela_count)) {
return false;
}
}
- if (si->rela != NULL) {
- DEBUG("[ relocating %s ]\n", si->name);
- if (soinfo_relocate(si, si->rela, si->rela_count, needed)) {
+ if (rela != nullptr) {
+ DEBUG("[ relocating %s ]\n", name);
+ if (Relocate(rela, rela_count)) {
return false;
}
}
#else
- if (si->plt_rel != NULL) {
- DEBUG("[ relocating %s plt ]", si->name);
- if (soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed)) {
+ if (plt_rel != nullptr) {
+ DEBUG("[ relocating %s plt ]", name);
+ if (Relocate(plt_rel, plt_rel_count)) {
return false;
}
}
- if (si->rel != NULL) {
- DEBUG("[ relocating %s ]", si->name);
- if (soinfo_relocate(si, si->rel, si->rel_count, needed)) {
+ if (rel != nullptr) {
+ DEBUG("[ relocating %s ]", name);
+ if (Relocate(rel, rel_count)) {
return false;
}
}
@@ -2063,59 +2107,59 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
// they cannot be resolved until the rest of the relocations are done
// because we need to call the resolution function which may be waiting
// on relocations.
- if(si->get_has_ifuncs()) {
+ if(get_has_ifuncs()) {
#if defined(__i386__)
- soinfo_ifunc_relocate(si, si->plt_rel, si->plt_rel_count, needed);
+ soinfo_ifunc_relocate(this, plt_rel, plt_rel_count);
#elif defined(__x86_64__)
- soinfo_ifunc_relocate(si, si->plt_rela, si->plt_rela_count, needed);
+ soinfo_ifunc_relocate(this, plt_rela, plt_rela_count);
#endif
}
#if defined(__mips__)
- if (!mips_relocate_got(si, needed)) {
+ if (!mips_relocate_got(this)) {
return false;
}
#endif
- si->flags |= FLAG_LINKED;
- DEBUG("[ finished linking %s ]", si->name);
+ flags |= FLAG_LINKED;
+ DEBUG("[ finished linking %s ]", name);
#if !defined(__LP64__)
- if (si->has_text_relocations) {
+ if (has_text_relocations) {
// All relocations are done, we can protect our segments back to read-only.
- if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
+ if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
DL_ERR("can't protect segments for \"%s\": %s",
- si->name, strerror(errno));
+ name, strerror(errno));
return false;
}
}
#endif
/* We can also turn on GNU RELRO protection */
- if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) {
+ if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
- si->name, strerror(errno));
+ name, strerror(errno));
return false;
}
/* Handle serializing/sharing the RELRO segment */
if (extinfo && (extinfo->flags & ANDROID_DLEXT_WRITE_RELRO)) {
- if (phdr_table_serialize_gnu_relro(si->phdr, si->phnum, si->load_bias,
+ if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
extinfo->relro_fd) < 0) {
DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
- si->name, strerror(errno));
+ name, strerror(errno));
return false;
}
} else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
- if (phdr_table_map_gnu_relro(si->phdr, si->phnum, si->load_bias,
+ if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
extinfo->relro_fd) < 0) {
DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
- si->name, strerror(errno));
+ name, strerror(errno));
return false;
}
}
- notify_gdb_of_load(si);
+ notify_gdb_of_load(this);
return true;
}
@@ -2127,11 +2171,11 @@ static bool soinfo_link_image(soinfo* si, const android_dlextinfo* extinfo) {
static void add_vdso(KernelArgumentBlock& args __unused) {
#if defined(AT_SYSINFO_EHDR)
ElfW(Ehdr)* ehdr_vdso = reinterpret_cast<ElfW(Ehdr)*>(args.getauxval(AT_SYSINFO_EHDR));
- if (ehdr_vdso == NULL) {
+ if (ehdr_vdso == nullptr) {
return;
}
- soinfo* si = soinfo_alloc("[vdso]", NULL);
+ soinfo* si = soinfo_alloc("[vdso]", nullptr);
si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
si->phnum = ehdr_vdso->e_phnum;
@@ -2139,14 +2183,19 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
si->size = phdr_table_get_load_size(si->phdr, si->phnum);
si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
- soinfo_link_image(si, NULL);
+ si->LinkImage(nullptr);
#endif
}
/*
* This is linker soinfo for GDB. See details below.
*/
-static soinfo linker_soinfo_for_gdb;
+#if defined(__LP64__)
+#define LINKER_PATH "/system/bin/linker64"
+#else
+#define LINKER_PATH "/system/bin/linker"
+#endif
+static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr);
/* gdb expects the linker to be in the debug shared object list.
* Without this, gdb has trouble locating the linker's ".text"
@@ -2156,12 +2205,6 @@ static soinfo linker_soinfo_for_gdb;
* be on the soinfo list.
*/
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
-#if defined(__LP64__)
- strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker64", sizeof(linker_soinfo_for_gdb.name));
-#else
- strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker", sizeof(linker_soinfo_for_gdb.name));
-#endif
- linker_soinfo_for_gdb.flags = FLAG_NEW_SOINFO;
linker_soinfo_for_gdb.base = linker_base;
/*
@@ -2173,7 +2216,7 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
- &linker_soinfo_for_gdb.dynamic, NULL, NULL);
+ &linker_soinfo_for_gdb.dynamic, nullptr, nullptr);
insert_soinfo_into_debug_map(&linker_soinfo_for_gdb);
}
@@ -2183,16 +2226,6 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
* and other non-local data at this point.
*/
static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
- /* NOTE: we store the args pointer on a special location
- * of the temporary TLS area in order to pass it to
- * the C Library's runtime initializer.
- *
- * The initializer must clear the slot and reset the TLS
- * to point to a different location to ensure that no other
- * shared library constructor can access it.
- */
- __libc_init_tls(args);
-
#if TIMING
struct timeval t0, t1;
gettimeofday(&t0, 0);
@@ -2211,14 +2244,14 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
// Get a few environment variables.
const char* LD_DEBUG = linker_env_get("LD_DEBUG");
- if (LD_DEBUG != NULL) {
+ if (LD_DEBUG != nullptr) {
g_ld_debug_verbosity = atoi(LD_DEBUG);
}
// Normally, these are cleaned by linker_env_init, but the test
// doesn't cost us anything.
- const char* ldpath_env = NULL;
- const char* ldpreload_env = NULL;
+ const char* ldpath_env = nullptr;
+ const char* ldpreload_env = nullptr;
if (!get_AT_SECURE()) {
ldpath_env = linker_env_get("LD_LIBRARY_PATH");
ldpreload_env = linker_env_get("LD_PRELOAD");
@@ -2226,8 +2259,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
INFO("[ android linker & debugger ]");
- soinfo* si = soinfo_alloc(args.argv[0], NULL);
- if (si == NULL) {
+ soinfo* si = soinfo_alloc(args.argv[0], nullptr);
+ if (si == nullptr) {
exit(EXIT_FAILURE);
}
@@ -2237,8 +2270,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
map->l_addr = 0;
map->l_name = args.argv[0];
- map->l_prev = NULL;
- map->l_next = NULL;
+ map->l_prev = nullptr;
+ map->l_next = nullptr;
_r_debug.r_map = map;
r_debug_tail = map;
@@ -2264,7 +2297,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
break;
}
}
- si->dynamic = NULL;
+ si->dynamic = nullptr;
si->ref_count = 1;
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(si->base);
@@ -2279,7 +2312,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
somain = si;
- if (!soinfo_link_image(si, NULL)) {
+ if (!si->LinkImage(nullptr)) {
__libc_format_fd(2, "CANNOT LINK EXECUTABLE: %s\n", linker_get_error_buffer());
exit(EXIT_FAILURE);
}
@@ -2288,11 +2321,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
si->CallPreInitConstructors();
- for (size_t i = 0; g_ld_preloads[i] != NULL; ++i) {
+ for (size_t i = 0; g_ld_preloads[i] != nullptr; ++i) {
g_ld_preloads[i]->CallConstructors();
}
- /* After the link_image, the si->load_bias is initialized.
+ /* After the LinkImage, the si->load_bias is initialized.
* For so lib, the map->l_addr will be updated in notify_gdb_of_load.
* We need to update this value for so exe here. So Unwind_Backtrace
* for some arch like x86 could work correctly within so exe.
@@ -2301,7 +2334,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
si->CallConstructors();
#if TIMING
- gettimeofday(&t1, NULL);
+ gettimeofday(&t1, nullptr);
PRINT("LINKER TIME: %s: %d microseconds", args.argv[0], (int) (
(((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
(((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)));
@@ -2380,10 +2413,6 @@ extern "C" void _start();
* function, or other GOT reference will generate a segfault.
*/
extern "C" ElfW(Addr) __linker_init(void* raw_args) {
- // Initialize static variables.
- solist = get_libdl_info();
- sonext = get_libdl_info();
-
KernelArgumentBlock args(raw_args);
ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
@@ -2391,8 +2420,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
- soinfo linker_so;
- memset(&linker_so, 0, sizeof(soinfo));
+ soinfo linker_so("[dynamic linker]", nullptr);
// If the linker is not acting as PT_INTERP entry_point is equal to
// _start. Which means that the linker is running as an executable and
@@ -2404,16 +2432,15 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
__libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
}
- strcpy(linker_so.name, "[dynamic linker]");
linker_so.base = linker_addr;
linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
- linker_so.dynamic = NULL;
+ linker_so.dynamic = nullptr;
linker_so.phdr = phdr;
linker_so.phnum = elf_hdr->e_phnum;
linker_so.flags |= FLAG_LINKER;
- if (!soinfo_link_image(&linker_so, NULL)) {
+ if (!linker_so.LinkImage(nullptr)) {
// It would be nice to print an error message, but if the linker
// can't link itself, there's no guarantee that we'll be able to
// call write() (because it involves a GOT reference). We may as
@@ -2425,9 +2452,17 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
_exit(EXIT_FAILURE);
}
+ __libc_init_tls(args);
+
// Initialize the linker's own global variables
linker_so.CallConstructors();
+ // Initialize static variables. Note that in order to
+ // get correct libdl_info we need to call constructors
+ // before get_libdl_info().
+ solist = get_libdl_info();
+ sonext = get_libdl_info();
+
// We have successfully fixed our own relocations. It's safe to run
// the main part of the linker now.
args.abort_message_ptr = &g_abort_message;
diff --git a/linker/linker.h b/linker/linker.h
index 0ea1f0301..6547d685e 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -30,6 +30,7 @@
#define _LINKER_H_
#include <elf.h>
+#include <inttypes.h>
#include <link.h>
#include <unistd.h>
#include <android/dlext.h>
@@ -88,6 +89,8 @@
#define FLAG_LINKER 0x00000010 // The linker itself
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
+#define SOINFO_VERSION 1
+
#define SOINFO_NAME_LEN 128
typedef void (*linker_function_t)();
@@ -195,9 +198,13 @@ struct soinfo {
bool has_text_relocations;
#endif
bool has_DT_SYMBOLIC;
+
+ soinfo(const char* name, const struct stat* file_stat);
+
void CallConstructors();
void CallDestructors();
void CallPreInitConstructors();
+ bool LinkImage(const android_dlextinfo* extinfo);
void add_child(soinfo* child);
void remove_all_links();
@@ -209,21 +216,27 @@ struct soinfo {
dev_t get_st_dev();
bool get_has_ifuncs();
-
-
soinfo_list_t& get_children();
+ bool inline has_min_version(uint32_t min_version) {
+ return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
+ }
private:
void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
void CallFunction(const char* function_name, linker_function_t function);
+ void resolve_ifunc_symbols();
+#if defined(USE_RELA)
+ int Relocate(ElfW(Rela)* rela, unsigned count);
+#else
+ int Relocate(ElfW(Rel)* rel, unsigned count);
+#endif
private:
// This part of the structure is only available
// when FLAG_NEW_SOINFO is set in this->flags.
- unsigned int version;
-
- bool has_ifuncs;
+ uint32_t version;
+ // version >= 0
dev_t st_dev;
ino_t st_ino;
@@ -231,6 +244,8 @@ struct soinfo {
soinfo_list_t children;
soinfo_list_t parents;
+ // version >= 1
+ bool has_ifuncs;
};
extern soinfo* get_libdl_info();
@@ -240,11 +255,11 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
void do_dlclose(soinfo* si);
-ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start, soinfo* caller_si);
+ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start);
soinfo* find_containing_library(const void* addr);
ElfW(Sym)* dladdr_find_symbol(soinfo* si, const void* addr);
-ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name, soinfo* caller_si);
+ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name);
void debuggerd_init();
extern "C" abort_msg_t* g_abort_message;
diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp
index 846624b9a..daee56f7e 100644
--- a/linker/linker_environ.cpp
+++ b/linker/linker_environ.cpp
@@ -58,7 +58,7 @@ static void __init_AT_SECURE(KernelArgumentBlock& args) {
// Check if the environment variable definition at 'envstr'
// starts with '<name>=', and if so return the address of the
-// first character after the equal sign. Otherwise return NULL.
+// first character after the equal sign. Otherwise return null.
static const char* env_match(const char* envstr, const char* name) {
size_t i = 0;
@@ -70,7 +70,7 @@ static const char* env_match(const char* envstr, const char* name) {
return envstr + i + 1;
}
- return NULL;
+ return nullptr;
}
static bool __is_valid_environment_variable(const char* name) {
@@ -78,7 +78,7 @@ static bool __is_valid_environment_variable(const char* name) {
// as the maximum size for an env. variable definition.
const int MAX_ENV_LEN = 32*4096;
- if (name == NULL) {
+ if (name == nullptr) {
return false;
}
@@ -136,10 +136,10 @@ static bool __is_unsafe_environment_variable(const char* name) {
"RES_OPTIONS",
"TMPDIR",
"TZDIR",
- NULL
+ nullptr
};
- for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) {
- if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) {
+ for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
+ if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
return true;
}
}
@@ -149,7 +149,7 @@ static bool __is_unsafe_environment_variable(const char* name) {
static void __sanitize_environment_variables() {
char** src = _envp;
char** dst = _envp;
- for (; src[0] != NULL; ++src) {
+ for (; src[0] != nullptr; ++src) {
if (!__is_valid_environment_variable(src[0])) {
continue;
}
@@ -160,11 +160,11 @@ static void __sanitize_environment_variables() {
dst[0] = src[0];
++dst;
}
- dst[0] = NULL;
+ dst[0] = nullptr;
}
void linker_env_init(KernelArgumentBlock& args) {
- // Store environment pointer - can't be NULL.
+ // Store environment pointer - can't be null.
_envp = args.envp;
__init_AT_SECURE(args);
@@ -172,18 +172,18 @@ void linker_env_init(KernelArgumentBlock& args) {
}
const char* linker_env_get(const char* name) {
- if (name == NULL || name[0] == '\0') {
- return NULL;
+ if (name == nullptr || name[0] == '\0') {
+ return nullptr;
}
- for (char** p = _envp; p[0] != NULL; ++p) {
+ for (char** p = _envp; p[0] != nullptr; ++p) {
const char* val = env_match(p[0], name);
- if (val != NULL) {
+ if (val != nullptr) {
if (val[0] == '\0') {
- return NULL; // Return NULL for empty strings.
+ return nullptr; // Return null for empty strings.
}
return val;
}
}
- return NULL;
+ return nullptr;
}
diff --git a/linker/linker_environ.h b/linker/linker_environ.h
index d3f54fd08..0f6ac084d 100644
--- a/linker/linker_environ.h
+++ b/linker/linker_environ.h
@@ -35,7 +35,7 @@ class KernelArgumentBlock;
extern void linker_env_init(KernelArgumentBlock& args);
// Returns the value of environment variable 'name' if defined and not
-// empty, or NULL otherwise.
+// empty, or null otherwise.
extern const char* linker_env_get(const char* name);
// Returns the value of this program's AT_SECURE variable.
diff --git a/tests/libs/dlsym_local_symbol.map b/linker/linker_libc_support.c
index 58a2299a8..17db6d4e7 100644
--- a/tests/libs/dlsym_local_symbol.map
+++ b/linker/linker_libc_support.c
@@ -13,10 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-LIBTEST_LOCAL_SYMBOL_1.0 {
- global:
- dlsym_local_symbol_get_taxicab_number;
- dlsym_local_symbol_get_taxicab_number_using_dlsym;
- local:
- *;
-};
+
+#include "../libc/arch-common/bionic/__dso_handle.h"
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 0b99d2065..1bbd57778 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -121,13 +121,13 @@
ElfReader::ElfReader(const char* name, int fd)
: name_(name), fd_(fd),
- phdr_num_(0), phdr_mmap_(NULL), phdr_table_(NULL), phdr_size_(0),
- load_start_(NULL), load_size_(0), load_bias_(0),
- loaded_phdr_(NULL) {
+ phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
+ load_start_(nullptr), load_size_(0), load_bias_(0),
+ loaded_phdr_(nullptr) {
}
ElfReader::~ElfReader() {
- if (phdr_mmap_ != NULL) {
+ if (phdr_mmap_ != nullptr) {
munmap(phdr_mmap_, phdr_size_);
}
}
@@ -225,7 +225,7 @@ bool ElfReader::ReadProgramHeader() {
phdr_size_ = page_max - page_min;
- void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
+ void* mmap_result = mmap(nullptr, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
if (mmap_result == MAP_FAILED) {
DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
return false;
@@ -242,7 +242,7 @@ bool ElfReader::ReadProgramHeader() {
* process' address space. If there are no loadable segments, 0 is
* returned.
*
- * If out_min_vaddr or out_max_vaddr are non-NULL, they will be
+ * If out_min_vaddr or out_max_vaddr are not null, they will be
* set to the minimum and maximum addresses of pages to be reserved,
* or 0 if there is nothing to load.
*/
@@ -276,10 +276,10 @@ size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
min_vaddr = PAGE_START(min_vaddr);
max_vaddr = PAGE_END(max_vaddr);
- if (out_min_vaddr != NULL) {
+ if (out_min_vaddr != nullptr) {
*out_min_vaddr = min_vaddr;
}
- if (out_max_vaddr != NULL) {
+ if (out_max_vaddr != nullptr) {
*out_max_vaddr = max_vaddr;
}
return max_vaddr - min_vaddr;
@@ -301,7 +301,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
size_t reserved_size = 0;
bool reserved_hint = true;
- if (extinfo != NULL) {
+ if (extinfo != nullptr) {
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
reserved_size = extinfo->reserved_size;
reserved_hint = false;
@@ -585,9 +585,9 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El
return -1;
}
off_t file_size = file_stat.st_size;
- void* temp_mapping = NULL;
+ void* temp_mapping = nullptr;
if (file_size > 0) {
- temp_mapping = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ temp_mapping = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (temp_mapping == MAP_FAILED) {
return -1;
}
@@ -667,7 +667,7 @@ int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, El
* phdr_count -> number of entries in tables
* load_bias -> load bias
* Output:
- * arm_exidx -> address of table in memory (NULL on failure).
+ * arm_exidx -> address of table in memory (null on failure).
* arm_exidx_count -> number of items in table (0 on failure).
* Return:
* 0 on error, -1 on failure (_no_ error code in errno)
@@ -687,21 +687,21 @@ int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count,
*arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
return 0;
}
- *arm_exidx = NULL;
+ *arm_exidx = nullptr;
*arm_exidx_count = 0;
return -1;
}
#endif
/* Return the address and size of the ELF file's .dynamic section in memory,
- * or NULL if missing.
+ * or null if missing.
*
* Input:
* phdr_table -> program header table
* phdr_count -> number of entries in tables
* load_bias -> load bias
* Output:
- * dynamic -> address of table in memory (NULL on failure).
+ * dynamic -> address of table in memory (null on failure).
* dynamic_count -> number of items in table (0 on failure).
* dynamic_flags -> protection flags for section (unset on failure)
* Return:
@@ -727,7 +727,7 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co
}
return;
}
- *dynamic = NULL;
+ *dynamic = nullptr;
if (dynamic_count) {
*dynamic_count = 0;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 611f1a7cb..50708a0e6 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -81,7 +81,7 @@ class ElfReader {
};
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
- ElfW(Addr)* min_vaddr = NULL, ElfW(Addr)* max_vaddr = NULL);
+ ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr);
int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias);
diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp
index b9816fa10..a555edb33 100644
--- a/linker/tests/linked_list_test.cpp
+++ b/linker/tests/linked_list_test.cpp
@@ -80,7 +80,7 @@ TEST(linked_list, simple) {
});
ASSERT_TRUE(!alloc_called);
- ASSERT_TRUE(!free_called);
+ ASSERT_TRUE(free_called);
ASSERT_EQ("dba", test_list_to_string(list));
alloc_called = free_called = false;
@@ -103,15 +103,118 @@ TEST(linked_list, push_pop) {
ASSERT_EQ("ab", test_list_to_string(list));
list.push_back("c");
ASSERT_EQ("abc", test_list_to_string(list));
- ASSERT_EQ("a", list.pop_front());
+ ASSERT_STREQ("a", list.pop_front());
ASSERT_EQ("bc", test_list_to_string(list));
- ASSERT_EQ("b", list.pop_front());
+ ASSERT_STREQ("b", list.pop_front());
ASSERT_EQ("c", test_list_to_string(list));
- ASSERT_EQ("c", list.pop_front());
+ ASSERT_STREQ("c", list.pop_front());
ASSERT_EQ("", test_list_to_string(list));
ASSERT_TRUE(list.pop_front() == nullptr);
list.push_back("r");
ASSERT_EQ("r", test_list_to_string(list));
- ASSERT_EQ("r", list.pop_front());
+ ASSERT_STREQ("r", list.pop_front());
+ ASSERT_TRUE(list.pop_front() == nullptr);
+}
+
+TEST(linked_list, remove_if_then_pop) {
+ test_list_t list;
+ list.push_back("a");
+ list.push_back("b");
+ list.push_back("c");
+ list.push_back("d");
+ list.remove_if([](const char* c) {
+ return *c == 'b' || *c == 'c';
+ });
+
+ ASSERT_EQ("ad", test_list_to_string(list));
+ ASSERT_STREQ("a", list.pop_front());
+ ASSERT_EQ("d", test_list_to_string(list));
+ ASSERT_STREQ("d", list.pop_front());
ASSERT_TRUE(list.pop_front() == nullptr);
}
+
+TEST(linked_list, copy_to_array) {
+ test_list_t list;
+ const size_t max_size = 128;
+ const char* buf[max_size];
+ memset(buf, 0, sizeof(buf));
+
+ ASSERT_EQ(0U, list.size());
+ ASSERT_EQ(0U, list.copy_to_array(buf, max_size));
+ ASSERT_EQ(nullptr, buf[0]);
+
+ list.push_back("a");
+ list.push_back("b");
+ list.push_back("c");
+ list.push_back("d");
+
+ memset(buf, 0, sizeof(buf));
+ ASSERT_EQ(4U, list.size());
+ ASSERT_EQ(2U, list.copy_to_array(buf, 2));
+ ASSERT_STREQ("a", buf[0]);
+ ASSERT_STREQ("b", buf[1]);
+ ASSERT_EQ(nullptr, buf[2]);
+
+ ASSERT_EQ(4U, list.copy_to_array(buf, max_size));
+ ASSERT_STREQ("a", buf[0]);
+ ASSERT_STREQ("b", buf[1]);
+ ASSERT_STREQ("c", buf[2]);
+ ASSERT_STREQ("d", buf[3]);
+ ASSERT_EQ(nullptr, buf[4]);
+
+ memset(buf, 0, sizeof(buf));
+ list.remove_if([](const char* c) {
+ return *c != 'c';
+ });
+ ASSERT_EQ(1U, list.size());
+ ASSERT_EQ(1U, list.copy_to_array(buf, max_size));
+ ASSERT_STREQ("c", buf[0]);
+ ASSERT_EQ(nullptr, buf[1]);
+
+ memset(buf, 0, sizeof(buf));
+
+ list.remove_if([](const char* c) {
+ return *c == 'c';
+ });
+
+ ASSERT_EQ(0U, list.size());
+ ASSERT_EQ(0U, list.copy_to_array(buf, max_size));
+ ASSERT_EQ(nullptr, buf[0]);
+}
+
+TEST(linked_list, test_visit) {
+ test_list_t list;
+ list.push_back("a");
+ list.push_back("b");
+ list.push_back("c");
+ list.push_back("d");
+
+ int visits = 0;
+ std::stringstream ss;
+ bool result = list.visit([&](const char* c) {
+ ++visits;
+ ss << c;
+ return true;
+ });
+
+ ASSERT_TRUE(result);
+ ASSERT_EQ(4, visits);
+ ASSERT_EQ("abcd", ss.str());
+
+ visits = 0;
+ ss.str(std::string());
+
+ result = list.visit([&](const char* c) {
+ if (++visits == 3) {
+ return false;
+ }
+
+ ss << c;
+ return true;
+ });
+
+ ASSERT_TRUE(!result);
+ ASSERT_EQ(3, visits);
+ ASSERT_EQ("ab", ss.str());
+}
+
diff --git a/tests/Android.mk b/tests/Android.mk
index b370b92c1..26014aca3 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -92,8 +92,10 @@ libBionicStandardTests_src_files := \
stdatomic_test.cpp \
stdint_test.cpp \
stdio_test.cpp \
+ stdio_ext_test.cpp \
stdlib_test.cpp \
string_test.cpp \
+ string_posix_strerror_r_test.cpp \
strings_test.cpp \
stubs_test.cpp \
sstream_test.cpp \
@@ -129,6 +131,7 @@ libBionicStandardTests_cppflags := \
libBionicStandardTests_c_includes := \
bionic/libc \
+ external/tinyxml2 \
libBionicStandardTests_ldlibs_host := \
-lrt \
@@ -237,11 +240,16 @@ include $(LOCAL_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
# Tests for the device using bionic's .so. Run with:
-# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
+# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
+# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
# -----------------------------------------------------------------------------
bionic-unit-tests_whole_static_libraries := \
libBionicTests \
+bionic-unit-tests_static_libraries := \
+ libtinyxml2 \
+ liblog \
+
bionic-unit-tests_src_files := \
atexit_test.cpp \
dlext_test.cpp \
@@ -269,7 +277,8 @@ include $(LOCAL_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
# Tests for the device linked against bionic's static library. Run with:
-# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static
+# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
+# adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static64
# -----------------------------------------------------------------------------
bionic-unit-tests-static_whole_static_libraries := \
libBionicTests \
@@ -279,6 +288,8 @@ bionic-unit-tests-static_static_libraries := \
libm \
libc \
libstdc++ \
+ libtinyxml2 \
+ liblog \
bionic-unit-tests-static_force_static_executable := true
@@ -354,6 +365,22 @@ bionic-unit-tests-run-on-host: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LIN
$(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS)
endif
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64))
+# add target to run lp32 tests
+bionic-unit-tests-run-on-host32: bionic-unit-tests_32 $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh
+ if [ ! -d /system -o ! -d /system/bin ]; then \
+ echo "Attempting to create /system/bin"; \
+ sudo mkdir -p -m 0777 /system/bin; \
+ fi
+ mkdir -p $(TARGET_OUT_DATA)/local/tmp
+ cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin
+ cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+ ANDROID_DATA=$(TARGET_OUT_DATA) \
+ ANDROID_ROOT=$(TARGET_OUT) \
+ LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \
+ $(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS)
+endif
+
endif # linux-x86
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/atexit_test.cpp b/tests/atexit_test.cpp
index e01220e1b..e92889d1c 100644
--- a/tests/atexit_test.cpp
+++ b/tests/atexit_test.cpp
@@ -24,20 +24,33 @@
#include <string>
-TEST(atexit, dlclose) {
+TEST(atexit, sofile) {
std::string atexit_call_sequence;
bool valid_this_in_static_dtor = false;
+ bool attr_dtor_called = false;
+
void* handle = dlopen("libtest_atexit.so", RTLD_NOW);
- ASSERT_TRUE(handle != NULL);
+ ASSERT_TRUE(handle != nullptr);
+
+ typedef int (*int_fn)(void);
+ int_fn get_cxx_ctor_called, get_attr_ctor_called;
+ get_cxx_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_cxx_ctor_called"));
+ get_attr_ctor_called = reinterpret_cast<int_fn>(dlsym(handle, "get_attr_ctor_called"));
+ ASSERT_TRUE(get_cxx_ctor_called != nullptr);
+ ASSERT_TRUE(get_attr_ctor_called != nullptr);
+
+ ASSERT_EQ(1, get_cxx_ctor_called());
+ ASSERT_EQ(1, get_attr_ctor_called());
void* sym = dlsym(handle, "register_atexit");
- ASSERT_TRUE(sym != NULL);
- reinterpret_cast<void (*)(std::string*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor);
+ ASSERT_TRUE(sym != nullptr);
+ reinterpret_cast<void (*)(std::string*, bool*, bool*)>(sym)(&atexit_call_sequence, &valid_this_in_static_dtor, &attr_dtor_called);
ASSERT_EQ(0, dlclose(handle));
// this test verifies atexit call from atexit handler. as well as the order of calls
ASSERT_EQ("Humpty Dumpty sat on a wall", atexit_call_sequence);
ASSERT_TRUE(valid_this_in_static_dtor);
+ ASSERT_TRUE(attr_dtor_called);
}
class TestMainStaticDtorClass {
@@ -57,7 +70,7 @@ class TestMainStaticDtorClass {
static const TestMainStaticDtorClass* expected_this;
};
-const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = NULL;
+const TestMainStaticDtorClass* TestMainStaticDtorClass::expected_this = nullptr;
static void atexit_func5() {
fprintf(stderr, "5");
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index da630463d..7bd59c84c 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -117,7 +117,7 @@ TEST_F(DlExtTest, Reserved) {
ASSERT_DL_NOTNULL(handle_);
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
ASSERT_DL_NOTNULL(f);
- EXPECT_GE(f, start);
+ EXPECT_GE(reinterpret_cast<void*>(f), start);
EXPECT_LT(reinterpret_cast<void*>(f),
reinterpret_cast<char*>(start) + LIBSIZE);
EXPECT_EQ(4, f());
@@ -147,7 +147,7 @@ TEST_F(DlExtTest, ReservedHint) {
ASSERT_DL_NOTNULL(handle_);
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
ASSERT_DL_NOTNULL(f);
- EXPECT_GE(f, start);
+ EXPECT_GE(reinterpret_cast<void*>(f), start);
EXPECT_LT(reinterpret_cast<void*>(f),
reinterpret_cast<char*>(start) + LIBSIZE);
EXPECT_EQ(4, f());
@@ -165,8 +165,9 @@ TEST_F(DlExtTest, ReservedHintTooSmall) {
ASSERT_DL_NOTNULL(handle_);
fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
ASSERT_DL_NOTNULL(f);
- EXPECT_TRUE(f < start || (reinterpret_cast<void*>(f) >=
- reinterpret_cast<char*>(start) + PAGE_SIZE));
+ EXPECT_TRUE(reinterpret_cast<void*>(f) < start ||
+ (reinterpret_cast<void*>(f) >=
+ reinterpret_cast<char*>(start) + PAGE_SIZE));
EXPECT_EQ(4, f());
}
@@ -259,6 +260,11 @@ TEST_F(DlExtRelroSharingTest, RelroFileEmpty) {
}
TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) {
+ if (geteuid() != 0) {
+ GTEST_LOG_(INFO) << "This test must be run as root.\n";
+ return;
+ }
+
ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME));
int relro_fd = open(relro_file_, O_RDONLY);
ASSERT_NOERROR(relro_fd);
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index be0523018..6bdde4450 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -62,25 +62,6 @@ TEST(dlfcn, dlsym_in_self) {
ASSERT_EQ(0, dlclose(self));
}
-#if defined(__arm__)
-// This seems to be working only for arm.
-// Others platforms optimize LOCAL PROTECTED symbols.
-TEST(dlfcn, dlsym_local_symbol) {
- void* handle = dlopen("libtest_local_symbol.so", RTLD_NOW);
- ASSERT_TRUE(handle != NULL);
- dlerror();
- void* sym = dlsym(handle, "private_taxicab_number");
- ASSERT_TRUE(sym == NULL);
- ASSERT_STREQ("undefined symbol: private_taxicab_number", dlerror());
-
- uint32_t (*f)(void);
- f = reinterpret_cast<uint32_t (*)(void)>(dlsym(handle, "dlsym_local_symbol_get_taxicab_number_using_dlsym"));
- ASSERT_TRUE(f != NULL);
- ASSERT_EQ(1729U, f());
- dlclose(handle);
-}
-#endif
-
TEST(dlfcn, dlsym_with_dependencies) {
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
ASSERT_TRUE(handle != NULL);
@@ -109,32 +90,42 @@ TEST(dlfcn, dlopen_noload) {
// ifuncs are only supported on intel for now
#if defined(__i386__) || defined(__x86_64__)
TEST(dlfcn, ifunc) {
- const char* (*foo_ptr)();
- const char* (*foo_library_ptr)();
+ typedef const char* (*fn_ptr)();
// ifunc's choice depends on whether IFUNC_CHOICE has a value
// first check the set case
setenv("IFUNC_CHOICE", "set", 1);
void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
ASSERT_TRUE(handle != NULL);
- *(void **)(&foo_ptr) = dlsym(handle, "foo");
- *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+ fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+ fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
ASSERT_TRUE(foo_ptr != NULL);
ASSERT_TRUE(foo_library_ptr != NULL);
- ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0);
- ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0);
+ ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
+ ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
dlclose(handle);
// then check the unset case
unsetenv("IFUNC_CHOICE");
handle = dlopen("libtest_ifunc.so", RTLD_NOW);
ASSERT_TRUE(handle != NULL);
- *(void **)(&foo_ptr) = dlsym(handle, "foo");
- *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+ foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+ foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
ASSERT_TRUE(foo_ptr != NULL);
ASSERT_TRUE(foo_library_ptr != NULL);
- ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0);
- ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0);
+ ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
+ ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
+ dlclose(handle);
+}
+
+TEST(dlfcn, ifunc_ctor_call) {
+ typedef const char* (*fn_ptr)();
+
+ void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+ ASSERT_TRUE(handle != NULL) << dlerror();
+ fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called"));
+ ASSERT_TRUE(is_ctor_called != NULL) << dlerror();
+ ASSERT_STREQ("true", is_ctor_called());
dlclose(handle);
}
#endif
@@ -240,10 +231,8 @@ TEST(dlfcn, dladdr) {
// Look in /proc/pid/maps to find out what address we were loaded at.
// TODO: factor /proc/pid/maps parsing out into a class and reuse all over bionic.
void* base_address = NULL;
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "/proc/%d/maps", getpid());
char line[BUFSIZ];
- FILE* fp = fopen(path, "r");
+ FILE* fp = fopen("/proc/self/maps", "r");
ASSERT_TRUE(fp != NULL);
while (fgets(line, sizeof(line), fp) != NULL) {
uintptr_t start = strtoul(line, 0, 16);
@@ -349,4 +338,6 @@ TEST(dlfcn, dlopen_symlink) {
ASSERT_TRUE(handle1 != NULL);
ASSERT_TRUE(handle2 != NULL);
ASSERT_EQ(handle1, handle2);
+ dlclose(handle1);
+ dlclose(handle2);
}
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
index 51c9db84e..b33115007 100644
--- a/tests/getauxval_test.cpp
+++ b/tests/getauxval_test.cpp
@@ -15,7 +15,6 @@
*/
#include <sys/cdefs.h>
-#include <features.h>
#include <gtest/gtest.h>
// getauxval() was only added as of glibc version 2.16.
diff --git a/tests/libc_logging_test.cpp b/tests/libc_logging_test.cpp
index 950161e78..d4ceded45 100644
--- a/tests/libc_logging_test.cpp
+++ b/tests/libc_logging_test.cpp
@@ -176,3 +176,15 @@ TEST(libc_logging, lld_LLONG_MIN) {
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
}
+
+TEST(libc_logging, buffer_overrun) {
+#if defined(__BIONIC__)
+ char buf[BUFSIZ];
+ ASSERT_EQ(11, __libc_format_buffer(buf, sizeof(buf), "hello %s", "world"));
+ EXPECT_STREQ("hello world", buf);
+ ASSERT_EQ(11, __libc_format_buffer(buf, 8, "hello %s", "world"));
+ EXPECT_STREQ("hello w", buf);
+#else // __BIONIC__
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif // __BIONIC__
+}
diff --git a/tests/libgen_test.cpp b/tests/libgen_test.cpp
index cae646f25..d0402dbf6 100644
--- a/tests/libgen_test.cpp
+++ b/tests/libgen_test.cpp
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <libgen.h>
#include <errno.h>
+#include <gtest/gtest.h>
static void TestBasename(const char* in, const char* expected_out) {
char* writable_in = (in != NULL) ? strdup(in) : NULL;
@@ -40,7 +39,7 @@ static void TestDirname(const char* in, const char* expected_out) {
// Do not use basename as the test name, it's defined to another value in glibc
// so leads to a differently named test on host versus target architectures.
-TEST(libgen, basename_smoke) {
+TEST(libgen, posix_basename) {
TestBasename(NULL, ".");
TestBasename("", ".");
TestBasename("/usr/lib", "lib");
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index bca2047e2..b1cc836c6 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -17,6 +17,7 @@
LOCAL_PATH := $(call my-dir)
TEST_PATH := $(LOCAL_PATH)/..
+common_cppflags += -std=gnu++11
# -----------------------------------------------------------------------------
# Library used by dlfcn tests.
# -----------------------------------------------------------------------------
@@ -129,21 +130,6 @@ ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64))
endif
# -----------------------------------------------------------------------------
-# Library used to test local symbol lookup
-# -----------------------------------------------------------------------------
-libtest_local_symbol_src_files := \
- dlsym_local_symbol_private.cpp \
- dlsym_local_symbol_public.cpp
-
-module := libtest_local_symbol
-build_target := SHARED_LIBRARY
-libtest_local_symbol_ldflags := -Wl,--version-script=$(LOCAL_PATH)/dlsym_local_symbol.map
-libtest_local_symbol_cppflags := -std=gnu++11
-libtest_local_symbol_shared_libraries_target := libdl
-build_type := target
-include $(TEST_PATH)/Android.build.mk
-
-# -----------------------------------------------------------------------------
# Library used by atexit tests
# -----------------------------------------------------------------------------
diff --git a/tests/libs/atexit_testlib.cpp b/tests/libs/atexit_testlib.cpp
index d35f57b74..314e8de26 100644
--- a/tests/libs/atexit_testlib.cpp
+++ b/tests/libs/atexit_testlib.cpp
@@ -19,12 +19,19 @@
#include <string>
// use external control number from main test
-static std::string* atexit_sequence = NULL;
-static bool* atexit_valid_this_in_static_dtor = NULL;
+static std::string* atexit_sequence = nullptr;
+static bool* atexit_valid_this_in_static_dtor = nullptr;
+static bool* atexit_attr_dtor_called = nullptr;
+
+static int cxx_ctor_called = 0;
+static int attr_ctor_called = 0;
static class AtExitStaticClass {
public:
- AtExitStaticClass() { expected_this = this; }
+ AtExitStaticClass() {
+ expected_this = this;
+ cxx_ctor_called = 1;
+ }
~AtExitStaticClass() {
if (atexit_valid_this_in_static_dtor) {
*atexit_valid_this_in_static_dtor = (expected_this == this);
@@ -35,7 +42,7 @@ static class AtExitStaticClass {
} static_obj;
-const AtExitStaticClass* AtExitStaticClass::expected_this = NULL;
+const AtExitStaticClass* AtExitStaticClass::expected_this = nullptr;
// 4
static void atexit_handler_from_atexit_from_atexit2() {
@@ -66,10 +73,30 @@ static void atexit_handler_regular() {
*atexit_sequence += " a wall";
}
-extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor) {
+// attribute c-tor and d-tor
+static void __attribute__((constructor)) atexit_attr_ctor() {
+ attr_ctor_called = 1;
+}
+
+static void __attribute__((destructor)) atexit_attr_dtor() {
+ if (atexit_attr_dtor_called) {
+ *atexit_attr_dtor_called = true;
+ }
+}
+
+extern "C" void register_atexit(std::string* sequence, bool* valid_this_in_static_dtor, bool* attr_dtor_called) {
atexit_sequence = sequence;
atexit_valid_this_in_static_dtor = valid_this_in_static_dtor;
+ atexit_attr_dtor_called = attr_dtor_called;
atexit(atexit_handler_regular);
atexit(atexit_handler_with_atexit);
}
+extern "C" int get_cxx_ctor_called() {
+ return cxx_ctor_called;
+}
+
+extern "C" int get_attr_ctor_called() {
+ return attr_ctor_called;
+}
+
diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c
index 1c4baface..48748417d 100644
--- a/tests/libs/dlopen_testlib_ifunc.c
+++ b/tests/libs/dlopen_testlib_ifunc.c
@@ -17,7 +17,22 @@
#include <stdio.h>
#include <stdlib.h>
+static int g_flag = 0;
+
+static void __attribute__((constructor)) init_flag() {
+ g_flag = 1;
+}
+
const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+const char* return_true() {
+ return "true";
+}
+
+const char* return_false() {
+ return "false";
+}
const char* f1() {
return "unset";
@@ -27,6 +42,10 @@ const char* f2() {
return "set";
}
+void* is_ctor_called_ifun() {
+ return g_flag == 0 ? return_false : return_true;
+}
+
void* foo_ifunc() {
char* choice = getenv("IFUNC_CHOICE");
return choice == NULL ? f1 : f2;
@@ -34,4 +53,4 @@ void* foo_ifunc() {
const char* foo_library() {
return foo();
-} \ No newline at end of file
+}
diff --git a/tests/libs/dlsym_local_symbol_public.cpp b/tests/libs/dlsym_local_symbol_public.cpp
deleted file mode 100644
index d9da32a59..000000000
--- a/tests/libs/dlsym_local_symbol_public.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <stdio.h>
-
-extern const uint32_t private_taxicab_number;
-
-extern "C" {
-uint32_t dlsym_local_symbol_get_taxicab_number();
-uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym();
-}
-
-uint32_t dlsym_local_symbol_get_taxicab_number() {
- return private_taxicab_number;
-}
-
-// Let's make sure that dlsym works correctly for local symbol
-uint32_t dlsym_local_symbol_get_taxicab_number_using_dlsym() {
- dlerror();
- uint32_t* ptr = reinterpret_cast<uint32_t*>(dlsym(RTLD_DEFAULT, "private_taxicab_number"));
- if (ptr == nullptr) {
- const char* dlerr = dlerror();
- if (dlerr != nullptr) {
- fprintf(stderr, "dlsym error: %s\n", dlerr);
- } else {
- fprintf(stderr, "dlsym returned NULL with no dlerror.\n");
- }
- return 0;
- }
-
- return *ptr;
-}
diff --git a/tests/locale_test.cpp b/tests/locale_test.cpp
index 325f6ceda..7ec607a28 100644
--- a/tests/locale_test.cpp
+++ b/tests/locale_test.cpp
@@ -114,11 +114,12 @@ TEST(locale, mb_cur_max) {
locale_t cloc = newlocale(LC_ALL, "C", 0);
locale_t cloc_utf8 = newlocale(LC_ALL, "C.UTF-8", 0);
- uselocale(cloc);
+ locale_t old_locale = uselocale(cloc);
ASSERT_EQ(1U, MB_CUR_MAX);
uselocale(cloc_utf8);
ASSERT_EQ(4U, MB_CUR_MAX);
+ uselocale(old_locale);
freelocale(cloc);
freelocale(cloc_utf8);
}
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 6b7a28b1c..b76625a7a 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -22,6 +22,8 @@
#include <malloc.h>
#include <unistd.h>
+#include <tinyxml2.h>
+
#include "private/bionic_config.h"
TEST(malloc, malloc_std) {
@@ -322,3 +324,51 @@ TEST(malloc, valloc_overflow) {
ASSERT_EQ(NULL, valloc(SIZE_MAX));
}
#endif
+
+TEST(malloc, malloc_info) {
+#ifdef __BIONIC__
+ char* buf;
+ size_t bufsize;
+ FILE* memstream = open_memstream(&buf, &bufsize);
+ ASSERT_NE(nullptr, memstream);
+ ASSERT_EQ(0, malloc_info(0, memstream));
+ ASSERT_EQ(0, fclose(memstream));
+
+ tinyxml2::XMLDocument doc;
+ ASSERT_EQ(tinyxml2::XML_SUCCESS, doc.Parse(buf));
+
+ auto root = doc.FirstChildElement();
+ ASSERT_NE(nullptr, root);
+ ASSERT_STREQ("malloc", root->Name());
+ ASSERT_STREQ("jemalloc-1", root->Attribute("version"));
+
+ auto arena = root->FirstChildElement();
+ for (; arena != nullptr; arena = arena->NextSiblingElement()) {
+ int val;
+
+ ASSERT_STREQ("heap", arena->Name());
+ ASSERT_EQ(tinyxml2::XML_SUCCESS, arena->QueryIntAttribute("nr", &val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-large")->QueryIntText(&val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-huge")->QueryIntText(&val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("allocated-bins")->QueryIntText(&val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ arena->FirstChildElement("bins-total")->QueryIntText(&val));
+
+ auto bin = arena->FirstChildElement("bin");
+ for (; bin != nullptr; bin = bin ->NextSiblingElement()) {
+ if (strcmp(bin->Name(), "bin") == 0) {
+ ASSERT_EQ(tinyxml2::XML_SUCCESS, bin->QueryIntAttribute("nr", &val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ bin->FirstChildElement("allocated")->QueryIntText(&val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ bin->FirstChildElement("nmalloc")->QueryIntText(&val));
+ ASSERT_EQ(tinyxml2::XML_SUCCESS,
+ bin->FirstChildElement("ndalloc")->QueryIntText(&val));
+ }
+ }
+ }
+#endif
+}
diff --git a/tests/math_cos_test.cpp b/tests/math_cos_test.cpp
index c0a2d82c7..4917e87fa 100644
--- a/tests/math_cos_test.cpp
+++ b/tests/math_cos_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -5634,6 +5636,7 @@ static cos_intel_data_t g_cos_intel_data[] = {
TEST(math_cos, cos_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_cos_intel_data)/sizeof(cos_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_cos_intel_data[i].expected, cos(g_cos_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_cosf_test.cpp b/tests/math_cosf_test.cpp
index ea95ff317..8520c1dcc 100644
--- a/tests/math_cosf_test.cpp
+++ b/tests/math_cosf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -4346,6 +4348,7 @@ static cosf_intel_data_t g_cosf_intel_data[] = {
TEST(math_cosf, cosf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_cosf_intel_data)/sizeof(cosf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_cosf_intel_data[i].expected, cosf(g_cosf_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_exp_test.cpp b/tests/math_exp_test.cpp
index beb258497..c9c6ad594 100644
--- a/tests/math_exp_test.cpp
+++ b/tests/math_exp_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -1966,6 +1968,7 @@ static exp_intel_data_t g_exp_intel_data[] = {
TEST(math_exp, exp_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_exp_intel_data)/sizeof(exp_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_exp_intel_data[i].expected, exp(g_exp_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_expf_test.cpp b/tests/math_expf_test.cpp
index 257aa26bb..30bc94690 100644
--- a/tests/math_expf_test.cpp
+++ b/tests/math_expf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -1430,6 +1432,7 @@ static expf_intel_data_t g_expf_intel_data[] = {
TEST(math_expf, expf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_expf_intel_data)/sizeof(expf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_expf_intel_data[i].expected, expf(g_expf_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_log_test.cpp b/tests/math_log_test.cpp
index da2a848e4..4f136a774 100644
--- a/tests/math_log_test.cpp
+++ b/tests/math_log_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -1666,6 +1668,7 @@ static log_intel_data_t g_log_intel_data[] = {
TEST(math_log, log_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_log_intel_data)/sizeof(log_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_log_intel_data[i].expected, log(g_log_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_logf_test.cpp b/tests/math_logf_test.cpp
index e5d0921d8..ca02095c1 100644
--- a/tests/math_logf_test.cpp
+++ b/tests/math_logf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -1318,6 +1320,7 @@ static logf_intel_data_t g_logf_intel_data[] = {
TEST(math_logf, logf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_logf_intel_data)/sizeof(logf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_logf_intel_data[i].expected, logf(g_logf_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_pow_test.cpp b/tests/math_pow_test.cpp
index c185424c7..a4caa36cc 100644
--- a/tests/math_pow_test.cpp
+++ b/tests/math_pow_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -3291,6 +3293,7 @@ static pow_intel_data_t g_pow_intel_data[] = {
TEST(math_pow, pow_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_pow_intel_data)/sizeof(pow_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_pow_intel_data[i].expected, pow(g_pow_intel_data[i].x_call_data, g_pow_intel_data[i].y_call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_powf_test.cpp b/tests/math_powf_test.cpp
index f77b23a4b..72726447f 100644
--- a/tests/math_powf_test.cpp
+++ b/tests/math_powf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -2779,6 +2781,7 @@ static powf_intel_data_t g_powf_intel_data[] = {
TEST(math_powf, powf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_powf_intel_data)/sizeof(powf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_powf_intel_data[i].expected, powf(g_powf_intel_data[i].x_call_data, g_powf_intel_data[i].y_call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_sin_test.cpp b/tests/math_sin_test.cpp
index ffa43409d..509642ca8 100644
--- a/tests/math_sin_test.cpp
+++ b/tests/math_sin_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -5786,6 +5788,7 @@ static sin_intel_data_t g_sin_intel_data[] = {
TEST(math_sin, sin_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_sin_intel_data)/sizeof(sin_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_sin_intel_data[i].expected, sin(g_sin_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_sincos_test.cpp b/tests/math_sincos_test.cpp
index 0fab2c20f..4093fb9df 100644
--- a/tests/math_sincos_test.cpp
+++ b/tests/math_sincos_test.cpp
@@ -14,8 +14,12 @@
* limitations under the License.
*/
+#define _GNU_SOURCE 1
+
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -4776,6 +4780,7 @@ static sincos_intel_data_t g_sincos_intel_data[] = {
TEST(math_sincos, sincos_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_sincos_intel_data)/sizeof(sincos_intel_data_t); i++) {
double dsin, dcos;
sincos(g_sincos_intel_data[i].call_data, &dsin, &dcos);
diff --git a/tests/math_sincosf_test.cpp b/tests/math_sincosf_test.cpp
index c1a32c9e0..d30f72e90 100644
--- a/tests/math_sincosf_test.cpp
+++ b/tests/math_sincosf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -4646,6 +4648,7 @@ static sincosf_intel_data_t g_sincosf_intel_data[] = {
TEST(math_sincosf, sincosf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_sincosf_intel_data)/sizeof(sincosf_intel_data_t); i++) {
float fsin, fcos;
sincosf(g_sincosf_intel_data[i].call_data, &fsin, &fcos);
diff --git a/tests/math_sinf_test.cpp b/tests/math_sinf_test.cpp
index bb1e2c953..0c2e6f172 100644
--- a/tests/math_sinf_test.cpp
+++ b/tests/math_sinf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -4386,6 +4388,7 @@ static sinf_intel_data_t g_sinf_intel_data[] = {
TEST(math_sinf, sinf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_sinf_intel_data)/sizeof(sinf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_sinf_intel_data[i].expected, sinf(g_sinf_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_tan_test.cpp b/tests/math_tan_test.cpp
index 68620194a..e555ef3c9 100644
--- a/tests/math_tan_test.cpp
+++ b/tests/math_tan_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -5194,6 +5196,7 @@ static tan_intel_data_t g_tan_intel_data[] = {
TEST(math_tan, tan_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_tan_intel_data)/sizeof(tan_intel_data_t); i++) {
EXPECT_DOUBLE_EQ(g_tan_intel_data[i].expected, tan(g_tan_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/math_tanf_test.cpp b/tests/math_tanf_test.cpp
index 9319046cb..db04116b5 100644
--- a/tests/math_tanf_test.cpp
+++ b/tests/math_tanf_test.cpp
@@ -16,6 +16,8 @@
#include <math.h>
+#include <fenv.h>
+
#include <gtest/gtest.h>
#if defined(__BIONIC__)
@@ -4450,6 +4452,7 @@ static tanf_intel_data_t g_tanf_intel_data[] = {
TEST(math_tanf, tanf_intel) {
#if defined(__BIONIC__)
+ fesetenv(FE_DFL_ENV);
for (size_t i = 0; i < sizeof(g_tanf_intel_data)/sizeof(tanf_intel_data_t); i++) {
EXPECT_FLOAT_EQ(g_tanf_intel_data[i].expected, tanf(g_tanf_intel_data[i].call_data)) << "Failed on element " << i;
}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 5328e48cf..bbac7fe95 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -23,6 +23,7 @@
#include <pthread.h>
#include <signal.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
@@ -104,6 +105,7 @@ TEST(pthread, pthread_key_fork) {
ASSERT_EQ(99, WEXITSTATUS(status));
ASSERT_EQ(expected, pthread_getspecific(key));
+ ASSERT_EQ(0, pthread_key_delete(key));
}
static void* DirtyKeyFn(void* key) {
@@ -131,6 +133,7 @@ TEST(pthread, pthread_key_dirty) {
ASSERT_EQ(nullptr, result); // Not ~0!
ASSERT_EQ(0, munmap(stack, stack_size));
+ ASSERT_EQ(0, pthread_key_delete(key));
}
static void* IdFn(void* arg) {
@@ -816,3 +819,81 @@ TEST(pthread, pthread_mutex_timedlock) {
ASSERT_EQ(0, pthread_mutex_unlock(&m));
ASSERT_EQ(0, pthread_mutex_destroy(&m));
}
+
+TEST(pthread, pthread_attr_getstack__main_thread) {
+ // This test is only meaningful for the main thread, so make sure we're running on it!
+ ASSERT_EQ(getpid(), syscall(__NR_gettid));
+
+ // Get the main thread's attributes.
+ pthread_attr_t attributes;
+ ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes));
+
+ // Check that we correctly report that the main thread has no guard page.
+ size_t guard_size;
+ ASSERT_EQ(0, pthread_attr_getguardsize(&attributes, &guard_size));
+ ASSERT_EQ(0U, guard_size); // The main thread has no guard page.
+
+ // Get the stack base and the stack size (both ways).
+ void* stack_base;
+ size_t stack_size;
+ ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size));
+ size_t stack_size2;
+ ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2));
+
+ // The two methods of asking for the stack size should agree.
+ EXPECT_EQ(stack_size, stack_size2);
+
+ // What does /proc/self/maps' [stack] line say?
+ void* maps_stack_hi = NULL;
+ FILE* fp = fopen("/proc/self/maps", "r");
+ ASSERT_TRUE(fp != NULL);
+ char line[BUFSIZ];
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ uintptr_t lo, hi;
+ char name[10];
+ sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d %10s", &lo, &hi, name);
+ if (strcmp(name, "[stack]") == 0) {
+ maps_stack_hi = reinterpret_cast<void*>(hi);
+ break;
+ }
+ }
+ fclose(fp);
+
+ // The stack size should correspond to RLIMIT_STACK.
+ rlimit rl;
+ ASSERT_EQ(0, getrlimit(RLIMIT_STACK, &rl));
+ EXPECT_EQ(rl.rlim_cur, stack_size);
+
+ // The high address of the /proc/self/maps [stack] region should equal stack_base + stack_size.
+ // Remember that the stack grows down (and is mapped in on demand), so the low address of the
+ // region isn't very interesting.
+ EXPECT_EQ(maps_stack_hi, reinterpret_cast<uint8_t*>(stack_base) + stack_size);
+
+ //
+ // What if RLIMIT_STACK is smaller than the stack's current extent?
+ //
+ rl.rlim_cur = rl.rlim_max = 1024; // 1KiB. We know the stack must be at least a page already.
+ rl.rlim_max = RLIM_INFINITY;
+ ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
+
+ ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes));
+ ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size));
+ ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2));
+
+ EXPECT_EQ(stack_size, stack_size2);
+ ASSERT_EQ(1024U, stack_size);
+
+ //
+ // What if RLIMIT_STACK isn't a whole number of pages?
+ //
+ rl.rlim_cur = rl.rlim_max = 6666; // Not a whole number of pages.
+ rl.rlim_max = RLIM_INFINITY;
+ ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl));
+
+ ASSERT_EQ(0, pthread_getattr_np(pthread_self(), &attributes));
+ ASSERT_EQ(0, pthread_attr_getstack(&attributes, &stack_base, &stack_size));
+ ASSERT_EQ(0, pthread_attr_getstacksize(&attributes, &stack_size2));
+
+ EXPECT_EQ(stack_size, stack_size2);
+ ASSERT_EQ(6666U, stack_size);
+}
diff --git a/tests/stdatomic_test.cpp b/tests/stdatomic_test.cpp
index 5e88c8801..b7fb19b0d 100644
--- a/tests/stdatomic_test.cpp
+++ b/tests/stdatomic_test.cpp
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
-#if !defined(__GLIBC__) /* TODO: fix our prebuilt toolchains! */
-
#include <stdatomic.h>
+#include <gtest/gtest.h>
+#include <pthread.h>
+#include <stdint.h>
TEST(stdatomic, LOCK_FREE) {
ASSERT_TRUE(ATOMIC_BOOL_LOCK_FREE);
@@ -64,14 +63,17 @@ TEST(stdatomic, atomic_signal_fence) {
TEST(stdatomic, atomic_is_lock_free) {
atomic_char small;
- atomic_intmax_t big;
ASSERT_TRUE(atomic_is_lock_free(&small));
+#if defined(__clang__) || __GNUC_PREREQ(4, 7)
+ // Otherwise stdatomic.h doesn't handle this.
+ atomic_intmax_t big;
// atomic_intmax_t(size = 64) is not lock free on mips32.
#if defined(__mips__) && !defined(__LP64__)
ASSERT_FALSE(atomic_is_lock_free(&big));
#else
ASSERT_TRUE(atomic_is_lock_free(&big));
#endif
+#endif
}
TEST(stdatomic, atomic_flag) {
@@ -167,4 +169,80 @@ TEST(stdatomic, atomic_fetch_and) {
ASSERT_EQ(0x002, atomic_load(&i));
}
-#endif
+// And a rudimentary test of acquire-release memory ordering:
+
+constexpr static uint_least32_t BIG = 10000000ul; // Assumed even below.
+
+struct three_atomics {
+ atomic_uint_least32_t x;
+ char a[123]; // Everything in different cache lines,
+ // increase chance of compiler getting alignment wrong.
+ atomic_uint_least32_t y;
+ char b[4013];
+ atomic_uint_least32_t z;
+};
+
+// Very simple acquire/release memory ordering sanity check.
+static void* writer(void* arg) {
+ three_atomics* a = reinterpret_cast<three_atomics*>(arg);
+ for (uint_least32_t i = 0; i <= BIG; i+=2) {
+ atomic_store_explicit(&a->x, i, memory_order_relaxed);
+ atomic_store_explicit(&a->z, i, memory_order_relaxed);
+ atomic_store_explicit(&a->y, i, memory_order_release);
+ atomic_store_explicit(&a->x, i+1, memory_order_relaxed);
+ atomic_store_explicit(&a->z, i+1, memory_order_relaxed);
+ atomic_store_explicit(&a->y, i+1, memory_order_release);
+ }
+ return 0;
+}
+
+static void* reader(void* arg) {
+ three_atomics* a = reinterpret_cast<three_atomics*>(arg);
+ uint_least32_t xval = 0, yval = 0, zval = 0;
+ size_t repeat = 0;
+ size_t repeat_limit = 1000;
+ while (yval != BIG + 1) {
+ yval = atomic_load_explicit(&a->y, memory_order_acquire);
+ zval = atomic_load_explicit(&a->z, memory_order_relaxed);
+ xval = atomic_load_explicit(&a->x, memory_order_relaxed);
+ // If we see a given value of y, the immediately preceding
+ // stores to z and x, or later ones, should also be visible.
+ if (zval < yval) {
+ // Cant just ASSERT, since we are in a non-void function.
+ ADD_FAILURE() << "acquire-release ordering violation: "
+ << zval << " < " << yval << ", " << xval << "\n";
+ return 0; // Only report once.
+ }
+ if (xval < yval) {
+ // Cant just ASSERT, since we are in a non-void function.
+ ADD_FAILURE() << "acquire-release ordering violation: "
+ << xval << " < " << yval << ", " << zval << "\n";
+ return 0; // Only report once.
+ }
+ if (repeat < repeat_limit) ++repeat;
+ }
+ // The following assertion is not technically guaranteed to hold.
+ // But if it fails to hold, this test was useless, and we have a
+ // serious scheduling issue that we should probably know about.
+ EXPECT_EQ(repeat, repeat_limit);
+ return 0;
+}
+
+TEST(stdatomic, ordering) {
+ // Run a memory ordering sanity test.
+ void* result;
+ three_atomics a;
+ atomic_init(&a.x, 0ul);
+ atomic_init(&a.y, 0ul);
+ atomic_init(&a.z, 0ul);
+ pthread_t t1,t2;
+ ASSERT_EQ(0, pthread_create(&t1, 0, reader, &a));
+ ASSERT_EQ(0, pthread_create(&t2, 0, writer, &a));
+ ASSERT_EQ(0, pthread_join(t1, &result));
+ EXPECT_EQ(0, result);
+ ASSERT_EQ(0, pthread_join(t2, &result));
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(atomic_load_explicit(&a.x, memory_order_consume), BIG + 1);
+ EXPECT_EQ(atomic_load_explicit(&a.y, memory_order_seq_cst), BIG + 1);
+ EXPECT_EQ(atomic_load(&a.z), BIG + 1);
+}
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
new file mode 100644
index 000000000..3dbc485a6
--- /dev/null
+++ b/tests/stdio_ext_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio_ext.h>
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <locale.h>
+
+#include "TemporaryFile.h"
+
+TEST(stdio_ext, __fbufsize) {
+ FILE* fp = fopen("/proc/version", "r");
+
+ char buf[128];
+
+ ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 1));
+ ASSERT_EQ(1U, __fbufsize(fp));
+
+ ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 8));
+ ASSERT_EQ(8U, __fbufsize(fp));
+
+ fclose(fp);
+}
+
+TEST(stdio_ext, __flbf) {
+ FILE* fp = fopen("/proc/version", "r");
+
+ ASSERT_FALSE(__flbf(fp));
+
+ char buf[128];
+ ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf)));
+
+ ASSERT_TRUE(__flbf(fp));
+
+ fclose(fp);
+}
+
+TEST(stdio_ext, __fpending) {
+ FILE* fp = fopen("/dev/null", "w");
+ ASSERT_EQ(0U, __fpending(fp));
+ ASSERT_EQ('x', fputc('x', fp));
+ ASSERT_EQ(1U, __fpending(fp));
+ ASSERT_EQ('y', fputc('y', fp));
+ ASSERT_EQ(2U, __fpending(fp));
+ fflush(fp);
+ ASSERT_EQ(0U, __fpending(fp));
+ fclose(fp);
+}
+
+TEST(stdio_ext, __fpurge) {
+ FILE* fp = tmpfile();
+
+ ASSERT_EQ('a', fputc('a', fp));
+ ASSERT_EQ(1U, __fpending(fp));
+ __fpurge(fp);
+ ASSERT_EQ(0U, __fpending(fp));
+
+ ASSERT_EQ('b', fputc('b', fp));
+ ASSERT_EQ('\n', fputc('\n', fp));
+ ASSERT_EQ(2U, __fpending(fp));
+
+ rewind(fp);
+
+ char buf[16];
+ char* s = fgets(buf, sizeof(buf), fp);
+ ASSERT_TRUE(s != NULL);
+ ASSERT_STREQ("b\n", s);
+
+ fclose(fp);
+}
+
+TEST(stdio_ext, _flushlbf) {
+ FILE* fp = fopen("/dev/null", "w");
+
+ char buf[128];
+ ASSERT_EQ(0, setvbuf(fp, buf, _IOLBF, sizeof(buf)));
+
+ ASSERT_EQ('a', fputc('a', fp));
+ ASSERT_EQ(1U, __fpending(fp));
+
+ _flushlbf();
+
+ ASSERT_EQ(0U, __fpending(fp));
+
+ fclose(fp);
+}
+
+TEST(stdio_ext, __freadable__fwritable) {
+ FILE* fp = fopen("/dev/null", "r");
+ ASSERT_TRUE(__freadable(fp));
+ ASSERT_FALSE(__fwritable(fp));
+ fclose(fp);
+
+ fp = fopen("/dev/null", "w");
+ ASSERT_FALSE(__freadable(fp));
+ ASSERT_TRUE(__fwritable(fp));
+ fclose(fp);
+
+ fp = fopen("/dev/null", "w+");
+ ASSERT_TRUE(__freadable(fp));
+ ASSERT_TRUE(__fwritable(fp));
+ fclose(fp);
+}
+
+TEST(stdio_ext, __fsetlocking) {
+ FILE* fp = fopen("/proc/version", "r");
+ // Android doesn't actually support the other modes.
+ ASSERT_EQ(FSETLOCKING_INTERNAL, __fsetlocking(fp, FSETLOCKING_QUERY));
+ fclose(fp);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index bb86509c2..c01ab683c 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -428,7 +428,7 @@ TEST(stdio, snprintf_negative_zero_5084292) {
TEST(stdio, snprintf_utf8_15439554) {
locale_t cloc = newlocale(LC_ALL, "C.UTF-8", 0);
- uselocale(cloc);
+ locale_t old_locale = uselocale(cloc);
// http://b/15439554
char buf[BUFSIZ];
@@ -446,6 +446,7 @@ TEST(stdio, snprintf_utf8_15439554) {
snprintf(buf, sizeof(buf), "%d\xf0\xa4\xad\xa2%d", 1, 2);
EXPECT_STREQ("1𤭢2", buf);
+ uselocale(old_locale);
freelocale(cloc);
}
@@ -676,3 +677,82 @@ TEST(stdio, fpos_t_and_seek) {
fclose(fp);
}
+
+TEST(stdio, fmemopen) {
+ char buf[16];
+ memset(buf, 0, sizeof(buf));
+ FILE* fp = fmemopen(buf, sizeof(buf), "r+");
+ ASSERT_EQ('<', fputc('<', fp));
+ ASSERT_NE(EOF, fputs("abc>\n", fp));
+ fflush(fp);
+
+ ASSERT_STREQ("<abc>\n", buf);
+
+ rewind(fp);
+
+ char line[16];
+ char* s = fgets(line, sizeof(line), fp);
+ ASSERT_TRUE(s != NULL);
+ ASSERT_STREQ("<abc>\n", s);
+
+ fclose(fp);
+}
+
+TEST(stdio, fmemopen_NULL) {
+ FILE* fp = fmemopen(nullptr, 128, "r+");
+ ASSERT_NE(EOF, fputs("xyz\n", fp));
+
+ rewind(fp);
+
+ char line[16];
+ char* s = fgets(line, sizeof(line), fp);
+ ASSERT_TRUE(s != NULL);
+ ASSERT_STREQ("xyz\n", s);
+
+ fclose(fp);
+}
+
+TEST(stdio, fmemopen_EINVAL) {
+ char buf[16];
+
+ // Invalid size.
+ errno = 0;
+ ASSERT_EQ(nullptr, fmemopen(buf, 0, "r+"));
+ ASSERT_EQ(EINVAL, errno);
+
+ // No '+' with NULL buffer.
+ errno = 0;
+ ASSERT_EQ(nullptr, fmemopen(nullptr, 0, "r"));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(stdio, open_memstream) {
+ char* p = nullptr;
+ size_t size = 0;
+ FILE* fp = open_memstream(&p, &size);
+ ASSERT_NE(EOF, fputs("hello, world!", fp));
+ fclose(fp);
+
+ ASSERT_STREQ("hello, world!", p);
+ ASSERT_EQ(strlen("hello, world!"), size);
+ free(p);
+}
+
+TEST(stdio, open_memstream_EINVAL) {
+#if defined(__BIONIC__)
+ char* p;
+ size_t size;
+
+ // Invalid buffer.
+ errno = 0;
+ ASSERT_EQ(nullptr, open_memstream(nullptr, &size));
+ ASSERT_EQ(EINVAL, errno);
+
+ // Invalid size.
+ errno = 0;
+ ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
+ ASSERT_EQ(EINVAL, errno);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
diff --git a/tests/string_posix_strerror_r_test.cpp b/tests/string_posix_strerror_r_test.cpp
new file mode 100644
index 000000000..09cebfecc
--- /dev/null
+++ b/tests/string_posix_strerror_r_test.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef _GNU_SOURCE
+
+// Old versions of glibc (like our current host prebuilt sysroot one) have
+// headers that don't work if you #undef _GNU_SOURCE, which makes it
+// impossible to build this test.
+#include <features.h>
+
+#if !defined(__GLIBC__)
+#include <string.h>
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(string, posix_strerror_r) {
+ char buf[256];
+
+ // Valid.
+ ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf)));
+ ASSERT_STREQ("Success", buf);
+ ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf)));
+ ASSERT_STREQ("Operation not permitted", buf);
+
+ // Invalid.
+ ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf)));
+ ASSERT_STREQ("Unknown error -1", buf);
+ ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf)));
+ ASSERT_STREQ("Unknown error 1234", buf);
+
+ // Buffer too small.
+ errno = 0;
+ memset(buf, 0, sizeof(buf));
+ ASSERT_EQ(-1, strerror_r(4567, buf, 2));
+ ASSERT_STREQ("U", buf);
+ // The POSIX strerror_r sets errno to ERANGE (the GNU one doesn't).
+ ASSERT_EQ(ERANGE, errno);
+}
+#else
+# if __GLIBC_PREREQ(2, 15)
+# error this test should work now
+# endif
+#endif
diff --git a/tests/string_test.cpp b/tests/string_test.cpp
index 8ec2928cc..ad0040aa9 100644
--- a/tests/string_test.cpp
+++ b/tests/string_test.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#define _GNU_SOURCE 1
+
+#include <string.h>
#include <errno.h>
+#include <gtest/gtest.h>
#include <malloc.h>
#include <math.h>
-#include <string.h>
#include "buffer_tests.h"
@@ -72,28 +74,34 @@ TEST(string, strerror_concurrent) {
#endif // __BIONIC__
}
-TEST(string, strerror_r) {
-#if defined(__BIONIC__) // glibc's strerror_r doesn't even have the same signature as the POSIX one.
+TEST(string, gnu_strerror_r) {
char buf[256];
+ // Note that glibc doesn't necessarily write into the buffer.
+
// Valid.
- ASSERT_EQ(0, strerror_r(0, buf, sizeof(buf)));
+ ASSERT_STREQ("Success", strerror_r(0, buf, sizeof(buf)));
+#if defined(__BIONIC__)
ASSERT_STREQ("Success", buf);
- ASSERT_EQ(0, strerror_r(1, buf, sizeof(buf)));
+#endif
+ ASSERT_STREQ("Operation not permitted", strerror_r(1, buf, sizeof(buf)));
+#if defined(__BIONIC__)
ASSERT_STREQ("Operation not permitted", buf);
+#endif
// Invalid.
- ASSERT_EQ(0, strerror_r(-1, buf, sizeof(buf)));
+ ASSERT_STREQ("Unknown error -1", strerror_r(-1, buf, sizeof(buf)));
ASSERT_STREQ("Unknown error -1", buf);
- ASSERT_EQ(0, strerror_r(1234, buf, sizeof(buf)));
+ ASSERT_STREQ("Unknown error 1234", strerror_r(1234, buf, sizeof(buf)));
ASSERT_STREQ("Unknown error 1234", buf);
// Buffer too small.
- ASSERT_EQ(-1, strerror_r(0, buf, 2));
- ASSERT_EQ(ERANGE, errno);
-#else // __BIONIC__
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif // __BIONIC__
+ errno = 0;
+ memset(buf, 0, sizeof(buf));
+ ASSERT_EQ(buf, strerror_r(4567, buf, 2));
+ ASSERT_STREQ("U", buf);
+ // The GNU strerror_r doesn't set errno (the POSIX one sets it to ERANGE).
+ ASSERT_EQ(0, errno);
}
TEST(string, strsignal) {
@@ -1274,3 +1282,22 @@ TEST(string, strchr_align) {
TEST(string, strchr_overread) {
RunSingleBufferOverreadTest(DoStrchrTest);
}
+
+static void TestBasename(const char* in, const char* expected_out) {
+ errno = 0;
+ const char* out = basename(in);
+ ASSERT_STREQ(expected_out, out) << in;
+ ASSERT_EQ(0, errno) << in;
+}
+
+TEST(string, __gnu_basename) {
+ TestBasename("", "");
+ TestBasename("/usr/lib", "lib");
+ TestBasename("/usr/", "");
+ TestBasename("usr", "usr");
+ TestBasename("/", "");
+ TestBasename(".", ".");
+ TestBasename("..", "..");
+ TestBasename("///", "");
+ TestBasename("//usr//lib//", "");
+}
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
index 0bde0243d..38ef68a99 100644
--- a/tests/sys_socket_test.cpp
+++ b/tests/sys_socket_test.cpp
@@ -23,13 +23,9 @@
#include <fcntl.h>
#if defined(__BIONIC__)
- #define ACCEPT4_SUPPORTED 1
#define RECVMMSG_SUPPORTED 1
#define SENDMMSG_SUPPORTED 1
#elif defined(__GLIBC_PREREQ)
- #if __GLIBC_PREREQ(2, 9)
- #define ACCEPT4_SUPPORTED 1
- #endif
#if __GLIBC_PREREQ(2, 12)
#define RECVMMSG_SUPPORTED 1
#endif
@@ -38,8 +34,6 @@
#endif
#endif
-#if defined(ACCEPT4_SUPPORTED) || defined(RECVMMSG_SUPPORTED) || defined(SENDMMSG_SUPPORTED)
-
#define SOCK_PATH "test"
static void* ConnectFn(void* data) {
@@ -105,18 +99,12 @@ static void RunTest(void (*test_fn)(struct sockaddr_un*, int),
close(fd);
}
-#endif
TEST(sys_socket, accept4_error) {
-#if defined(ACCEPT4_SUPPORTED)
ASSERT_EQ(-1, accept4(-1, NULL, NULL, 0));
ASSERT_EQ(EBADF, errno);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
}
-#if defined(ACCEPT4_SUPPORTED)
static void TestAccept4(struct sockaddr_un* addr, int fd) {
socklen_t len = sizeof(*addr);
int fd_acc = accept4(fd, reinterpret_cast<struct sockaddr*>(addr), &len, SOCK_CLOEXEC);
@@ -127,14 +115,9 @@ static void TestAccept4(struct sockaddr_un* addr, int fd) {
close(fd_acc);
}
-#endif
TEST(sys_socket, accept4_smoke) {
-#if defined(ACCEPT4_SUPPORTED)
RunTest(TestAccept4, NULL);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
}
#if defined(RECVMMSG_SUPPORTED)
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 241c4a0c4..c9ead8dbb 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -17,7 +17,6 @@
#include <time.h>
#include <errno.h>
-#include <features.h>
#include <gtest/gtest.h>
#include <pthread.h>
#include <signal.h>
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index eca3c5ea4..c887f8abd 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -19,7 +19,6 @@
#if defined(__BIONIC__)
#define HAVE_UCHAR 1
#elif defined(__GLIBC__)
-#include <features.h>
#define HAVE_UCHAR __GLIBC_PREREQ(2, 16)
#endif
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 2a656574c..8195ea8f4 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -431,6 +431,10 @@ TEST(unistd, getpid_caching_and_clone) {
void* child_stack[1024];
int clone_result = clone(GetPidCachingCloneStartRoutine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL);
+ if (clone_result == -1 && errno == EPERM && getuid() != 0) {
+ GTEST_LOG_(INFO) << "This test only works if you have permission to CLONE_NEWNS; try running as root.\n";
+ return;
+ }
ASSERT_NE(clone_result, -1);
ASSERT_EQ(parent_pid, getpid());
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index d02c4bf2f..760475fa1 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -489,3 +489,34 @@ TEST(wchar, mbrtowc_15439554) {
EXPECT_EQ(4U, n);
EXPECT_EQ(L'𤭢', wc);
}
+
+TEST(wchar, open_wmemstream) {
+ wchar_t* p = nullptr;
+ size_t size = 0;
+ FILE* fp = open_wmemstream(&p, &size);
+ ASSERT_NE(EOF, fputws(L"hello, world!", fp));
+ fclose(fp);
+
+ ASSERT_STREQ(L"hello, world!", p);
+ ASSERT_EQ(wcslen(L"hello, world!"), size);
+ free(p);
+}
+
+TEST(stdio, open_wmemstream_EINVAL) {
+#if defined(__BIONIC__)
+ wchar_t* p;
+ size_t size;
+
+ // Invalid buffer.
+ errno = 0;
+ ASSERT_EQ(nullptr, open_wmemstream(nullptr, &size));
+ ASSERT_EQ(EINVAL, errno);
+
+ // Invalid size.
+ errno = 0;
+ ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr));
+ ASSERT_EQ(EINVAL, errno);
+#else
+ GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}