From 690d8ff9d54dc6065418d37cb0e42c128edcbf3b Mon Sep 17 00:00:00 2001 From: yayaws_zk <584363327@qq.com> Date: Sat, 6 Sep 2025 22:40:32 +0800 Subject: [PATCH 1/6] add libc --- aosp/bionic/libc/Android.bp | 2507 +++++++ aosp/bionic/libc/MODULE_LICENSE_BSD | 0 aosp/bionic/libc/NOTICE | 6058 +++++++++++++++++ aosp/bionic/libc/SECCOMP_BLACKLIST_APP.TXT | 49 + aosp/bionic/libc/SECCOMP_BLACKLIST_COMMON.TXT | 10 + aosp/bionic/libc/SECCOMP_PRIORITY.TXT | 10 + aosp/bionic/libc/SECCOMP_WHITELIST_APP.TXT | 58 + aosp/bionic/libc/SECCOMP_WHITELIST_COMMON.TXT | 76 + aosp/bionic/libc/SECCOMP_WHITELIST_SYSTEM.TXT | 6 + aosp/bionic/libc/SYSCALLS.TXT | 360 + aosp/bionic/libc/arch-arm/bionic/__aeabi.c | 183 + .../libc/arch-arm/bionic/__aeabi_read_tp.S | 48 + .../libc/arch-arm/bionic/__bionic_clone.S | 69 + aosp/bionic/libc/arch-arm/bionic/__restore.S | 63 + .../bionic/_exit_with_stack_teardown.S | 41 + .../libc/arch-arm/bionic/atexit_legacy.c | 60 + .../bionic/libc/arch-arm/bionic/atomics_arm.c | 87 + aosp/bionic/libc/arch-arm/bionic/bpabi.c | 43 + .../libc/arch-arm/bionic/exidx_dynamic.c | 49 + .../libc/arch-arm/bionic/exidx_static.c | 53 + .../libc/arch-arm/bionic/kuser_helper_on.S | 39 + .../libc/arch-arm/bionic/libcrt_compat.c | 225 + .../libc/arch-arm/bionic/popcount_tab.c | 42 + aosp/bionic/libc/arch-arm/bionic/setjmp.S | 273 + aosp/bionic/libc/arch-arm/bionic/syscall.S | 51 + aosp/bionic/libc/arch-arm/bionic/vfork.S | 58 + .../arch-arm/cortex-a15/bionic/__strcat_chk.S | 203 + .../arch-arm/cortex-a15/bionic/__strcpy_chk.S | 165 + .../libc/arch-arm/cortex-a15/bionic/memcpy.S | 75 + .../arch-arm/cortex-a15/bionic/memcpy_base.S | 154 + .../libc/arch-arm/cortex-a15/bionic/memmove.S | 280 + .../libc/arch-arm/cortex-a15/bionic/memset.S | 174 + .../libc/arch-arm/cortex-a15/bionic/stpcpy.S | 30 + .../libc/arch-arm/cortex-a15/bionic/strcat.S | 575 ++ .../libc/arch-arm/cortex-a15/bionic/strcmp.S | 495 ++ .../libc/arch-arm/cortex-a15/bionic/strcpy.S | 30 + .../arch-arm/cortex-a15/bionic/string_copy.S | 520 ++ .../libc/arch-arm/cortex-a15/bionic/strlen.S | 165 + .../arch-arm/cortex-a53/bionic/__strcat_chk.S | 203 + .../arch-arm/cortex-a53/bionic/__strcpy_chk.S | 165 + .../libc/arch-arm/cortex-a53/bionic/memcpy.S | 75 + .../arch-arm/cortex-a53/bionic/memcpy_base.S | 143 + .../arch-arm/cortex-a55/bionic/__strcat_chk.S | 198 + .../arch-arm/cortex-a55/bionic/__strcpy_chk.S | 168 + .../libc/arch-arm/cortex-a55/bionic/memcpy.S | 78 + .../arch-arm/cortex-a55/bionic/memcpy_base.S | 234 + .../arch-arm/cortex-a7/bionic/__strcat_chk.S | 203 + .../arch-arm/cortex-a7/bionic/__strcpy_chk.S | 165 + .../libc/arch-arm/cortex-a7/bionic/memcpy.S | 75 + .../arch-arm/cortex-a7/bionic/memcpy_base.S | 176 + .../libc/arch-arm/cortex-a7/bionic/memset.S | 163 + .../arch-arm/cortex-a9/bionic/__strcat_chk.S | 202 + .../arch-arm/cortex-a9/bionic/__strcpy_chk.S | 170 + .../libc/arch-arm/cortex-a9/bionic/memcpy.S | 53 + .../arch-arm/cortex-a9/bionic/memcpy_base.S | 228 + .../libc/arch-arm/cortex-a9/bionic/memset.S | 161 + .../libc/arch-arm/cortex-a9/bionic/stpcpy.S | 30 + .../libc/arch-arm/cortex-a9/bionic/strcat.S | 559 ++ .../libc/arch-arm/cortex-a9/bionic/strcpy.S | 30 + .../arch-arm/cortex-a9/bionic/string_copy.S | 546 ++ .../libc/arch-arm/cortex-a9/bionic/strlen.S | 171 + .../arch-arm/dynamic_function_dispatch.cpp | 292 + .../arch-arm/generic/bionic/__memcpy_chk.S | 43 + .../libc/arch-arm/generic/bionic/memcmp.S | 343 + .../libc/arch-arm/generic/bionic/memmove.S | 471 ++ .../libc/arch-arm/generic/bionic/memset.S | 111 + .../libc/arch-arm/generic/bionic/stpcpy.c | 30 + .../libc/arch-arm/generic/bionic/strcat.c | 30 + .../libc/arch-arm/generic/bionic/strcmp.S | 320 + .../libc/arch-arm/generic/bionic/strcpy.S | 138 + .../libc/arch-arm/generic/bionic/strlen.c | 129 + .../libc/arch-arm/krait/bionic/__strcat_chk.S | 203 + .../libc/arch-arm/krait/bionic/__strcpy_chk.S | 165 + .../libc/arch-arm/krait/bionic/memcpy.S | 53 + .../libc/arch-arm/krait/bionic/memcpy_base.S | 193 + .../libc/arch-arm/krait/bionic/memset.S | 85 + .../bionic/libc/arch-arm/kryo/bionic/memcpy.S | 132 + .../libc/arch-arm/static_function_dispatch.S | 46 + .../libc/arch-arm64/bionic/__bionic_clone.S | 59 + .../bionic/libc/arch-arm64/bionic/__set_tls.c | 33 + .../bionic/_exit_with_stack_teardown.S | 41 + aosp/bionic/libc/arch-arm64/bionic/setjmp.S | 299 + aosp/bionic/libc/arch-arm64/bionic/syscall.S | 49 + aosp/bionic/libc/arch-arm64/bionic/vfork.S | 87 + .../libc/arch-arm64/default/bionic/memchr.S | 164 + .../libc/arch-arm64/default/bionic/strchr.S | 153 + .../libc/arch-arm64/default/bionic/strcmp.S | 192 + .../libc/arch-arm64/default/bionic/strlen.S | 227 + .../libc/arch-arm64/default/bionic/strncmp.S | 280 + .../libc/arch-arm64/default/bionic/strnlen.S | 174 + .../arch-arm64/dynamic_function_dispatch.cpp | 99 + .../arch-arm64/generic/bionic/__memcpy_chk.S | 45 + .../libc/arch-arm64/generic/bionic/memcmp.S | 167 + .../libc/arch-arm64/generic/bionic/memcpy.S | 35 + .../arch-arm64/generic/bionic/memcpy_base.S | 217 + .../libc/arch-arm64/generic/bionic/memmove.S | 155 + .../libc/arch-arm64/generic/bionic/memset.S | 251 + .../libc/arch-arm64/generic/bionic/stpcpy.S | 29 + .../libc/arch-arm64/generic/bionic/strcpy.S | 29 + .../arch-arm64/generic/bionic/string_copy.S | 245 + .../libc/arch-arm64/generic/bionic/wmemmove.S | 30 + .../libc/arch-arm64/mte/bionic/memchr.c | 32 + .../libc/arch-arm64/mte/bionic/strchr.cpp | 30 + .../libc/arch-arm64/mte/bionic/strcmp.c | 32 + .../libc/arch-arm64/mte/bionic/strlen.c | 32 + .../libc/arch-arm64/mte/bionic/strncmp.c | 32 + .../libc/arch-arm64/mte/bionic/strnlen.c | 30 + .../arch-arm64/static_function_dispatch.S | 41 + .../libc/arch-common/bionic/__dso_handle.h | 33 + .../libc/arch-common/bionic/__dso_handle_so.h | 39 + .../libc/arch-common/bionic/asm_multiarch.h | 36 + aosp/bionic/libc/arch-common/bionic/atexit.h | 45 + .../bionic/libc/arch-common/bionic/crtbegin.c | 94 + .../libc/arch-common/bionic/crtbegin_so.c | 78 + .../bionic/libc/arch-common/bionic/crtbrand.S | 44 + aosp/bionic/libc/arch-common/bionic/crtend.S | 55 + .../libc/arch-common/bionic/crtend_so.S | 41 + .../libc/arch-common/bionic/pthread_atfork.h | 36 + aosp/bionic/libc/arch-x86/atom/string/cache.h | 36 + .../arch-x86/atom/string/sse2-memchr-atom.S | 556 ++ .../arch-x86/atom/string/sse2-memrchr-atom.S | 778 +++ .../arch-x86/atom/string/sse2-memset-atom.S | 842 +++ .../arch-x86/atom/string/sse2-strchr-atom.S | 391 ++ .../arch-x86/atom/string/sse2-strlen-atom.S | 749 ++ .../arch-x86/atom/string/sse2-strnlen-atom.S | 33 + .../arch-x86/atom/string/sse2-strrchr-atom.S | 753 ++ .../arch-x86/atom/string/sse2-wcschr-atom.S | 267 + .../arch-x86/atom/string/sse2-wcscmp-atom.S | 1062 +++ .../arch-x86/atom/string/sse2-wcslen-atom.S | 306 + .../arch-x86/atom/string/sse2-wcsrchr-atom.S | 402 ++ .../arch-x86/atom/string/ssse3-memcmp-atom.S | 2496 +++++++ .../arch-x86/atom/string/ssse3-memcpy-atom.S | 3124 +++++++++ .../arch-x86/atom/string/ssse3-memmove-atom.S | 34 + .../arch-x86/atom/string/ssse3-strcat-atom.S | 620 ++ .../arch-x86/atom/string/ssse3-strcmp-atom.S | 2275 +++++++ .../arch-x86/atom/string/ssse3-strcpy-atom.S | 3955 +++++++++++ .../arch-x86/atom/string/ssse3-strlcat-atom.S | 1225 ++++ .../arch-x86/atom/string/ssse3-strlcpy-atom.S | 1403 ++++ .../arch-x86/atom/string/ssse3-strncat-atom.S | 34 + .../arch-x86/atom/string/ssse3-strncmp-atom.S | 35 + .../arch-x86/atom/string/ssse3-strncpy-atom.S | 33 + .../arch-x86/atom/string/ssse3-wcscat-atom.S | 114 + .../arch-x86/atom/string/ssse3-wcscpy-atom.S | 652 ++ .../arch-x86/atom/string/ssse3-wmemcmp-atom.S | 35 + .../libc/arch-x86/bionic/__bionic_clone.S | 64 + .../arch-x86/bionic/__libc_init_sysinfo.cpp | 47 + aosp/bionic/libc/arch-x86/bionic/__restore.S | 135 + .../bionic/libc/arch-x86/bionic/__set_tls.cpp | 73 + .../arch-x86/bionic/__stack_chk_fail_local.h | 57 + .../bionic/_exit_with_stack_teardown.S | 16 + aosp/bionic/libc/arch-x86/bionic/atexit.h | 35 + .../libc/arch-x86/bionic/libcrt_compat.c | 41 + aosp/bionic/libc/arch-x86/bionic/setjmp.S | 218 + aosp/bionic/libc/arch-x86/bionic/syscall.S | 73 + aosp/bionic/libc/arch-x86/bionic/vfork.S | 66 + .../arch-x86/dynamic_function_dispatch.cpp | 161 + .../libc/arch-x86/generic/string/memcmp.S | 44 + .../libc/arch-x86/generic/string/strcat.S | 74 + .../libc/arch-x86/generic/string/strcmp.S | 82 + .../libc/arch-x86/generic/string/strlcat.c | 32 + .../libc/arch-x86/generic/string/strlcpy.c | 32 + .../libc/arch-x86/generic/string/strncat.c | 32 + .../libc/arch-x86/generic/string/strncmp.S | 114 + .../libc/arch-x86/generic/string/wcscat.c | 30 + .../libc/arch-x86/generic/string/wcscpy.c | 30 + .../libc/arch-x86/generic/string/wmemcmp.c | 30 + .../libc/arch-x86/generic/string/wmemset.c | 19 + .../kabylake/string/avx2-wmemset-kbl.S | 148 + .../libc/arch-x86/silvermont/string/cache.h | 36 + .../silvermont/string/sse2-memmove-slm.S | 539 ++ .../silvermont/string/sse2-memset-slm.S | 761 +++ .../silvermont/string/sse2-stpcpy-slm.S | 33 + .../silvermont/string/sse2-stpncpy-slm.S | 34 + .../silvermont/string/sse2-strcpy-slm.S | 2157 ++++++ .../silvermont/string/sse2-strlen-slm.S | 328 + .../silvermont/string/sse2-strncpy-slm.S | 33 + .../silvermont/string/sse4-memcmp-slm.S | 1278 ++++ .../silvermont/string/sse4-wmemcmp-slm.S | 33 + .../libc/arch-x86/static_function_dispatch.S | 53 + .../libc/arch-x86_64/bionic/__bionic_clone.S | 76 + .../libc/arch-x86_64/bionic/__restore_rt.S | 143 + .../libc/arch-x86_64/bionic/__set_tls.c | 37 + .../bionic/_exit_with_stack_teardown.S | 41 + aosp/bionic/libc/arch-x86_64/bionic/setjmp.S | 215 + aosp/bionic/libc/arch-x86_64/bionic/syscall.S | 63 + aosp/bionic/libc/arch-x86_64/bionic/vfork.S | 61 + .../arch-x86_64/string/avx2-wmemset-kbl.S | 140 + aosp/bionic/libc/arch-x86_64/string/cache.h | 36 + .../arch-x86_64/string/sse2-memmove-slm.S | 518 ++ .../libc/arch-x86_64/string/sse2-memset-slm.S | 149 + .../libc/arch-x86_64/string/sse2-stpcpy-slm.S | 33 + .../arch-x86_64/string/sse2-stpncpy-slm.S | 34 + .../libc/arch-x86_64/string/sse2-strcat-slm.S | 87 + .../libc/arch-x86_64/string/sse2-strcpy-slm.S | 1921 ++++++ .../libc/arch-x86_64/string/sse2-strlen-slm.S | 294 + .../arch-x86_64/string/sse2-strncat-slm.S | 33 + .../arch-x86_64/string/sse2-strncpy-slm.S | 33 + .../libc/arch-x86_64/string/sse4-memcmp-slm.S | 1799 +++++ .../arch-x86_64/string/ssse3-strcmp-slm.S | 1925 ++++++ .../arch-x86_64/string/ssse3-strncmp-slm.S | 33 + aosp/bionic/libc/async_safe/Android.bp | 48 + aosp/bionic/libc/async_safe/README.md | 10 + .../bionic/libc/async_safe/async_safe_log.cpp | 578 ++ .../async_safe/include/async_safe/CHECK.h | 47 + .../libc/async_safe/include/async_safe/log.h | 76 + aosp/bionic/libc/bionic/NetdClient.cpp | 74 + .../bionic/libc/bionic/NetdClientDispatch.cpp | 80 + .../libc/bionic/__bionic_get_shell_path.cpp | 59 + aosp/bionic/libc/bionic/__cmsg_nxthdr.cpp | 39 + aosp/bionic/libc/bionic/__cxa_guard.cpp | 126 + .../bionic/libc/bionic/__cxa_pure_virtual.cpp | 21 + .../libc/bionic/__cxa_thread_atexit_impl.cpp | 63 + aosp/bionic/libc/bionic/__errno.cpp | 36 + aosp/bionic/libc/bionic/__gnu_basename.cpp | 35 + .../libc/bionic/__libc_current_sigrtmax.cpp | 35 + .../libc/bionic/__libc_current_sigrtmin.cpp | 35 + .../libc/bionic/__libc_init_main_thread.cpp | 166 + aosp/bionic/libc/bionic/__set_errno.cpp | 48 + aosp/bionic/libc/bionic/__stack_chk_fail.cpp | 37 + aosp/bionic/libc/bionic/abort.cpp | 57 + aosp/bionic/libc/bionic/accept.cpp | 21 + aosp/bionic/libc/bionic/access.cpp | 34 + .../libc/bionic/android_profiling_dynamic.cpp | 207 + .../libc/bionic/android_set_abort_message.cpp | 95 + .../android_unsafe_frame_pointer_chase.cpp | 81 + aosp/bionic/libc/bionic/arpa_inet.cpp | 72 + aosp/bionic/libc/bionic/assert.cpp | 41 + aosp/bionic/libc/bionic/atexit.cpp | 283 + aosp/bionic/libc/bionic/atexit.h | 42 + aosp/bionic/libc/bionic/atof.cpp | 35 + aosp/bionic/libc/bionic/bionic_allocator.cpp | 404 ++ aosp/bionic/libc/bionic/bionic_arc4random.cpp | 57 + .../bionic/bionic_call_ifunc_resolver.cpp | 64 + aosp/bionic/libc/bionic/bionic_elf_tls.cpp | 366 + aosp/bionic/libc/bionic/bionic_futex.cpp | 71 + aosp/bionic/libc/bionic/bionic_netlink.cpp | 94 + aosp/bionic/libc/bionic/bionic_netlink.h | 52 + aosp/bionic/libc/bionic/bionic_systrace.cpp | 105 + .../libc/bionic/bionic_time_conversions.cpp | 74 + aosp/bionic/libc/bionic/brk.cpp | 76 + aosp/bionic/libc/bionic/c16rtomb.cpp | 67 + aosp/bionic/libc/bionic/c32rtomb.cpp | 97 + aosp/bionic/libc/bionic/chmod.cpp | 35 + aosp/bionic/libc/bionic/chown.cpp | 36 + aosp/bionic/libc/bionic/clearenv.cpp | 40 + aosp/bionic/libc/bionic/clock.cpp | 42 + .../libc/bionic/clock_getcpuclockid.cpp | 49 + aosp/bionic/libc/bionic/clock_nanosleep.cpp | 40 + aosp/bionic/libc/bionic/clone.cpp | 127 + aosp/bionic/libc/bionic/ctype.cpp | 88 + aosp/bionic/libc/bionic/dirent.cpp | 204 + .../libc/bionic/dl_iterate_phdr_static.cpp | 104 + aosp/bionic/libc/bionic/dup.cpp | 57 + aosp/bionic/libc/bionic/environ.cpp | 35 + aosp/bionic/libc/bionic/error.cpp | 96 + aosp/bionic/libc/bionic/ether_aton.c | 89 + aosp/bionic/libc/bionic/ether_ntoa.c | 55 + aosp/bionic/libc/bionic/eventfd.cpp | 46 + aosp/bionic/libc/bionic/eventfd_write.cpp | 31 + aosp/bionic/libc/bionic/exec.cpp | 182 + aosp/bionic/libc/bionic/faccessat.cpp | 60 + aosp/bionic/libc/bionic/fchmod.cpp | 71 + aosp/bionic/libc/bionic/fchmodat.cpp | 62 + aosp/bionic/libc/bionic/fcntl.cpp | 76 + aosp/bionic/libc/bionic/fdsan.cpp | 395 ++ aosp/bionic/libc/bionic/fdtrack.cpp | 59 + aosp/bionic/libc/bionic/ffs.cpp | 33 + aosp/bionic/libc/bionic/fgetxattr.cpp | 59 + aosp/bionic/libc/bionic/flistxattr.cpp | 58 + aosp/bionic/libc/bionic/flockfile.cpp | 58 + aosp/bionic/libc/bionic/fork.cpp | 71 + aosp/bionic/libc/bionic/fortify.cpp | 509 ++ aosp/bionic/libc/bionic/fpclassify.cpp | 106 + aosp/bionic/libc/bionic/fsetxattr.cpp | 58 + aosp/bionic/libc/bionic/ftruncate.cpp | 31 + aosp/bionic/libc/bionic/fts.c | 1048 +++ aosp/bionic/libc/bionic/ftw.cpp | 125 + aosp/bionic/libc/bionic/futimens.cpp | 34 + .../libc/bionic/get_device_api_level.cpp | 30 + aosp/bionic/libc/bionic/getauxval.cpp | 56 + aosp/bionic/libc/bionic/getcwd.cpp | 77 + aosp/bionic/libc/bionic/getdomainname.cpp | 49 + aosp/bionic/libc/bionic/getentropy.cpp | 78 + aosp/bionic/libc/bionic/gethostname.cpp | 48 + aosp/bionic/libc/bionic/getloadavg.cpp | 44 + aosp/bionic/libc/bionic/getpagesize.cpp | 35 + aosp/bionic/libc/bionic/getpgrp.cpp | 33 + aosp/bionic/libc/bionic/getpid.cpp | 55 + aosp/bionic/libc/bionic/getpriority.cpp | 36 + aosp/bionic/libc/bionic/gettid.cpp | 45 + aosp/bionic/libc/bionic/grp_pwd.cpp | 816 +++ aosp/bionic/libc/bionic/grp_pwd_file.cpp | 350 + aosp/bionic/libc/bionic/grp_pwd_file.h | 101 + aosp/bionic/libc/bionic/gwp_asan_wrappers.cpp | 280 + aosp/bionic/libc/bionic/gwp_asan_wrappers.h | 44 + aosp/bionic/libc/bionic/heap_tagging.cpp | 113 + aosp/bionic/libc/bionic/heap_tagging.h | 34 + aosp/bionic/libc/bionic/iconv.cpp | 369 + aosp/bionic/libc/bionic/icu.cpp | 66 + aosp/bionic/libc/bionic/icu_static.cpp | 34 + aosp/bionic/libc/bionic/icu_wrappers.cpp | 49 + aosp/bionic/libc/bionic/ifaddrs.cpp | 345 + aosp/bionic/libc/bionic/initgroups.c | 58 + aosp/bionic/libc/bionic/inotify_init.cpp | 33 + aosp/bionic/libc/bionic/ioctl.cpp | 40 + aosp/bionic/libc/bionic/isatty.c | 39 + aosp/bionic/libc/bionic/jemalloc.h | 42 + aosp/bionic/libc/bionic/jemalloc_wrapper.cpp | 174 + aosp/bionic/libc/bionic/killpg.cpp | 38 + aosp/bionic/libc/bionic/langinfo.cpp | 103 + aosp/bionic/libc/bionic/lchown.cpp | 36 + .../libc/bionic/legacy_32_bit_support.cpp | 122 + aosp/bionic/libc/bionic/lfs64_support.cpp | 48 + aosp/bionic/libc/bionic/libc_init_common.cpp | 376 + aosp/bionic/libc/bionic/libc_init_common.h | 63 + aosp/bionic/libc/bionic/libc_init_dynamic.cpp | 160 + aosp/bionic/libc/bionic/libc_init_static.cpp | 238 + aosp/bionic/libc/bionic/libgen.cpp | 170 + aosp/bionic/libc/bionic/link.cpp | 34 + aosp/bionic/libc/bionic/locale.cpp | 199 + aosp/bionic/libc/bionic/lockf.cpp | 73 + aosp/bionic/libc/bionic/lstat.cpp | 37 + aosp/bionic/libc/bionic/malloc_common.cpp | 360 + aosp/bionic/libc/bionic/malloc_common.h | 96 + .../libc/bionic/malloc_common_dynamic.cpp | 568 ++ .../libc/bionic/malloc_common_dynamic.h | 50 + aosp/bionic/libc/bionic/malloc_heapprofd.cpp | 467 ++ aosp/bionic/libc/bionic/malloc_heapprofd.h | 46 + aosp/bionic/libc/bionic/malloc_limit.cpp | 392 ++ aosp/bionic/libc/bionic/malloc_limit.h | 38 + .../libc/bionic/malloc_tagged_pointers.h | 131 + aosp/bionic/libc/bionic/mblen.cpp | 35 + aosp/bionic/libc/bionic/mbrtoc16.cpp | 89 + aosp/bionic/libc/bionic/mbrtoc32.cpp | 138 + aosp/bionic/libc/bionic/memmem.cpp | 60 + aosp/bionic/libc/bionic/mempcpy.cpp | 33 + aosp/bionic/libc/bionic/mkdir.cpp | 35 + aosp/bionic/libc/bionic/mkfifo.cpp | 39 + aosp/bionic/libc/bionic/mknod.cpp | 36 + aosp/bionic/libc/bionic/mmap.cpp | 77 + aosp/bionic/libc/bionic/mntent.cpp | 96 + aosp/bionic/libc/bionic/mremap.cpp | 57 + aosp/bionic/libc/bionic/ndk_cruft.cpp | 392 ++ aosp/bionic/libc/bionic/ndk_cruft_data.cpp | 94 + aosp/bionic/libc/bionic/net_if.cpp | 153 + aosp/bionic/libc/bionic/netdb.cpp | 67 + aosp/bionic/libc/bionic/netinet_in.cpp | 71 + aosp/bionic/libc/bionic/new.cpp | 64 + aosp/bionic/libc/bionic/nl_types.cpp | 45 + aosp/bionic/libc/bionic/open.cpp | 92 + aosp/bionic/libc/bionic/pathconf.cpp | 156 + aosp/bionic/libc/bionic/pause.cpp | 35 + aosp/bionic/libc/bionic/pipe.cpp | 51 + aosp/bionic/libc/bionic/poll.cpp | 140 + aosp/bionic/libc/bionic/posix_fadvise.cpp | 51 + aosp/bionic/libc/bionic/posix_fallocate.cpp | 41 + aosp/bionic/libc/bionic/posix_madvise.cpp | 42 + aosp/bionic/libc/bionic/posix_timers.cpp | 221 + aosp/bionic/libc/bionic/pthread_atfork.cpp | 182 + aosp/bionic/libc/bionic/pthread_attr.cpp | 274 + aosp/bionic/libc/bionic/pthread_barrier.cpp | 183 + aosp/bionic/libc/bionic/pthread_cond.cpp | 258 + aosp/bionic/libc/bionic/pthread_create.cpp | 444 ++ aosp/bionic/libc/bionic/pthread_detach.cpp | 54 + aosp/bionic/libc/bionic/pthread_equal.cpp | 33 + aosp/bionic/libc/bionic/pthread_exit.cpp | 140 + .../libc/bionic/pthread_getcpuclockid.cpp | 48 + .../libc/bionic/pthread_getschedparam.cpp | 45 + aosp/bionic/libc/bionic/pthread_gettid_np.cpp | 35 + aosp/bionic/libc/bionic/pthread_internal.cpp | 117 + aosp/bionic/libc/bionic/pthread_internal.h | 244 + aosp/bionic/libc/bionic/pthread_join.cpp | 74 + aosp/bionic/libc/bionic/pthread_key.cpp | 191 + aosp/bionic/libc/bionic/pthread_kill.cpp | 46 + aosp/bionic/libc/bionic/pthread_mutex.cpp | 1032 +++ aosp/bionic/libc/bionic/pthread_once.cpp | 85 + aosp/bionic/libc/bionic/pthread_rwlock.cpp | 531 ++ aosp/bionic/libc/bionic/pthread_self.cpp | 33 + .../bionic/libc/bionic/pthread_setname_np.cpp | 107 + .../libc/bionic/pthread_setschedparam.cpp | 56 + aosp/bionic/libc/bionic/pthread_sigqueue.cpp | 53 + aosp/bionic/libc/bionic/pthread_spinlock.cpp | 81 + aosp/bionic/libc/bionic/ptrace.cpp | 55 + aosp/bionic/libc/bionic/pty.cpp | 196 + aosp/bionic/libc/bionic/pututline.c | 64 + aosp/bionic/libc/bionic/raise.cpp | 40 + aosp/bionic/libc/bionic/rand.cpp | 29 + aosp/bionic/libc/bionic/readlink.cpp | 36 + aosp/bionic/libc/bionic/realpath.cpp | 78 + aosp/bionic/libc/bionic/reboot.cpp | 36 + aosp/bionic/libc/bionic/recv.cpp | 33 + aosp/bionic/libc/bionic/recvmsg.cpp | 87 + aosp/bionic/libc/bionic/rename.cpp | 34 + aosp/bionic/libc/bionic/rmdir.cpp | 34 + aosp/bionic/libc/bionic/scandir.cpp | 137 + aosp/bionic/libc/bionic/sched_cpualloc.c | 43 + aosp/bionic/libc/bionic/sched_cpucount.c | 41 + aosp/bionic/libc/bionic/sched_getaffinity.cpp | 45 + aosp/bionic/libc/bionic/sched_getcpu.cpp | 41 + aosp/bionic/libc/bionic/scudo.h | 79 + aosp/bionic/libc/bionic/scudo/Android.bp | 63 + aosp/bionic/libc/bionic/scudo/exported32.map | 16 + aosp/bionic/libc/bionic/scudo/exported64.map | 14 + aosp/bionic/libc/bionic/scudo/scudo.cpp | 165 + aosp/bionic/libc/bionic/scudo_wrapper.cpp | 72 + aosp/bionic/libc/bionic/semaphore.cpp | 329 + aosp/bionic/libc/bionic/send.cpp | 33 + aosp/bionic/libc/bionic/setegid.cpp | 33 + aosp/bionic/libc/bionic/seteuid.cpp | 33 + aosp/bionic/libc/bionic/setjmp_cookie.cpp | 69 + aosp/bionic/libc/bionic/setpgrp.cpp | 33 + aosp/bionic/libc/bionic/sigaction.cpp | 137 + aosp/bionic/libc/bionic/signal.cpp | 314 + aosp/bionic/libc/bionic/sigprocmask.cpp | 83 + aosp/bionic/libc/bionic/sleep.cpp | 41 + aosp/bionic/libc/bionic/socketpair.cpp | 43 + aosp/bionic/libc/bionic/spawn.cpp | 343 + aosp/bionic/libc/bionic/stat.cpp | 37 + aosp/bionic/libc/bionic/stdlib_l.cpp | 59 + aosp/bionic/libc/bionic/strchr.cpp | 34 + aosp/bionic/libc/bionic/strchrnul.cpp | 22 + aosp/bionic/libc/bionic/strerror.cpp | 223 + aosp/bionic/libc/bionic/string_l.cpp | 42 + aosp/bionic/libc/bionic/strings_l.cpp | 38 + aosp/bionic/libc/bionic/strnlen.c | 38 + aosp/bionic/libc/bionic/strrchr.cpp | 34 + aosp/bionic/libc/bionic/strsignal.cpp | 68 + aosp/bionic/libc/bionic/strtol.cpp | 206 + aosp/bionic/libc/bionic/strtold.cpp | 45 + aosp/bionic/libc/bionic/swab.cpp | 41 + aosp/bionic/libc/bionic/symlink.cpp | 34 + aosp/bionic/libc/bionic/sync_file_range.cpp | 40 + aosp/bionic/libc/bionic/sys_epoll.cpp | 67 + aosp/bionic/libc/bionic/sys_msg.cpp | 68 + aosp/bionic/libc/bionic/sys_sem.cpp | 69 + aosp/bionic/libc/bionic/sys_shm.cpp | 73 + aosp/bionic/libc/bionic/sys_signalfd.cpp | 43 + aosp/bionic/libc/bionic/sys_statfs.cpp | 55 + aosp/bionic/libc/bionic/sys_statvfs.cpp | 32 + aosp/bionic/libc/bionic/sys_time.cpp | 65 + aosp/bionic/libc/bionic/sysconf.cpp | 242 + aosp/bionic/libc/bionic/syslog.cpp | 82 + aosp/bionic/libc/bionic/system.cpp | 71 + .../libc/bionic/system_property_api.cpp | 131 + .../libc/bionic/system_property_set.cpp | 310 + aosp/bionic/libc/bionic/tdestroy.cpp | 41 + aosp/bionic/libc/bionic/termios.cpp | 46 + aosp/bionic/libc/bionic/thread_private.cpp | 42 + aosp/bionic/libc/bionic/threads.cpp | 32 + aosp/bionic/libc/bionic/time64.c | 802 +++ aosp/bionic/libc/bionic/time64_config.h | 75 + aosp/bionic/libc/bionic/timespec_get.cpp | 33 + aosp/bionic/libc/bionic/tmpfile.cpp | 100 + aosp/bionic/libc/bionic/umount.cpp | 33 + aosp/bionic/libc/bionic/unlink.cpp | 34 + aosp/bionic/libc/bionic/usleep.cpp | 38 + aosp/bionic/libc/bionic/vdso.cpp | 139 + aosp/bionic/libc/bionic/wait.cpp | 45 + aosp/bionic/libc/bionic/wchar.cpp | 212 + aosp/bionic/libc/bionic/wchar_l.cpp | 78 + aosp/bionic/libc/bionic/wcstod.cpp | 106 + aosp/bionic/libc/bionic/wctype.cpp | 186 + aosp/bionic/libc/bionic/wcwidth.cpp | 92 + aosp/bionic/libc/bionic/wmempcpy.cpp | 33 + aosp/bionic/libc/dns/include/hostent.h | 93 + aosp/bionic/libc/dns/include/nsswitch.h | 217 + aosp/bionic/libc/dns/include/resolv_cache.h | 76 + aosp/bionic/libc/dns/include/resolv_netid.h | 113 + aosp/bionic/libc/dns/include/resolv_params.h | 62 + aosp/bionic/libc/dns/include/resolv_private.h | 536 ++ aosp/bionic/libc/dns/include/resolv_static.h | 32 + aosp/bionic/libc/dns/include/resolv_stats.h | 84 + aosp/bionic/libc/dns/nameser/ns_name.c | 1169 ++++ aosp/bionic/libc/dns/nameser/ns_netint.c | 59 + aosp/bionic/libc/dns/nameser/ns_parse.c | 277 + aosp/bionic/libc/dns/nameser/ns_print.c | 1259 ++++ aosp/bionic/libc/dns/nameser/ns_samedomain.c | 210 + aosp/bionic/libc/dns/nameser/ns_ttl.c | 161 + aosp/bionic/libc/dns/net/getaddrinfo.c | 2469 +++++++ aosp/bionic/libc/dns/net/gethnamaddr.c | 1635 +++++ aosp/bionic/libc/dns/net/getnameinfo.c | 442 ++ aosp/bionic/libc/dns/net/getservent.c | 151 + aosp/bionic/libc/dns/net/nsdispatch.c | 146 + aosp/bionic/libc/dns/net/services.h | 549 ++ aosp/bionic/libc/dns/net/sethostent.c | 285 + aosp/bionic/libc/dns/resolv/herror.c | 133 + aosp/bionic/libc/dns/resolv/res_cache.c | 2343 +++++++ aosp/bionic/libc/dns/resolv/res_comp.c | 266 + aosp/bionic/libc/dns/resolv/res_data.c | 327 + aosp/bionic/libc/dns/resolv/res_debug.c | 1225 ++++ aosp/bionic/libc/dns/resolv/res_debug.h | 36 + aosp/bionic/libc/dns/resolv/res_init.c | 783 +++ aosp/bionic/libc/dns/resolv/res_mkquery.c | 298 + aosp/bionic/libc/dns/resolv/res_private.h | 22 + aosp/bionic/libc/dns/resolv/res_query.c | 425 ++ aosp/bionic/libc/dns/resolv/res_send.c | 1350 ++++ aosp/bionic/libc/dns/resolv/res_state.c | 186 + aosp/bionic/libc/dns/resolv/res_stats.c | 186 + aosp/bionic/libc/fs_config_generator.py | 1 + aosp/bionic/libc/include/.clang-format | 3 + aosp/bionic/libc/include/alloca.h | 46 + aosp/bionic/libc/include/android/api-level.h | 147 + aosp/bionic/libc/include/android/dlext.h | 190 + aosp/bionic/libc/include/android/fdsan.h | 204 + .../include/android/legacy_errno_inlines.h | 46 + .../include/android/legacy_fenv_inlines_arm.h | 43 + .../include/android/legacy_signal_inlines.h | 121 + .../include/android/legacy_stdlib_inlines.h | 112 + .../include/android/legacy_strings_inlines.h | 44 + .../include/android/legacy_sys_mman_inlines.h | 71 + .../include/android/legacy_sys_stat_inlines.h | 45 + .../android/legacy_sys_statvfs_inlines.h | 48 + .../include/android/legacy_sys_wait_inlines.h | 47 + .../include/android/legacy_termios_inlines.h | 45 + .../include/android/legacy_threads_inlines.h | 38 + .../libc/include/android/set_abort_message.h | 51 + aosp/bionic/libc/include/android/versioning.h | 47 + aosp/bionic/libc/include/ar.h | 72 + aosp/bionic/libc/include/arpa/ftp.h | 107 + aosp/bionic/libc/include/arpa/inet.h | 53 + aosp/bionic/libc/include/arpa/nameser.h | 625 ++ .../bionic/libc/include/arpa/nameser_compat.h | 176 + aosp/bionic/libc/include/arpa/telnet.h | 343 + aosp/bionic/libc/include/arpa/tftp.h | 81 + aosp/bionic/libc/include/assert.h | 86 + aosp/bionic/libc/include/bits/auxvec.h | 49 + aosp/bionic/libc/include/bits/ctype_inlines.h | 209 + aosp/bionic/libc/include/bits/elf_arm.h | 131 + aosp/bionic/libc/include/bits/elf_arm64.h | 92 + aosp/bionic/libc/include/bits/elf_x86.h | 60 + aosp/bionic/libc/include/bits/elf_x86_64.h | 55 + aosp/bionic/libc/include/bits/epoll_event.h | 55 + aosp/bionic/libc/include/bits/fcntl.h | 48 + aosp/bionic/libc/include/bits/fenv_arm.h | 74 + .../libc/include/bits/fenv_inlines_arm.h | 142 + aosp/bionic/libc/include/bits/fenv_x86.h | 66 + aosp/bionic/libc/include/bits/fenv_x86_64.h | 92 + aosp/bionic/libc/include/bits/flock.h | 66 + aosp/bionic/libc/include/bits/flock64.h | 31 + aosp/bionic/libc/include/bits/fortify/fcntl.h | 148 + aosp/bionic/libc/include/bits/fortify/poll.h | 93 + .../bionic/libc/include/bits/fortify/socket.h | 86 + aosp/bionic/libc/include/bits/fortify/stat.h | 49 + aosp/bionic/libc/include/bits/fortify/stdio.h | 137 + .../bionic/libc/include/bits/fortify/stdlib.h | 47 + .../bionic/libc/include/bits/fortify/string.h | 264 + .../libc/include/bits/fortify/strings.h | 61 + .../bionic/libc/include/bits/fortify/unistd.h | 218 + .../bits/get_device_api_level_inlines.h | 50 + aosp/bionic/libc/include/bits/getopt.h | 67 + .../bionic/libc/include/bits/glibc-syscalls.h | 1340 ++++ aosp/bionic/libc/include/bits/in_addr.h | 45 + aosp/bionic/libc/include/bits/ioctl.h | 63 + .../bionic/libc/include/bits/ip_mreq_source.h | 46 + aosp/bionic/libc/include/bits/ip_msfilter.h | 46 + aosp/bionic/libc/include/bits/lockf.h | 67 + aosp/bionic/libc/include/bits/mbstate_t.h | 47 + aosp/bionic/libc/include/bits/posix_limits.h | 180 + aosp/bionic/libc/include/bits/pthread_types.h | 104 + aosp/bionic/libc/include/bits/sa_family_t.h | 39 + .../bionic/libc/include/bits/seek_constants.h | 61 + aosp/bionic/libc/include/bits/signal_types.h | 109 + aosp/bionic/libc/include/bits/stdatomic.h | 286 + aosp/bionic/libc/include/bits/strcasecmp.h | 71 + aosp/bionic/libc/include/bits/struct_file.h | 44 + .../libc/include/bits/sys_statvfs_inlines.h | 95 + aosp/bionic/libc/include/bits/sysconf.h | 197 + .../libc/include/bits/termios_inlines.h | 128 + .../libc/include/bits/threads_inlines.h | 209 + aosp/bionic/libc/include/bits/timespec.h | 52 + aosp/bionic/libc/include/bits/wait.h | 68 + aosp/bionic/libc/include/bits/wchar_limits.h | 48 + aosp/bionic/libc/include/bits/wctype.h | 66 + aosp/bionic/libc/include/byteswap.h | 55 + aosp/bionic/libc/include/complex.h | 154 + aosp/bionic/libc/include/cpio.h | 80 + aosp/bionic/libc/include/ctype.h | 39 + aosp/bionic/libc/include/dirent.h | 102 + aosp/bionic/libc/include/dlfcn.h | 80 + aosp/bionic/libc/include/elf.h | 555 ++ aosp/bionic/libc/include/endian.h | 10 + aosp/bionic/libc/include/err.h | 117 + aosp/bionic/libc/include/errno.h | 62 + aosp/bionic/libc/include/error.h | 85 + aosp/bionic/libc/include/fcntl.h | 254 + aosp/bionic/libc/include/features.h | 36 + aosp/bionic/libc/include/fenv.h | 82 + aosp/bionic/libc/include/fnmatch.h | 70 + aosp/bionic/libc/include/fts.h | 133 + aosp/bionic/libc/include/ftw.h | 64 + aosp/bionic/libc/include/getopt.h | 87 + aosp/bionic/libc/include/glob.h | 98 + aosp/bionic/libc/include/grp.h | 65 + aosp/bionic/libc/include/iconv.h | 83 + aosp/bionic/libc/include/ifaddrs.h | 93 + aosp/bionic/libc/include/inttypes.h | 266 + aosp/bionic/libc/include/langinfo.h | 100 + aosp/bionic/libc/include/lastlog.h | 10 + aosp/bionic/libc/include/libgen.h | 77 + aosp/bionic/libc/include/limits.h | 153 + aosp/bionic/libc/include/link.h | 93 + aosp/bionic/libc/include/locale.h | 111 + aosp/bionic/libc/include/malloc.h | 250 + aosp/bionic/libc/include/math.h | 412 ++ aosp/bionic/libc/include/memory.h | 10 + aosp/bionic/libc/include/mntent.h | 68 + aosp/bionic/libc/include/net/ethernet.h | 80 + aosp/bionic/libc/include/net/if.h | 54 + aosp/bionic/libc/include/net/if_arp.h | 2 + aosp/bionic/libc/include/net/if_packet.h | 1 + aosp/bionic/libc/include/net/route.h | 35 + aosp/bionic/libc/include/netdb.h | 244 + aosp/bionic/libc/include/netinet/ether.h | 73 + aosp/bionic/libc/include/netinet/icmp6.h | 515 ++ aosp/bionic/libc/include/netinet/if_ether.h | 110 + aosp/bionic/libc/include/netinet/in.h | 56 + aosp/bionic/libc/include/netinet/in6.h | 104 + aosp/bionic/libc/include/netinet/in_systm.h | 58 + aosp/bionic/libc/include/netinet/ip.h | 263 + aosp/bionic/libc/include/netinet/ip6.h | 242 + aosp/bionic/libc/include/netinet/ip_icmp.h | 216 + aosp/bionic/libc/include/netinet/tcp.h | 114 + aosp/bionic/libc/include/netinet/udp.h | 54 + aosp/bionic/libc/include/netpacket/packet.h | 1 + aosp/bionic/libc/include/nl_types.h | 84 + aosp/bionic/libc/include/poll.h | 77 + aosp/bionic/libc/include/pthread.h | 319 + aosp/bionic/libc/include/pty.h | 64 + aosp/bionic/libc/include/pwd.h | 97 + aosp/bionic/libc/include/regex.h | 106 + aosp/bionic/libc/include/resolv.h | 67 + aosp/bionic/libc/include/sched.h | 151 + aosp/bionic/libc/include/search.h | 219 + aosp/bionic/libc/include/semaphore.h | 73 + aosp/bionic/libc/include/setjmp.h | 75 + aosp/bionic/libc/include/signal.h | 133 + aosp/bionic/libc/include/spawn.h | 90 + aosp/bionic/libc/include/stdatomic.h | 135 + aosp/bionic/libc/include/stdint.h | 229 + aosp/bionic/libc/include/stdio.h | 321 + aosp/bionic/libc/include/stdio_ext.h | 138 + aosp/bionic/libc/include/stdlib.h | 222 + aosp/bionic/libc/include/string.h | 234 + aosp/bionic/libc/include/strings.h | 81 + .../libc/include/sys/_system_properties.h | 137 + aosp/bionic/libc/include/sys/auxv.h | 53 + aosp/bionic/libc/include/sys/cachectl.h | 33 + aosp/bionic/libc/include/sys/capability.h | 57 + aosp/bionic/libc/include/sys/cdefs.h | 365 + aosp/bionic/libc/include/sys/endian.h | 107 + aosp/bionic/libc/include/sys/epoll.h | 65 + aosp/bionic/libc/include/sys/errno.h | 10 + aosp/bionic/libc/include/sys/eventfd.h | 75 + aosp/bionic/libc/include/sys/fcntl.h | 10 + aosp/bionic/libc/include/sys/file.h | 51 + aosp/bionic/libc/include/sys/fsuid.h | 61 + aosp/bionic/libc/include/sys/ifunc.h | 71 + aosp/bionic/libc/include/sys/inotify.h | 63 + aosp/bionic/libc/include/sys/ioctl.h | 45 + aosp/bionic/libc/include/sys/ipc.h | 57 + aosp/bionic/libc/include/sys/klog.h | 71 + aosp/bionic/libc/include/sys/limits.h | 10 + aosp/bionic/libc/include/sys/mman.h | 212 + aosp/bionic/libc/include/sys/mount.h | 76 + aosp/bionic/libc/include/sys/msg.h | 57 + aosp/bionic/libc/include/sys/mtio.h | 1 + aosp/bionic/libc/include/sys/param.h | 71 + aosp/bionic/libc/include/sys/personality.h | 49 + aosp/bionic/libc/include/sys/poll.h | 10 + aosp/bionic/libc/include/sys/prctl.h | 50 + aosp/bionic/libc/include/sys/procfs.h | 62 + aosp/bionic/libc/include/sys/ptrace.h | 66 + aosp/bionic/libc/include/sys/queue.h | 559 ++ aosp/bionic/libc/include/sys/quota.h | 56 + aosp/bionic/libc/include/sys/random.h | 67 + aosp/bionic/libc/include/sys/reboot.h | 60 + aosp/bionic/libc/include/sys/reg.h | 86 + aosp/bionic/libc/include/sys/resource.h | 61 + aosp/bionic/libc/include/sys/select.h | 131 + aosp/bionic/libc/include/sys/sem.h | 64 + aosp/bionic/libc/include/sys/sendfile.h | 62 + aosp/bionic/libc/include/sys/shm.h | 58 + aosp/bionic/libc/include/sys/signal.h | 10 + aosp/bionic/libc/include/sys/signalfd.h | 58 + aosp/bionic/libc/include/sys/socket.h | 328 + aosp/bionic/libc/include/sys/stat.h | 188 + aosp/bionic/libc/include/sys/statfs.h | 1 + aosp/bionic/libc/include/sys/statvfs.h | 149 + aosp/bionic/libc/include/sys/swap.h | 72 + aosp/bionic/libc/include/sys/syscall.h | 38 + aosp/bionic/libc/include/sys/sysconf.h | 14 + aosp/bionic/libc/include/sys/sysinfo.h | 88 + aosp/bionic/libc/include/sys/syslog.h | 10 + aosp/bionic/libc/include/sys/sysmacros.h | 51 + aosp/bionic/libc/include/sys/time.h | 100 + aosp/bionic/libc/include/sys/timerfd.h | 83 + aosp/bionic/libc/include/sys/times.h | 51 + aosp/bionic/libc/include/sys/timex.h | 60 + aosp/bionic/libc/include/sys/ttydefaults.h | 83 + aosp/bionic/libc/include/sys/types.h | 146 + aosp/bionic/libc/include/sys/ucontext.h | 320 + aosp/bionic/libc/include/sys/uio.h | 55 + aosp/bionic/libc/include/sys/un.h | 44 + aosp/bionic/libc/include/sys/unistd.h | 10 + aosp/bionic/libc/include/sys/user.h | 244 + aosp/bionic/libc/include/sys/utsname.h | 67 + aosp/bionic/libc/include/sys/vfs.h | 114 + aosp/bionic/libc/include/sys/vt.h | 1 + aosp/bionic/libc/include/sys/wait.h | 61 + aosp/bionic/libc/include/sys/xattr.h | 158 + aosp/bionic/libc/include/syscall.h | 10 + aosp/bionic/libc/include/sysexits.h | 165 + aosp/bionic/libc/include/syslog.h | 161 + aosp/bionic/libc/include/tar.h | 89 + aosp/bionic/libc/include/termio.h | 10 + aosp/bionic/libc/include/termios.h | 154 + aosp/bionic/libc/include/threads.h | 229 + aosp/bionic/libc/include/time.h | 116 + aosp/bionic/libc/include/time64.h | 66 + aosp/bionic/libc/include/uchar.h | 93 + aosp/bionic/libc/include/ucontext.h | 10 + aosp/bionic/libc/include/unistd.h | 324 + aosp/bionic/libc/include/utime.h | 52 + aosp/bionic/libc/include/utmp.h | 108 + aosp/bionic/libc/include/wait.h | 10 + aosp/bionic/libc/include/wchar.h | 145 + aosp/bionic/libc/include/wctype.h | 66 + aosp/bionic/libc/include/xlocale.h | 49 + aosp/bionic/libc/kernel/.clang-format | 3 + aosp/bionic/libc/kernel/README.md | 93 + aosp/bionic/libc/kernel/android/README.md | 17 + .../libc/kernel/android/scsi/scsi/scsi.h | 74 + .../kernel/android/scsi/scsi/scsi_ioctl.h | 31 + .../kernel/android/scsi/scsi/scsi_proto.h | 208 + .../bionic/libc/kernel/android/scsi/scsi/sg.h | 147 + .../libc/kernel/android/uapi/linux/compiler.h | 18 + .../android/uapi/linux/compiler_types.h | 5 + aosp/bionic/libc/kernel/tools/clean_header.py | 218 + aosp/bionic/libc/kernel/tools/cpp.py | 2246 ++++++ aosp/bionic/libc/kernel/tools/defaults.py | 156 + .../kernel/tools/generate_uapi_headers.sh | 276 + aosp/bionic/libc/kernel/tools/kernel.py | 340 + aosp/bionic/libc/kernel/tools/update_all.py | 157 + aosp/bionic/libc/kernel/tools/utils.py | 164 + .../libc/kernel/uapi/asm-arm/asm/auxvec.h | 22 + .../kernel/uapi/asm-arm/asm/bitsperlong.h | 19 + .../kernel/uapi/asm-arm/asm/bpf_perf_event.h | 19 + .../libc/kernel/uapi/asm-arm/asm/byteorder.h | 22 + .../libc/kernel/uapi/asm-arm/asm/errno.h | 19 + .../libc/kernel/uapi/asm-arm/asm/fcntl.h | 26 + .../libc/kernel/uapi/asm-arm/asm/hwcap.h | 49 + .../libc/kernel/uapi/asm-arm/asm/ioctl.h | 19 + .../libc/kernel/uapi/asm-arm/asm/ioctls.h | 23 + .../libc/kernel/uapi/asm-arm/asm/ipcbuf.h | 19 + .../bionic/libc/kernel/uapi/asm-arm/asm/kvm.h | 216 + .../libc/kernel/uapi/asm-arm/asm/kvm_para.h | 19 + .../libc/kernel/uapi/asm-arm/asm/mman.h | 20 + .../libc/kernel/uapi/asm-arm/asm/msgbuf.h | 19 + .../libc/kernel/uapi/asm-arm/asm/param.h | 19 + .../libc/kernel/uapi/asm-arm/asm/perf_regs.h | 40 + .../libc/kernel/uapi/asm-arm/asm/poll.h | 19 + .../kernel/uapi/asm-arm/asm/posix_types.h | 31 + .../libc/kernel/uapi/asm-arm/asm/ptrace.h | 104 + .../libc/kernel/uapi/asm-arm/asm/resource.h | 19 + .../libc/kernel/uapi/asm-arm/asm/sembuf.h | 19 + .../libc/kernel/uapi/asm-arm/asm/setup.h | 128 + .../libc/kernel/uapi/asm-arm/asm/shmbuf.h | 19 + .../libc/kernel/uapi/asm-arm/asm/sigcontext.h | 44 + .../libc/kernel/uapi/asm-arm/asm/siginfo.h | 19 + .../libc/kernel/uapi/asm-arm/asm/signal.h | 92 + .../libc/kernel/uapi/asm-arm/asm/socket.h | 19 + .../libc/kernel/uapi/asm-arm/asm/sockios.h | 19 + .../libc/kernel/uapi/asm-arm/asm/stat.h | 77 + .../libc/kernel/uapi/asm-arm/asm/statfs.h | 23 + .../libc/kernel/uapi/asm-arm/asm/swab.h | 29 + .../libc/kernel/uapi/asm-arm/asm/termbits.h | 19 + .../libc/kernel/uapi/asm-arm/asm/termios.h | 19 + .../libc/kernel/uapi/asm-arm/asm/types.h | 22 + .../kernel/uapi/asm-arm/asm/unistd-common.h | 410 ++ .../kernel/uapi/asm-arm/asm/unistd-eabi.h | 21 + .../kernel/uapi/asm-arm/asm/unistd-oabi.h | 33 + .../libc/kernel/uapi/asm-arm/asm/unistd.h | 33 + .../libc/kernel/uapi/asm-arm64/asm/auxvec.h | 24 + .../kernel/uapi/asm-arm64/asm/bitsperlong.h | 23 + .../uapi/asm-arm64/asm/bpf_perf_event.h | 23 + .../kernel/uapi/asm-arm64/asm/byteorder.h | 26 + .../libc/kernel/uapi/asm-arm64/asm/errno.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/fcntl.h | 26 + .../libc/kernel/uapi/asm-arm64/asm/hwcap.h | 62 + .../libc/kernel/uapi/asm-arm64/asm/ioctl.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/ioctls.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/ipcbuf.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/kvm.h | 228 + .../libc/kernel/uapi/asm-arm64/asm/kvm_para.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/mman.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/msgbuf.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/param.h | 23 + .../kernel/uapi/asm-arm64/asm/perf_regs.h | 57 + .../libc/kernel/uapi/asm-arm64/asm/poll.h | 19 + .../kernel/uapi/asm-arm64/asm/posix_types.h | 25 + .../libc/kernel/uapi/asm-arm64/asm/ptrace.h | 119 + .../libc/kernel/uapi/asm-arm64/asm/resource.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/sembuf.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/setup.h | 23 + .../libc/kernel/uapi/asm-arm64/asm/shmbuf.h | 19 + .../kernel/uapi/asm-arm64/asm/sigcontext.h | 85 + .../libc/kernel/uapi/asm-arm64/asm/siginfo.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/signal.h | 25 + .../libc/kernel/uapi/asm-arm64/asm/socket.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/sockios.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/stat.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/statfs.h | 23 + .../kernel/uapi/asm-arm64/asm/sve_context.h | 42 + .../libc/kernel/uapi/asm-arm64/asm/swab.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/termbits.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/termios.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/types.h | 19 + .../libc/kernel/uapi/asm-arm64/asm/ucontext.h | 30 + .../libc/kernel/uapi/asm-arm64/asm/unistd.h | 24 + .../libc/kernel/uapi/asm-generic/auxvec.h | 21 + .../kernel/uapi/asm-generic/bitsperlong.h | 24 + .../kernel/uapi/asm-generic/bpf_perf_event.h | 23 + .../libc/kernel/uapi/asm-generic/errno-base.h | 55 + .../libc/kernel/uapi/asm-generic/errno.h | 121 + .../libc/kernel/uapi/asm-generic/fcntl.h | 156 + .../kernel/uapi/asm-generic/hugetlb_encode.h | 35 + .../libc/kernel/uapi/asm-generic/int-l64.h | 32 + .../libc/kernel/uapi/asm-generic/int-ll64.h | 37 + .../libc/kernel/uapi/asm-generic/ioctl.h | 64 + .../libc/kernel/uapi/asm-generic/ioctls.h | 112 + .../libc/kernel/uapi/asm-generic/ipcbuf.h | 35 + .../libc/kernel/uapi/asm-generic/kvm_para.h | 18 + .../kernel/uapi/asm-generic/mman-common.h | 67 + .../libc/kernel/uapi/asm-generic/mman.h | 30 + .../libc/kernel/uapi/asm-generic/msgbuf.h | 45 + .../libc/kernel/uapi/asm-generic/param.h | 31 + .../libc/kernel/uapi/asm-generic/poll.h | 51 + .../kernel/uapi/asm-generic/posix_types.h | 86 + .../libc/kernel/uapi/asm-generic/resource.h | 51 + .../libc/kernel/uapi/asm-generic/sembuf.h | 38 + .../libc/kernel/uapi/asm-generic/setup.h | 22 + .../libc/kernel/uapi/asm-generic/shmbuf.h | 54 + .../libc/kernel/uapi/asm-generic/siginfo.h | 238 + .../kernel/uapi/asm-generic/signal-defs.h | 40 + .../libc/kernel/uapi/asm-generic/signal.h | 99 + .../libc/kernel/uapi/asm-generic/socket.h | 114 + .../libc/kernel/uapi/asm-generic/sockios.h | 28 + .../libc/kernel/uapi/asm-generic/stat.h | 69 + .../libc/kernel/uapi/asm-generic/statfs.h | 77 + .../libc/kernel/uapi/asm-generic/swab.h | 27 + .../libc/kernel/uapi/asm-generic/termbits.h | 194 + .../libc/kernel/uapi/asm-generic/termios.h | 52 + .../libc/kernel/uapi/asm-generic/types.h | 22 + .../libc/kernel/uapi/asm-generic/ucontext.h | 28 + .../libc/kernel/uapi/asm-generic/unistd.h | 437 ++ .../libc/kernel/uapi/asm-x86/asm/a.out.h | 34 + .../libc/kernel/uapi/asm-x86/asm/auxvec.h | 26 + .../kernel/uapi/asm-x86/asm/bitsperlong.h | 27 + .../libc/kernel/uapi/asm-x86/asm/boot.h | 24 + .../libc/kernel/uapi/asm-x86/asm/bootparam.h | 195 + .../kernel/uapi/asm-x86/asm/bpf_perf_event.h | 19 + .../libc/kernel/uapi/asm-x86/asm/byteorder.h | 22 + .../libc/kernel/uapi/asm-x86/asm/debugreg.h | 56 + .../libc/kernel/uapi/asm-x86/asm/e820.h | 51 + .../libc/kernel/uapi/asm-x86/asm/errno.h | 19 + .../libc/kernel/uapi/asm-x86/asm/fcntl.h | 19 + .../kernel/uapi/asm-x86/asm/hw_breakpoint.h | 18 + .../libc/kernel/uapi/asm-x86/asm/hwcap2.h | 22 + .../libc/kernel/uapi/asm-x86/asm/ioctl.h | 19 + .../libc/kernel/uapi/asm-x86/asm/ioctls.h | 19 + .../libc/kernel/uapi/asm-x86/asm/ipcbuf.h | 19 + .../bionic/libc/kernel/uapi/asm-x86/asm/ist.h | 28 + .../bionic/libc/kernel/uapi/asm-x86/asm/kvm.h | 363 + .../libc/kernel/uapi/asm-x86/asm/kvm_para.h | 103 + .../libc/kernel/uapi/asm-x86/asm/kvm_perf.h | 29 + .../bionic/libc/kernel/uapi/asm-x86/asm/ldt.h | 42 + .../bionic/libc/kernel/uapi/asm-x86/asm/mce.h | 52 + .../libc/kernel/uapi/asm-x86/asm/mman.h | 23 + .../libc/kernel/uapi/asm-x86/asm/msgbuf.h | 39 + .../bionic/libc/kernel/uapi/asm-x86/asm/msr.h | 27 + .../libc/kernel/uapi/asm-x86/asm/mtrr.h | 86 + .../libc/kernel/uapi/asm-x86/asm/param.h | 19 + .../libc/kernel/uapi/asm-x86/asm/perf_regs.h | 67 + .../libc/kernel/uapi/asm-x86/asm/poll.h | 19 + .../kernel/uapi/asm-x86/asm/posix_types.h | 25 + .../kernel/uapi/asm-x86/asm/posix_types_32.h | 31 + .../kernel/uapi/asm-x86/asm/posix_types_64.h | 27 + .../kernel/uapi/asm-x86/asm/posix_types_x32.h | 25 + .../libc/kernel/uapi/asm-x86/asm/prctl.h | 30 + .../kernel/uapi/asm-x86/asm/processor-flags.h | 147 + .../libc/kernel/uapi/asm-x86/asm/ptrace-abi.h | 84 + .../libc/kernel/uapi/asm-x86/asm/ptrace.h | 71 + .../libc/kernel/uapi/asm-x86/asm/resource.h | 19 + .../libc/kernel/uapi/asm-x86/asm/sembuf.h | 39 + .../libc/kernel/uapi/asm-x86/asm/setup.h | 18 + .../libc/kernel/uapi/asm-x86/asm/shmbuf.h | 48 + .../libc/kernel/uapi/asm-x86/asm/sigcontext.h | 225 + .../kernel/uapi/asm-x86/asm/sigcontext32.h | 22 + .../libc/kernel/uapi/asm-x86/asm/siginfo.h | 29 + .../libc/kernel/uapi/asm-x86/asm/signal.h | 105 + .../libc/kernel/uapi/asm-x86/asm/socket.h | 19 + .../libc/kernel/uapi/asm-x86/asm/sockios.h | 19 + .../libc/kernel/uapi/asm-x86/asm/stat.h | 114 + .../libc/kernel/uapi/asm-x86/asm/statfs.h | 23 + .../bionic/libc/kernel/uapi/asm-x86/asm/svm.h | 100 + .../libc/kernel/uapi/asm-x86/asm/swab.h | 28 + .../libc/kernel/uapi/asm-x86/asm/termbits.h | 19 + .../libc/kernel/uapi/asm-x86/asm/termios.h | 19 + .../libc/kernel/uapi/asm-x86/asm/types.h | 19 + .../libc/kernel/uapi/asm-x86/asm/ucontext.h | 27 + .../libc/kernel/uapi/asm-x86/asm/unistd.h | 29 + .../libc/kernel/uapi/asm-x86/asm/unistd_32.h | 446 ++ .../libc/kernel/uapi/asm-x86/asm/unistd_64.h | 368 + .../libc/kernel/uapi/asm-x86/asm/unistd_x32.h | 357 + .../libc/kernel/uapi/asm-x86/asm/vm86.h | 96 + .../bionic/libc/kernel/uapi/asm-x86/asm/vmx.h | 85 + .../libc/kernel/uapi/asm-x86/asm/vsyscall.h | 27 + aosp/bionic/libc/kernel/uapi/drm/amdgpu_drm.h | 640 ++ aosp/bionic/libc/kernel/uapi/drm/armada_drm.h | 52 + aosp/bionic/libc/kernel/uapi/drm/drm.h | 642 ++ aosp/bionic/libc/kernel/uapi/drm/drm_fourcc.h | 203 + aosp/bionic/libc/kernel/uapi/drm/drm_mode.h | 501 ++ aosp/bionic/libc/kernel/uapi/drm/drm_sarea.h | 60 + .../bionic/libc/kernel/uapi/drm/etnaviv_drm.h | 201 + aosp/bionic/libc/kernel/uapi/drm/exynos_drm.h | 231 + aosp/bionic/libc/kernel/uapi/drm/i810_drm.h | 220 + aosp/bionic/libc/kernel/uapi/drm/i915_drm.h | 913 +++ aosp/bionic/libc/kernel/uapi/drm/lima_drm.h | 129 + aosp/bionic/libc/kernel/uapi/drm/mga_drm.h | 246 + aosp/bionic/libc/kernel/uapi/drm/msm_drm.h | 181 + .../bionic/libc/kernel/uapi/drm/nouveau_drm.h | 159 + aosp/bionic/libc/kernel/uapi/drm/omap_drm.h | 89 + .../libc/kernel/uapi/drm/panfrost_drm.h | 141 + aosp/bionic/libc/kernel/uapi/drm/qxl_drm.h | 103 + aosp/bionic/libc/kernel/uapi/drm/r128_drm.h | 235 + aosp/bionic/libc/kernel/uapi/drm/radeon_drm.h | 807 +++ aosp/bionic/libc/kernel/uapi/drm/savage_drm.h | 157 + aosp/bionic/libc/kernel/uapi/drm/sis_drm.h | 54 + aosp/bionic/libc/kernel/uapi/drm/tegra_drm.h | 169 + aosp/bionic/libc/kernel/uapi/drm/v3d_drm.h | 118 + aosp/bionic/libc/kernel/uapi/drm/vc4_drm.h | 239 + aosp/bionic/libc/kernel/uapi/drm/vgem_drm.h | 43 + aosp/bionic/libc/kernel/uapi/drm/via_drm.h | 202 + .../bionic/libc/kernel/uapi/drm/virtgpu_drm.h | 122 + aosp/bionic/libc/kernel/uapi/drm/vmwgfx_drm.h | 357 + aosp/bionic/libc/kernel/uapi/linux/a.out.h | 163 + aosp/bionic/libc/kernel/uapi/linux/acct.h | 86 + aosp/bionic/libc/kernel/uapi/linux/adb.h | 42 + aosp/bionic/libc/kernel/uapi/linux/adfs_fs.h | 55 + .../libc/kernel/uapi/linux/affs_hardblocks.h | 77 + aosp/bionic/libc/kernel/uapi/linux/agpgart.h | 83 + aosp/bionic/libc/kernel/uapi/linux/aio_abi.h | 66 + .../libc/kernel/uapi/linux/am437x-vpfe.h | 80 + .../libc/kernel/uapi/linux/android/binder.h | 223 + .../libc/kernel/uapi/linux/android/binderfs.h | 31 + aosp/bionic/libc/kernel/uapi/linux/apm_bios.h | 103 + aosp/bionic/libc/kernel/uapi/linux/arcfb.h | 23 + aosp/bionic/libc/kernel/uapi/linux/arm_sdei.h | 72 + aosp/bionic/libc/kernel/uapi/linux/ashmem.h | 44 + .../libc/kernel/uapi/linux/aspeed-lpc-ctrl.h | 36 + .../libc/kernel/uapi/linux/aspeed-p2a-ctrl.h | 33 + aosp/bionic/libc/kernel/uapi/linux/atalk.h | 49 + aosp/bionic/libc/kernel/uapi/linux/atm.h | 146 + aosp/bionic/libc/kernel/uapi/linux/atm_eni.h | 27 + aosp/bionic/libc/kernel/uapi/linux/atm_he.h | 31 + .../libc/kernel/uapi/linux/atm_idt77105.h | 32 + .../libc/kernel/uapi/linux/atm_nicstar.h | 40 + aosp/bionic/libc/kernel/uapi/linux/atm_tcp.h | 44 + aosp/bionic/libc/kernel/uapi/linux/atm_zatm.h | 42 + aosp/bionic/libc/kernel/uapi/linux/atmapi.h | 29 + aosp/bionic/libc/kernel/uapi/linux/atmarp.h | 42 + .../bionic/libc/kernel/uapi/linux/atmbr2684.h | 82 + aosp/bionic/libc/kernel/uapi/linux/atmclip.h | 28 + aosp/bionic/libc/kernel/uapi/linux/atmdev.h | 114 + aosp/bionic/libc/kernel/uapi/linux/atmioc.h | 43 + aosp/bionic/libc/kernel/uapi/linux/atmlec.h | 86 + aosp/bionic/libc/kernel/uapi/linux/atmmpc.h | 113 + aosp/bionic/libc/kernel/uapi/linux/atmppp.h | 29 + aosp/bionic/libc/kernel/uapi/linux/atmsap.h | 103 + aosp/bionic/libc/kernel/uapi/linux/atmsvc.h | 56 + aosp/bionic/libc/kernel/uapi/linux/audit.h | 373 + .../libc/kernel/uapi/linux/auto_dev-ioctl.h | 120 + aosp/bionic/libc/kernel/uapi/linux/auto_fs.h | 128 + aosp/bionic/libc/kernel/uapi/linux/auto_fs4.h | 22 + aosp/bionic/libc/kernel/uapi/linux/auxvec.h | 45 + aosp/bionic/libc/kernel/uapi/linux/ax25.h | 109 + aosp/bionic/libc/kernel/uapi/linux/b1lli.h | 64 + .../libc/kernel/uapi/linux/batadv_packet.h | 282 + .../libc/kernel/uapi/linux/batman_adv.h | 147 + aosp/bionic/libc/kernel/uapi/linux/baycom.h | 33 + aosp/bionic/libc/kernel/uapi/linux/bcache.h | 179 + .../libc/kernel/uapi/linux/bcm933xx_hcs.h | 35 + aosp/bionic/libc/kernel/uapi/linux/bfs_fs.h | 70 + aosp/bionic/libc/kernel/uapi/linux/binfmts.h | 26 + aosp/bionic/libc/kernel/uapi/linux/blkpg.h | 42 + .../libc/kernel/uapi/linux/blktrace_api.h | 125 + aosp/bionic/libc/kernel/uapi/linux/blkzoned.h | 65 + aosp/bionic/libc/kernel/uapi/linux/bpf.h | 826 +++ .../libc/kernel/uapi/linux/bpf_common.h | 64 + .../libc/kernel/uapi/linux/bpf_perf_event.h | 27 + aosp/bionic/libc/kernel/uapi/linux/bpfilter.h | 34 + aosp/bionic/libc/kernel/uapi/linux/bpqether.h | 41 + aosp/bionic/libc/kernel/uapi/linux/bsg.h | 63 + aosp/bionic/libc/kernel/uapi/linux/bt-bmc.h | 24 + aosp/bionic/libc/kernel/uapi/linux/btf.h | 104 + aosp/bionic/libc/kernel/uapi/linux/btrfs.h | 520 ++ .../libc/kernel/uapi/linux/btrfs_tree.h | 431 ++ .../kernel/uapi/linux/byteorder/big_endian.h | 69 + .../uapi/linux/byteorder/little_endian.h | 69 + .../libc/kernel/uapi/linux/caif/caif_socket.h | 84 + .../libc/kernel/uapi/linux/caif/if_caif.h | 32 + aosp/bionic/libc/kernel/uapi/linux/can.h | 86 + aosp/bionic/libc/kernel/uapi/linux/can/bcm.h | 62 + .../bionic/libc/kernel/uapi/linux/can/error.h | 79 + aosp/bionic/libc/kernel/uapi/linux/can/gw.h | 105 + .../bionic/libc/kernel/uapi/linux/can/j1939.h | 67 + .../libc/kernel/uapi/linux/can/netlink.h | 100 + aosp/bionic/libc/kernel/uapi/linux/can/raw.h | 31 + .../bionic/libc/kernel/uapi/linux/can/vxcan.h | 27 + .../libc/kernel/uapi/linux/capability.h | 112 + aosp/bionic/libc/kernel/uapi/linux/capi.h | 75 + .../libc/kernel/uapi/linux/cciss_defs.h | 122 + .../libc/kernel/uapi/linux/cciss_ioctl.h | 82 + aosp/bionic/libc/kernel/uapi/linux/cdrom.h | 654 ++ .../bionic/libc/kernel/uapi/linux/cec-funcs.h | 94 + aosp/bionic/libc/kernel/uapi/linux/cec.h | 620 ++ .../libc/kernel/uapi/linux/cgroupstats.h | 49 + aosp/bionic/libc/kernel/uapi/linux/chio.h | 121 + .../libc/kernel/uapi/linux/cifs/cifs_mount.h | 26 + .../bionic/libc/kernel/uapi/linux/cm4000_cs.h | 54 + aosp/bionic/libc/kernel/uapi/linux/cn_proc.h | 97 + aosp/bionic/libc/kernel/uapi/linux/coda.h | 526 ++ aosp/bionic/libc/kernel/uapi/linux/coff.h | 198 + .../bionic/libc/kernel/uapi/linux/connector.h | 55 + aosp/bionic/libc/kernel/uapi/linux/const.h | 33 + .../libc/kernel/uapi/linux/coresight-stm.h | 27 + .../bionic/libc/kernel/uapi/linux/cramfs_fs.h | 63 + .../libc/kernel/uapi/linux/cryptouser.h | 173 + aosp/bionic/libc/kernel/uapi/linux/cuda.h | 40 + aosp/bionic/libc/kernel/uapi/linux/cyclades.h | 306 + aosp/bionic/libc/kernel/uapi/linux/cycx_cfm.h | 63 + aosp/bionic/libc/kernel/uapi/linux/dcbnl.h | 348 + aosp/bionic/libc/kernel/uapi/linux/dccp.h | 160 + aosp/bionic/libc/kernel/uapi/linux/devlink.h | 343 + aosp/bionic/libc/kernel/uapi/linux/dlm.h | 36 + .../libc/kernel/uapi/linux/dlm_device.h | 87 + .../libc/kernel/uapi/linux/dlm_netlink.h | 59 + .../bionic/libc/kernel/uapi/linux/dlm_plock.h | 47 + .../libc/kernel/uapi/linux/dlmconstants.h | 51 + aosp/bionic/libc/kernel/uapi/linux/dm-ioctl.h | 127 + .../libc/kernel/uapi/linux/dm-log-userspace.h | 54 + aosp/bionic/libc/kernel/uapi/linux/dma-buf.h | 35 + aosp/bionic/libc/kernel/uapi/linux/dn.h | 114 + .../libc/kernel/uapi/linux/dns_resolver.h | 78 + .../bionic/libc/kernel/uapi/linux/dqblk_xfs.h | 131 + .../bionic/libc/kernel/uapi/linux/dvb/audio.h | 76 + aosp/bionic/libc/kernel/uapi/linux/dvb/ca.h | 69 + aosp/bionic/libc/kernel/uapi/linux/dvb/dmx.h | 130 + .../libc/kernel/uapi/linux/dvb/frontend.h | 432 ++ aosp/bionic/libc/kernel/uapi/linux/dvb/net.h | 38 + aosp/bionic/libc/kernel/uapi/linux/dvb/osd.h | 84 + .../libc/kernel/uapi/linux/dvb/version.h | 23 + .../bionic/libc/kernel/uapi/linux/dvb/video.h | 129 + aosp/bionic/libc/kernel/uapi/linux/edd.h | 165 + .../bionic/libc/kernel/uapi/linux/efs_fs_sb.h | 61 + aosp/bionic/libc/kernel/uapi/linux/elf-em.h | 69 + .../bionic/libc/kernel/uapi/linux/elf-fdpic.h | 34 + aosp/bionic/libc/kernel/uapi/linux/elf.h | 376 + aosp/bionic/libc/kernel/uapi/linux/elfcore.h | 69 + aosp/bionic/libc/kernel/uapi/linux/errno.h | 19 + aosp/bionic/libc/kernel/uapi/linux/errqueue.h | 55 + aosp/bionic/libc/kernel/uapi/linux/erspan.h | 43 + aosp/bionic/libc/kernel/uapi/linux/ethtool.h | 804 +++ .../bionic/libc/kernel/uapi/linux/eventpoll.h | 49 + aosp/bionic/libc/kernel/uapi/linux/fadvise.h | 32 + aosp/bionic/libc/kernel/uapi/linux/falloc.h | 28 + aosp/bionic/libc/kernel/uapi/linux/fanotify.h | 101 + aosp/bionic/libc/kernel/uapi/linux/fb.h | 325 + aosp/bionic/libc/kernel/uapi/linux/fcntl.h | 65 + aosp/bionic/libc/kernel/uapi/linux/fd.h | 196 + aosp/bionic/libc/kernel/uapi/linux/fdreg.h | 101 + .../bionic/libc/kernel/uapi/linux/fib_rules.h | 92 + aosp/bionic/libc/kernel/uapi/linux/fiemap.h | 55 + aosp/bionic/libc/kernel/uapi/linux/filter.h | 70 + .../libc/kernel/uapi/linux/firewire-cdev.h | 270 + .../kernel/uapi/linux/firewire-constants.h | 74 + aosp/bionic/libc/kernel/uapi/linux/fou.h | 52 + aosp/bionic/libc/kernel/uapi/linux/fpga-dfl.h | 76 + aosp/bionic/libc/kernel/uapi/linux/fs.h | 197 + aosp/bionic/libc/kernel/uapi/linux/fscrypt.h | 139 + aosp/bionic/libc/kernel/uapi/linux/fsi.h | 51 + .../libc/kernel/uapi/linux/fsl_hypervisor.h | 72 + aosp/bionic/libc/kernel/uapi/linux/fsmap.h | 55 + aosp/bionic/libc/kernel/uapi/linux/fsverity.h | 43 + aosp/bionic/libc/kernel/uapi/linux/fuse.h | 517 ++ aosp/bionic/libc/kernel/uapi/linux/futex.h | 77 + aosp/bionic/libc/kernel/uapi/linux/gameport.h | 34 + .../bionic/libc/kernel/uapi/linux/gen_stats.h | 58 + .../bionic/libc/kernel/uapi/linux/genetlink.h | 81 + .../kernel/uapi/linux/genwqe/genwqe_card.h | 270 + .../libc/kernel/uapi/linux/gfs2_ondisk.h | 349 + .../libc/kernel/uapi/linux/gigaset_dev.h | 30 + aosp/bionic/libc/kernel/uapi/linux/gpio.h | 90 + aosp/bionic/libc/kernel/uapi/linux/gsmmux.h | 50 + aosp/bionic/libc/kernel/uapi/linux/gtp.h | 47 + .../bionic/libc/kernel/uapi/linux/hash_info.h | 44 + aosp/bionic/libc/kernel/uapi/linux/hdlc.h | 23 + .../libc/kernel/uapi/linux/hdlc/ioctl.h | 83 + aosp/bionic/libc/kernel/uapi/linux/hdlcdrv.h | 85 + aosp/bionic/libc/kernel/uapi/linux/hdreg.h | 390 ++ aosp/bionic/libc/kernel/uapi/linux/hid.h | 35 + aosp/bionic/libc/kernel/uapi/linux/hiddev.h | 126 + aosp/bionic/libc/kernel/uapi/linux/hidraw.h | 42 + aosp/bionic/libc/kernel/uapi/linux/hpet.h | 36 + .../libc/kernel/uapi/linux/hsi/cs-protocol.h | 75 + .../libc/kernel/uapi/linux/hsi/hsi_char.h | 52 + .../libc/kernel/uapi/linux/hsr_netlink.h | 47 + .../libc/kernel/uapi/linux/hw_breakpoint.h | 44 + aosp/bionic/libc/kernel/uapi/linux/hyperv.h | 194 + aosp/bionic/libc/kernel/uapi/linux/hysdn_if.h | 31 + aosp/bionic/libc/kernel/uapi/linux/i2c-dev.h | 44 + aosp/bionic/libc/kernel/uapi/linux/i2c.h | 80 + aosp/bionic/libc/kernel/uapi/linux/i2o-dev.h | 317 + aosp/bionic/libc/kernel/uapi/linux/i8k.h | 43 + aosp/bionic/libc/kernel/uapi/linux/icmp.h | 80 + aosp/bionic/libc/kernel/uapi/linux/icmpv6.h | 123 + aosp/bionic/libc/kernel/uapi/linux/if.h | 192 + aosp/bionic/libc/kernel/uapi/linux/if_addr.h | 66 + .../libc/kernel/uapi/linux/if_addrlabel.h | 36 + aosp/bionic/libc/kernel/uapi/linux/if_alg.h | 40 + .../bionic/libc/kernel/uapi/linux/if_arcnet.h | 81 + aosp/bionic/libc/kernel/uapi/linux/if_arp.h | 122 + .../libc/kernel/uapi/linux/if_bonding.h | 92 + .../bionic/libc/kernel/uapi/linux/if_bridge.h | 249 + .../libc/kernel/uapi/linux/if_cablemodem.h | 27 + aosp/bionic/libc/kernel/uapi/linux/if_eql.h | 44 + aosp/bionic/libc/kernel/uapi/linux/if_ether.h | 134 + aosp/bionic/libc/kernel/uapi/linux/if_fc.h | 38 + aosp/bionic/libc/kernel/uapi/linux/if_fddi.h | 90 + aosp/bionic/libc/kernel/uapi/linux/if_frad.h | 79 + aosp/bionic/libc/kernel/uapi/linux/if_hippi.h | 88 + .../libc/kernel/uapi/linux/if_infiniband.h | 22 + aosp/bionic/libc/kernel/uapi/linux/if_link.h | 809 +++ aosp/bionic/libc/kernel/uapi/linux/if_ltalk.h | 24 + .../bionic/libc/kernel/uapi/linux/if_macsec.h | 159 + .../bionic/libc/kernel/uapi/linux/if_packet.h | 225 + .../bionic/libc/kernel/uapi/linux/if_phonet.h | 24 + aosp/bionic/libc/kernel/uapi/linux/if_plip.h | 30 + aosp/bionic/libc/kernel/uapi/linux/if_ppp.h | 19 + .../libc/kernel/uapi/linux/if_pppol2tp.h | 66 + aosp/bionic/libc/kernel/uapi/linux/if_pppox.h | 113 + aosp/bionic/libc/kernel/uapi/linux/if_slip.h | 32 + aosp/bionic/libc/kernel/uapi/linux/if_team.h | 76 + aosp/bionic/libc/kernel/uapi/linux/if_tun.h | 86 + .../bionic/libc/kernel/uapi/linux/if_tunnel.h | 173 + aosp/bionic/libc/kernel/uapi/linux/if_vlan.h | 60 + aosp/bionic/libc/kernel/uapi/linux/if_x25.h | 26 + aosp/bionic/libc/kernel/uapi/linux/if_xdp.h | 82 + aosp/bionic/libc/kernel/uapi/linux/ife.h | 31 + aosp/bionic/libc/kernel/uapi/linux/igmp.h | 91 + .../libc/kernel/uapi/linux/iio/events.h | 35 + .../bionic/libc/kernel/uapi/linux/iio/types.h | 118 + aosp/bionic/libc/kernel/uapi/linux/ila.h | 69 + aosp/bionic/libc/kernel/uapi/linux/in.h | 222 + aosp/bionic/libc/kernel/uapi/linux/in6.h | 181 + aosp/bionic/libc/kernel/uapi/linux/in_route.h | 40 + .../bionic/libc/kernel/uapi/linux/inet_diag.h | 168 + aosp/bionic/libc/kernel/uapi/linux/inotify.h | 58 + .../kernel/uapi/linux/input-event-codes.h | 771 +++ aosp/bionic/libc/kernel/uapi/linux/input.h | 218 + aosp/bionic/libc/kernel/uapi/linux/io_uring.h | 137 + aosp/bionic/libc/kernel/uapi/linux/ioctl.h | 22 + aosp/bionic/libc/kernel/uapi/linux/iommu.h | 152 + aosp/bionic/libc/kernel/uapi/linux/ip.h | 152 + .../libc/kernel/uapi/linux/ip6_tunnel.h | 59 + aosp/bionic/libc/kernel/uapi/linux/ip_vs.h | 290 + aosp/bionic/libc/kernel/uapi/linux/ipc.h | 62 + aosp/bionic/libc/kernel/uapi/linux/ipmi.h | 136 + aosp/bionic/libc/kernel/uapi/linux/ipmi_bmc.h | 26 + .../libc/kernel/uapi/linux/ipmi_msgdefs.h | 83 + aosp/bionic/libc/kernel/uapi/linux/ipsec.h | 54 + aosp/bionic/libc/kernel/uapi/linux/ipv6.h | 146 + .../libc/kernel/uapi/linux/ipv6_route.h | 56 + aosp/bionic/libc/kernel/uapi/linux/ipx.h | 90 + aosp/bionic/libc/kernel/uapi/linux/irqnr.h | 18 + .../libc/kernel/uapi/linux/isdn/capicmd.h | 97 + aosp/bionic/libc/kernel/uapi/linux/iso_fs.h | 154 + aosp/bionic/libc/kernel/uapi/linux/isst_if.h | 76 + aosp/bionic/libc/kernel/uapi/linux/ivtv.h | 40 + aosp/bionic/libc/kernel/uapi/linux/ivtvfb.h | 29 + aosp/bionic/libc/kernel/uapi/linux/jffs2.h | 163 + aosp/bionic/libc/kernel/uapi/linux/joystick.h | 90 + aosp/bionic/libc/kernel/uapi/linux/kcm.h | 36 + aosp/bionic/libc/kernel/uapi/linux/kcmp.h | 38 + aosp/bionic/libc/kernel/uapi/linux/kcov.h | 45 + aosp/bionic/libc/kernel/uapi/linux/kd.h | 162 + aosp/bionic/libc/kernel/uapi/linux/kdev_t.h | 24 + .../kernel/uapi/linux/kernel-page-flags.h | 48 + aosp/bionic/libc/kernel/uapi/linux/kernel.h | 25 + .../libc/kernel/uapi/linux/kernelcapi.h | 42 + aosp/bionic/libc/kernel/uapi/linux/kexec.h | 49 + aosp/bionic/libc/kernel/uapi/linux/keyboard.h | 454 ++ aosp/bionic/libc/kernel/uapi/linux/keyctl.h | 120 + .../bionic/libc/kernel/uapi/linux/kfd_ioctl.h | 324 + aosp/bionic/libc/kernel/uapi/linux/kvm.h | 1231 ++++ aosp/bionic/libc/kernel/uapi/linux/kvm_para.h | 39 + aosp/bionic/libc/kernel/uapi/linux/l2tp.h | 140 + .../libc/kernel/uapi/linux/libc-compat.h | 172 + aosp/bionic/libc/kernel/uapi/linux/lightnvm.h | 167 + aosp/bionic/libc/kernel/uapi/linux/limits.h | 34 + aosp/bionic/libc/kernel/uapi/linux/lirc.h | 135 + aosp/bionic/libc/kernel/uapi/linux/llc.h | 80 + aosp/bionic/libc/kernel/uapi/linux/loop.h | 84 + aosp/bionic/libc/kernel/uapi/linux/lp.h | 67 + aosp/bionic/libc/kernel/uapi/linux/lwtunnel.h | 108 + aosp/bionic/libc/kernel/uapi/linux/magic.h | 102 + aosp/bionic/libc/kernel/uapi/linux/major.h | 162 + .../libc/kernel/uapi/linux/map_to_7segment.h | 47 + aosp/bionic/libc/kernel/uapi/linux/matroxfb.h | 49 + aosp/bionic/libc/kernel/uapi/linux/max2175.h | 25 + aosp/bionic/libc/kernel/uapi/linux/mdio.h | 249 + .../libc/kernel/uapi/linux/media-bus-format.h | 129 + aosp/bionic/libc/kernel/uapi/linux/media.h | 232 + aosp/bionic/libc/kernel/uapi/linux/mei.h | 36 + .../libc/kernel/uapi/linux/membarrier.h | 32 + aosp/bionic/libc/kernel/uapi/linux/memfd.h | 39 + .../bionic/libc/kernel/uapi/linux/mempolicy.h | 46 + aosp/bionic/libc/kernel/uapi/linux/meye.h | 38 + .../libc/kernel/uapi/linux/mic_common.h | 96 + .../bionic/libc/kernel/uapi/linux/mic_ioctl.h | 32 + aosp/bionic/libc/kernel/uapi/linux/mii.h | 145 + aosp/bionic/libc/kernel/uapi/linux/minix_fs.h | 86 + aosp/bionic/libc/kernel/uapi/linux/mman.h | 45 + .../bionic/libc/kernel/uapi/linux/mmc/ioctl.h | 47 + aosp/bionic/libc/kernel/uapi/linux/mmtimer.h | 28 + aosp/bionic/libc/kernel/uapi/linux/module.h | 23 + aosp/bionic/libc/kernel/uapi/linux/mount.h | 89 + aosp/bionic/libc/kernel/uapi/linux/mpls.h | 60 + .../libc/kernel/uapi/linux/mpls_iptunnel.h | 28 + aosp/bionic/libc/kernel/uapi/linux/mqueue.h | 35 + aosp/bionic/libc/kernel/uapi/linux/mroute.h | 151 + aosp/bionic/libc/kernel/uapi/linux/mroute6.h | 112 + aosp/bionic/libc/kernel/uapi/linux/msdos_fs.h | 159 + aosp/bionic/libc/kernel/uapi/linux/msg.h | 67 + aosp/bionic/libc/kernel/uapi/linux/mtio.h | 147 + aosp/bionic/libc/kernel/uapi/linux/n_r3964.h | 46 + .../libc/kernel/uapi/linux/nbd-netlink.h | 73 + aosp/bionic/libc/kernel/uapi/linux/nbd.h | 63 + aosp/bionic/libc/kernel/uapi/linux/ncsi.h | 69 + aosp/bionic/libc/kernel/uapi/linux/ndctl.h | 162 + .../bionic/libc/kernel/uapi/linux/neighbour.h | 138 + aosp/bionic/libc/kernel/uapi/linux/net.h | 52 + .../libc/kernel/uapi/linux/net_dropmon.h | 111 + .../libc/kernel/uapi/linux/net_namespace.h | 32 + .../libc/kernel/uapi/linux/net_tstamp.h | 86 + aosp/bionic/libc/kernel/uapi/linux/netconf.h | 42 + .../bionic/libc/kernel/uapi/linux/netdevice.h | 45 + .../bionic/libc/kernel/uapi/linux/netfilter.h | 69 + .../uapi/linux/netfilter/ipset/ip_set.h | 254 + .../linux/netfilter/ipset/ip_set_bitmap.h | 26 + .../uapi/linux/netfilter/ipset/ip_set_hash.h | 30 + .../uapi/linux/netfilter/ipset/ip_set_list.h | 30 + .../linux/netfilter/nf_conntrack_common.h | 92 + .../uapi/linux/netfilter/nf_conntrack_ftp.h | 27 + .../uapi/linux/netfilter/nf_conntrack_sctp.h | 35 + .../uapi/linux/netfilter/nf_conntrack_tcp.h | 52 + .../netfilter/nf_conntrack_tuple_common.h | 51 + .../libc/kernel/uapi/linux/netfilter/nf_log.h | 29 + .../libc/kernel/uapi/linux/netfilter/nf_nat.h | 57 + .../kernel/uapi/linux/netfilter/nf_synproxy.h | 33 + .../kernel/uapi/linux/netfilter/nf_tables.h | 977 +++ .../uapi/linux/netfilter/nf_tables_compat.h | 50 + .../kernel/uapi/linux/netfilter/nfnetlink.h | 76 + .../uapi/linux/netfilter/nfnetlink_acct.h | 57 + .../uapi/linux/netfilter/nfnetlink_compat.h | 50 + .../linux/netfilter/nfnetlink_conntrack.h | 268 + .../uapi/linux/netfilter/nfnetlink_cthelper.h | 66 + .../linux/netfilter/nfnetlink_cttimeout.h | 122 + .../uapi/linux/netfilter/nfnetlink_log.h | 107 + .../uapi/linux/netfilter/nfnetlink_osf.h | 97 + .../uapi/linux/netfilter/nfnetlink_queue.h | 120 + .../kernel/uapi/linux/netfilter/x_tables.h | 102 + .../kernel/uapi/linux/netfilter/xt_AUDIT.h | 32 + .../kernel/uapi/linux/netfilter/xt_CHECKSUM.h | 26 + .../kernel/uapi/linux/netfilter/xt_CLASSIFY.h | 25 + .../kernel/uapi/linux/netfilter/xt_CONNMARK.h | 22 + .../uapi/linux/netfilter/xt_CONNSECMARK.h | 29 + .../libc/kernel/uapi/linux/netfilter/xt_CT.h | 47 + .../kernel/uapi/linux/netfilter/xt_DSCP.h | 30 + .../kernel/uapi/linux/netfilter/xt_HMARK.h | 64 + .../uapi/linux/netfilter/xt_IDLETIMER.h | 32 + .../libc/kernel/uapi/linux/netfilter/xt_LED.h | 28 + .../libc/kernel/uapi/linux/netfilter/xt_LOG.h | 33 + .../kernel/uapi/linux/netfilter/xt_MARK.h | 22 + .../kernel/uapi/linux/netfilter/xt_NFLOG.h | 34 + .../kernel/uapi/linux/netfilter/xt_NFQUEUE.h | 42 + .../kernel/uapi/linux/netfilter/xt_RATEEST.h | 29 + .../kernel/uapi/linux/netfilter/xt_SECMARK.h | 29 + .../kernel/uapi/linux/netfilter/xt_SYNPROXY.h | 28 + .../kernel/uapi/linux/netfilter/xt_TCPMSS.h | 26 + .../uapi/linux/netfilter/xt_TCPOPTSTRIP.h | 27 + .../libc/kernel/uapi/linux/netfilter/xt_TEE.h | 27 + .../kernel/uapi/linux/netfilter/xt_TPROXY.h | 35 + .../kernel/uapi/linux/netfilter/xt_addrtype.h | 53 + .../libc/kernel/uapi/linux/netfilter/xt_bpf.h | 48 + .../kernel/uapi/linux/netfilter/xt_cgroup.h | 48 + .../kernel/uapi/linux/netfilter/xt_cluster.h | 32 + .../kernel/uapi/linux/netfilter/xt_comment.h | 25 + .../uapi/linux/netfilter/xt_connbytes.h | 40 + .../uapi/linux/netfilter/xt_connlabel.h | 31 + .../uapi/linux/netfilter/xt_connlimit.h | 40 + .../kernel/uapi/linux/netfilter/xt_connmark.h | 43 + .../uapi/linux/netfilter/xt_conntrack.h | 83 + .../libc/kernel/uapi/linux/netfilter/xt_cpu.h | 26 + .../kernel/uapi/linux/netfilter/xt_dccp.h | 35 + .../kernel/uapi/linux/netfilter/xt_devgroup.h | 35 + .../kernel/uapi/linux/netfilter/xt_dscp.h | 34 + .../libc/kernel/uapi/linux/netfilter/xt_ecn.h | 38 + .../libc/kernel/uapi/linux/netfilter/xt_esp.h | 28 + .../uapi/linux/netfilter/xt_hashlimit.h | 101 + .../kernel/uapi/linux/netfilter/xt_helper.h | 25 + .../kernel/uapi/linux/netfilter/xt_ipcomp.h | 29 + .../kernel/uapi/linux/netfilter/xt_iprange.h | 34 + .../kernel/uapi/linux/netfilter/xt_ipvs.h | 43 + .../kernel/uapi/linux/netfilter/xt_l2tp.h | 39 + .../kernel/uapi/linux/netfilter/xt_length.h | 26 + .../kernel/uapi/linux/netfilter/xt_limit.h | 32 + .../libc/kernel/uapi/linux/netfilter/xt_mac.h | 26 + .../kernel/uapi/linux/netfilter/xt_mark.h | 29 + .../uapi/linux/netfilter/xt_multiport.h | 40 + .../kernel/uapi/linux/netfilter/xt_nfacct.h | 31 + .../libc/kernel/uapi/linux/netfilter/xt_osf.h | 42 + .../kernel/uapi/linux/netfilter/xt_owner.h | 34 + .../kernel/uapi/linux/netfilter/xt_physdev.h | 37 + .../kernel/uapi/linux/netfilter/xt_pkttype.h | 25 + .../kernel/uapi/linux/netfilter/xt_policy.h | 64 + .../kernel/uapi/linux/netfilter/xt_quota.h | 33 + .../kernel/uapi/linux/netfilter/xt_rateest.h | 49 + .../kernel/uapi/linux/netfilter/xt_realm.h | 27 + .../kernel/uapi/linux/netfilter/xt_recent.h | 53 + .../kernel/uapi/linux/netfilter/xt_rpfilter.h | 31 + .../kernel/uapi/linux/netfilter/xt_sctp.h | 56 + .../libc/kernel/uapi/linux/netfilter/xt_set.h | 81 + .../kernel/uapi/linux/netfilter/xt_socket.h | 39 + .../kernel/uapi/linux/netfilter/xt_state.h | 27 + .../uapi/linux/netfilter/xt_statistic.h | 48 + .../kernel/uapi/linux/netfilter/xt_string.h | 44 + .../kernel/uapi/linux/netfilter/xt_tcpmss.h | 26 + .../kernel/uapi/linux/netfilter/xt_tcpudp.h | 43 + .../kernel/uapi/linux/netfilter/xt_time.h | 40 + .../libc/kernel/uapi/linux/netfilter/xt_u32.h | 48 + .../libc/kernel/uapi/linux/netfilter_arp.h | 27 + .../uapi/linux/netfilter_arp/arp_tables.h | 109 + .../uapi/linux/netfilter_arp/arpt_mangle.h | 40 + .../libc/kernel/uapi/linux/netfilter_bridge.h | 44 + .../uapi/linux/netfilter_bridge/ebt_802_3.h | 58 + .../uapi/linux/netfilter_bridge/ebt_among.h | 44 + .../uapi/linux/netfilter_bridge/ebt_arp.h | 48 + .../linux/netfilter_bridge/ebt_arpreply.h | 27 + .../uapi/linux/netfilter_bridge/ebt_ip.h | 51 + .../uapi/linux/netfilter_bridge/ebt_ip6.h | 50 + .../uapi/linux/netfilter_bridge/ebt_limit.h | 31 + .../uapi/linux/netfilter_bridge/ebt_log.h | 34 + .../uapi/linux/netfilter_bridge/ebt_mark_m.h | 31 + .../uapi/linux/netfilter_bridge/ebt_mark_t.h | 30 + .../uapi/linux/netfilter_bridge/ebt_nat.h | 29 + .../uapi/linux/netfilter_bridge/ebt_nflog.h | 35 + .../uapi/linux/netfilter_bridge/ebt_pkttype.h | 27 + .../linux/netfilter_bridge/ebt_redirect.h | 25 + .../uapi/linux/netfilter_bridge/ebt_stp.h | 56 + .../uapi/linux/netfilter_bridge/ebt_vlan.h | 34 + .../uapi/linux/netfilter_bridge/ebtables.h | 155 + .../libc/kernel/uapi/linux/netfilter_decnet.h | 57 + .../libc/kernel/uapi/linux/netfilter_ipv4.h | 47 + .../uapi/linux/netfilter_ipv4/ip_tables.h | 126 + .../uapi/linux/netfilter_ipv4/ipt_CLUSTERIP.h | 42 + .../uapi/linux/netfilter_ipv4/ipt_ECN.h | 37 + .../uapi/linux/netfilter_ipv4/ipt_LOG.h | 33 + .../uapi/linux/netfilter_ipv4/ipt_REJECT.h | 35 + .../uapi/linux/netfilter_ipv4/ipt_TTL.h | 32 + .../kernel/uapi/linux/netfilter_ipv4/ipt_ah.h | 28 + .../uapi/linux/netfilter_ipv4/ipt_ecn.h | 30 + .../uapi/linux/netfilter_ipv4/ipt_ttl.h | 32 + .../libc/kernel/uapi/linux/netfilter_ipv6.h | 45 + .../uapi/linux/netfilter_ipv6/ip6_tables.h | 146 + .../uapi/linux/netfilter_ipv6/ip6t_HL.h | 32 + .../uapi/linux/netfilter_ipv6/ip6t_LOG.h | 33 + .../uapi/linux/netfilter_ipv6/ip6t_NPT.h | 30 + .../uapi/linux/netfilter_ipv6/ip6t_REJECT.h | 36 + .../uapi/linux/netfilter_ipv6/ip6t_ah.h | 34 + .../uapi/linux/netfilter_ipv6/ip6t_frag.h | 37 + .../uapi/linux/netfilter_ipv6/ip6t_hl.h | 32 + .../linux/netfilter_ipv6/ip6t_ipv6header.h | 35 + .../uapi/linux/netfilter_ipv6/ip6t_mh.h | 28 + .../uapi/linux/netfilter_ipv6/ip6t_opts.h | 35 + .../uapi/linux/netfilter_ipv6/ip6t_rt.h | 44 + .../uapi/linux/netfilter_ipv6/ip6t_srh.h | 77 + aosp/bionic/libc/kernel/uapi/linux/netlink.h | 162 + .../libc/kernel/uapi/linux/netlink_diag.h | 67 + aosp/bionic/libc/kernel/uapi/linux/netrom.h | 42 + aosp/bionic/libc/kernel/uapi/linux/nexthop.h | 55 + aosp/bionic/libc/kernel/uapi/linux/nfc.h | 176 + aosp/bionic/libc/kernel/uapi/linux/nfs.h | 129 + aosp/bionic/libc/kernel/uapi/linux/nfs2.h | 70 + aosp/bionic/libc/kernel/uapi/linux/nfs3.h | 98 + aosp/bionic/libc/kernel/uapi/linux/nfs4.h | 142 + .../libc/kernel/uapi/linux/nfs4_mount.h | 53 + aosp/bionic/libc/kernel/uapi/linux/nfs_fs.h | 53 + .../bionic/libc/kernel/uapi/linux/nfs_idmap.h | 38 + .../bionic/libc/kernel/uapi/linux/nfs_mount.h | 65 + aosp/bionic/libc/kernel/uapi/linux/nfsacl.h | 34 + aosp/bionic/libc/kernel/uapi/linux/nfsd/cld.h | 75 + .../libc/kernel/uapi/linux/nfsd/debug.h | 35 + .../libc/kernel/uapi/linux/nfsd/export.h | 44 + .../libc/kernel/uapi/linux/nfsd/nfsfh.h | 63 + .../libc/kernel/uapi/linux/nfsd/stats.h | 23 + .../libc/kernel/uapi/linux/nilfs2_api.h | 145 + .../libc/kernel/uapi/linux/nilfs2_ondisk.h | 288 + aosp/bionic/libc/kernel/uapi/linux/nl80211.h | 1658 +++++ aosp/bionic/libc/kernel/uapi/linux/nsfs.h | 27 + aosp/bionic/libc/kernel/uapi/linux/nubus.h | 158 + .../libc/kernel/uapi/linux/nvme_ioctl.h | 87 + aosp/bionic/libc/kernel/uapi/linux/nvram.h | 26 + aosp/bionic/libc/kernel/uapi/linux/omap3isp.h | 338 + aosp/bionic/libc/kernel/uapi/linux/omapfb.h | 187 + aosp/bionic/libc/kernel/uapi/linux/oom.h | 26 + .../libc/kernel/uapi/linux/openvswitch.h | 505 ++ .../libc/kernel/uapi/linux/packet_diag.h | 84 + aosp/bionic/libc/kernel/uapi/linux/param.h | 22 + aosp/bionic/libc/kernel/uapi/linux/parport.h | 78 + aosp/bionic/libc/kernel/uapi/linux/patchkey.h | 34 + aosp/bionic/libc/kernel/uapi/linux/pci.h | 30 + aosp/bionic/libc/kernel/uapi/linux/pci_regs.h | 911 +++ aosp/bionic/libc/kernel/uapi/linux/pcitest.h | 30 + .../libc/kernel/uapi/linux/perf_event.h | 443 ++ .../libc/kernel/uapi/linux/personality.h | 60 + aosp/bionic/libc/kernel/uapi/linux/pfkeyv2.h | 306 + aosp/bionic/libc/kernel/uapi/linux/pg.h | 39 + aosp/bionic/libc/kernel/uapi/linux/phantom.h | 46 + aosp/bionic/libc/kernel/uapi/linux/phonet.h | 85 + aosp/bionic/libc/kernel/uapi/linux/pkt_cls.h | 557 ++ .../bionic/libc/kernel/uapi/linux/pkt_sched.h | 900 +++ aosp/bionic/libc/kernel/uapi/linux/pktcdvd.h | 62 + aosp/bionic/libc/kernel/uapi/linux/pmu.h | 110 + aosp/bionic/libc/kernel/uapi/linux/poll.h | 19 + .../bionic/libc/kernel/uapi/linux/posix_acl.h | 33 + .../libc/kernel/uapi/linux/posix_acl_xattr.h | 32 + .../libc/kernel/uapi/linux/posix_types.h | 31 + aosp/bionic/libc/kernel/uapi/linux/ppdev.h | 58 + aosp/bionic/libc/kernel/uapi/linux/ppp-comp.h | 59 + .../bionic/libc/kernel/uapi/linux/ppp-ioctl.h | 111 + aosp/bionic/libc/kernel/uapi/linux/ppp_defs.h | 119 + aosp/bionic/libc/kernel/uapi/linux/pps.h | 91 + aosp/bionic/libc/kernel/uapi/linux/pr.h | 59 + aosp/bionic/libc/kernel/uapi/linux/prctl.h | 158 + aosp/bionic/libc/kernel/uapi/linux/psample.h | 43 + aosp/bionic/libc/kernel/uapi/linux/psci.h | 84 + aosp/bionic/libc/kernel/uapi/linux/psp-sev.h | 101 + .../bionic/libc/kernel/uapi/linux/ptp_clock.h | 115 + aosp/bionic/libc/kernel/uapi/linux/ptrace.h | 107 + .../libc/kernel/uapi/linux/qemu_fw_cfg.h | 86 + aosp/bionic/libc/kernel/uapi/linux/qnx4_fs.h | 85 + aosp/bionic/libc/kernel/uapi/linux/qnxtypes.h | 33 + aosp/bionic/libc/kernel/uapi/linux/qrtr.h | 58 + aosp/bionic/libc/kernel/uapi/linux/quota.h | 134 + aosp/bionic/libc/kernel/uapi/linux/radeonfb.h | 27 + .../bionic/libc/kernel/uapi/linux/raid/md_p.h | 248 + .../bionic/libc/kernel/uapi/linux/raid/md_u.h | 97 + aosp/bionic/libc/kernel/uapi/linux/random.h | 38 + aosp/bionic/libc/kernel/uapi/linux/raw.h | 30 + aosp/bionic/libc/kernel/uapi/linux/rds.h | 283 + aosp/bionic/libc/kernel/uapi/linux/reboot.h | 34 + .../libc/kernel/uapi/linux/reiserfs_fs.h | 28 + .../libc/kernel/uapi/linux/reiserfs_xattr.h | 32 + aosp/bionic/libc/kernel/uapi/linux/resource.h | 62 + aosp/bionic/libc/kernel/uapi/linux/rfkill.h | 53 + .../libc/kernel/uapi/linux/rio_cm_cdev.h | 51 + .../libc/kernel/uapi/linux/rio_mport_cdev.h | 173 + aosp/bionic/libc/kernel/uapi/linux/romfs_fs.h | 60 + aosp/bionic/libc/kernel/uapi/linux/rose.h | 89 + aosp/bionic/libc/kernel/uapi/linux/route.h | 50 + aosp/bionic/libc/kernel/uapi/linux/rpmsg.h | 30 + aosp/bionic/libc/kernel/uapi/linux/rseq.h | 68 + aosp/bionic/libc/kernel/uapi/linux/rtc.h | 73 + .../bionic/libc/kernel/uapi/linux/rtnetlink.h | 566 ++ aosp/bionic/libc/kernel/uapi/linux/rxrpc.h | 92 + aosp/bionic/libc/kernel/uapi/linux/scc.h | 140 + aosp/bionic/libc/kernel/uapi/linux/sched.h | 81 + .../libc/kernel/uapi/linux/sched/types.h | 39 + .../libc/kernel/uapi/linux/scif_ioctl.h | 93 + .../libc/kernel/uapi/linux/screen_info.h | 76 + aosp/bionic/libc/kernel/uapi/linux/sctp.h | 707 ++ aosp/bionic/libc/kernel/uapi/linux/sdla.h | 91 + aosp/bionic/libc/kernel/uapi/linux/seccomp.h | 78 + .../libc/kernel/uapi/linux/securebits.h | 41 + aosp/bionic/libc/kernel/uapi/linux/sed-opal.h | 131 + aosp/bionic/libc/kernel/uapi/linux/seg6.h | 48 + .../bionic/libc/kernel/uapi/linux/seg6_genl.h | 44 + .../bionic/libc/kernel/uapi/linux/seg6_hmac.h | 35 + .../libc/kernel/uapi/linux/seg6_iptunnel.h | 38 + .../libc/kernel/uapi/linux/seg6_local.h | 62 + .../libc/kernel/uapi/linux/selinux_netlink.h | 45 + aosp/bionic/libc/kernel/uapi/linux/sem.h | 78 + aosp/bionic/libc/kernel/uapi/linux/serial.h | 114 + .../libc/kernel/uapi/linux/serial_core.h | 141 + .../libc/kernel/uapi/linux/serial_reg.h | 246 + aosp/bionic/libc/kernel/uapi/linux/serio.h | 80 + aosp/bionic/libc/kernel/uapi/linux/shm.h | 86 + aosp/bionic/libc/kernel/uapi/linux/signal.h | 27 + aosp/bionic/libc/kernel/uapi/linux/signalfd.h | 49 + aosp/bionic/libc/kernel/uapi/linux/smc.h | 38 + aosp/bionic/libc/kernel/uapi/linux/smc_diag.h | 101 + aosp/bionic/libc/kernel/uapi/linux/smiapp.h | 26 + aosp/bionic/libc/kernel/uapi/linux/snmp.h | 303 + .../bionic/libc/kernel/uapi/linux/sock_diag.h | 49 + aosp/bionic/libc/kernel/uapi/linux/socket.h | 32 + aosp/bionic/libc/kernel/uapi/linux/sockios.h | 110 + aosp/bionic/libc/kernel/uapi/linux/sonet.h | 46 + aosp/bionic/libc/kernel/uapi/linux/sonypi.h | 111 + aosp/bionic/libc/kernel/uapi/linux/sound.h | 37 + .../bionic/libc/kernel/uapi/linux/soundcard.h | 677 ++ .../libc/kernel/uapi/linux/spi/spidev.h | 65 + aosp/bionic/libc/kernel/uapi/linux/stat.h | 104 + aosp/bionic/libc/kernel/uapi/linux/stddef.h | 22 + aosp/bionic/libc/kernel/uapi/linux/stm.h | 36 + aosp/bionic/libc/kernel/uapi/linux/string.h | 22 + .../libc/kernel/uapi/linux/sunrpc/debug.h | 44 + .../libc/kernel/uapi/linux/suspend_ioctls.h | 42 + aosp/bionic/libc/kernel/uapi/linux/swab.h | 128 + .../libc/kernel/uapi/linux/switchtec_ioctl.h | 129 + .../bionic/libc/kernel/uapi/linux/sync_file.h | 48 + aosp/bionic/libc/kernel/uapi/linux/synclink.h | 244 + aosp/bionic/libc/kernel/uapi/linux/sysctl.h | 759 +++ aosp/bionic/libc/kernel/uapi/linux/sysinfo.h | 39 + .../libc/kernel/uapi/linux/target_core_user.h | 98 + .../bionic/libc/kernel/uapi/linux/taskstats.h | 101 + .../libc/kernel/uapi/linux/tc_act/tc_bpf.h | 39 + .../kernel/uapi/linux/tc_act/tc_connmark.h | 35 + .../libc/kernel/uapi/linux/tc_act/tc_csum.h | 44 + .../libc/kernel/uapi/linux/tc_act/tc_ct.h | 52 + .../libc/kernel/uapi/linux/tc_act/tc_ctinfo.h | 41 + .../libc/kernel/uapi/linux/tc_act/tc_defact.h | 34 + .../libc/kernel/uapi/linux/tc_act/tc_gact.h | 44 + .../libc/kernel/uapi/linux/tc_act/tc_ife.h | 42 + .../libc/kernel/uapi/linux/tc_act/tc_ipt.h | 34 + .../libc/kernel/uapi/linux/tc_act/tc_mirred.h | 40 + .../libc/kernel/uapi/linux/tc_act/tc_mpls.h | 43 + .../libc/kernel/uapi/linux/tc_act/tc_nat.h | 39 + .../libc/kernel/uapi/linux/tc_act/tc_pedit.h | 71 + .../libc/kernel/uapi/linux/tc_act/tc_sample.h | 38 + .../kernel/uapi/linux/tc_act/tc_skbedit.h | 45 + .../libc/kernel/uapi/linux/tc_act/tc_skbmod.h | 41 + .../kernel/uapi/linux/tc_act/tc_tunnel_key.h | 77 + .../libc/kernel/uapi/linux/tc_act/tc_vlan.h | 40 + .../kernel/uapi/linux/tc_ematch/tc_em_cmp.h | 38 + .../kernel/uapi/linux/tc_ematch/tc_em_ipt.h | 33 + .../kernel/uapi/linux/tc_ematch/tc_em_meta.h | 102 + .../kernel/uapi/linux/tc_ematch/tc_em_nbyte.h | 28 + .../kernel/uapi/linux/tc_ematch/tc_em_text.h | 33 + aosp/bionic/libc/kernel/uapi/linux/tcp.h | 243 + .../libc/kernel/uapi/linux/tcp_metrics.h | 60 + aosp/bionic/libc/kernel/uapi/linux/tee.h | 122 + aosp/bionic/libc/kernel/uapi/linux/termios.h | 34 + aosp/bionic/libc/kernel/uapi/linux/thermal.h | 43 + aosp/bionic/libc/kernel/uapi/linux/time.h | 65 + .../libc/kernel/uapi/linux/time_types.h | 38 + aosp/bionic/libc/kernel/uapi/linux/timerfd.h | 29 + aosp/bionic/libc/kernel/uapi/linux/times.h | 28 + aosp/bionic/libc/kernel/uapi/linux/timex.h | 142 + aosp/bionic/libc/kernel/uapi/linux/tiocl.h | 48 + aosp/bionic/libc/kernel/uapi/linux/tipc.h | 170 + .../libc/kernel/uapi/linux/tipc_config.h | 159 + .../libc/kernel/uapi/linux/tipc_netlink.h | 262 + .../kernel/uapi/linux/tipc_sockets_diag.h | 29 + aosp/bionic/libc/kernel/uapi/linux/tls.h | 91 + aosp/bionic/libc/kernel/uapi/linux/toshiba.h | 35 + aosp/bionic/libc/kernel/uapi/linux/tty.h | 50 + .../bionic/libc/kernel/uapi/linux/tty_flags.h | 86 + aosp/bionic/libc/kernel/uapi/linux/types.h | 39 + aosp/bionic/libc/kernel/uapi/linux/udf_fs_i.h | 25 + aosp/bionic/libc/kernel/uapi/linux/udmabuf.h | 43 + aosp/bionic/libc/kernel/uapi/linux/udp.h | 40 + aosp/bionic/libc/kernel/uapi/linux/uhid.h | 155 + aosp/bionic/libc/kernel/uapi/linux/uinput.h | 79 + aosp/bionic/libc/kernel/uapi/linux/uio.h | 29 + aosp/bionic/libc/kernel/uapi/linux/uleds.h | 26 + .../libc/kernel/uapi/linux/ultrasound.h | 56 + aosp/bionic/libc/kernel/uapi/linux/un.h | 28 + aosp/bionic/libc/kernel/uapi/linux/unistd.h | 22 + .../bionic/libc/kernel/uapi/linux/unix_diag.h | 66 + .../bionic/libc/kernel/uapi/linux/usb/audio.h | 310 + .../libc/kernel/uapi/linux/usb/cdc-wdm.h | 23 + aosp/bionic/libc/kernel/uapi/linux/usb/cdc.h | 311 + aosp/bionic/libc/kernel/uapi/linux/usb/ch11.h | 179 + aosp/bionic/libc/kernel/uapi/linux/usb/ch9.h | 581 ++ .../libc/kernel/uapi/linux/usb/charger.h | 33 + .../libc/kernel/uapi/linux/usb/f_accessory.h | 46 + .../libc/kernel/uapi/linux/usb/functionfs.h | 111 + .../libc/kernel/uapi/linux/usb/g_printer.h | 26 + .../bionic/libc/kernel/uapi/linux/usb/g_uvc.h | 44 + .../libc/kernel/uapi/linux/usb/gadgetfs.h | 41 + aosp/bionic/libc/kernel/uapi/linux/usb/midi.h | 72 + aosp/bionic/libc/kernel/uapi/linux/usb/tmc.h | 101 + .../bionic/libc/kernel/uapi/linux/usb/video.h | 374 + .../libc/kernel/uapi/linux/usbdevice_fs.h | 165 + aosp/bionic/libc/kernel/uapi/linux/usbip.h | 30 + .../libc/kernel/uapi/linux/userfaultfd.h | 118 + aosp/bionic/libc/kernel/uapi/linux/userio.h | 31 + aosp/bionic/libc/kernel/uapi/linux/utime.h | 26 + aosp/bionic/libc/kernel/uapi/linux/utsname.h | 45 + aosp/bionic/libc/kernel/uapi/linux/uuid.h | 31 + aosp/bionic/libc/kernel/uapi/linux/uvcvideo.h | 72 + .../libc/kernel/uapi/linux/v4l2-common.h | 49 + .../libc/kernel/uapi/linux/v4l2-controls.h | 947 +++ .../libc/kernel/uapi/linux/v4l2-dv-timings.h | 255 + .../libc/kernel/uapi/linux/v4l2-mediabus.h | 114 + .../libc/kernel/uapi/linux/v4l2-subdev.h | 105 + aosp/bionic/libc/kernel/uapi/linux/vbox_err.h | 157 + .../kernel/uapi/linux/vbox_vmmdev_types.h | 191 + .../bionic/libc/kernel/uapi/linux/vboxguest.h | 161 + aosp/bionic/libc/kernel/uapi/linux/version.h | 20 + aosp/bionic/libc/kernel/uapi/linux/veth.h | 27 + aosp/bionic/libc/kernel/uapi/linux/vfio.h | 355 + aosp/bionic/libc/kernel/uapi/linux/vfio_ccw.h | 37 + aosp/bionic/libc/kernel/uapi/linux/vhost.h | 56 + .../libc/kernel/uapi/linux/vhost_types.h | 94 + .../bionic/libc/kernel/uapi/linux/videodev2.h | 1420 ++++ .../bionic/libc/kernel/uapi/linux/virtio_9p.h | 29 + .../libc/kernel/uapi/linux/virtio_balloon.h | 57 + .../libc/kernel/uapi/linux/virtio_blk.h | 101 + .../libc/kernel/uapi/linux/virtio_config.h | 39 + .../libc/kernel/uapi/linux/virtio_console.h | 48 + .../libc/kernel/uapi/linux/virtio_crypto.h | 293 + .../bionic/libc/kernel/uapi/linux/virtio_fs.h | 29 + .../libc/kernel/uapi/linux/virtio_gpu.h | 241 + .../libc/kernel/uapi/linux/virtio_ids.h | 38 + .../libc/kernel/uapi/linux/virtio_input.h | 61 + .../libc/kernel/uapi/linux/virtio_iommu.h | 136 + .../libc/kernel/uapi/linux/virtio_mmio.h | 54 + .../libc/kernel/uapi/linux/virtio_net.h | 128 + .../libc/kernel/uapi/linux/virtio_pci.h | 114 + .../libc/kernel/uapi/linux/virtio_pmem.h | 35 + .../libc/kernel/uapi/linux/virtio_ring.h | 78 + .../libc/kernel/uapi/linux/virtio_rng.h | 23 + .../libc/kernel/uapi/linux/virtio_scsi.h | 131 + .../libc/kernel/uapi/linux/virtio_types.h | 25 + .../libc/kernel/uapi/linux/virtio_vsock.h | 62 + .../libc/kernel/uapi/linux/vm_sockets.h | 46 + .../libc/kernel/uapi/linux/vm_sockets_diag.h | 43 + aosp/bionic/libc/kernel/uapi/linux/vmcore.h | 31 + aosp/bionic/libc/kernel/uapi/linux/vsoc_shm.h | 84 + aosp/bionic/libc/kernel/uapi/linux/vsockmon.h | 44 + aosp/bionic/libc/kernel/uapi/linux/vt.h | 82 + .../libc/kernel/uapi/linux/vtpm_proxy.h | 36 + aosp/bionic/libc/kernel/uapi/linux/wait.h | 34 + aosp/bionic/libc/kernel/uapi/linux/watchdog.h | 57 + aosp/bionic/libc/kernel/uapi/linux/wimax.h | 72 + .../libc/kernel/uapi/linux/wimax/i2400m.h | 309 + aosp/bionic/libc/kernel/uapi/linux/wireless.h | 448 ++ aosp/bionic/libc/kernel/uapi/linux/wmi.h | 62 + aosp/bionic/libc/kernel/uapi/linux/x25.h | 97 + aosp/bionic/libc/kernel/uapi/linux/xattr.h | 67 + aosp/bionic/libc/kernel/uapi/linux/xdp_diag.h | 73 + aosp/bionic/libc/kernel/uapi/linux/xfrm.h | 459 ++ .../kernel/uapi/linux/xilinx-v4l2-controls.h | 42 + aosp/bionic/libc/kernel/uapi/linux/zorro.h | 78 + .../bionic/libc/kernel/uapi/linux/zorro_ids.h | 446 ++ aosp/bionic/libc/kernel/uapi/misc/cxl.h | 123 + aosp/bionic/libc/kernel/uapi/misc/fastrpc.h | 63 + .../bionic/libc/kernel/uapi/misc/habanalabs.h | 296 + aosp/bionic/libc/kernel/uapi/misc/ocxl.h | 76 + .../libc/kernel/uapi/misc/xilinx_sdfec.h | 131 + aosp/bionic/libc/kernel/uapi/mtd/inftl-user.h | 83 + aosp/bionic/libc/kernel/uapi/mtd/mtd-abi.h | 153 + aosp/bionic/libc/kernel/uapi/mtd/mtd-user.h | 27 + aosp/bionic/libc/kernel/uapi/mtd/nftl-user.h | 69 + aosp/bionic/libc/kernel/uapi/mtd/ubi-user.h | 108 + .../libc/kernel/uapi/rdma/bnxt_re-abi.h | 77 + aosp/bionic/libc/kernel/uapi/rdma/cxgb4-abi.h | 80 + aosp/bionic/libc/kernel/uapi/rdma/efa-abi.h | 93 + .../libc/kernel/uapi/rdma/hfi/hfi1_ioctl.h | 72 + .../libc/kernel/uapi/rdma/hfi/hfi1_user.h | 121 + aosp/bionic/libc/kernel/uapi/rdma/hns-abi.h | 58 + aosp/bionic/libc/kernel/uapi/rdma/i40iw-abi.h | 75 + .../kernel/uapi/rdma/ib_user_ioctl_cmds.h | 190 + .../kernel/uapi/rdma/ib_user_ioctl_verbs.h | 149 + .../libc/kernel/uapi/rdma/ib_user_mad.h | 93 + .../bionic/libc/kernel/uapi/rdma/ib_user_sa.h | 57 + .../libc/kernel/uapi/rdma/ib_user_verbs.h | 1078 +++ aosp/bionic/libc/kernel/uapi/rdma/mlx4-abi.h | 129 + aosp/bionic/libc/kernel/uapi/rdma/mlx5-abi.h | 372 + .../kernel/uapi/rdma/mlx5_user_ioctl_cmds.h | 181 + .../kernel/uapi/rdma/mlx5_user_ioctl_verbs.h | 53 + aosp/bionic/libc/kernel/uapi/rdma/mthca-abi.h | 69 + .../bionic/libc/kernel/uapi/rdma/ocrdma-abi.h | 108 + aosp/bionic/libc/kernel/uapi/rdma/qedr-abi.h | 96 + .../libc/kernel/uapi/rdma/rdma_netlink.h | 311 + .../libc/kernel/uapi/rdma/rdma_user_cm.h | 261 + .../libc/kernel/uapi/rdma/rdma_user_ioctl.h | 42 + .../kernel/uapi/rdma/rdma_user_ioctl_cmds.h | 55 + .../libc/kernel/uapi/rdma/rdma_user_rxe.h | 146 + aosp/bionic/libc/kernel/uapi/rdma/rvt-abi.h | 47 + aosp/bionic/libc/kernel/uapi/rdma/siw-abi.h | 153 + .../libc/kernel/uapi/rdma/vmw_pvrdma-abi.h | 243 + .../libc/kernel/uapi/scsi/cxlflash_ioctl.h | 186 + aosp/bionic/libc/kernel/uapi/scsi/fc/fc_els.h | 562 ++ aosp/bionic/libc/kernel/uapi/scsi/fc/fc_fs.h | 210 + aosp/bionic/libc/kernel/uapi/scsi/fc/fc_gs.h | 68 + aosp/bionic/libc/kernel/uapi/scsi/fc/fc_ns.h | 121 + .../libc/kernel/uapi/scsi/scsi_bsg_fc.h | 102 + .../libc/kernel/uapi/scsi/scsi_bsg_ufs.h | 62 + .../libc/kernel/uapi/scsi/scsi_netlink.h | 51 + .../libc/kernel/uapi/scsi/scsi_netlink_fc.h | 35 + .../libc/kernel/uapi/sound/asequencer.h | 405 ++ aosp/bionic/libc/kernel/uapi/sound/asoc.h | 391 ++ aosp/bionic/libc/kernel/uapi/sound/asound.h | 840 +++ .../bionic/libc/kernel/uapi/sound/asound_fm.h | 89 + .../libc/kernel/uapi/sound/compress_offload.h | 91 + .../libc/kernel/uapi/sound/compress_params.h | 210 + aosp/bionic/libc/kernel/uapi/sound/emu10k1.h | 315 + aosp/bionic/libc/kernel/uapi/sound/firewire.h | 102 + aosp/bionic/libc/kernel/uapi/sound/hdsp.h | 91 + aosp/bionic/libc/kernel/uapi/sound/hdspm.h | 152 + aosp/bionic/libc/kernel/uapi/sound/sb16_csp.h | 76 + .../bionic/libc/kernel/uapi/sound/sfnt_info.h | 149 + .../kernel/uapi/sound/skl-tplg-interface.h | 183 + .../libc/kernel/uapi/sound/snd_sst_tokens.h | 102 + aosp/bionic/libc/kernel/uapi/sound/sof/abi.h | 37 + aosp/bionic/libc/kernel/uapi/sound/sof/fw.h | 65 + .../libc/kernel/uapi/sound/sof/header.h | 30 + .../libc/kernel/uapi/sound/sof/tokens.h | 76 + aosp/bionic/libc/kernel/uapi/sound/tlv.h | 55 + .../libc/kernel/uapi/sound/usb_stream.h | 63 + aosp/bionic/libc/kernel/uapi/video/edid.h | 24 + aosp/bionic/libc/kernel/uapi/video/sisfb.h | 131 + aosp/bionic/libc/kernel/uapi/video/uvesafb.h | 67 + aosp/bionic/libc/kernel/uapi/xen/evtchn.h | 46 + aosp/bionic/libc/kernel/uapi/xen/gntalloc.h | 44 + aosp/bionic/libc/kernel/uapi/xen/gntdev.h | 104 + aosp/bionic/libc/kernel/uapi/xen/privcmd.h | 77 + aosp/bionic/libc/libc.map.txt | 1763 +++++ aosp/bionic/libc/libstdc++.map.txt | 22 + aosp/bionic/libc/malloc_debug/Android.bp | 187 + aosp/bionic/libc/malloc_debug/Config.cpp | 411 ++ aosp/bionic/libc/malloc_debug/Config.h | 163 + aosp/bionic/libc/malloc_debug/DebugData.cpp | 97 + aosp/bionic/libc/malloc_debug/DebugData.h | 100 + aosp/bionic/libc/malloc_debug/GuardData.cpp | 99 + aosp/bionic/libc/malloc_debug/GuardData.h | 94 + aosp/bionic/libc/malloc_debug/MapData.cpp | 213 + aosp/bionic/libc/malloc_debug/MapData.h | 75 + aosp/bionic/libc/malloc_debug/OptionData.h | 43 + aosp/bionic/libc/malloc_debug/PointerData.cpp | 638 ++ aosp/bionic/libc/malloc_debug/PointerData.h | 191 + aosp/bionic/libc/malloc_debug/README.md | 715 ++ aosp/bionic/libc/malloc_debug/README_api.md | 58 + .../README_marshmallow_and_earlier.md | 128 + aosp/bionic/libc/malloc_debug/RecordData.cpp | 223 + aosp/bionic/libc/malloc_debug/RecordData.h | 174 + .../libc/malloc_debug/UnwindBacktrace.cpp | 119 + .../libc/malloc_debug/UnwindBacktrace.h | 41 + aosp/bionic/libc/malloc_debug/backtrace.cpp | 189 + aosp/bionic/libc/malloc_debug/backtrace.h | 40 + .../libc/malloc_debug/debug_disable.cpp | 65 + aosp/bionic/libc/malloc_debug/debug_disable.h | 61 + aosp/bionic/libc/malloc_debug/debug_log.h | 42 + aosp/bionic/libc/malloc_debug/exported32.map | 29 + aosp/bionic/libc/malloc_debug/exported64.map | 27 + .../bionic/libc/malloc_debug/malloc_debug.cpp | 1015 +++ aosp/bionic/libc/malloc_debug/malloc_debug.h | 66 + .../malloc_debug/tests/backtrace_fake.cpp | 89 + .../libc/malloc_debug/tests/backtrace_fake.h | 32 + .../libc/malloc_debug/tests/libc_fake.cpp | 19 + .../libc/malloc_debug/tests/log_fake.cpp | 113 + .../bionic/libc/malloc_debug/tests/log_fake.h | 26 + .../tests/malloc_debug_config_tests.cpp | 763 +++ .../tests/malloc_debug_system_tests.cpp | 574 ++ .../tests/malloc_debug_unit_tests.cpp | 2691 ++++++++ .../libc/malloc_debug/tools/gen_malloc.pl | 334 + aosp/bionic/libc/malloc_hooks/Android.bp | 75 + aosp/bionic/libc/malloc_hooks/README.md | 118 + aosp/bionic/libc/malloc_hooks/exported32.map | 28 + aosp/bionic/libc/malloc_hooks/exported64.map | 26 + .../bionic/libc/malloc_hooks/malloc_hooks.cpp | 245 + .../malloc_hooks/tests/malloc_hooks_tests.cpp | 409 ++ .../android_unsafe_frame_pointer_chase.h | 47 + aosp/bionic/libc/platform/bionic/fdtrack.h | 73 + aosp/bionic/libc/platform/bionic/macros.h | 93 + aosp/bionic/libc/platform/bionic/malloc.h | 125 + aosp/bionic/libc/platform/bionic/mte.h | 67 + aosp/bionic/libc/platform/bionic/mte_kernel.h | 54 + aosp/bionic/libc/platform/bionic/page.h | 30 + .../libc/platform/bionic/reserved_signals.h | 87 + aosp/bionic/libc/platform/bionic/tls.h | 43 + .../bionic/libc/platform/bionic/tls_defines.h | 119 + aosp/bionic/libc/private/CFIShadow.h | 91 + aosp/bionic/libc/private/CachedProperty.h | 107 + aosp/bionic/libc/private/ErrnoRestorer.h | 40 + aosp/bionic/libc/private/FdPath.h | 31 + .../bionic/libc/private/KernelArgumentBlock.h | 67 + aosp/bionic/libc/private/MallocXmlElem.h | 57 + aosp/bionic/libc/private/NetdClientDispatch.h | 37 + aosp/bionic/libc/private/ScopedFd.h | 64 + .../libc/private/ScopedPthreadMutexLocker.h | 37 + aosp/bionic/libc/private/ScopedRWLock.h | 51 + aosp/bionic/libc/private/ScopedReaddir.h | 50 + .../bionic/libc/private/ScopedSignalBlocker.h | 56 + .../bionic/libc/private/ScopedSignalHandler.h | 47 + aosp/bionic/libc/private/SigSetConverter.h | 35 + aosp/bionic/libc/private/WriteProtected.h | 93 + .../libc/private/__bionic_get_shell_path.h | 31 + aosp/bionic/libc/private/bionic_allocator.h | 123 + aosp/bionic/libc/private/bionic_arc4random.h | 41 + aosp/bionic/libc/private/bionic_asm.h | 86 + aosp/bionic/libc/private/bionic_asm_arm.h | 48 + aosp/bionic/libc/private/bionic_asm_arm64.h | 43 + aosp/bionic/libc/private/bionic_asm_x86.h | 51 + aosp/bionic/libc/private/bionic_asm_x86_64.h | 42 + aosp/bionic/libc/private/bionic_auxv.h | 33 + .../libc/private/bionic_call_ifunc_resolver.h | 34 + aosp/bionic/libc/private/bionic_config.h | 26 + aosp/bionic/libc/private/bionic_constants.h | 31 + aosp/bionic/libc/private/bionic_defs.h | 39 + aosp/bionic/libc/private/bionic_elf_tls.h | 177 + aosp/bionic/libc/private/bionic_fdsan.h | 63 + aosp/bionic/libc/private/bionic_fdtrack.h | 95 + aosp/bionic/libc/private/bionic_fortify.h | 81 + aosp/bionic/libc/private/bionic_futex.h | 80 + aosp/bionic/libc/private/bionic_globals.h | 123 + aosp/bionic/libc/private/bionic_ieee.h | 118 + aosp/bionic/libc/private/bionic_ifuncs.h | 55 + .../bionic/libc/private/bionic_inline_raise.h | 67 + aosp/bionic/libc/private/bionic_lock.h | 99 + .../libc/private/bionic_malloc_dispatch.h | 81 + aosp/bionic/libc/private/bionic_mbstate.h | 75 + aosp/bionic/libc/private/bionic_sigdefs.h | 75 + aosp/bionic/libc/private/bionic_ssp.h | 43 + .../bionic/libc/private/bionic_string_utils.h | 31 + aosp/bionic/libc/private/bionic_systrace.h | 37 + .../libc/private/bionic_time_conversions.h | 77 + aosp/bionic/libc/private/bionic_tls.h | 144 + aosp/bionic/libc/private/bionic_vdso.h | 63 + .../libc/private/get_cpu_count_from_string.h | 53 + aosp/bionic/libc/private/grp_pwd.h | 50 + aosp/bionic/libc/private/icu.h | 87 + .../libc/private/linker_native_bridge.h | 31 + aosp/bionic/libc/private/thread_private.h | 36 + aosp/bionic/libc/seccomp/gen_syscall_nrs.cpp | 1 + .../libc/seccomp/gen_syscall_nrs_x86.cpp | 1 + .../libc/seccomp/gen_syscall_nrs_x86_64.cpp | 1 + .../libc/seccomp/include/seccomp_policy.h | 29 + aosp/bionic/libc/seccomp/seccomp_bpfs.h | 48 + aosp/bionic/libc/seccomp/seccomp_policy.cpp | 287 + aosp/bionic/libc/stdio/fmemopen.cpp | 158 + aosp/bionic/libc/stdio/glue.h | 52 + aosp/bionic/libc/stdio/local.h | 309 + aosp/bionic/libc/stdio/parsefloat.c | 335 + aosp/bionic/libc/stdio/printf_common.h | 814 +++ aosp/bionic/libc/stdio/refill.c | 124 + aosp/bionic/libc/stdio/stdio.cpp | 1256 ++++ aosp/bionic/libc/stdio/stdio_ext.cpp | 92 + aosp/bionic/libc/stdio/vfprintf.cpp | 689 ++ aosp/bionic/libc/stdio/vfscanf.cpp | 820 +++ aosp/bionic/libc/stdio/vfwprintf.cpp | 675 ++ aosp/bionic/libc/stdio/vfwscanf.c | 638 ++ aosp/bionic/libc/stdlib/exit.c | 42 + aosp/bionic/libc/system_properties/Android.bp | 31 + .../libc/system_properties/context_node.cpp | 98 + .../system_properties/contexts_serialized.cpp | 172 + .../libc/system_properties/contexts_split.cpp | 363 + .../include/system_properties/context_node.h | 67 + .../include/system_properties/contexts.h | 45 + .../system_properties/contexts_pre_split.h | 69 + .../system_properties/contexts_serialized.h | 61 + .../system_properties/contexts_split.h | 59 + .../include/system_properties/prop_area.h | 179 + .../system_properties/system_properties.h | 90 + .../libc/system_properties/prop_info.cpp | 55 + .../system_properties/system_properties.cpp | 375 + aosp/bionic/libc/tools/Android.bp | 4 + aosp/bionic/libc/tools/check-symbols-glibc.py | 263 + aosp/bionic/libc/tools/check-symbols.py | 87 + aosp/bionic/libc/tools/generate-NOTICE.py | 182 + aosp/bionic/libc/tools/genfunctosyscallnrs.py | 60 + aosp/bionic/libc/tools/genseccomp.py | 307 + aosp/bionic/libc/tools/genserv.py | 74 + aosp/bionic/libc/tools/gensyscalls.py | 470 ++ aosp/bionic/libc/tools/ndk_missing_symbols.py | 48 + aosp/bionic/libc/tools/posix-2013.txt | 1191 ++++ aosp/bionic/libc/tools/pylintrc | 280 + aosp/bionic/libc/tools/symbols.py | 90 + aosp/bionic/libc/tools/test_genseccomp.py | 221 + aosp/bionic/libc/tzcode/asctime.c | 128 + aosp/bionic/libc/tzcode/bionic.cpp | 257 + aosp/bionic/libc/tzcode/difftime.c | 58 + aosp/bionic/libc/tzcode/localtime.c | 2303 +++++++ aosp/bionic/libc/tzcode/private.h | 585 ++ aosp/bionic/libc/tzcode/strftime.c | 712 ++ aosp/bionic/libc/tzcode/strptime.c | 497 ++ aosp/bionic/libc/tzcode/tzfile.h | 169 + .../libc/upstream-freebsd/.clang-format | 3 + aosp/bionic/libc/upstream-freebsd/README.md | 5 + .../android/include/collate.h | 0 .../android/include/freebsd-compat.h | 26 + .../android/include/machine/atomic.h | 0 .../android/include/machine/endian.h | 1 + .../android/include/namespace.h | 0 .../android/include/un-namespace.h | 0 .../libc/upstream-freebsd/lib/libc/gen/glob.c | 1125 +++ .../upstream-freebsd/lib/libc/gen/ldexp.c | 123 + .../lib/libc/stdlib/getopt_long.c | 614 ++ .../lib/libc/stdlib/hcreate.c | 75 + .../lib/libc/stdlib/hcreate_r.c | 63 + .../lib/libc/stdlib/hdestroy_r.c | 43 + .../lib/libc/stdlib/hsearch.h | 40 + .../lib/libc/stdlib/hsearch_r.c | 150 + .../upstream-freebsd/lib/libc/stdlib/qsort.c | 200 + .../lib/libc/stdlib/quick_exit.c | 87 + .../upstream-freebsd/lib/libc/string/wcpcpy.c | 48 + .../lib/libc/string/wcpncpy.c | 47 + .../lib/libc/string/wcscasecmp.c | 47 + .../upstream-freebsd/lib/libc/string/wcscat.c | 53 + .../upstream-freebsd/lib/libc/string/wcschr.c | 43 + .../upstream-freebsd/lib/libc/string/wcscmp.c | 58 + .../upstream-freebsd/lib/libc/string/wcscpy.c | 51 + .../lib/libc/string/wcscspn.c | 60 + .../upstream-freebsd/lib/libc/string/wcsdup.c | 45 + .../lib/libc/string/wcslcat.c | 76 + .../upstream-freebsd/lib/libc/string/wcslen.c | 51 + .../lib/libc/string/wcsncasecmp.c | 51 + .../lib/libc/string/wcsncat.c | 59 + .../lib/libc/string/wcsncmp.c | 59 + .../lib/libc/string/wcsncpy.c | 66 + .../lib/libc/string/wcsnlen.c | 44 + .../lib/libc/string/wcspbrk.c | 60 + .../lib/libc/string/wcsrchr.c | 49 + .../upstream-freebsd/lib/libc/string/wcsspn.c | 62 + .../upstream-freebsd/lib/libc/string/wcsstr.c | 65 + .../upstream-freebsd/lib/libc/string/wcstok.c | 88 + .../lib/libc/string/wmemchr.c | 54 + .../lib/libc/string/wmemcmp.c | 55 + .../lib/libc/string/wmemcpy.c | 46 + .../lib/libc/string/wmemmove.c | 46 + .../lib/libc/string/wmemset.c | 53 + .../bionic/libc/upstream-netbsd/.clang-format | 3 + aosp/bionic/libc/upstream-netbsd/README.md | 5 + .../upstream-netbsd/android/include/env.h | 0 .../upstream-netbsd/android/include/extern.h | 25 + .../android/include/fd_setsize.h | 1 + .../android/include/namespace.h | 20 + .../android/include/netbsd-compat.h | 48 + .../android/include/port_after.h | 0 .../android/include/port_before.h | 25 + .../upstream-netbsd/android/include/rand48.h | 34 + .../android/include/reentrant.h | 31 + .../android/include/resolv_mt.h | 4 + .../android/include/sys/sha1.h | 31 + .../common/lib/libc/hash/sha1/sha1.c | 289 + .../common/lib/libc/stdlib/random.c | 530 ++ .../libc/upstream-netbsd/lib/libc/gen/nice.c | 70 + .../upstream-netbsd/lib/libc/gen/psignal.c | 85 + .../libc/upstream-netbsd/lib/libc/gen/utime.c | 65 + .../libc/upstream-netbsd/lib/libc/gen/utmp.c | 106 + .../lib/libc/include/isc/assertions.h | 132 + .../lib/libc/include/isc/dst.h | 170 + .../lib/libc/include/isc/eventlib.h | 206 + .../lib/libc/include/isc/heap.h | 51 + .../lib/libc/include/isc/list.h | 120 + .../lib/libc/include/isc/memcluster.h | 52 + .../upstream-netbsd/lib/libc/inet/nsap_addr.c | 130 + .../upstream-netbsd/lib/libc/isc/ev_streams.c | 319 + .../upstream-netbsd/lib/libc/isc/ev_timers.c | 519 ++ .../upstream-netbsd/lib/libc/isc/eventlib_p.h | 283 + .../upstream-netbsd/lib/libc/regex/cclass.h | 104 + .../upstream-netbsd/lib/libc/regex/cname.h | 175 + .../upstream-netbsd/lib/libc/regex/engine.c | 1188 ++++ .../upstream-netbsd/lib/libc/regex/regcomp.c | 1929 ++++++ .../upstream-netbsd/lib/libc/regex/regerror.c | 223 + .../upstream-netbsd/lib/libc/regex/regex2.h | 209 + .../upstream-netbsd/lib/libc/regex/regexec.c | 234 + .../upstream-netbsd/lib/libc/regex/regfree.c | 129 + .../upstream-netbsd/lib/libc/regex/utils.h | 91 + .../upstream-netbsd/lib/libc/stdlib/_rand48.c | 57 + .../upstream-netbsd/lib/libc/stdlib/bsearch.c | 85 + .../upstream-netbsd/lib/libc/stdlib/drand48.c | 32 + .../upstream-netbsd/lib/libc/stdlib/erand48.c | 42 + .../upstream-netbsd/lib/libc/stdlib/jrand48.c | 39 + .../upstream-netbsd/lib/libc/stdlib/lcong48.c | 43 + .../upstream-netbsd/lib/libc/stdlib/lrand48.c | 33 + .../upstream-netbsd/lib/libc/stdlib/mrand48.c | 33 + .../upstream-netbsd/lib/libc/stdlib/nrand48.c | 38 + .../upstream-netbsd/lib/libc/stdlib/rand_r.c | 51 + .../lib/libc/stdlib/reallocarr.c | 95 + .../upstream-netbsd/lib/libc/stdlib/seed48.c | 49 + .../upstream-netbsd/lib/libc/stdlib/srand48.c | 38 + .../libc/upstream-openbsd/.clang-format | 3 + aosp/bionic/libc/upstream-openbsd/README.md | 5 + .../android/gdtoa_support.cpp | 19 + .../android/include/arc4random.h | 87 + .../upstream-openbsd/android/include/arith.h | 26 + .../android/include/gd_qnan.h | 33 + .../android/include/machine/ieee.h | 1 + .../android/include/openbsd-compat.h | 72 + .../lib/libc/crypt/arc4random.c | 198 + .../lib/libc/crypt/arc4random_uniform.c | 57 + .../lib/libc/crypt/chacha_private.h | 222 + .../upstream-openbsd/lib/libc/gdtoa/dmisc.c | 225 + .../upstream-openbsd/lib/libc/gdtoa/dtoa.c | 840 +++ .../upstream-openbsd/lib/libc/gdtoa/gdtoa.c | 830 +++ .../upstream-openbsd/lib/libc/gdtoa/gdtoa.h | 155 + .../lib/libc/gdtoa/gdtoa_fltrnds.h | 18 + .../lib/libc/gdtoa/gdtoaimp.h | 665 ++ .../upstream-openbsd/lib/libc/gdtoa/gethex.c | 360 + .../upstream-openbsd/lib/libc/gdtoa/gmisc.c | 86 + .../upstream-openbsd/lib/libc/gdtoa/hd_init.c | 55 + .../upstream-openbsd/lib/libc/gdtoa/hdtoa.c | 335 + .../upstream-openbsd/lib/libc/gdtoa/hexnan.c | 150 + .../upstream-openbsd/lib/libc/gdtoa/ldtoa.c | 124 + .../upstream-openbsd/lib/libc/gdtoa/misc.c | 907 +++ .../upstream-openbsd/lib/libc/gdtoa/smisc.c | 201 + .../upstream-openbsd/lib/libc/gdtoa/strtod.c | 1105 +++ .../upstream-openbsd/lib/libc/gdtoa/strtodg.c | 1154 ++++ .../upstream-openbsd/lib/libc/gdtoa/strtof.c | 82 + .../upstream-openbsd/lib/libc/gdtoa/strtorQ.c | 120 + .../upstream-openbsd/lib/libc/gdtoa/strtord.c | 96 + .../upstream-openbsd/lib/libc/gdtoa/sum.c | 102 + .../upstream-openbsd/lib/libc/gdtoa/ulp.c | 70 + .../upstream-openbsd/lib/libc/gen/alarm.c | 48 + .../upstream-openbsd/lib/libc/gen/charclass.h | 29 + .../upstream-openbsd/lib/libc/gen/ctype_.c | 79 + .../upstream-openbsd/lib/libc/gen/daemon.c | 64 + .../libc/upstream-openbsd/lib/libc/gen/err.c | 43 + .../libc/upstream-openbsd/lib/libc/gen/errx.c | 43 + .../upstream-openbsd/lib/libc/gen/fnmatch.c | 484 ++ .../libc/upstream-openbsd/lib/libc/gen/ftok.c | 42 + .../lib/libc/gen/getprogname.c | 24 + .../lib/libc/gen/setprogname.c | 31 + .../libc/upstream-openbsd/lib/libc/gen/verr.c | 52 + .../upstream-openbsd/lib/libc/gen/verrx.c | 45 + .../upstream-openbsd/lib/libc/gen/vwarn.c | 51 + .../upstream-openbsd/lib/libc/gen/vwarnx.c | 44 + .../libc/upstream-openbsd/lib/libc/gen/warn.c | 43 + .../upstream-openbsd/lib/libc/gen/warnx.c | 43 + .../lib/libc/include/ctype_private.h | 9 + .../lib/libc/locale/_wcstol.h | 136 + .../lib/libc/locale/_wcstoul.h | 116 + .../upstream-openbsd/lib/libc/locale/btowc.c | 53 + .../upstream-openbsd/lib/libc/locale/mbrlen.c | 40 + .../lib/libc/locale/mbstowcs.c | 44 + .../upstream-openbsd/lib/libc/locale/mbtowc.c | 50 + .../lib/libc/locale/wcscoll.c | 41 + .../lib/libc/locale/wcstoimax.c | 19 + .../upstream-openbsd/lib/libc/locale/wcstol.c | 18 + .../lib/libc/locale/wcstoll.c | 18 + .../lib/libc/locale/wcstombs.c | 43 + .../lib/libc/locale/wcstoul.c | 17 + .../lib/libc/locale/wcstoull.c | 17 + .../lib/libc/locale/wcstoumax.c | 18 + .../lib/libc/locale/wcsxfrm.c | 42 + .../upstream-openbsd/lib/libc/locale/wctob.c | 44 + .../lib/libc/locale/wctoint.h | 79 + .../upstream-openbsd/lib/libc/locale/wctomb.c | 47 + .../upstream-openbsd/lib/libc/net/base64.c | 315 + .../upstream-openbsd/lib/libc/net/htonl.c | 21 + .../upstream-openbsd/lib/libc/net/htons.c | 21 + .../lib/libc/net/inet_lnaof.c | 50 + .../lib/libc/net/inet_makeaddr.c | 53 + .../lib/libc/net/inet_netof.c | 49 + .../upstream-openbsd/lib/libc/net/inet_ntoa.c | 51 + .../upstream-openbsd/lib/libc/net/inet_ntop.c | 205 + .../upstream-openbsd/lib/libc/net/inet_pton.c | 213 + .../upstream-openbsd/lib/libc/net/ntohl.c | 21 + .../upstream-openbsd/lib/libc/net/ntohs.c | 21 + .../lib/libc/net/res_random.c | 281 + .../upstream-openbsd/lib/libc/stdio/fgetln.c | 144 + .../upstream-openbsd/lib/libc/stdio/fgetwc.c | 91 + .../upstream-openbsd/lib/libc/stdio/fgetws.c | 80 + .../upstream-openbsd/lib/libc/stdio/flags.c | 105 + .../upstream-openbsd/lib/libc/stdio/fpurge.c | 62 + .../upstream-openbsd/lib/libc/stdio/fputwc.c | 88 + .../upstream-openbsd/lib/libc/stdio/fputws.c | 58 + .../upstream-openbsd/lib/libc/stdio/fvwrite.c | 204 + .../upstream-openbsd/lib/libc/stdio/fvwrite.h | 35 + .../upstream-openbsd/lib/libc/stdio/fwide.c | 65 + .../lib/libc/stdio/getdelim.c | 135 + .../upstream-openbsd/lib/libc/stdio/gets.c | 59 + .../upstream-openbsd/lib/libc/stdio/makebuf.c | 106 + .../upstream-openbsd/lib/libc/stdio/mktemp.c | 163 + .../lib/libc/stdio/open_memstream.c | 159 + .../lib/libc/stdio/open_wmemstream.c | 169 + .../upstream-openbsd/lib/libc/stdio/rget.c | 52 + .../upstream-openbsd/lib/libc/stdio/setvbuf.c | 160 + .../upstream-openbsd/lib/libc/stdio/tempnam.c | 100 + .../upstream-openbsd/lib/libc/stdio/tmpnam.c | 53 + .../upstream-openbsd/lib/libc/stdio/ungetc.c | 146 + .../upstream-openbsd/lib/libc/stdio/ungetwc.c | 78 + .../lib/libc/stdio/vasprintf.c | 57 + .../lib/libc/stdio/vdprintf.c | 74 + .../upstream-openbsd/lib/libc/stdio/vsscanf.c | 59 + .../lib/libc/stdio/vswprintf.c | 97 + .../lib/libc/stdio/vswscanf.c | 89 + .../upstream-openbsd/lib/libc/stdio/wbuf.c | 85 + .../upstream-openbsd/lib/libc/stdio/wsetup.c | 86 + .../upstream-openbsd/lib/libc/stdlib/abs.c | 38 + .../upstream-openbsd/lib/libc/stdlib/div.c | 72 + .../upstream-openbsd/lib/libc/stdlib/getenv.c | 80 + .../lib/libc/stdlib/getsubopt.c | 92 + .../lib/libc/stdlib/imaxabs.c | 38 + .../lib/libc/stdlib/imaxdiv.c | 50 + .../upstream-openbsd/lib/libc/stdlib/insque.c | 54 + .../upstream-openbsd/lib/libc/stdlib/labs.c | 37 + .../upstream-openbsd/lib/libc/stdlib/ldiv.c | 50 + .../upstream-openbsd/lib/libc/stdlib/llabs.c | 40 + .../upstream-openbsd/lib/libc/stdlib/lldiv.c | 52 + .../lib/libc/stdlib/lsearch.c | 84 + .../upstream-openbsd/lib/libc/stdlib/remque.c | 48 + .../upstream-openbsd/lib/libc/stdlib/setenv.c | 181 + .../upstream-openbsd/lib/libc/stdlib/tfind.c | 40 + .../lib/libc/stdlib/tsearch.c | 118 + .../lib/libc/string/memccpy.c | 49 + .../upstream-openbsd/lib/libc/string/memchr.c | 49 + .../lib/libc/string/memrchr.c | 39 + .../upstream-openbsd/lib/libc/string/stpcpy.c | 44 + .../lib/libc/string/stpncpy.c | 57 + .../lib/libc/string/strcasecmp.c | 107 + .../lib/libc/string/strcasestr.c | 61 + .../upstream-openbsd/lib/libc/string/strcat.c | 47 + .../upstream-openbsd/lib/libc/string/strcmp.c | 48 + .../lib/libc/string/strcoll.c | 45 + .../upstream-openbsd/lib/libc/string/strcpy.c | 46 + .../lib/libc/string/strcspn.c | 59 + .../upstream-openbsd/lib/libc/string/strdup.c | 50 + .../lib/libc/string/strlcat.c | 56 + .../lib/libc/string/strlcpy.c | 51 + .../upstream-openbsd/lib/libc/string/strlen.c | 44 + .../lib/libc/string/strncat.c | 58 + .../lib/libc/string/strncmp.c | 48 + .../lib/libc/string/strncpy.c | 59 + .../lib/libc/string/strndup.c | 40 + .../lib/libc/string/strpbrk.c | 49 + .../upstream-openbsd/lib/libc/string/strsep.c | 71 + .../upstream-openbsd/lib/libc/string/strspn.c | 52 + .../upstream-openbsd/lib/libc/string/strstr.c | 197 + .../upstream-openbsd/lib/libc/string/strtok.c | 87 + .../lib/libc/string/strxfrm.c | 52 + .../lib/libc/string/wcslcpy.c | 51 + .../lib/libc/string/wcswidth.c | 51 + .../upstream-openbsd/lib/libc/time/wcsftime.c | 550 ++ aosp/bionic/libc/version_script.txt | 12 + .../arm/kernel_uapi_asm-arm | 1 + .../arm64/kernel_uapi_asm-arm64 | 1 + .../common/clang-builtins | 1 + .../common/kernel_android_uapi | 1 + .../versioner-dependencies/common/kernel_uapi | 1 + .../x86/kernel_uapi_asm-x86 | 1 + .../x86_64/kernel_uapi_asm-x86 | 1 + 2156 files changed, 305004 insertions(+) create mode 100644 aosp/bionic/libc/Android.bp create mode 100644 aosp/bionic/libc/MODULE_LICENSE_BSD create mode 100644 aosp/bionic/libc/NOTICE create mode 100644 aosp/bionic/libc/SECCOMP_BLACKLIST_APP.TXT create mode 100644 aosp/bionic/libc/SECCOMP_BLACKLIST_COMMON.TXT create mode 100644 aosp/bionic/libc/SECCOMP_PRIORITY.TXT create mode 100644 aosp/bionic/libc/SECCOMP_WHITELIST_APP.TXT create mode 100644 aosp/bionic/libc/SECCOMP_WHITELIST_COMMON.TXT create mode 100644 aosp/bionic/libc/SECCOMP_WHITELIST_SYSTEM.TXT create mode 100644 aosp/bionic/libc/SYSCALLS.TXT create mode 100644 aosp/bionic/libc/arch-arm/bionic/__aeabi.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/__aeabi_read_tp.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/__bionic_clone.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/__restore.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/_exit_with_stack_teardown.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/atexit_legacy.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/atomics_arm.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/bpabi.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/exidx_dynamic.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/exidx_static.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/kuser_helper_on.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/libcrt_compat.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/popcount_tab.c create mode 100644 aosp/bionic/libc/arch-arm/bionic/setjmp.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/syscall.S create mode 100644 aosp/bionic/libc/arch-arm/bionic/vfork.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/memmove.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/stpcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcat.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/string_copy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a15/bionic/strlen.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a7/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/stpcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcat.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcpy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/string_copy.S create mode 100644 aosp/bionic/libc/arch-arm/cortex-a9/bionic/strlen.S create mode 100644 aosp/bionic/libc/arch-arm/dynamic_function_dispatch.cpp create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/__memcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/memcmp.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/memmove.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/stpcpy.c create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/strcat.c create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/strcmp.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/strcpy.S create mode 100644 aosp/bionic/libc/arch-arm/generic/bionic/strlen.c create mode 100644 aosp/bionic/libc/arch-arm/krait/bionic/__strcat_chk.S create mode 100644 aosp/bionic/libc/arch-arm/krait/bionic/__strcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm/krait/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/krait/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm/krait/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm/kryo/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm/static_function_dispatch.S create mode 100644 aosp/bionic/libc/arch-arm64/bionic/__bionic_clone.S create mode 100644 aosp/bionic/libc/arch-arm64/bionic/__set_tls.c create mode 100644 aosp/bionic/libc/arch-arm64/bionic/_exit_with_stack_teardown.S create mode 100644 aosp/bionic/libc/arch-arm64/bionic/setjmp.S create mode 100644 aosp/bionic/libc/arch-arm64/bionic/syscall.S create mode 100644 aosp/bionic/libc/arch-arm64/bionic/vfork.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/memchr.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/strchr.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/strcmp.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/strlen.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/strncmp.S create mode 100644 aosp/bionic/libc/arch-arm64/default/bionic/strnlen.S create mode 100644 aosp/bionic/libc/arch-arm64/dynamic_function_dispatch.cpp create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/__memcpy_chk.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/memcmp.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/memcpy.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/memcpy_base.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/memmove.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/memset.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/stpcpy.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/strcpy.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/string_copy.S create mode 100644 aosp/bionic/libc/arch-arm64/generic/bionic/wmemmove.S create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/memchr.c create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/strchr.cpp create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/strcmp.c create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/strlen.c create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/strncmp.c create mode 100644 aosp/bionic/libc/arch-arm64/mte/bionic/strnlen.c create mode 100644 aosp/bionic/libc/arch-arm64/static_function_dispatch.S create mode 100644 aosp/bionic/libc/arch-common/bionic/__dso_handle.h create mode 100644 aosp/bionic/libc/arch-common/bionic/__dso_handle_so.h create mode 100644 aosp/bionic/libc/arch-common/bionic/asm_multiarch.h create mode 100644 aosp/bionic/libc/arch-common/bionic/atexit.h create mode 100644 aosp/bionic/libc/arch-common/bionic/crtbegin.c create mode 100644 aosp/bionic/libc/arch-common/bionic/crtbegin_so.c create mode 100644 aosp/bionic/libc/arch-common/bionic/crtbrand.S create mode 100644 aosp/bionic/libc/arch-common/bionic/crtend.S create mode 100644 aosp/bionic/libc/arch-common/bionic/crtend_so.S create mode 100644 aosp/bionic/libc/arch-common/bionic/pthread_atfork.h create mode 100644 aosp/bionic/libc/arch-x86/atom/string/cache.h create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-memchr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-memrchr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-memset-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-strchr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-strlen-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-strnlen-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-strrchr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-wcschr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-wcscmp-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-wcslen-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-memcmp-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-memcpy-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-memmove-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strcat-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strcmp-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strcpy-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcat-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strncat-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strncmp-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-strncpy-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscat-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S create mode 100644 aosp/bionic/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/__bionic_clone.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/__libc_init_sysinfo.cpp create mode 100644 aosp/bionic/libc/arch-x86/bionic/__restore.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/__set_tls.cpp create mode 100644 aosp/bionic/libc/arch-x86/bionic/__stack_chk_fail_local.h create mode 100644 aosp/bionic/libc/arch-x86/bionic/_exit_with_stack_teardown.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/atexit.h create mode 100644 aosp/bionic/libc/arch-x86/bionic/libcrt_compat.c create mode 100644 aosp/bionic/libc/arch-x86/bionic/setjmp.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/syscall.S create mode 100644 aosp/bionic/libc/arch-x86/bionic/vfork.S create mode 100644 aosp/bionic/libc/arch-x86/dynamic_function_dispatch.cpp create mode 100644 aosp/bionic/libc/arch-x86/generic/string/memcmp.S create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strcat.S create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strcmp.S create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strlcat.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strlcpy.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strncat.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/strncmp.S create mode 100644 aosp/bionic/libc/arch-x86/generic/string/wcscat.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/wcscpy.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/wmemcmp.c create mode 100644 aosp/bionic/libc/arch-x86/generic/string/wmemset.c create mode 100644 aosp/bionic/libc/arch-x86/kabylake/string/avx2-wmemset-kbl.S create mode 100644 aosp/bionic/libc/arch-x86/silvermont/string/cache.h create mode 100644 aosp/bionic/libc/arch-x86/silvermont/string/sse2-memmove-slm.S create mode 100644 aosp/bionic/libc/arch-x86/silvermont/string/sse2-memset-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpcpy-slm.S create mode 100644 aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpncpy-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse2-strlen-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S create mode 100755 aosp/bionic/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S create mode 100644 aosp/bionic/libc/arch-x86/static_function_dispatch.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/__bionic_clone.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/__restore_rt.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/__set_tls.c create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/_exit_with_stack_teardown.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/setjmp.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/syscall.S create mode 100644 aosp/bionic/libc/arch-x86_64/bionic/vfork.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/avx2-wmemset-kbl.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/cache.h create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-memmove-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-memset-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-stpcpy-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-stpncpy-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-strcat-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-strcpy-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-strlen-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-strncat-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse2-strncpy-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/sse4-memcmp-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/ssse3-strcmp-slm.S create mode 100644 aosp/bionic/libc/arch-x86_64/string/ssse3-strncmp-slm.S create mode 100644 aosp/bionic/libc/async_safe/Android.bp create mode 100644 aosp/bionic/libc/async_safe/README.md create mode 100644 aosp/bionic/libc/async_safe/async_safe_log.cpp create mode 100644 aosp/bionic/libc/async_safe/include/async_safe/CHECK.h create mode 100644 aosp/bionic/libc/async_safe/include/async_safe/log.h create mode 100644 aosp/bionic/libc/bionic/NetdClient.cpp create mode 100644 aosp/bionic/libc/bionic/NetdClientDispatch.cpp create mode 100644 aosp/bionic/libc/bionic/__bionic_get_shell_path.cpp create mode 100644 aosp/bionic/libc/bionic/__cmsg_nxthdr.cpp create mode 100644 aosp/bionic/libc/bionic/__cxa_guard.cpp create mode 100644 aosp/bionic/libc/bionic/__cxa_pure_virtual.cpp create mode 100644 aosp/bionic/libc/bionic/__cxa_thread_atexit_impl.cpp create mode 100644 aosp/bionic/libc/bionic/__errno.cpp create mode 100644 aosp/bionic/libc/bionic/__gnu_basename.cpp create mode 100644 aosp/bionic/libc/bionic/__libc_current_sigrtmax.cpp create mode 100644 aosp/bionic/libc/bionic/__libc_current_sigrtmin.cpp create mode 100644 aosp/bionic/libc/bionic/__libc_init_main_thread.cpp create mode 100644 aosp/bionic/libc/bionic/__set_errno.cpp create mode 100644 aosp/bionic/libc/bionic/__stack_chk_fail.cpp create mode 100644 aosp/bionic/libc/bionic/abort.cpp create mode 100644 aosp/bionic/libc/bionic/accept.cpp create mode 100644 aosp/bionic/libc/bionic/access.cpp create mode 100644 aosp/bionic/libc/bionic/android_profiling_dynamic.cpp create mode 100644 aosp/bionic/libc/bionic/android_set_abort_message.cpp create mode 100644 aosp/bionic/libc/bionic/android_unsafe_frame_pointer_chase.cpp create mode 100644 aosp/bionic/libc/bionic/arpa_inet.cpp create mode 100644 aosp/bionic/libc/bionic/assert.cpp create mode 100644 aosp/bionic/libc/bionic/atexit.cpp create mode 100644 aosp/bionic/libc/bionic/atexit.h create mode 100644 aosp/bionic/libc/bionic/atof.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_allocator.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_arc4random.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_call_ifunc_resolver.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_elf_tls.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_futex.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_netlink.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_netlink.h create mode 100644 aosp/bionic/libc/bionic/bionic_systrace.cpp create mode 100644 aosp/bionic/libc/bionic/bionic_time_conversions.cpp create mode 100644 aosp/bionic/libc/bionic/brk.cpp create mode 100644 aosp/bionic/libc/bionic/c16rtomb.cpp create mode 100644 aosp/bionic/libc/bionic/c32rtomb.cpp create mode 100644 aosp/bionic/libc/bionic/chmod.cpp create mode 100644 aosp/bionic/libc/bionic/chown.cpp create mode 100644 aosp/bionic/libc/bionic/clearenv.cpp create mode 100644 aosp/bionic/libc/bionic/clock.cpp create mode 100644 aosp/bionic/libc/bionic/clock_getcpuclockid.cpp create mode 100644 aosp/bionic/libc/bionic/clock_nanosleep.cpp create mode 100644 aosp/bionic/libc/bionic/clone.cpp create mode 100644 aosp/bionic/libc/bionic/ctype.cpp create mode 100644 aosp/bionic/libc/bionic/dirent.cpp create mode 100644 aosp/bionic/libc/bionic/dl_iterate_phdr_static.cpp create mode 100644 aosp/bionic/libc/bionic/dup.cpp create mode 100644 aosp/bionic/libc/bionic/environ.cpp create mode 100644 aosp/bionic/libc/bionic/error.cpp create mode 100644 aosp/bionic/libc/bionic/ether_aton.c create mode 100644 aosp/bionic/libc/bionic/ether_ntoa.c create mode 100644 aosp/bionic/libc/bionic/eventfd.cpp create mode 100644 aosp/bionic/libc/bionic/eventfd_write.cpp create mode 100644 aosp/bionic/libc/bionic/exec.cpp create mode 100644 aosp/bionic/libc/bionic/faccessat.cpp create mode 100644 aosp/bionic/libc/bionic/fchmod.cpp create mode 100644 aosp/bionic/libc/bionic/fchmodat.cpp create mode 100644 aosp/bionic/libc/bionic/fcntl.cpp create mode 100644 aosp/bionic/libc/bionic/fdsan.cpp create mode 100644 aosp/bionic/libc/bionic/fdtrack.cpp create mode 100644 aosp/bionic/libc/bionic/ffs.cpp create mode 100644 aosp/bionic/libc/bionic/fgetxattr.cpp create mode 100644 aosp/bionic/libc/bionic/flistxattr.cpp create mode 100644 aosp/bionic/libc/bionic/flockfile.cpp create mode 100644 aosp/bionic/libc/bionic/fork.cpp create mode 100644 aosp/bionic/libc/bionic/fortify.cpp create mode 100644 aosp/bionic/libc/bionic/fpclassify.cpp create mode 100644 aosp/bionic/libc/bionic/fsetxattr.cpp create mode 100644 aosp/bionic/libc/bionic/ftruncate.cpp create mode 100644 aosp/bionic/libc/bionic/fts.c create mode 100644 aosp/bionic/libc/bionic/ftw.cpp create mode 100644 aosp/bionic/libc/bionic/futimens.cpp create mode 100644 aosp/bionic/libc/bionic/get_device_api_level.cpp create mode 100644 aosp/bionic/libc/bionic/getauxval.cpp create mode 100644 aosp/bionic/libc/bionic/getcwd.cpp create mode 100644 aosp/bionic/libc/bionic/getdomainname.cpp create mode 100644 aosp/bionic/libc/bionic/getentropy.cpp create mode 100644 aosp/bionic/libc/bionic/gethostname.cpp create mode 100644 aosp/bionic/libc/bionic/getloadavg.cpp create mode 100644 aosp/bionic/libc/bionic/getpagesize.cpp create mode 100644 aosp/bionic/libc/bionic/getpgrp.cpp create mode 100644 aosp/bionic/libc/bionic/getpid.cpp create mode 100644 aosp/bionic/libc/bionic/getpriority.cpp create mode 100644 aosp/bionic/libc/bionic/gettid.cpp create mode 100644 aosp/bionic/libc/bionic/grp_pwd.cpp create mode 100644 aosp/bionic/libc/bionic/grp_pwd_file.cpp create mode 100644 aosp/bionic/libc/bionic/grp_pwd_file.h create mode 100644 aosp/bionic/libc/bionic/gwp_asan_wrappers.cpp create mode 100644 aosp/bionic/libc/bionic/gwp_asan_wrappers.h create mode 100644 aosp/bionic/libc/bionic/heap_tagging.cpp create mode 100644 aosp/bionic/libc/bionic/heap_tagging.h create mode 100644 aosp/bionic/libc/bionic/iconv.cpp create mode 100644 aosp/bionic/libc/bionic/icu.cpp create mode 100644 aosp/bionic/libc/bionic/icu_static.cpp create mode 100644 aosp/bionic/libc/bionic/icu_wrappers.cpp create mode 100644 aosp/bionic/libc/bionic/ifaddrs.cpp create mode 100644 aosp/bionic/libc/bionic/initgroups.c create mode 100644 aosp/bionic/libc/bionic/inotify_init.cpp create mode 100644 aosp/bionic/libc/bionic/ioctl.cpp create mode 100644 aosp/bionic/libc/bionic/isatty.c create mode 100644 aosp/bionic/libc/bionic/jemalloc.h create mode 100644 aosp/bionic/libc/bionic/jemalloc_wrapper.cpp create mode 100644 aosp/bionic/libc/bionic/killpg.cpp create mode 100644 aosp/bionic/libc/bionic/langinfo.cpp create mode 100644 aosp/bionic/libc/bionic/lchown.cpp create mode 100644 aosp/bionic/libc/bionic/legacy_32_bit_support.cpp create mode 100644 aosp/bionic/libc/bionic/lfs64_support.cpp create mode 100644 aosp/bionic/libc/bionic/libc_init_common.cpp create mode 100644 aosp/bionic/libc/bionic/libc_init_common.h create mode 100644 aosp/bionic/libc/bionic/libc_init_dynamic.cpp create mode 100644 aosp/bionic/libc/bionic/libc_init_static.cpp create mode 100644 aosp/bionic/libc/bionic/libgen.cpp create mode 100644 aosp/bionic/libc/bionic/link.cpp create mode 100644 aosp/bionic/libc/bionic/locale.cpp create mode 100644 aosp/bionic/libc/bionic/lockf.cpp create mode 100644 aosp/bionic/libc/bionic/lstat.cpp create mode 100644 aosp/bionic/libc/bionic/malloc_common.cpp create mode 100644 aosp/bionic/libc/bionic/malloc_common.h create mode 100644 aosp/bionic/libc/bionic/malloc_common_dynamic.cpp create mode 100644 aosp/bionic/libc/bionic/malloc_common_dynamic.h create mode 100644 aosp/bionic/libc/bionic/malloc_heapprofd.cpp create mode 100644 aosp/bionic/libc/bionic/malloc_heapprofd.h create mode 100644 aosp/bionic/libc/bionic/malloc_limit.cpp create mode 100644 aosp/bionic/libc/bionic/malloc_limit.h create mode 100644 aosp/bionic/libc/bionic/malloc_tagged_pointers.h create mode 100644 aosp/bionic/libc/bionic/mblen.cpp create mode 100644 aosp/bionic/libc/bionic/mbrtoc16.cpp create mode 100644 aosp/bionic/libc/bionic/mbrtoc32.cpp create mode 100644 aosp/bionic/libc/bionic/memmem.cpp create mode 100644 aosp/bionic/libc/bionic/mempcpy.cpp create mode 100644 aosp/bionic/libc/bionic/mkdir.cpp create mode 100644 aosp/bionic/libc/bionic/mkfifo.cpp create mode 100644 aosp/bionic/libc/bionic/mknod.cpp create mode 100644 aosp/bionic/libc/bionic/mmap.cpp create mode 100644 aosp/bionic/libc/bionic/mntent.cpp create mode 100644 aosp/bionic/libc/bionic/mremap.cpp create mode 100644 aosp/bionic/libc/bionic/ndk_cruft.cpp create mode 100644 aosp/bionic/libc/bionic/ndk_cruft_data.cpp create mode 100644 aosp/bionic/libc/bionic/net_if.cpp create mode 100644 aosp/bionic/libc/bionic/netdb.cpp create mode 100644 aosp/bionic/libc/bionic/netinet_in.cpp create mode 100644 aosp/bionic/libc/bionic/new.cpp create mode 100644 aosp/bionic/libc/bionic/nl_types.cpp create mode 100644 aosp/bionic/libc/bionic/open.cpp create mode 100644 aosp/bionic/libc/bionic/pathconf.cpp create mode 100644 aosp/bionic/libc/bionic/pause.cpp create mode 100644 aosp/bionic/libc/bionic/pipe.cpp create mode 100644 aosp/bionic/libc/bionic/poll.cpp create mode 100644 aosp/bionic/libc/bionic/posix_fadvise.cpp create mode 100644 aosp/bionic/libc/bionic/posix_fallocate.cpp create mode 100644 aosp/bionic/libc/bionic/posix_madvise.cpp create mode 100644 aosp/bionic/libc/bionic/posix_timers.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_atfork.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_attr.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_barrier.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_cond.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_create.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_detach.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_equal.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_exit.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_getcpuclockid.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_getschedparam.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_gettid_np.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_internal.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_internal.h create mode 100644 aosp/bionic/libc/bionic/pthread_join.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_key.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_kill.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_mutex.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_once.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_rwlock.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_self.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_setname_np.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_setschedparam.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_sigqueue.cpp create mode 100644 aosp/bionic/libc/bionic/pthread_spinlock.cpp create mode 100644 aosp/bionic/libc/bionic/ptrace.cpp create mode 100644 aosp/bionic/libc/bionic/pty.cpp create mode 100644 aosp/bionic/libc/bionic/pututline.c create mode 100644 aosp/bionic/libc/bionic/raise.cpp create mode 100644 aosp/bionic/libc/bionic/rand.cpp create mode 100644 aosp/bionic/libc/bionic/readlink.cpp create mode 100644 aosp/bionic/libc/bionic/realpath.cpp create mode 100644 aosp/bionic/libc/bionic/reboot.cpp create mode 100644 aosp/bionic/libc/bionic/recv.cpp create mode 100644 aosp/bionic/libc/bionic/recvmsg.cpp create mode 100644 aosp/bionic/libc/bionic/rename.cpp create mode 100644 aosp/bionic/libc/bionic/rmdir.cpp create mode 100644 aosp/bionic/libc/bionic/scandir.cpp create mode 100644 aosp/bionic/libc/bionic/sched_cpualloc.c create mode 100644 aosp/bionic/libc/bionic/sched_cpucount.c create mode 100644 aosp/bionic/libc/bionic/sched_getaffinity.cpp create mode 100644 aosp/bionic/libc/bionic/sched_getcpu.cpp create mode 100644 aosp/bionic/libc/bionic/scudo.h create mode 100644 aosp/bionic/libc/bionic/scudo/Android.bp create mode 100644 aosp/bionic/libc/bionic/scudo/exported32.map create mode 100644 aosp/bionic/libc/bionic/scudo/exported64.map create mode 100644 aosp/bionic/libc/bionic/scudo/scudo.cpp create mode 100644 aosp/bionic/libc/bionic/scudo_wrapper.cpp create mode 100644 aosp/bionic/libc/bionic/semaphore.cpp create mode 100644 aosp/bionic/libc/bionic/send.cpp create mode 100644 aosp/bionic/libc/bionic/setegid.cpp create mode 100644 aosp/bionic/libc/bionic/seteuid.cpp create mode 100644 aosp/bionic/libc/bionic/setjmp_cookie.cpp create mode 100644 aosp/bionic/libc/bionic/setpgrp.cpp create mode 100644 aosp/bionic/libc/bionic/sigaction.cpp create mode 100644 aosp/bionic/libc/bionic/signal.cpp create mode 100644 aosp/bionic/libc/bionic/sigprocmask.cpp create mode 100644 aosp/bionic/libc/bionic/sleep.cpp create mode 100644 aosp/bionic/libc/bionic/socketpair.cpp create mode 100644 aosp/bionic/libc/bionic/spawn.cpp create mode 100644 aosp/bionic/libc/bionic/stat.cpp create mode 100644 aosp/bionic/libc/bionic/stdlib_l.cpp create mode 100644 aosp/bionic/libc/bionic/strchr.cpp create mode 100644 aosp/bionic/libc/bionic/strchrnul.cpp create mode 100644 aosp/bionic/libc/bionic/strerror.cpp create mode 100644 aosp/bionic/libc/bionic/string_l.cpp create mode 100644 aosp/bionic/libc/bionic/strings_l.cpp create mode 100644 aosp/bionic/libc/bionic/strnlen.c create mode 100644 aosp/bionic/libc/bionic/strrchr.cpp create mode 100644 aosp/bionic/libc/bionic/strsignal.cpp create mode 100644 aosp/bionic/libc/bionic/strtol.cpp create mode 100644 aosp/bionic/libc/bionic/strtold.cpp create mode 100644 aosp/bionic/libc/bionic/swab.cpp create mode 100644 aosp/bionic/libc/bionic/symlink.cpp create mode 100644 aosp/bionic/libc/bionic/sync_file_range.cpp create mode 100644 aosp/bionic/libc/bionic/sys_epoll.cpp create mode 100644 aosp/bionic/libc/bionic/sys_msg.cpp create mode 100644 aosp/bionic/libc/bionic/sys_sem.cpp create mode 100644 aosp/bionic/libc/bionic/sys_shm.cpp create mode 100644 aosp/bionic/libc/bionic/sys_signalfd.cpp create mode 100644 aosp/bionic/libc/bionic/sys_statfs.cpp create mode 100644 aosp/bionic/libc/bionic/sys_statvfs.cpp create mode 100644 aosp/bionic/libc/bionic/sys_time.cpp create mode 100644 aosp/bionic/libc/bionic/sysconf.cpp create mode 100644 aosp/bionic/libc/bionic/syslog.cpp create mode 100644 aosp/bionic/libc/bionic/system.cpp create mode 100644 aosp/bionic/libc/bionic/system_property_api.cpp create mode 100644 aosp/bionic/libc/bionic/system_property_set.cpp create mode 100644 aosp/bionic/libc/bionic/tdestroy.cpp create mode 100644 aosp/bionic/libc/bionic/termios.cpp create mode 100644 aosp/bionic/libc/bionic/thread_private.cpp create mode 100644 aosp/bionic/libc/bionic/threads.cpp create mode 100644 aosp/bionic/libc/bionic/time64.c create mode 100644 aosp/bionic/libc/bionic/time64_config.h create mode 100644 aosp/bionic/libc/bionic/timespec_get.cpp create mode 100644 aosp/bionic/libc/bionic/tmpfile.cpp create mode 100644 aosp/bionic/libc/bionic/umount.cpp create mode 100644 aosp/bionic/libc/bionic/unlink.cpp create mode 100644 aosp/bionic/libc/bionic/usleep.cpp create mode 100644 aosp/bionic/libc/bionic/vdso.cpp create mode 100644 aosp/bionic/libc/bionic/wait.cpp create mode 100644 aosp/bionic/libc/bionic/wchar.cpp create mode 100644 aosp/bionic/libc/bionic/wchar_l.cpp create mode 100644 aosp/bionic/libc/bionic/wcstod.cpp create mode 100644 aosp/bionic/libc/bionic/wctype.cpp create mode 100644 aosp/bionic/libc/bionic/wcwidth.cpp create mode 100644 aosp/bionic/libc/bionic/wmempcpy.cpp create mode 100644 aosp/bionic/libc/dns/include/hostent.h create mode 100644 aosp/bionic/libc/dns/include/nsswitch.h create mode 100644 aosp/bionic/libc/dns/include/resolv_cache.h create mode 100644 aosp/bionic/libc/dns/include/resolv_netid.h create mode 100644 aosp/bionic/libc/dns/include/resolv_params.h create mode 100644 aosp/bionic/libc/dns/include/resolv_private.h create mode 100644 aosp/bionic/libc/dns/include/resolv_static.h create mode 100644 aosp/bionic/libc/dns/include/resolv_stats.h create mode 100644 aosp/bionic/libc/dns/nameser/ns_name.c create mode 100644 aosp/bionic/libc/dns/nameser/ns_netint.c create mode 100644 aosp/bionic/libc/dns/nameser/ns_parse.c create mode 100644 aosp/bionic/libc/dns/nameser/ns_print.c create mode 100644 aosp/bionic/libc/dns/nameser/ns_samedomain.c create mode 100644 aosp/bionic/libc/dns/nameser/ns_ttl.c create mode 100644 aosp/bionic/libc/dns/net/getaddrinfo.c create mode 100644 aosp/bionic/libc/dns/net/gethnamaddr.c create mode 100644 aosp/bionic/libc/dns/net/getnameinfo.c create mode 100644 aosp/bionic/libc/dns/net/getservent.c create mode 100644 aosp/bionic/libc/dns/net/nsdispatch.c create mode 100644 aosp/bionic/libc/dns/net/services.h create mode 100644 aosp/bionic/libc/dns/net/sethostent.c create mode 100644 aosp/bionic/libc/dns/resolv/herror.c create mode 100644 aosp/bionic/libc/dns/resolv/res_cache.c create mode 100644 aosp/bionic/libc/dns/resolv/res_comp.c create mode 100644 aosp/bionic/libc/dns/resolv/res_data.c create mode 100644 aosp/bionic/libc/dns/resolv/res_debug.c create mode 100644 aosp/bionic/libc/dns/resolv/res_debug.h create mode 100644 aosp/bionic/libc/dns/resolv/res_init.c create mode 100644 aosp/bionic/libc/dns/resolv/res_mkquery.c create mode 100644 aosp/bionic/libc/dns/resolv/res_private.h create mode 100644 aosp/bionic/libc/dns/resolv/res_query.c create mode 100644 aosp/bionic/libc/dns/resolv/res_send.c create mode 100644 aosp/bionic/libc/dns/resolv/res_state.c create mode 100644 aosp/bionic/libc/dns/resolv/res_stats.c create mode 120000 aosp/bionic/libc/fs_config_generator.py create mode 100644 aosp/bionic/libc/include/.clang-format create mode 100644 aosp/bionic/libc/include/alloca.h create mode 100644 aosp/bionic/libc/include/android/api-level.h create mode 100644 aosp/bionic/libc/include/android/dlext.h create mode 100644 aosp/bionic/libc/include/android/fdsan.h create mode 100644 aosp/bionic/libc/include/android/legacy_errno_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_fenv_inlines_arm.h create mode 100644 aosp/bionic/libc/include/android/legacy_signal_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_stdlib_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_strings_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_sys_mman_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_sys_stat_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_sys_statvfs_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_sys_wait_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_termios_inlines.h create mode 100644 aosp/bionic/libc/include/android/legacy_threads_inlines.h create mode 100644 aosp/bionic/libc/include/android/set_abort_message.h create mode 100644 aosp/bionic/libc/include/android/versioning.h create mode 100644 aosp/bionic/libc/include/ar.h create mode 100644 aosp/bionic/libc/include/arpa/ftp.h create mode 100644 aosp/bionic/libc/include/arpa/inet.h create mode 100644 aosp/bionic/libc/include/arpa/nameser.h create mode 100644 aosp/bionic/libc/include/arpa/nameser_compat.h create mode 100644 aosp/bionic/libc/include/arpa/telnet.h create mode 100644 aosp/bionic/libc/include/arpa/tftp.h create mode 100644 aosp/bionic/libc/include/assert.h create mode 100644 aosp/bionic/libc/include/bits/auxvec.h create mode 100644 aosp/bionic/libc/include/bits/ctype_inlines.h create mode 100644 aosp/bionic/libc/include/bits/elf_arm.h create mode 100644 aosp/bionic/libc/include/bits/elf_arm64.h create mode 100644 aosp/bionic/libc/include/bits/elf_x86.h create mode 100644 aosp/bionic/libc/include/bits/elf_x86_64.h create mode 100644 aosp/bionic/libc/include/bits/epoll_event.h create mode 100644 aosp/bionic/libc/include/bits/fcntl.h create mode 100644 aosp/bionic/libc/include/bits/fenv_arm.h create mode 100644 aosp/bionic/libc/include/bits/fenv_inlines_arm.h create mode 100644 aosp/bionic/libc/include/bits/fenv_x86.h create mode 100644 aosp/bionic/libc/include/bits/fenv_x86_64.h create mode 100644 aosp/bionic/libc/include/bits/flock.h create mode 100644 aosp/bionic/libc/include/bits/flock64.h create mode 100644 aosp/bionic/libc/include/bits/fortify/fcntl.h create mode 100644 aosp/bionic/libc/include/bits/fortify/poll.h create mode 100644 aosp/bionic/libc/include/bits/fortify/socket.h create mode 100644 aosp/bionic/libc/include/bits/fortify/stat.h create mode 100644 aosp/bionic/libc/include/bits/fortify/stdio.h create mode 100644 aosp/bionic/libc/include/bits/fortify/stdlib.h create mode 100644 aosp/bionic/libc/include/bits/fortify/string.h create mode 100644 aosp/bionic/libc/include/bits/fortify/strings.h create mode 100644 aosp/bionic/libc/include/bits/fortify/unistd.h create mode 100644 aosp/bionic/libc/include/bits/get_device_api_level_inlines.h create mode 100644 aosp/bionic/libc/include/bits/getopt.h create mode 100644 aosp/bionic/libc/include/bits/glibc-syscalls.h create mode 100644 aosp/bionic/libc/include/bits/in_addr.h create mode 100644 aosp/bionic/libc/include/bits/ioctl.h create mode 100644 aosp/bionic/libc/include/bits/ip_mreq_source.h create mode 100644 aosp/bionic/libc/include/bits/ip_msfilter.h create mode 100644 aosp/bionic/libc/include/bits/lockf.h create mode 100644 aosp/bionic/libc/include/bits/mbstate_t.h create mode 100644 aosp/bionic/libc/include/bits/posix_limits.h create mode 100644 aosp/bionic/libc/include/bits/pthread_types.h create mode 100644 aosp/bionic/libc/include/bits/sa_family_t.h create mode 100644 aosp/bionic/libc/include/bits/seek_constants.h create mode 100644 aosp/bionic/libc/include/bits/signal_types.h create mode 100644 aosp/bionic/libc/include/bits/stdatomic.h create mode 100644 aosp/bionic/libc/include/bits/strcasecmp.h create mode 100644 aosp/bionic/libc/include/bits/struct_file.h create mode 100644 aosp/bionic/libc/include/bits/sys_statvfs_inlines.h create mode 100644 aosp/bionic/libc/include/bits/sysconf.h create mode 100644 aosp/bionic/libc/include/bits/termios_inlines.h create mode 100644 aosp/bionic/libc/include/bits/threads_inlines.h create mode 100644 aosp/bionic/libc/include/bits/timespec.h create mode 100644 aosp/bionic/libc/include/bits/wait.h create mode 100644 aosp/bionic/libc/include/bits/wchar_limits.h create mode 100644 aosp/bionic/libc/include/bits/wctype.h create mode 100644 aosp/bionic/libc/include/byteswap.h create mode 100644 aosp/bionic/libc/include/complex.h create mode 100644 aosp/bionic/libc/include/cpio.h create mode 100644 aosp/bionic/libc/include/ctype.h create mode 100644 aosp/bionic/libc/include/dirent.h create mode 100644 aosp/bionic/libc/include/dlfcn.h create mode 100644 aosp/bionic/libc/include/elf.h create mode 100644 aosp/bionic/libc/include/endian.h create mode 100644 aosp/bionic/libc/include/err.h create mode 100644 aosp/bionic/libc/include/errno.h create mode 100644 aosp/bionic/libc/include/error.h create mode 100644 aosp/bionic/libc/include/fcntl.h create mode 100644 aosp/bionic/libc/include/features.h create mode 100644 aosp/bionic/libc/include/fenv.h create mode 100644 aosp/bionic/libc/include/fnmatch.h create mode 100644 aosp/bionic/libc/include/fts.h create mode 100644 aosp/bionic/libc/include/ftw.h create mode 100644 aosp/bionic/libc/include/getopt.h create mode 100644 aosp/bionic/libc/include/glob.h create mode 100644 aosp/bionic/libc/include/grp.h create mode 100644 aosp/bionic/libc/include/iconv.h create mode 100644 aosp/bionic/libc/include/ifaddrs.h create mode 100644 aosp/bionic/libc/include/inttypes.h create mode 100644 aosp/bionic/libc/include/langinfo.h create mode 100644 aosp/bionic/libc/include/lastlog.h create mode 100644 aosp/bionic/libc/include/libgen.h create mode 100644 aosp/bionic/libc/include/limits.h create mode 100644 aosp/bionic/libc/include/link.h create mode 100644 aosp/bionic/libc/include/locale.h create mode 100644 aosp/bionic/libc/include/malloc.h create mode 100644 aosp/bionic/libc/include/math.h create mode 100644 aosp/bionic/libc/include/memory.h create mode 100644 aosp/bionic/libc/include/mntent.h create mode 100644 aosp/bionic/libc/include/net/ethernet.h create mode 100644 aosp/bionic/libc/include/net/if.h create mode 100644 aosp/bionic/libc/include/net/if_arp.h create mode 100644 aosp/bionic/libc/include/net/if_packet.h create mode 100644 aosp/bionic/libc/include/net/route.h create mode 100644 aosp/bionic/libc/include/netdb.h create mode 100644 aosp/bionic/libc/include/netinet/ether.h create mode 100644 aosp/bionic/libc/include/netinet/icmp6.h create mode 100644 aosp/bionic/libc/include/netinet/if_ether.h create mode 100644 aosp/bionic/libc/include/netinet/in.h create mode 100644 aosp/bionic/libc/include/netinet/in6.h create mode 100644 aosp/bionic/libc/include/netinet/in_systm.h create mode 100644 aosp/bionic/libc/include/netinet/ip.h create mode 100644 aosp/bionic/libc/include/netinet/ip6.h create mode 100644 aosp/bionic/libc/include/netinet/ip_icmp.h create mode 100644 aosp/bionic/libc/include/netinet/tcp.h create mode 100644 aosp/bionic/libc/include/netinet/udp.h create mode 100644 aosp/bionic/libc/include/netpacket/packet.h create mode 100644 aosp/bionic/libc/include/nl_types.h create mode 100644 aosp/bionic/libc/include/poll.h create mode 100644 aosp/bionic/libc/include/pthread.h create mode 100644 aosp/bionic/libc/include/pty.h create mode 100644 aosp/bionic/libc/include/pwd.h create mode 100644 aosp/bionic/libc/include/regex.h create mode 100644 aosp/bionic/libc/include/resolv.h create mode 100644 aosp/bionic/libc/include/sched.h create mode 100644 aosp/bionic/libc/include/search.h create mode 100644 aosp/bionic/libc/include/semaphore.h create mode 100644 aosp/bionic/libc/include/setjmp.h create mode 100644 aosp/bionic/libc/include/signal.h create mode 100644 aosp/bionic/libc/include/spawn.h create mode 100644 aosp/bionic/libc/include/stdatomic.h create mode 100644 aosp/bionic/libc/include/stdint.h create mode 100644 aosp/bionic/libc/include/stdio.h create mode 100644 aosp/bionic/libc/include/stdio_ext.h create mode 100644 aosp/bionic/libc/include/stdlib.h create mode 100644 aosp/bionic/libc/include/string.h create mode 100644 aosp/bionic/libc/include/strings.h create mode 100644 aosp/bionic/libc/include/sys/_system_properties.h create mode 100644 aosp/bionic/libc/include/sys/auxv.h create mode 100644 aosp/bionic/libc/include/sys/cachectl.h create mode 100644 aosp/bionic/libc/include/sys/capability.h create mode 100644 aosp/bionic/libc/include/sys/cdefs.h create mode 100644 aosp/bionic/libc/include/sys/endian.h create mode 100644 aosp/bionic/libc/include/sys/epoll.h create mode 100644 aosp/bionic/libc/include/sys/errno.h create mode 100644 aosp/bionic/libc/include/sys/eventfd.h create mode 100644 aosp/bionic/libc/include/sys/fcntl.h create mode 100644 aosp/bionic/libc/include/sys/file.h create mode 100644 aosp/bionic/libc/include/sys/fsuid.h create mode 100644 aosp/bionic/libc/include/sys/ifunc.h create mode 100644 aosp/bionic/libc/include/sys/inotify.h create mode 100644 aosp/bionic/libc/include/sys/ioctl.h create mode 100644 aosp/bionic/libc/include/sys/ipc.h create mode 100644 aosp/bionic/libc/include/sys/klog.h create mode 100644 aosp/bionic/libc/include/sys/limits.h create mode 100644 aosp/bionic/libc/include/sys/mman.h create mode 100644 aosp/bionic/libc/include/sys/mount.h create mode 100644 aosp/bionic/libc/include/sys/msg.h create mode 100644 aosp/bionic/libc/include/sys/mtio.h create mode 100644 aosp/bionic/libc/include/sys/param.h create mode 100644 aosp/bionic/libc/include/sys/personality.h create mode 100644 aosp/bionic/libc/include/sys/poll.h create mode 100644 aosp/bionic/libc/include/sys/prctl.h create mode 100644 aosp/bionic/libc/include/sys/procfs.h create mode 100644 aosp/bionic/libc/include/sys/ptrace.h create mode 100644 aosp/bionic/libc/include/sys/queue.h create mode 100644 aosp/bionic/libc/include/sys/quota.h create mode 100644 aosp/bionic/libc/include/sys/random.h create mode 100644 aosp/bionic/libc/include/sys/reboot.h create mode 100644 aosp/bionic/libc/include/sys/reg.h create mode 100644 aosp/bionic/libc/include/sys/resource.h create mode 100644 aosp/bionic/libc/include/sys/select.h create mode 100644 aosp/bionic/libc/include/sys/sem.h create mode 100644 aosp/bionic/libc/include/sys/sendfile.h create mode 100644 aosp/bionic/libc/include/sys/shm.h create mode 100644 aosp/bionic/libc/include/sys/signal.h create mode 100644 aosp/bionic/libc/include/sys/signalfd.h create mode 100644 aosp/bionic/libc/include/sys/socket.h create mode 100644 aosp/bionic/libc/include/sys/stat.h create mode 100644 aosp/bionic/libc/include/sys/statfs.h create mode 100644 aosp/bionic/libc/include/sys/statvfs.h create mode 100644 aosp/bionic/libc/include/sys/swap.h create mode 100644 aosp/bionic/libc/include/sys/syscall.h create mode 100644 aosp/bionic/libc/include/sys/sysconf.h create mode 100644 aosp/bionic/libc/include/sys/sysinfo.h create mode 100644 aosp/bionic/libc/include/sys/syslog.h create mode 100644 aosp/bionic/libc/include/sys/sysmacros.h create mode 100644 aosp/bionic/libc/include/sys/time.h create mode 100644 aosp/bionic/libc/include/sys/timerfd.h create mode 100644 aosp/bionic/libc/include/sys/times.h create mode 100644 aosp/bionic/libc/include/sys/timex.h create mode 100644 aosp/bionic/libc/include/sys/ttydefaults.h create mode 100644 aosp/bionic/libc/include/sys/types.h create mode 100644 aosp/bionic/libc/include/sys/ucontext.h create mode 100644 aosp/bionic/libc/include/sys/uio.h create mode 100644 aosp/bionic/libc/include/sys/un.h create mode 100644 aosp/bionic/libc/include/sys/unistd.h create mode 100644 aosp/bionic/libc/include/sys/user.h create mode 100644 aosp/bionic/libc/include/sys/utsname.h create mode 100644 aosp/bionic/libc/include/sys/vfs.h create mode 100644 aosp/bionic/libc/include/sys/vt.h create mode 100644 aosp/bionic/libc/include/sys/wait.h create mode 100644 aosp/bionic/libc/include/sys/xattr.h create mode 100644 aosp/bionic/libc/include/syscall.h create mode 100644 aosp/bionic/libc/include/sysexits.h create mode 100644 aosp/bionic/libc/include/syslog.h create mode 100644 aosp/bionic/libc/include/tar.h create mode 100644 aosp/bionic/libc/include/termio.h create mode 100644 aosp/bionic/libc/include/termios.h create mode 100644 aosp/bionic/libc/include/threads.h create mode 100644 aosp/bionic/libc/include/time.h create mode 100644 aosp/bionic/libc/include/time64.h create mode 100644 aosp/bionic/libc/include/uchar.h create mode 100644 aosp/bionic/libc/include/ucontext.h create mode 100644 aosp/bionic/libc/include/unistd.h create mode 100644 aosp/bionic/libc/include/utime.h create mode 100644 aosp/bionic/libc/include/utmp.h create mode 100644 aosp/bionic/libc/include/wait.h create mode 100644 aosp/bionic/libc/include/wchar.h create mode 100644 aosp/bionic/libc/include/wctype.h create mode 100644 aosp/bionic/libc/include/xlocale.h create mode 100644 aosp/bionic/libc/kernel/.clang-format create mode 100644 aosp/bionic/libc/kernel/README.md create mode 100644 aosp/bionic/libc/kernel/android/README.md create mode 100644 aosp/bionic/libc/kernel/android/scsi/scsi/scsi.h create mode 100644 aosp/bionic/libc/kernel/android/scsi/scsi/scsi_ioctl.h create mode 100644 aosp/bionic/libc/kernel/android/scsi/scsi/scsi_proto.h create mode 100644 aosp/bionic/libc/kernel/android/scsi/scsi/sg.h create mode 100644 aosp/bionic/libc/kernel/android/uapi/linux/compiler.h create mode 100644 aosp/bionic/libc/kernel/android/uapi/linux/compiler_types.h create mode 100755 aosp/bionic/libc/kernel/tools/clean_header.py create mode 100755 aosp/bionic/libc/kernel/tools/cpp.py create mode 100644 aosp/bionic/libc/kernel/tools/defaults.py create mode 100755 aosp/bionic/libc/kernel/tools/generate_uapi_headers.sh create mode 100644 aosp/bionic/libc/kernel/tools/kernel.py create mode 100755 aosp/bionic/libc/kernel/tools/update_all.py create mode 100644 aosp/bionic/libc/kernel/tools/utils.py create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/auxvec.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/bitsperlong.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/bpf_perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/byteorder.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/errno.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/fcntl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/hwcap.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/ioctls.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/ipcbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/kvm.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/kvm_para.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/mman.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/msgbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/param.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/perf_regs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/poll.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/posix_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/ptrace.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/resource.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/sembuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/setup.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/shmbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/sigcontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/siginfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/signal.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/sockios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/stat.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/statfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/swab.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/termbits.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/termios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/unistd-common.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/unistd-eabi.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/unistd-oabi.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm/asm/unistd.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/auxvec.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/bitsperlong.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/bpf_perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/byteorder.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/errno.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/fcntl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/hwcap.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/ioctls.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/ipcbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/kvm.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/kvm_para.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/mman.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/msgbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/param.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/perf_regs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/poll.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/posix_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/ptrace.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/resource.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/sembuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/setup.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/shmbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/sigcontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/siginfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/signal.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/sockios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/stat.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/statfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/sve_context.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/swab.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/termbits.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/termios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/ucontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-arm64/asm/unistd.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/auxvec.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/bitsperlong.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/bpf_perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/errno-base.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/errno.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/fcntl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/hugetlb_encode.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/int-l64.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/int-ll64.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/ioctls.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/ipcbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/kvm_para.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/mman-common.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/mman.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/msgbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/param.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/poll.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/posix_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/resource.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/sembuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/setup.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/shmbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/siginfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/signal-defs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/signal.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/sockios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/stat.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/statfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/swab.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/termbits.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/termios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/ucontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-generic/unistd.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/a.out.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/auxvec.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/bitsperlong.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/boot.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/bootparam.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/bpf_perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/byteorder.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/debugreg.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/e820.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/errno.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/fcntl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/hw_breakpoint.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/hwcap2.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ioctls.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ipcbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ist.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/kvm.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/kvm_para.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/kvm_perf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ldt.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/mce.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/mman.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/msgbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/msr.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/mtrr.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/param.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/perf_regs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/poll.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/posix_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/posix_types_32.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/posix_types_64.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/posix_types_x32.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/prctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/processor-flags.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ptrace-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ptrace.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/resource.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/sembuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/setup.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/shmbuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/sigcontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/sigcontext32.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/siginfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/signal.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/sockios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/stat.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/statfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/svm.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/swab.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/termbits.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/termios.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/ucontext.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/unistd.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/unistd_32.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/unistd_64.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/unistd_x32.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/vm86.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/vmx.h create mode 100644 aosp/bionic/libc/kernel/uapi/asm-x86/asm/vsyscall.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/amdgpu_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/armada_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/drm_fourcc.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/drm_mode.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/drm_sarea.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/etnaviv_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/exynos_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/i810_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/i915_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/lima_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/mga_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/msm_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/nouveau_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/omap_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/panfrost_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/qxl_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/r128_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/radeon_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/savage_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/sis_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/tegra_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/v3d_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/vc4_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/vgem_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/via_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/virtgpu_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/drm/vmwgfx_drm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/a.out.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/acct.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/adb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/adfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/affs_hardblocks.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/agpgart.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/aio_abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/am437x-vpfe.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/android/binder.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/android/binderfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/apm_bios.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/arcfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/arm_sdei.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ashmem.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/aspeed-lpc-ctrl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/aspeed-p2a-ctrl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atalk.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_eni.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_he.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_idt77105.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_nicstar.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_tcp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atm_zatm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmapi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmarp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmbr2684.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmclip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmioc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmlec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmmpc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmppp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmsap.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/atmsvc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/audit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/auto_dev-ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/auto_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/auto_fs4.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/auxvec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ax25.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/b1lli.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/batadv_packet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/batman_adv.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/baycom.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bcache.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bcm933xx_hcs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/binfmts.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/blkpg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/blktrace_api.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/blkzoned.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bpf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bpf_common.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bpf_perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bpfilter.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bpqether.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bsg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/bt-bmc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/btf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/btrfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/btrfs_tree.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/byteorder/big_endian.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/byteorder/little_endian.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/caif/caif_socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/caif/if_caif.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/bcm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/error.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/gw.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/j1939.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/raw.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/can/vxcan.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/capability.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/capi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cciss_defs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cciss_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cdrom.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cec-funcs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cgroupstats.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/chio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cifs/cifs_mount.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cm4000_cs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cn_proc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/coda.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/coff.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/connector.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/const.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/coresight-stm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cramfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cryptouser.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cuda.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cyclades.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/cycx_cfm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dcbnl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dccp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/devlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dlm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dlm_device.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dlm_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dlm_plock.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dlmconstants.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dm-ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dm-log-userspace.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dma-buf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dn.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dns_resolver.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dqblk_xfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/audio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/ca.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/dmx.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/frontend.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/net.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/osd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/version.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/dvb/video.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/edd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/efs_fs_sb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/elf-em.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/elf-fdpic.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/elf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/elfcore.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/errno.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/errqueue.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/erspan.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ethtool.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/eventpoll.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fadvise.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/falloc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fanotify.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fcntl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fdreg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fib_rules.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fiemap.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/filter.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/firewire-cdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/firewire-constants.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fou.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fpga-dfl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fscrypt.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fsi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fsl_hypervisor.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fsmap.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fsverity.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/fuse.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/futex.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gameport.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gen_stats.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/genetlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/genwqe/genwqe_card.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gfs2_ondisk.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gigaset_dev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gpio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gsmmux.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/gtp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hash_info.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hdlc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hdlc/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hdlcdrv.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hdreg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hid.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hiddev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hidraw.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hpet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hsi/cs-protocol.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hsi/hsi_char.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hsr_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hw_breakpoint.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hyperv.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/hysdn_if.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/i2c-dev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/i2c.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/i2o-dev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/i8k.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/icmp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/icmpv6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_addr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_addrlabel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_alg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_arcnet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_arp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_bonding.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_bridge.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_cablemodem.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_eql.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_ether.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_fc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_fddi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_frad.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_hippi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_infiniband.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_link.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_ltalk.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_macsec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_packet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_phonet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_plip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_ppp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_pppol2tp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_pppox.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_slip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_team.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_tun.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_tunnel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_vlan.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_x25.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/if_xdp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ife.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/igmp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/iio/events.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/iio/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ila.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/in.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/in6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/in_route.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/inet_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/inotify.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/input-event-codes.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/input.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/io_uring.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/iommu.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ip6_tunnel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ip_vs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipmi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipmi_bmc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipmi_msgdefs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipsec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipv6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipv6_route.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ipx.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/irqnr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/isdn/capicmd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/iso_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/isst_if.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ivtv.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ivtvfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/jffs2.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/joystick.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kcm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kcmp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kcov.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kdev_t.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kernel-page-flags.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kernel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kernelcapi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kexec.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/keyboard.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/keyctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kfd_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kvm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/kvm_para.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/l2tp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/libc-compat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/lightnvm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/limits.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/lirc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/llc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/loop.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/lp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/lwtunnel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/magic.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/major.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/map_to_7segment.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/matroxfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/max2175.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mdio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/media-bus-format.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/media.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mei.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/membarrier.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/memfd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mempolicy.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/meye.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mic_common.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mic_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mii.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/minix_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mman.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mmc/ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mmtimer.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/module.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mount.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mpls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mpls_iptunnel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mqueue.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mroute.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mroute6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/msdos_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/msg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/mtio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/n_r3964.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nbd-netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nbd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ncsi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ndctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/neighbour.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/net.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/net_dropmon.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/net_namespace.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/net_tstamp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netconf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netdevice.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/ipset/ip_set.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/ipset/ip_set_bitmap.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/ipset/ip_set_hash.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/ipset/ip_set_list.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_conntrack_common.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_conntrack_ftp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_conntrack_sctp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_conntrack_tcp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_conntrack_tuple_common.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_log.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_nat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_synproxy.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_tables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nf_tables_compat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_acct.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_compat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_conntrack.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_cthelper.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_cttimeout.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_log.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_osf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/nfnetlink_queue.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/x_tables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_AUDIT.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_CHECKSUM.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_CLASSIFY.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_CONNMARK.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_CONNSECMARK.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_CT.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_DSCP.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_HMARK.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_IDLETIMER.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_LED.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_LOG.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_MARK.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_NFLOG.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_NFQUEUE.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_RATEEST.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_SECMARK.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_SYNPROXY.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_TCPMSS.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_TCPOPTSTRIP.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_TEE.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_TPROXY.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_addrtype.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_bpf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_cgroup.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_cluster.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_comment.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_connbytes.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_connlabel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_connlimit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_connmark.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_conntrack.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_cpu.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_dccp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_devgroup.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_dscp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_ecn.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_esp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_hashlimit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_helper.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_ipcomp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_iprange.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_ipvs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_l2tp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_length.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_limit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_mac.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_mark.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_multiport.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_nfacct.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_osf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_owner.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_physdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_pkttype.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_policy.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_quota.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_rateest.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_realm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_recent.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_rpfilter.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_sctp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_set.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_state.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_statistic.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_string.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_tcpmss.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_tcpudp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_time.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter/xt_u32.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_arp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_arp/arp_tables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_arp/arpt_mangle.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_802_3.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_among.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_arp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_arpreply.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_ip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_ip6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_limit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_log.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_mark_m.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_mark_t.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_nat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_nflog.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_pkttype.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_redirect.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_stp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebt_vlan.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_bridge/ebtables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_decnet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ip_tables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_CLUSTERIP.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_ECN.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_LOG.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_REJECT.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_TTL.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_ah.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_ecn.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv4/ipt_ttl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6_tables.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_HL.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_LOG.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_NPT.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_REJECT.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_ah.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_frag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_hl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_ipv6header.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_mh.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_opts.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_rt.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netfilter_ipv6/ip6t_srh.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netlink_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/netrom.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nexthop.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs2.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs3.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs4.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs4_mount.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs_idmap.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfs_mount.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsacl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsd/cld.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsd/debug.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsd/export.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsd/nfsfh.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nfsd/stats.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nilfs2_api.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nilfs2_ondisk.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nl80211.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nsfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nubus.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nvme_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/nvram.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/omap3isp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/omapfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/oom.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/openvswitch.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/packet_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/param.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/parport.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/patchkey.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pci.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pci_regs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pcitest.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/perf_event.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/personality.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pfkeyv2.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/phantom.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/phonet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pkt_cls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pkt_sched.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pktcdvd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pmu.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/poll.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/posix_acl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/posix_acl_xattr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/posix_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ppdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ppp-comp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ppp-ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ppp_defs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pps.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/pr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/prctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/psample.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/psci.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/psp-sev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ptp_clock.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ptrace.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/qemu_fw_cfg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/qnx4_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/qnxtypes.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/qrtr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/quota.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/radeonfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/raid/md_p.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/raid/md_u.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/random.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/raw.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rds.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/reboot.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/reiserfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/reiserfs_xattr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/resource.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rfkill.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rio_cm_cdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rio_mport_cdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/romfs_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rose.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/route.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rpmsg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rseq.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rtc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rtnetlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/rxrpc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/scc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sched.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sched/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/scif_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/screen_info.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sctp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sdla.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seccomp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/securebits.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sed-opal.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seg6.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seg6_genl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seg6_hmac.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seg6_iptunnel.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/seg6_local.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/selinux_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sem.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/serial.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/serial_core.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/serial_reg.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/serio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/shm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/signal.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/signalfd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/smc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/smc_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/smiapp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/snmp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sock_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/socket.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sockios.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sonet.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sonypi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sound.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/soundcard.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/spi/spidev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/stat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/stddef.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/stm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/string.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sunrpc/debug.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/suspend_ioctls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/swab.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/switchtec_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sync_file.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/synclink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sysctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/sysinfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/target_core_user.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/taskstats.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_bpf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_connmark.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_csum.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_ct.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_ctinfo.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_defact.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_gact.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_ife.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_ipt.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_mirred.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_mpls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_nat.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_pedit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_sample.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_skbedit.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_skbmod.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_tunnel_key.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_act/tc_vlan.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_ematch/tc_em_cmp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_ematch/tc_em_ipt.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_ematch/tc_em_meta.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_ematch/tc_em_nbyte.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tc_ematch/tc_em_text.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tcp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tcp_metrics.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tee.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/termios.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/thermal.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/time.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/time_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/timerfd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/times.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/timex.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tiocl.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tipc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tipc_config.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tipc_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tipc_sockets_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/toshiba.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tty.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/tty_flags.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/udf_fs_i.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/udmabuf.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/udp.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uhid.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uinput.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uleds.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/ultrasound.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/un.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/unistd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/unix_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/audio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/cdc-wdm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/cdc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/ch11.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/ch9.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/charger.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/f_accessory.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/functionfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/g_printer.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/g_uvc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/gadgetfs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/midi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/tmc.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usb/video.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usbdevice_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/usbip.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/userfaultfd.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/userio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/utime.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/utsname.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uuid.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/uvcvideo.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/v4l2-common.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/v4l2-controls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/v4l2-dv-timings.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/v4l2-mediabus.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/v4l2-subdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vbox_err.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vbox_vmmdev_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vboxguest.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/version.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/veth.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vfio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vfio_ccw.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vhost.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vhost_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/videodev2.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_9p.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_balloon.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_blk.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_config.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_console.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_crypto.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_gpu.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_ids.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_input.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_iommu.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_mmio.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_net.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_pci.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_pmem.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_ring.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_rng.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_scsi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_types.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/virtio_vsock.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vm_sockets.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vm_sockets_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vmcore.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vsoc_shm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vsockmon.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vt.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/vtpm_proxy.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/wait.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/watchdog.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/wimax.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/wimax/i2400m.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/wireless.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/wmi.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/x25.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/xattr.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/xdp_diag.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/xfrm.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/xilinx-v4l2-controls.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/zorro.h create mode 100644 aosp/bionic/libc/kernel/uapi/linux/zorro_ids.h create mode 100644 aosp/bionic/libc/kernel/uapi/misc/cxl.h create mode 100644 aosp/bionic/libc/kernel/uapi/misc/fastrpc.h create mode 100644 aosp/bionic/libc/kernel/uapi/misc/habanalabs.h create mode 100644 aosp/bionic/libc/kernel/uapi/misc/ocxl.h create mode 100644 aosp/bionic/libc/kernel/uapi/misc/xilinx_sdfec.h create mode 100644 aosp/bionic/libc/kernel/uapi/mtd/inftl-user.h create mode 100644 aosp/bionic/libc/kernel/uapi/mtd/mtd-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/mtd/mtd-user.h create mode 100644 aosp/bionic/libc/kernel/uapi/mtd/nftl-user.h create mode 100644 aosp/bionic/libc/kernel/uapi/mtd/ubi-user.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/bnxt_re-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/cxgb4-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/efa-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/hfi/hfi1_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/hfi/hfi1_user.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/hns-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/i40iw-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ib_user_ioctl_cmds.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ib_user_ioctl_verbs.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ib_user_mad.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ib_user_sa.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ib_user_verbs.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/mlx4-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/mlx5-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/mlx5_user_ioctl_cmds.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/mlx5_user_ioctl_verbs.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/mthca-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/ocrdma-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/qedr-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rdma_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rdma_user_cm.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rdma_user_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rdma_user_ioctl_cmds.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rdma_user_rxe.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/rvt-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/siw-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/rdma/vmw_pvrdma-abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/cxlflash_ioctl.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/fc/fc_els.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/fc/fc_fs.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/fc/fc_gs.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/fc/fc_ns.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/scsi_bsg_fc.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/scsi_bsg_ufs.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/scsi_netlink.h create mode 100644 aosp/bionic/libc/kernel/uapi/scsi/scsi_netlink_fc.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/asequencer.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/asoc.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/asound.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/asound_fm.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/compress_offload.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/compress_params.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/emu10k1.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/firewire.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/hdsp.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/hdspm.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sb16_csp.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sfnt_info.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/skl-tplg-interface.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/snd_sst_tokens.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sof/abi.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sof/fw.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sof/header.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/sof/tokens.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/tlv.h create mode 100644 aosp/bionic/libc/kernel/uapi/sound/usb_stream.h create mode 100644 aosp/bionic/libc/kernel/uapi/video/edid.h create mode 100644 aosp/bionic/libc/kernel/uapi/video/sisfb.h create mode 100644 aosp/bionic/libc/kernel/uapi/video/uvesafb.h create mode 100644 aosp/bionic/libc/kernel/uapi/xen/evtchn.h create mode 100644 aosp/bionic/libc/kernel/uapi/xen/gntalloc.h create mode 100644 aosp/bionic/libc/kernel/uapi/xen/gntdev.h create mode 100644 aosp/bionic/libc/kernel/uapi/xen/privcmd.h create mode 100644 aosp/bionic/libc/libc.map.txt create mode 100644 aosp/bionic/libc/libstdc++.map.txt create mode 100644 aosp/bionic/libc/malloc_debug/Android.bp create mode 100644 aosp/bionic/libc/malloc_debug/Config.cpp create mode 100644 aosp/bionic/libc/malloc_debug/Config.h create mode 100644 aosp/bionic/libc/malloc_debug/DebugData.cpp create mode 100644 aosp/bionic/libc/malloc_debug/DebugData.h create mode 100644 aosp/bionic/libc/malloc_debug/GuardData.cpp create mode 100644 aosp/bionic/libc/malloc_debug/GuardData.h create mode 100644 aosp/bionic/libc/malloc_debug/MapData.cpp create mode 100644 aosp/bionic/libc/malloc_debug/MapData.h create mode 100644 aosp/bionic/libc/malloc_debug/OptionData.h create mode 100644 aosp/bionic/libc/malloc_debug/PointerData.cpp create mode 100644 aosp/bionic/libc/malloc_debug/PointerData.h create mode 100644 aosp/bionic/libc/malloc_debug/README.md create mode 100644 aosp/bionic/libc/malloc_debug/README_api.md create mode 100644 aosp/bionic/libc/malloc_debug/README_marshmallow_and_earlier.md create mode 100644 aosp/bionic/libc/malloc_debug/RecordData.cpp create mode 100644 aosp/bionic/libc/malloc_debug/RecordData.h create mode 100644 aosp/bionic/libc/malloc_debug/UnwindBacktrace.cpp create mode 100644 aosp/bionic/libc/malloc_debug/UnwindBacktrace.h create mode 100644 aosp/bionic/libc/malloc_debug/backtrace.cpp create mode 100644 aosp/bionic/libc/malloc_debug/backtrace.h create mode 100644 aosp/bionic/libc/malloc_debug/debug_disable.cpp create mode 100644 aosp/bionic/libc/malloc_debug/debug_disable.h create mode 100644 aosp/bionic/libc/malloc_debug/debug_log.h create mode 100644 aosp/bionic/libc/malloc_debug/exported32.map create mode 100644 aosp/bionic/libc/malloc_debug/exported64.map create mode 100644 aosp/bionic/libc/malloc_debug/malloc_debug.cpp create mode 100644 aosp/bionic/libc/malloc_debug/malloc_debug.h create mode 100644 aosp/bionic/libc/malloc_debug/tests/backtrace_fake.cpp create mode 100644 aosp/bionic/libc/malloc_debug/tests/backtrace_fake.h create mode 100644 aosp/bionic/libc/malloc_debug/tests/libc_fake.cpp create mode 100644 aosp/bionic/libc/malloc_debug/tests/log_fake.cpp create mode 100644 aosp/bionic/libc/malloc_debug/tests/log_fake.h create mode 100644 aosp/bionic/libc/malloc_debug/tests/malloc_debug_config_tests.cpp create mode 100644 aosp/bionic/libc/malloc_debug/tests/malloc_debug_system_tests.cpp create mode 100644 aosp/bionic/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp create mode 100755 aosp/bionic/libc/malloc_debug/tools/gen_malloc.pl create mode 100644 aosp/bionic/libc/malloc_hooks/Android.bp create mode 100644 aosp/bionic/libc/malloc_hooks/README.md create mode 100644 aosp/bionic/libc/malloc_hooks/exported32.map create mode 100644 aosp/bionic/libc/malloc_hooks/exported64.map create mode 100644 aosp/bionic/libc/malloc_hooks/malloc_hooks.cpp create mode 100644 aosp/bionic/libc/malloc_hooks/tests/malloc_hooks_tests.cpp create mode 100644 aosp/bionic/libc/platform/bionic/android_unsafe_frame_pointer_chase.h create mode 100644 aosp/bionic/libc/platform/bionic/fdtrack.h create mode 100644 aosp/bionic/libc/platform/bionic/macros.h create mode 100644 aosp/bionic/libc/platform/bionic/malloc.h create mode 100644 aosp/bionic/libc/platform/bionic/mte.h create mode 100644 aosp/bionic/libc/platform/bionic/mte_kernel.h create mode 100644 aosp/bionic/libc/platform/bionic/page.h create mode 100644 aosp/bionic/libc/platform/bionic/reserved_signals.h create mode 100644 aosp/bionic/libc/platform/bionic/tls.h create mode 100644 aosp/bionic/libc/platform/bionic/tls_defines.h create mode 100644 aosp/bionic/libc/private/CFIShadow.h create mode 100644 aosp/bionic/libc/private/CachedProperty.h create mode 100644 aosp/bionic/libc/private/ErrnoRestorer.h create mode 100644 aosp/bionic/libc/private/FdPath.h create mode 100644 aosp/bionic/libc/private/KernelArgumentBlock.h create mode 100644 aosp/bionic/libc/private/MallocXmlElem.h create mode 100644 aosp/bionic/libc/private/NetdClientDispatch.h create mode 100644 aosp/bionic/libc/private/ScopedFd.h create mode 100644 aosp/bionic/libc/private/ScopedPthreadMutexLocker.h create mode 100644 aosp/bionic/libc/private/ScopedRWLock.h create mode 100644 aosp/bionic/libc/private/ScopedReaddir.h create mode 100644 aosp/bionic/libc/private/ScopedSignalBlocker.h create mode 100644 aosp/bionic/libc/private/ScopedSignalHandler.h create mode 100644 aosp/bionic/libc/private/SigSetConverter.h create mode 100644 aosp/bionic/libc/private/WriteProtected.h create mode 100644 aosp/bionic/libc/private/__bionic_get_shell_path.h create mode 100644 aosp/bionic/libc/private/bionic_allocator.h create mode 100644 aosp/bionic/libc/private/bionic_arc4random.h create mode 100644 aosp/bionic/libc/private/bionic_asm.h create mode 100644 aosp/bionic/libc/private/bionic_asm_arm.h create mode 100644 aosp/bionic/libc/private/bionic_asm_arm64.h create mode 100644 aosp/bionic/libc/private/bionic_asm_x86.h create mode 100644 aosp/bionic/libc/private/bionic_asm_x86_64.h create mode 100644 aosp/bionic/libc/private/bionic_auxv.h create mode 100644 aosp/bionic/libc/private/bionic_call_ifunc_resolver.h create mode 100644 aosp/bionic/libc/private/bionic_config.h create mode 100644 aosp/bionic/libc/private/bionic_constants.h create mode 100644 aosp/bionic/libc/private/bionic_defs.h create mode 100644 aosp/bionic/libc/private/bionic_elf_tls.h create mode 100644 aosp/bionic/libc/private/bionic_fdsan.h create mode 100644 aosp/bionic/libc/private/bionic_fdtrack.h create mode 100644 aosp/bionic/libc/private/bionic_fortify.h create mode 100644 aosp/bionic/libc/private/bionic_futex.h create mode 100644 aosp/bionic/libc/private/bionic_globals.h create mode 100644 aosp/bionic/libc/private/bionic_ieee.h create mode 100644 aosp/bionic/libc/private/bionic_ifuncs.h create mode 100644 aosp/bionic/libc/private/bionic_inline_raise.h create mode 100644 aosp/bionic/libc/private/bionic_lock.h create mode 100644 aosp/bionic/libc/private/bionic_malloc_dispatch.h create mode 100644 aosp/bionic/libc/private/bionic_mbstate.h create mode 100644 aosp/bionic/libc/private/bionic_sigdefs.h create mode 100644 aosp/bionic/libc/private/bionic_ssp.h create mode 100644 aosp/bionic/libc/private/bionic_string_utils.h create mode 100644 aosp/bionic/libc/private/bionic_systrace.h create mode 100644 aosp/bionic/libc/private/bionic_time_conversions.h create mode 100644 aosp/bionic/libc/private/bionic_tls.h create mode 100644 aosp/bionic/libc/private/bionic_vdso.h create mode 100644 aosp/bionic/libc/private/get_cpu_count_from_string.h create mode 100644 aosp/bionic/libc/private/grp_pwd.h create mode 100644 aosp/bionic/libc/private/icu.h create mode 100644 aosp/bionic/libc/private/linker_native_bridge.h create mode 100644 aosp/bionic/libc/private/thread_private.h create mode 100644 aosp/bionic/libc/seccomp/gen_syscall_nrs.cpp create mode 100644 aosp/bionic/libc/seccomp/gen_syscall_nrs_x86.cpp create mode 100644 aosp/bionic/libc/seccomp/gen_syscall_nrs_x86_64.cpp create mode 100644 aosp/bionic/libc/seccomp/include/seccomp_policy.h create mode 100644 aosp/bionic/libc/seccomp/seccomp_bpfs.h create mode 100644 aosp/bionic/libc/seccomp/seccomp_policy.cpp create mode 100644 aosp/bionic/libc/stdio/fmemopen.cpp create mode 100644 aosp/bionic/libc/stdio/glue.h create mode 100644 aosp/bionic/libc/stdio/local.h create mode 100644 aosp/bionic/libc/stdio/parsefloat.c create mode 100644 aosp/bionic/libc/stdio/printf_common.h create mode 100644 aosp/bionic/libc/stdio/refill.c create mode 100644 aosp/bionic/libc/stdio/stdio.cpp create mode 100644 aosp/bionic/libc/stdio/stdio_ext.cpp create mode 100644 aosp/bionic/libc/stdio/vfprintf.cpp create mode 100644 aosp/bionic/libc/stdio/vfscanf.cpp create mode 100644 aosp/bionic/libc/stdio/vfwprintf.cpp create mode 100644 aosp/bionic/libc/stdio/vfwscanf.c create mode 100644 aosp/bionic/libc/stdlib/exit.c create mode 100644 aosp/bionic/libc/system_properties/Android.bp create mode 100644 aosp/bionic/libc/system_properties/context_node.cpp create mode 100644 aosp/bionic/libc/system_properties/contexts_serialized.cpp create mode 100644 aosp/bionic/libc/system_properties/contexts_split.cpp create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/context_node.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/contexts.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/contexts_pre_split.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/contexts_serialized.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/contexts_split.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/prop_area.h create mode 100644 aosp/bionic/libc/system_properties/include/system_properties/system_properties.h create mode 100644 aosp/bionic/libc/system_properties/prop_info.cpp create mode 100644 aosp/bionic/libc/system_properties/system_properties.cpp create mode 100644 aosp/bionic/libc/tools/Android.bp create mode 100755 aosp/bionic/libc/tools/check-symbols-glibc.py create mode 100755 aosp/bionic/libc/tools/check-symbols.py create mode 100755 aosp/bionic/libc/tools/generate-NOTICE.py create mode 100755 aosp/bionic/libc/tools/genfunctosyscallnrs.py create mode 100755 aosp/bionic/libc/tools/genseccomp.py create mode 100755 aosp/bionic/libc/tools/genserv.py create mode 100755 aosp/bionic/libc/tools/gensyscalls.py create mode 100755 aosp/bionic/libc/tools/ndk_missing_symbols.py create mode 100644 aosp/bionic/libc/tools/posix-2013.txt create mode 100644 aosp/bionic/libc/tools/pylintrc create mode 100644 aosp/bionic/libc/tools/symbols.py create mode 100755 aosp/bionic/libc/tools/test_genseccomp.py create mode 100644 aosp/bionic/libc/tzcode/asctime.c create mode 100644 aosp/bionic/libc/tzcode/bionic.cpp create mode 100644 aosp/bionic/libc/tzcode/difftime.c create mode 100644 aosp/bionic/libc/tzcode/localtime.c create mode 100644 aosp/bionic/libc/tzcode/private.h create mode 100644 aosp/bionic/libc/tzcode/strftime.c create mode 100644 aosp/bionic/libc/tzcode/strptime.c create mode 100644 aosp/bionic/libc/tzcode/tzfile.h create mode 100644 aosp/bionic/libc/upstream-freebsd/.clang-format create mode 100644 aosp/bionic/libc/upstream-freebsd/README.md create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/collate.h create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/freebsd-compat.h create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/machine/atomic.h create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/machine/endian.h create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/namespace.h create mode 100644 aosp/bionic/libc/upstream-freebsd/android/include/un-namespace.h create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/gen/glob.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/gen/ldexp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/getopt_long.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/hcreate.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/hcreate_r.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/hdestroy_r.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/hsearch.h create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/hsearch_r.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/qsort.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/stdlib/quick_exit.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcpcpy.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcpncpy.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcscasecmp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcscat.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcschr.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcscmp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcscpy.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcscspn.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsdup.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcslcat.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcslen.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsncasecmp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsncat.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsncmp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsncpy.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsnlen.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcspbrk.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsrchr.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsspn.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcsstr.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wcstok.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wmemchr.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wmemcmp.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wmemcpy.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wmemmove.c create mode 100644 aosp/bionic/libc/upstream-freebsd/lib/libc/string/wmemset.c create mode 100644 aosp/bionic/libc/upstream-netbsd/.clang-format create mode 100644 aosp/bionic/libc/upstream-netbsd/README.md create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/env.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/extern.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/fd_setsize.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/namespace.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/netbsd-compat.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/port_after.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/port_before.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/rand48.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/reentrant.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/resolv_mt.h create mode 100644 aosp/bionic/libc/upstream-netbsd/android/include/sys/sha1.h create mode 100644 aosp/bionic/libc/upstream-netbsd/common/lib/libc/hash/sha1/sha1.c create mode 100644 aosp/bionic/libc/upstream-netbsd/common/lib/libc/stdlib/random.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/gen/nice.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/gen/psignal.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/gen/utime.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/gen/utmp.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/assertions.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/dst.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/eventlib.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/heap.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/list.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/include/isc/memcluster.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/inet/nsap_addr.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/isc/ev_streams.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/isc/ev_timers.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/isc/eventlib_p.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/cclass.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/cname.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/engine.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/regcomp.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/regerror.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/regex2.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/regexec.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/regfree.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/regex/utils.h create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/_rand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/bsearch.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/drand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/erand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/jrand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/lcong48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/lrand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/mrand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/nrand48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/rand_r.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/reallocarr.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/seed48.c create mode 100644 aosp/bionic/libc/upstream-netbsd/lib/libc/stdlib/srand48.c create mode 100644 aosp/bionic/libc/upstream-openbsd/.clang-format create mode 100644 aosp/bionic/libc/upstream-openbsd/README.md create mode 100644 aosp/bionic/libc/upstream-openbsd/android/gdtoa_support.cpp create mode 100644 aosp/bionic/libc/upstream-openbsd/android/include/arc4random.h create mode 100644 aosp/bionic/libc/upstream-openbsd/android/include/arith.h create mode 100644 aosp/bionic/libc/upstream-openbsd/android/include/gd_qnan.h create mode 100644 aosp/bionic/libc/upstream-openbsd/android/include/machine/ieee.h create mode 100644 aosp/bionic/libc/upstream-openbsd/android/include/openbsd-compat.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/crypt/arc4random.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/crypt/arc4random_uniform.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/crypt/chacha_private.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/dmisc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/dtoa.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa_fltrnds.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gethex.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/gmisc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/hd_init.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/hdtoa.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/hexnan.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/ldtoa.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/misc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/smisc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtod.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtodg.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtof.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtorQ.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtord.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/sum.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gdtoa/ulp.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/alarm.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/charclass.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/ctype_.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/daemon.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/err.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/errx.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/fnmatch.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/ftok.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/getprogname.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/setprogname.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/verr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/verrx.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/vwarn.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/vwarnx.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/warn.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/gen/warnx.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/include/ctype_private.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/_wcstol.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/_wcstoul.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/btowc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/mbrlen.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/mbstowcs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/mbtowc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcscoll.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstoimax.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstol.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstoll.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstombs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstoul.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstoull.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcstoumax.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wcsxfrm.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wctob.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wctoint.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/locale/wctomb.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/base64.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/htonl.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/htons.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_lnaof.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_makeaddr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_netof.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_ntoa.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_ntop.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/inet_pton.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/ntohl.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/ntohs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/net/res_random.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fgetln.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fgetwc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fgetws.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/flags.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fpurge.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fputwc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fputws.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fvwrite.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/fwide.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/getdelim.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/gets.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/makebuf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/mktemp.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/open_memstream.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/open_wmemstream.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/rget.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/tempnam.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/tmpnam.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/ungetc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/vasprintf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/vdprintf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/vsscanf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/vswprintf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/wbuf.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdio/wsetup.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/abs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/div.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/getenv.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/getsubopt.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/imaxabs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/imaxdiv.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/insque.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/labs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/ldiv.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/llabs.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/lldiv.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/lsearch.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/remque.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/setenv.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/tfind.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/stdlib/tsearch.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/memccpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/memchr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/memrchr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/stpcpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/stpncpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcasecmp.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcasestr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcat.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcmp.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcoll.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strcspn.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strdup.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strlcat.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strlcpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strlen.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strncat.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strncmp.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strncpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strndup.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strpbrk.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strsep.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strspn.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strstr.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strtok.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/strxfrm.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/wcslcpy.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/string/wcswidth.c create mode 100644 aosp/bionic/libc/upstream-openbsd/lib/libc/time/wcsftime.c create mode 100644 aosp/bionic/libc/version_script.txt create mode 120000 aosp/bionic/libc/versioner-dependencies/arm/kernel_uapi_asm-arm create mode 120000 aosp/bionic/libc/versioner-dependencies/arm64/kernel_uapi_asm-arm64 create mode 120000 aosp/bionic/libc/versioner-dependencies/common/clang-builtins create mode 120000 aosp/bionic/libc/versioner-dependencies/common/kernel_android_uapi create mode 120000 aosp/bionic/libc/versioner-dependencies/common/kernel_uapi create mode 120000 aosp/bionic/libc/versioner-dependencies/x86/kernel_uapi_asm-x86 create mode 120000 aosp/bionic/libc/versioner-dependencies/x86_64/kernel_uapi_asm-x86 diff --git a/aosp/bionic/libc/Android.bp b/aosp/bionic/libc/Android.bp new file mode 100644 index 000000000..d3271ae91 --- /dev/null +++ b/aosp/bionic/libc/Android.bp @@ -0,0 +1,2507 @@ +// Define the common source files for all the libc instances +// ========================================================= +libc_common_src_files = [ + "async_safe/async_safe_log.cpp", + "bionic/ether_aton.c", + "bionic/ether_ntoa.c", + "bionic/fts.c", + "bionic/initgroups.c", + "bionic/isatty.c", + "bionic/pututline.c", + "bionic/sched_cpualloc.c", + "bionic/sched_cpucount.c", + "stdio/fmemopen.cpp", + "stdio/parsefloat.c", + "stdio/refill.c", + "stdio/stdio.cpp", + "stdio/stdio_ext.cpp", + "stdio/vfscanf.cpp", + "stdio/vfwscanf.c", + "stdlib/exit.c", +] + +// off64_t/time64_t support on LP32. +// ======================================================== +libc_common_src_files_32 = [ + "bionic/legacy_32_bit_support.cpp", + "bionic/time64.c", +] + +libc_common_flags = [ + "-D_LIBC=1", + "-D__BIONIC_LP32_USE_STAT64", + "-Wall", + "-Wextra", + "-Wunused", + "-Wno-char-subscripts", + "-Wno-deprecated-declarations", + "-Wno-gcc-compat", + "-Wframe-larger-than=2048", + + // Try to catch typical 32-bit assumptions that break with 64-bit pointers. + "-Werror=pointer-to-int-cast", + "-Werror=int-to-pointer-cast", + "-Werror=type-limits", + "-Werror", + + // Clang's exit-time destructor registration hides __dso_handle, but + // __dso_handle needs to have default visibility on ARM32. See b/73485611. + "-Wexit-time-destructors", + + // GWP-ASan requires platform TLS. + "-fno-emulated-tls", +] + +// Define some common cflags +// ======================================================== +cc_defaults { + name: "libc_defaults", + defaults: ["linux_bionic_supported"], + cflags: libc_common_flags, + asflags: libc_common_flags, + conlyflags: ["-std=gnu99"], + cppflags: [], + include_dirs: [ + "bionic/libc/async_safe/include", + ], + + header_libs: ["gwp_asan_headers"], + + stl: "none", + system_shared_libs: [], + sanitize: { + address: false, + integer_overflow: false, + // TODO(b/132640749): Fix broken fuzzer support. + fuzzer: false, + }, + native_coverage: false, + ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + + // lld complains about duplicate symbols in libcrt and libgcc. Suppress the + // warning since this is intended right now. + ldflags: ["-Wl,-z,muldefs"], + + product_variables: { + experimental_mte: { + cflags: ["-DANDROID_EXPERIMENTAL_MTE"], + }, + }, +} + +libc_scudo_product_variables = { + malloc_not_svelte: { + cflags: ["-DUSE_SCUDO"], + whole_static_libs: ["libscudo"], + exclude_static_libs: [ + "libjemalloc5", + "libc_jemalloc_wrapper", + ], + }, +} + +// Defaults for native allocator libs/includes to make it +// easier to change. +// To disable scudo for the non-svelte config remove the line: +// product_variables: libc_scudo_product_variables, +// in the cc_defaults below. +// ======================================================== +cc_defaults { + name: "libc_native_allocator_defaults", + + whole_static_libs: [ + "libjemalloc5", + "libc_jemalloc_wrapper", + ], + header_libs: ["gwp_asan_headers"], + product_variables: libc_scudo_product_variables, +} + +// Functions not implemented by jemalloc directly, or that need to +// be modified for Android. +cc_library_static { + name: "libc_jemalloc_wrapper", + defaults: ["libc_defaults"], + srcs: ["bionic/jemalloc_wrapper.cpp"], + cflags: ["-fvisibility=hidden"], + + // Used to pull in the jemalloc include directory so that if the + // library is removed, the include directory is also removed. + static_libs: ["libjemalloc5"], +} + +// ======================================================== +// libc_bootstrap.a - -fno-stack-protector and -ffreestanding +// ======================================================== +// +// Code that implements the stack protector (or that runs before TLS has been set up) needs to be +// compiled with -fno-stack-protector, since it accesses the stack canary TLS slot. In the linker, +// some of this code runs before ifunc resolvers have made string.h functions work, so compile with +// -ffreestanding. + +cc_library_static { + + srcs: [ + "bionic/__libc_init_main_thread.cpp", + "bionic/__stack_chk_fail.cpp", + "bionic/bionic_call_ifunc_resolver.cpp", + "bionic/getauxval.cpp", + ], + arch: { + arm64: { + srcs: ["arch-arm64/bionic/__set_tls.c"], + }, + x86: { + srcs: [ + "arch-x86/bionic/__libc_init_sysinfo.cpp", + "arch-x86/bionic/__set_tls.cpp", + ], + }, + x86_64: { + srcs: ["arch-x86_64/bionic/__set_tls.c"], + }, + }, + + defaults: ["libc_defaults"], + cflags: ["-fno-stack-protector", "-ffreestanding"], + name: "libc_bootstrap", +} + +// libc_init_static.cpp and libc_init_dynamic.cpp need to be built without stack protector. +// libc_init_static.cpp sets up TLS for static executables, and libc_init_dynamic.cpp initializes +// the stack protector global variable. + +cc_library_static { + name: "libc_init_static", + defaults: ["libc_defaults"], + srcs: ["bionic/libc_init_static.cpp"], + cflags: [ + "-fno-stack-protector", + + // Compile libc_init_static.cpp with -ffreestanding, because some of its code is called + // from the linker before ifunc resolvers have made string.h functions available. + "-ffreestanding", + ], +} + +cc_library_static { + name: "libc_init_dynamic", + defaults: ["libc_defaults"], + srcs: ["bionic/libc_init_dynamic.cpp"], + cflags: ["-fno-stack-protector"], +} + +// ======================================================== +// libc_tzcode.a - upstream 'tzcode' code +// ======================================================== + +cc_library_static { + + defaults: ["libc_defaults"], + srcs: [ + "tzcode/**/*.c", + "tzcode/bionic.cpp", + "upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one. + ], + + cflags: [ + "-Wno-unused-parameter", + // Don't use ridiculous amounts of stack. + "-DALL_STATE", + // Include tzsetwall, timelocal, timegm, time2posix, and posix2time. + "-DSTD_INSPIRED", + // Obviously, we want to be thread-safe. + "-DTHREAD_SAFE", + // The name of the tm_gmtoff field in our struct tm. + "-DTM_GMTOFF=tm_gmtoff", + // Where we store our tzdata. + "-DTZDIR=\"/system/usr/share/zoneinfo\"", + // Include `tzname`, `timezone`, and `daylight` globals. + "-DHAVE_POSIX_DECLS=0", + "-DUSG_COMPAT=1", + // Use the empty string (instead of " ") as the timezone abbreviation + // fallback. + "-DWILDABBR=\"\"", + "-DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU", + "-Dlint", + ], + + local_include_dirs: ["tzcode/"], + name: "libc_tzcode", +} + +// ======================================================== +// libc_dns.a - modified NetBSD DNS code +// ======================================================== + +cc_library_static { + + defaults: ["libc_defaults"], + srcs: [ + "dns/**/*.c", + + "upstream-netbsd/lib/libc/isc/ev_streams.c", + "upstream-netbsd/lib/libc/isc/ev_timers.c", + ], + + cflags: [ + "-DANDROID_CHANGES", + "-DINET6", + "-Wno-unused-parameter", + "-include netbsd-compat.h", + "-Wframe-larger-than=66000", + ], + + local_include_dirs: [ + "dns/include", + "private", + "upstream-netbsd/lib/libc/include", + "upstream-netbsd/android/include", + ], + + name: "libc_dns", +} + +// ======================================================== +// libc_freebsd.a - upstream FreeBSD C library code +// ======================================================== +// +// These files are built with the freebsd-compat.h header file +// automatically included. + +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "upstream-freebsd/lib/libc/gen/ldexp.c", + "upstream-freebsd/lib/libc/stdlib/getopt_long.c", + "upstream-freebsd/lib/libc/stdlib/hcreate.c", + "upstream-freebsd/lib/libc/stdlib/hcreate_r.c", + "upstream-freebsd/lib/libc/stdlib/hdestroy_r.c", + "upstream-freebsd/lib/libc/stdlib/hsearch_r.c", + "upstream-freebsd/lib/libc/stdlib/qsort.c", + "upstream-freebsd/lib/libc/stdlib/quick_exit.c", + "upstream-freebsd/lib/libc/string/wcpcpy.c", + "upstream-freebsd/lib/libc/string/wcpncpy.c", + "upstream-freebsd/lib/libc/string/wcscasecmp.c", + "upstream-freebsd/lib/libc/string/wcscat.c", + "upstream-freebsd/lib/libc/string/wcschr.c", + "upstream-freebsd/lib/libc/string/wcscmp.c", + "upstream-freebsd/lib/libc/string/wcscpy.c", + "upstream-freebsd/lib/libc/string/wcscspn.c", + "upstream-freebsd/lib/libc/string/wcsdup.c", + "upstream-freebsd/lib/libc/string/wcslcat.c", + "upstream-freebsd/lib/libc/string/wcslen.c", + "upstream-freebsd/lib/libc/string/wcsncasecmp.c", + "upstream-freebsd/lib/libc/string/wcsncat.c", + "upstream-freebsd/lib/libc/string/wcsncmp.c", + "upstream-freebsd/lib/libc/string/wcsncpy.c", + "upstream-freebsd/lib/libc/string/wcsnlen.c", + "upstream-freebsd/lib/libc/string/wcspbrk.c", + "upstream-freebsd/lib/libc/string/wcsrchr.c", + "upstream-freebsd/lib/libc/string/wcsspn.c", + "upstream-freebsd/lib/libc/string/wcsstr.c", + "upstream-freebsd/lib/libc/string/wcstok.c", + "upstream-freebsd/lib/libc/string/wmemchr.c", + "upstream-freebsd/lib/libc/string/wmemcmp.c", + "upstream-freebsd/lib/libc/string/wmemcpy.c", + "upstream-freebsd/lib/libc/string/wmemmove.c", + "upstream-freebsd/lib/libc/string/wmemset.c", + ], + arch: { + arm64: { + exclude_srcs: [ + "upstream-freebsd/lib/libc/string/wmemmove.c", + ], + }, + x86: { + exclude_srcs: [ + "upstream-freebsd/lib/libc/string/wcschr.c", + "upstream-freebsd/lib/libc/string/wcscmp.c", + "upstream-freebsd/lib/libc/string/wcslen.c", + "upstream-freebsd/lib/libc/string/wcsrchr.c", + "upstream-freebsd/lib/libc/string/wmemcmp.c", + "upstream-freebsd/lib/libc/string/wcscat.c", + "upstream-freebsd/lib/libc/string/wcscpy.c", + "upstream-freebsd/lib/libc/string/wmemcmp.c", + "upstream-freebsd/lib/libc/string/wmemset.c", + ], + }, + }, + + cflags: [ + "-Wno-sign-compare", + "-Wno-unused-parameter", + "-include freebsd-compat.h", + ], + + local_include_dirs: [ + "upstream-freebsd/android/include", + ], + + name: "libc_freebsd", +} + +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "upstream-freebsd/lib/libc/gen/glob.c", + ], + + cflags: [ + "-Wno-sign-compare", + "-include freebsd-compat.h", + "-Wframe-larger-than=66000", + ], + + local_include_dirs: [ + "upstream-freebsd/android/include", + ], + + name: "libc_freebsd_large_stack", +} + +// ======================================================== +// libc_netbsd.a - upstream NetBSD C library code +// ======================================================== +// +// These files are built with the netbsd-compat.h header file +// automatically included. + +cc_library_static { + + defaults: ["libc_defaults"], + srcs: [ + "upstream-netbsd/common/lib/libc/stdlib/random.c", + "upstream-netbsd/lib/libc/gen/nice.c", + "upstream-netbsd/lib/libc/gen/psignal.c", + "upstream-netbsd/lib/libc/gen/utime.c", + "upstream-netbsd/lib/libc/gen/utmp.c", + "upstream-netbsd/lib/libc/inet/nsap_addr.c", + "upstream-netbsd/lib/libc/regex/regcomp.c", + "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/stdlib/bsearch.c", + "upstream-netbsd/lib/libc/stdlib/drand48.c", + "upstream-netbsd/lib/libc/stdlib/erand48.c", + "upstream-netbsd/lib/libc/stdlib/jrand48.c", + "upstream-netbsd/lib/libc/stdlib/lcong48.c", + "upstream-netbsd/lib/libc/stdlib/lrand48.c", + "upstream-netbsd/lib/libc/stdlib/mrand48.c", + "upstream-netbsd/lib/libc/stdlib/nrand48.c", + "upstream-netbsd/lib/libc/stdlib/_rand48.c", + "upstream-netbsd/lib/libc/stdlib/rand_r.c", + "upstream-netbsd/lib/libc/stdlib/reallocarr.c", + "upstream-netbsd/lib/libc/stdlib/seed48.c", + "upstream-netbsd/lib/libc/stdlib/srand48.c", + ], + multilib: { + lib32: { + // LP32 cruft + srcs: ["upstream-netbsd/common/lib/libc/hash/sha1/sha1.c"], + }, + }, + cflags: [ + "-Wno-sign-compare", + "-Wno-unused-parameter", + "-DPOSIX_MISTAKE", + "-include netbsd-compat.h", + ], + + local_include_dirs: [ + "upstream-netbsd/android/include", + "upstream-netbsd/lib/libc/include", + ], + + name: "libc_netbsd", +} + +// ======================================================== +// libc_openbsd_ndk.a - upstream OpenBSD C library code +// that can be safely included in the libc_ndk.a (doesn't +// contain any troublesome global data or constructors). +// ======================================================== +// +// These files are built with the openbsd-compat.h header file +// automatically included. + +cc_library_static { + name: "libc_openbsd_ndk", + defaults: ["libc_defaults"], + srcs: [ + "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/fnmatch.c", + "upstream-openbsd/lib/libc/gen/ftok.c", + "upstream-openbsd/lib/libc/gen/getprogname.c", + "upstream-openbsd/lib/libc/gen/setprogname.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", + "upstream-openbsd/lib/libc/locale/mbtowc.c", + "upstream-openbsd/lib/libc/locale/wcscoll.c", + "upstream-openbsd/lib/libc/locale/wcstoimax.c", + "upstream-openbsd/lib/libc/locale/wcstol.c", + "upstream-openbsd/lib/libc/locale/wcstoll.c", + "upstream-openbsd/lib/libc/locale/wcstombs.c", + "upstream-openbsd/lib/libc/locale/wcstoul.c", + "upstream-openbsd/lib/libc/locale/wcstoull.c", + "upstream-openbsd/lib/libc/locale/wcstoumax.c", + "upstream-openbsd/lib/libc/locale/wcsxfrm.c", + "upstream-openbsd/lib/libc/locale/wctob.c", + "upstream-openbsd/lib/libc/locale/wctomb.c", + "upstream-openbsd/lib/libc/net/base64.c", + "upstream-openbsd/lib/libc/net/htonl.c", + "upstream-openbsd/lib/libc/net/htons.c", + "upstream-openbsd/lib/libc/net/inet_lnaof.c", + "upstream-openbsd/lib/libc/net/inet_makeaddr.c", + "upstream-openbsd/lib/libc/net/inet_netof.c", + "upstream-openbsd/lib/libc/net/inet_ntoa.c", + "upstream-openbsd/lib/libc/net/inet_ntop.c", + "upstream-openbsd/lib/libc/net/inet_pton.c", + "upstream-openbsd/lib/libc/net/ntohl.c", + "upstream-openbsd/lib/libc/net/ntohs.c", + "upstream-openbsd/lib/libc/net/res_random.c", + "upstream-openbsd/lib/libc/stdio/fgetln.c", + "upstream-openbsd/lib/libc/stdio/fgetwc.c", + "upstream-openbsd/lib/libc/stdio/fgetws.c", + "upstream-openbsd/lib/libc/stdio/flags.c", + "upstream-openbsd/lib/libc/stdio/fpurge.c", + "upstream-openbsd/lib/libc/stdio/fputwc.c", + "upstream-openbsd/lib/libc/stdio/fputws.c", + "upstream-openbsd/lib/libc/stdio/fvwrite.c", + "upstream-openbsd/lib/libc/stdio/fwide.c", + "upstream-openbsd/lib/libc/stdio/getdelim.c", + "upstream-openbsd/lib/libc/stdio/gets.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/rget.c", + "upstream-openbsd/lib/libc/stdio/setvbuf.c", + "upstream-openbsd/lib/libc/stdio/tempnam.c", + "upstream-openbsd/lib/libc/stdio/tmpnam.c", + "upstream-openbsd/lib/libc/stdio/ungetc.c", + "upstream-openbsd/lib/libc/stdio/ungetwc.c", + "upstream-openbsd/lib/libc/stdio/vasprintf.c", + "upstream-openbsd/lib/libc/stdio/vdprintf.c", + "upstream-openbsd/lib/libc/stdio/vsscanf.c", + "upstream-openbsd/lib/libc/stdio/vswprintf.c", + "upstream-openbsd/lib/libc/stdio/vswscanf.c", + "upstream-openbsd/lib/libc/stdio/wbuf.c", + "upstream-openbsd/lib/libc/stdio/wsetup.c", + "upstream-openbsd/lib/libc/stdlib/abs.c", + "upstream-openbsd/lib/libc/stdlib/div.c", + "upstream-openbsd/lib/libc/stdlib/getenv.c", + "upstream-openbsd/lib/libc/stdlib/getsubopt.c", + "upstream-openbsd/lib/libc/stdlib/insque.c", + "upstream-openbsd/lib/libc/stdlib/imaxabs.c", + "upstream-openbsd/lib/libc/stdlib/imaxdiv.c", + "upstream-openbsd/lib/libc/stdlib/labs.c", + "upstream-openbsd/lib/libc/stdlib/ldiv.c", + "upstream-openbsd/lib/libc/stdlib/llabs.c", + "upstream-openbsd/lib/libc/stdlib/lldiv.c", + "upstream-openbsd/lib/libc/stdlib/lsearch.c", + "upstream-openbsd/lib/libc/stdlib/remque.c", + "upstream-openbsd/lib/libc/stdlib/setenv.c", + "upstream-openbsd/lib/libc/stdlib/tfind.c", + "upstream-openbsd/lib/libc/stdlib/tsearch.c", + "upstream-openbsd/lib/libc/string/memccpy.c", + "upstream-openbsd/lib/libc/string/strcasecmp.c", + "upstream-openbsd/lib/libc/string/strcasestr.c", + "upstream-openbsd/lib/libc/string/strcoll.c", + "upstream-openbsd/lib/libc/string/strcspn.c", + "upstream-openbsd/lib/libc/string/strdup.c", + "upstream-openbsd/lib/libc/string/strndup.c", + "upstream-openbsd/lib/libc/string/strpbrk.c", + "upstream-openbsd/lib/libc/string/strsep.c", + "upstream-openbsd/lib/libc/string/strspn.c", + "upstream-openbsd/lib/libc/string/strtok.c", + "upstream-openbsd/lib/libc/string/strxfrm.c", + "upstream-openbsd/lib/libc/string/wcslcpy.c", + "upstream-openbsd/lib/libc/string/wcswidth.c", + ], + + cflags: [ + "-Wno-sign-compare", + "-Wno-unused-parameter", + "-include openbsd-compat.h", + ], + + local_include_dirs: [ + "private", + "stdio", + "upstream-openbsd/android/include", + "upstream-openbsd/lib/libc/include", + "upstream-openbsd/lib/libc/gdtoa/", + ], +} + +cc_library_static { + name: "libc_openbsd_large_stack", + defaults: ["libc_defaults"], + srcs: [ + "stdio/vfprintf.cpp", + "stdio/vfwprintf.cpp", + "upstream-openbsd/lib/libc/string/strstr.c", + ], + cflags: [ + "-include openbsd-compat.h", + "-Wno-sign-compare", + "-Wframe-larger-than=5000", + ], + + local_include_dirs: [ + "upstream-openbsd/android/include/", + "upstream-openbsd/lib/libc/include/", + "upstream-openbsd/lib/libc/gdtoa/", + "upstream-openbsd/lib/libc/stdio/", + ], +} + +// ======================================================== +// libc_openbsd.a - upstream OpenBSD C library code +// ======================================================== +// +// These files are built with the openbsd-compat.h header file +// automatically included. +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + // These two depend on getentropy, which isn't in libc_ndk.a. + "upstream-openbsd/lib/libc/crypt/arc4random.c", + "upstream-openbsd/lib/libc/crypt/arc4random_uniform.c", + + // May be overriden by per-arch optimized versions + "upstream-openbsd/lib/libc/string/memchr.c", + "upstream-openbsd/lib/libc/string/memrchr.c", + "upstream-openbsd/lib/libc/string/stpcpy.c", + "upstream-openbsd/lib/libc/string/stpncpy.c", + "upstream-openbsd/lib/libc/string/strcat.c", + "upstream-openbsd/lib/libc/string/strcpy.c", + "upstream-openbsd/lib/libc/string/strlcat.c", + "upstream-openbsd/lib/libc/string/strlcpy.c", + "upstream-openbsd/lib/libc/string/strncat.c", + "upstream-openbsd/lib/libc/string/strncmp.c", + "upstream-openbsd/lib/libc/string/strncpy.c", + ], + + arch: { + arm: { + exclude_srcs: [ + "upstream-openbsd/lib/libc/string/strcpy.c", + "upstream-openbsd/lib/libc/string/stpcpy.c", + "upstream-openbsd/lib/libc/string/strcat.c", + ], + }, + arm64: { + exclude_srcs: [ + "upstream-openbsd/lib/libc/string/memchr.c", + "upstream-openbsd/lib/libc/string/stpcpy.c", + "upstream-openbsd/lib/libc/string/strcpy.c", + "upstream-openbsd/lib/libc/string/strncmp.c", + ], + }, + x86: { + exclude_srcs: [ + "upstream-openbsd/lib/libc/string/memchr.c", + "upstream-openbsd/lib/libc/string/memrchr.c", + "upstream-openbsd/lib/libc/string/stpcpy.c", + "upstream-openbsd/lib/libc/string/stpncpy.c", + "upstream-openbsd/lib/libc/string/strcat.c", + "upstream-openbsd/lib/libc/string/strcpy.c", + "upstream-openbsd/lib/libc/string/strncmp.c", + "upstream-openbsd/lib/libc/string/strncpy.c", + "upstream-openbsd/lib/libc/string/strlcat.c", + "upstream-openbsd/lib/libc/string/strlcpy.c", + "upstream-openbsd/lib/libc/string/strncat.c", + ], + }, + + x86_64: { + exclude_srcs: [ + "upstream-openbsd/lib/libc/string/stpcpy.c", + "upstream-openbsd/lib/libc/string/stpncpy.c", + "upstream-openbsd/lib/libc/string/strcat.c", + "upstream-openbsd/lib/libc/string/strcpy.c", + "upstream-openbsd/lib/libc/string/strncat.c", + "upstream-openbsd/lib/libc/string/strncmp.c", + "upstream-openbsd/lib/libc/string/strncpy.c", + ], + }, + }, + + cflags: [ + "-Wno-sign-compare", + "-Wno-unused-parameter", + "-include openbsd-compat.h", + ], + + local_include_dirs: [ + "private", + "upstream-openbsd/android/include", + ], + + name: "libc_openbsd", +} + +// ======================================================== +// libc_gdtoa.a - upstream OpenBSD C library gdtoa code +// ======================================================== +// +// These files are built with the openbsd-compat.h header file +// automatically included. + +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "upstream-openbsd/android/gdtoa_support.cpp", + "upstream-openbsd/lib/libc/gdtoa/dmisc.c", + "upstream-openbsd/lib/libc/gdtoa/dtoa.c", + "upstream-openbsd/lib/libc/gdtoa/gdtoa.c", + "upstream-openbsd/lib/libc/gdtoa/gethex.c", + "upstream-openbsd/lib/libc/gdtoa/gmisc.c", + "upstream-openbsd/lib/libc/gdtoa/hd_init.c", + "upstream-openbsd/lib/libc/gdtoa/hdtoa.c", + "upstream-openbsd/lib/libc/gdtoa/hexnan.c", + "upstream-openbsd/lib/libc/gdtoa/ldtoa.c", + "upstream-openbsd/lib/libc/gdtoa/misc.c", + "upstream-openbsd/lib/libc/gdtoa/smisc.c", + "upstream-openbsd/lib/libc/gdtoa/strtod.c", + "upstream-openbsd/lib/libc/gdtoa/strtodg.c", + "upstream-openbsd/lib/libc/gdtoa/strtof.c", + "upstream-openbsd/lib/libc/gdtoa/strtord.c", + "upstream-openbsd/lib/libc/gdtoa/sum.c", + "upstream-openbsd/lib/libc/gdtoa/ulp.c", + ], + multilib: { + lib64: { + srcs: ["upstream-openbsd/lib/libc/gdtoa/strtorQ.c"], + }, + }, + + cflags: [ + "-Wno-sign-compare", + "-include openbsd-compat.h", + ], + + local_include_dirs: [ + "private", + "upstream-openbsd/android/include", + "upstream-openbsd/lib/libc/include", + ], + + name: "libc_gdtoa", +} + +// ======================================================== +// libc_fortify.a - container for our FORITFY +// implementation details +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + srcs: ["bionic/fortify.cpp"], + + name: "libc_fortify", + + // Disable FORTIFY for the compilation of these, so we don't end up having + // FORTIFY silently call itself. + cflags: [ + "-U_FORTIFY_SOURCE", + "-D__BIONIC_DECLARE_FORTIFY_HELPERS", + ], + + arch: { + arm: { + cflags: [ + "-DNO___MEMCPY_CHK", + "-DRENAME___STRCAT_CHK", + "-DRENAME___STRCPY_CHK", + ], + srcs: [ + "arch-arm/generic/bionic/__memcpy_chk.S", + + "arch-arm/cortex-a15/bionic/__strcat_chk.S", + "arch-arm/cortex-a15/bionic/__strcpy_chk.S", + + "arch-arm/cortex-a7/bionic/__strcat_chk.S", + "arch-arm/cortex-a7/bionic/__strcpy_chk.S", + + "arch-arm/cortex-a9/bionic/__strcat_chk.S", + "arch-arm/cortex-a9/bionic/__strcpy_chk.S", + + "arch-arm/krait/bionic/__strcat_chk.S", + "arch-arm/krait/bionic/__strcpy_chk.S", + + "arch-arm/cortex-a53/bionic/__strcat_chk.S", + "arch-arm/cortex-a53/bionic/__strcpy_chk.S", + + "arch-arm/cortex-a55/bionic/__strcat_chk.S", + "arch-arm/cortex-a55/bionic/__strcpy_chk.S", + ], + }, + arm64: { + cflags: ["-DNO___MEMCPY_CHK"], + srcs: [ + "arch-arm64/generic/bionic/__memcpy_chk.S", + ], + }, + }, +} + +// ======================================================== +// libc_bionic.a - home-grown C library code +// ======================================================== + +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + // These require getauxval, which isn't available on older platforms. + "bionic/sysconf.cpp", + "bionic/vdso.cpp", + "bionic/setjmp_cookie.cpp", + + // The following must not be statically linked into libc_ndk.a, because + // debuggerd will look for the abort message in libc.so's copy. + "bionic/android_set_abort_message.cpp", + + "bionic/strchr.cpp", + "bionic/strnlen.c", + "bionic/strrchr.cpp", + ], + + arch: { + arm: { + asflags: libc_common_flags + ["-mno-restrict-it"], + srcs: [ + "arch-arm/generic/bionic/memcmp.S", + "arch-arm/generic/bionic/memmove.S", + "arch-arm/generic/bionic/memset.S", + "arch-arm/generic/bionic/stpcpy.c", + "arch-arm/generic/bionic/strcat.c", + "arch-arm/generic/bionic/strcmp.S", + "arch-arm/generic/bionic/strcpy.S", + "arch-arm/generic/bionic/strlen.c", + + "arch-arm/bionic/__aeabi_read_tp.S", + "arch-arm/bionic/__bionic_clone.S", + "arch-arm/bionic/__restore.S", + "arch-arm/bionic/_exit_with_stack_teardown.S", + "arch-arm/bionic/atomics_arm.c", + "arch-arm/bionic/bpabi.c", + "arch-arm/bionic/libcrt_compat.c", + "arch-arm/bionic/popcount_tab.c", + "arch-arm/bionic/setjmp.S", + "arch-arm/bionic/syscall.S", + "arch-arm/bionic/vfork.S", + + "arch-arm/cortex-a15/bionic/memcpy.S", + "arch-arm/cortex-a15/bionic/memmove.S", + "arch-arm/cortex-a15/bionic/memset.S", + "arch-arm/cortex-a15/bionic/stpcpy.S", + "arch-arm/cortex-a15/bionic/strcat.S", + "arch-arm/cortex-a15/bionic/strcmp.S", + "arch-arm/cortex-a15/bionic/strcpy.S", + "arch-arm/cortex-a15/bionic/strlen.S", + + "arch-arm/cortex-a7/bionic/memcpy.S", + "arch-arm/cortex-a7/bionic/memset.S", + + "arch-arm/cortex-a9/bionic/memcpy.S", + "arch-arm/cortex-a9/bionic/memset.S", + "arch-arm/cortex-a9/bionic/stpcpy.S", + "arch-arm/cortex-a9/bionic/strcat.S", + "arch-arm/cortex-a9/bionic/strcpy.S", + "arch-arm/cortex-a9/bionic/strlen.S", + + "arch-arm/krait/bionic/memcpy.S", + "arch-arm/krait/bionic/memset.S", + + "arch-arm/cortex-a53/bionic/memcpy.S", + + "arch-arm/cortex-a55/bionic/memcpy.S", + + "arch-arm/kryo/bionic/memcpy.S", + ], + }, + arm64: { + srcs: [ + "arch-arm64/generic/bionic/memcmp.S", + "arch-arm64/generic/bionic/memcpy.S", + "arch-arm64/generic/bionic/memmove.S", + "arch-arm64/generic/bionic/memset.S", + "arch-arm64/generic/bionic/stpcpy.S", + "arch-arm64/generic/bionic/strcpy.S", + "arch-arm64/generic/bionic/wmemmove.S", + + "arch-arm64/default/bionic/memchr.S", + "arch-arm64/default/bionic/strchr.S", + "arch-arm64/default/bionic/strcmp.S", + "arch-arm64/default/bionic/strlen.S", + "arch-arm64/default/bionic/strncmp.S", + "arch-arm64/default/bionic/strnlen.S", + + "arch-arm64/mte/bionic/memchr.c", + "arch-arm64/mte/bionic/strchr.cpp", + "arch-arm64/mte/bionic/strcmp.c", + "arch-arm64/mte/bionic/strlen.c", + "arch-arm64/mte/bionic/strncmp.c", + "arch-arm64/mte/bionic/strnlen.c", + + "arch-arm64/bionic/__bionic_clone.S", + "arch-arm64/bionic/_exit_with_stack_teardown.S", + "arch-arm64/bionic/setjmp.S", + "arch-arm64/bionic/syscall.S", + "arch-arm64/bionic/vfork.S", + ], + exclude_srcs: [ + "bionic/__memcpy_chk.cpp", + "bionic/strchr.cpp", + "bionic/strnlen.c", + ], + }, + + x86: { + srcs: [ + "arch-x86/generic/string/memcmp.S", + "arch-x86/generic/string/strcmp.S", + "arch-x86/generic/string/strncmp.S", + "arch-x86/generic/string/strcat.S", + + "arch-x86/generic/string/strlcat.c", + "arch-x86/generic/string/strlcpy.c", + "arch-x86/generic/string/strncat.c", + "arch-x86/generic/string/wcscat.c", + "arch-x86/generic/string/wcscpy.c", + "arch-x86/generic/string/wmemcmp.c", + "arch-x86/generic/string/wmemset.c", + + "arch-x86/atom/string/sse2-memchr-atom.S", + "arch-x86/atom/string/sse2-memrchr-atom.S", + "arch-x86/atom/string/sse2-strchr-atom.S", + "arch-x86/atom/string/sse2-strnlen-atom.S", + "arch-x86/atom/string/sse2-strrchr-atom.S", + "arch-x86/atom/string/sse2-wcschr-atom.S", + "arch-x86/atom/string/sse2-wcsrchr-atom.S", + "arch-x86/atom/string/sse2-wcslen-atom.S", + "arch-x86/atom/string/sse2-wcscmp-atom.S", + "arch-x86/silvermont/string/sse2-memmove-slm.S", + "arch-x86/silvermont/string/sse2-memset-slm.S", + "arch-x86/silvermont/string/sse2-stpcpy-slm.S", + "arch-x86/silvermont/string/sse2-stpncpy-slm.S", + "arch-x86/silvermont/string/sse2-strcpy-slm.S", + "arch-x86/silvermont/string/sse2-strlen-slm.S", + "arch-x86/silvermont/string/sse2-strncpy-slm.S", + + "arch-x86/bionic/__bionic_clone.S", + "arch-x86/bionic/_exit_with_stack_teardown.S", + "arch-x86/bionic/libcrt_compat.c", + "arch-x86/bionic/__restore.S", + "arch-x86/bionic/setjmp.S", + "arch-x86/bionic/syscall.S", + "arch-x86/bionic/vfork.S", + + // ssse3 functions + "arch-x86/atom/string/ssse3-strcat-atom.S", + "arch-x86/atom/string/ssse3-strcmp-atom.S", + "arch-x86/atom/string/ssse3-strlcat-atom.S", + "arch-x86/atom/string/ssse3-strlcpy-atom.S", + "arch-x86/atom/string/ssse3-strncat-atom.S", + "arch-x86/atom/string/ssse3-strncmp-atom.S", + "arch-x86/atom/string/ssse3-wcscat-atom.S", + "arch-x86/atom/string/ssse3-wcscpy-atom.S", + + // sse4 functions + "arch-x86/silvermont/string/sse4-memcmp-slm.S", + "arch-x86/silvermont/string/sse4-wmemcmp-slm.S", + + // atom functions + "arch-x86/atom/string/sse2-memset-atom.S", + "arch-x86/atom/string/sse2-strlen-atom.S", + "arch-x86/atom/string/ssse3-memcmp-atom.S", + "arch-x86/atom/string/ssse3-memmove-atom.S", + "arch-x86/atom/string/ssse3-strcpy-atom.S", + "arch-x86/atom/string/ssse3-strncpy-atom.S", + "arch-x86/atom/string/ssse3-wmemcmp-atom.S", + + // avx2 functions + "arch-x86/kabylake/string/avx2-wmemset-kbl.S", + ], + + exclude_srcs: [ + "bionic/strchr.cpp", + "bionic/strnlen.c", + "bionic/strrchr.cpp", + ], + }, + x86_64: { + srcs: [ + "arch-x86_64/string/sse2-memmove-slm.S", + "arch-x86_64/string/sse2-memset-slm.S", + "arch-x86_64/string/sse2-stpcpy-slm.S", + "arch-x86_64/string/sse2-stpncpy-slm.S", + "arch-x86_64/string/sse2-strcat-slm.S", + "arch-x86_64/string/sse2-strcpy-slm.S", + "arch-x86_64/string/sse2-strlen-slm.S", + "arch-x86_64/string/sse2-strncat-slm.S", + "arch-x86_64/string/sse2-strncpy-slm.S", + "arch-x86_64/string/sse4-memcmp-slm.S", + "arch-x86_64/string/ssse3-strcmp-slm.S", + "arch-x86_64/string/ssse3-strncmp-slm.S", + "arch-x86_64/string/avx2-wmemset-kbl.S", + + "arch-x86_64/bionic/__bionic_clone.S", + "arch-x86_64/bionic/_exit_with_stack_teardown.S", + "arch-x86_64/bionic/__restore_rt.S", + "arch-x86_64/bionic/setjmp.S", + "arch-x86_64/bionic/syscall.S", + "arch-x86_64/bionic/vfork.S", + ], + }, + }, + + cppflags: ["-Wold-style-cast"], + include_dirs: ["bionic/libstdc++/include"], + name: "libc_bionic", +} + +genrule { + name: "generated_android_ids", + out: ["generated_android_ids.h"], + srcs: [":android_filesystem_config_header"], + tool_files: ["fs_config_generator.py"], + cmd: "$(location fs_config_generator.py) aidarray $(in) > $(out)", +} + +// ======================================================== +// libc_bionic_ndk.a- The portions of libc_bionic that can +// be safely used in libc_ndk.a (no troublesome global data +// or constructors). +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "bionic/NetdClientDispatch.cpp", + "bionic/__bionic_get_shell_path.cpp", + "bionic/__cmsg_nxthdr.cpp", + "bionic/__errno.cpp", + "bionic/__gnu_basename.cpp", + "bionic/__libc_current_sigrtmax.cpp", + "bionic/__libc_current_sigrtmin.cpp", + "bionic/abort.cpp", + "bionic/accept.cpp", + "bionic/access.cpp", + "bionic/arpa_inet.cpp", + "bionic/assert.cpp", + "bionic/atof.cpp", + "bionic/bionic_allocator.cpp", + "bionic/bionic_arc4random.cpp", + "bionic/bionic_futex.cpp", + "bionic/bionic_netlink.cpp", + "bionic/bionic_systrace.cpp", + "bionic/bionic_time_conversions.cpp", + "bionic/brk.cpp", + "bionic/c16rtomb.cpp", + "bionic/c32rtomb.cpp", + "bionic/chmod.cpp", + "bionic/chown.cpp", + "bionic/clearenv.cpp", + "bionic/clock.cpp", + "bionic/clock_getcpuclockid.cpp", + "bionic/clock_nanosleep.cpp", + "bionic/clone.cpp", + "bionic/ctype.cpp", + "bionic/dirent.cpp", + "bionic/dup.cpp", + "bionic/environ.cpp", + "bionic/error.cpp", + "bionic/eventfd.cpp", + "bionic/exec.cpp", + "bionic/faccessat.cpp", + "bionic/fchmod.cpp", + "bionic/fchmodat.cpp", + "bionic/fcntl.cpp", + "bionic/fdsan.cpp", + "bionic/fdtrack.cpp", + "bionic/ffs.cpp", + "bionic/fgetxattr.cpp", + "bionic/flistxattr.cpp", + "bionic/flockfile.cpp", + "bionic/fpclassify.cpp", + "bionic/fsetxattr.cpp", + "bionic/ftruncate.cpp", + "bionic/ftw.cpp", + "bionic/futimens.cpp", + "bionic/getcwd.cpp", + "bionic/getdomainname.cpp", + "bionic/getentropy.cpp", + "bionic/gethostname.cpp", + "bionic/getloadavg.cpp", + "bionic/getpagesize.cpp", + "bionic/getpgrp.cpp", + "bionic/getpid.cpp", + "bionic/getpriority.cpp", + "bionic/gettid.cpp", + "bionic/get_device_api_level.cpp", + "bionic/grp_pwd.cpp", + "bionic/grp_pwd_file.cpp", + "bionic/iconv.cpp", + "bionic/icu_wrappers.cpp", + "bionic/ifaddrs.cpp", + "bionic/inotify_init.cpp", + "bionic/ioctl.cpp", + "bionic/killpg.cpp", + "bionic/langinfo.cpp", + "bionic/lchown.cpp", + "bionic/lfs64_support.cpp", + "bionic/libc_init_common.cpp", + "bionic/libgen.cpp", + "bionic/link.cpp", + "bionic/locale.cpp", + "bionic/lockf.cpp", + "bionic/lstat.cpp", + "bionic/mblen.cpp", + "bionic/mbrtoc16.cpp", + "bionic/mbrtoc32.cpp", + "bionic/memmem.cpp", + "bionic/mempcpy.cpp", + "bionic/mkdir.cpp", + "bionic/mkfifo.cpp", + "bionic/mknod.cpp", + "bionic/mntent.cpp", + "bionic/mremap.cpp", + "bionic/net_if.cpp", + "bionic/netdb.cpp", + "bionic/netinet_in.cpp", + "bionic/nl_types.cpp", + "bionic/open.cpp", + "bionic/pathconf.cpp", + "bionic/pause.cpp", + "bionic/pipe.cpp", + "bionic/poll.cpp", + "bionic/posix_fadvise.cpp", + "bionic/posix_fallocate.cpp", + "bionic/posix_madvise.cpp", + "bionic/posix_timers.cpp", + "bionic/ptrace.cpp", + "bionic/pty.cpp", + "bionic/raise.cpp", + "bionic/rand.cpp", + "bionic/readlink.cpp", + "bionic/realpath.cpp", + "bionic/reboot.cpp", + "bionic/recv.cpp", + "bionic/recvmsg.cpp", + "bionic/rename.cpp", + "bionic/rmdir.cpp", + "bionic/scandir.cpp", + "bionic/sched_getaffinity.cpp", + "bionic/sched_getcpu.cpp", + "bionic/semaphore.cpp", + "bionic/send.cpp", + "bionic/setegid.cpp", + "bionic/seteuid.cpp", + "bionic/setpgrp.cpp", + "bionic/sigaction.cpp", + "bionic/signal.cpp", + "bionic/sigprocmask.cpp", + "bionic/sleep.cpp", + "bionic/socketpair.cpp", + "bionic/spawn.cpp", + "bionic/stat.cpp", + "bionic/stdlib_l.cpp", + "bionic/strchrnul.cpp", + "bionic/strerror.cpp", + "bionic/string_l.cpp", + "bionic/strings_l.cpp", + "bionic/strsignal.cpp", + "bionic/strtol.cpp", + "bionic/strtold.cpp", + "bionic/swab.cpp", + "bionic/symlink.cpp", + "bionic/sync_file_range.cpp", + "bionic/sys_epoll.cpp", + "bionic/sys_msg.cpp", + "bionic/sys_sem.cpp", + "bionic/sys_shm.cpp", + "bionic/sys_signalfd.cpp", + "bionic/sys_statfs.cpp", + "bionic/sys_statvfs.cpp", + "bionic/sys_time.cpp", + "bionic/sysinfo.cpp", + "bionic/syslog.cpp", + "bionic/system.cpp", + "bionic/system_property_api.cpp", + "bionic/system_property_set.cpp", + "bionic/tdestroy.cpp", + "bionic/termios.cpp", + "bionic/thread_private.cpp", + "bionic/threads.cpp", + "bionic/timespec_get.cpp", + "bionic/tmpfile.cpp", + "bionic/umount.cpp", + "bionic/unlink.cpp", + "bionic/usleep.cpp", + "bionic/wait.cpp", + "bionic/wchar.cpp", + "bionic/wchar_l.cpp", + "bionic/wcstod.cpp", + "bionic/wctype.cpp", + "bionic/wcwidth.cpp", + "bionic/wmempcpy.cpp", + + // This contains a weak stub implementation of __find_icu_symbol for wctype.cpp, + // which will be overridden by the actual one in libc.so. + "bionic/icu_static.cpp", + ], + + multilib: { + lib32: { + // LP32 cruft + srcs: ["bionic/mmap.cpp"], + }, + }, + product_variables: { + treble_linker_namespaces: { + cflags: ["-DTREBLE_LINKER_NAMESPACES"], + }, + }, + whole_static_libs: ["libsystemproperties"], + cppflags: ["-Wold-style-cast"], + local_include_dirs: ["stdio"], + include_dirs: ["bionic/libstdc++/include"], + name: "libc_bionic_ndk", + generated_headers: ["generated_android_ids"], +} + +// ======================================================== +// libc_pthread.a - pthreads parts that previously lived in +// libc_bionic.a. Relocated to their own library because +// they can't be included in libc_ndk.a (as the layout of +// pthread_t has changed over the years and has ABI +// compatibility issues). +// ======================================================== + +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "bionic/bionic_elf_tls.cpp", + "bionic/pthread_atfork.cpp", + "bionic/pthread_attr.cpp", + "bionic/pthread_barrier.cpp", + "bionic/pthread_cond.cpp", + "bionic/pthread_create.cpp", + "bionic/pthread_detach.cpp", + "bionic/pthread_equal.cpp", + "bionic/pthread_exit.cpp", + "bionic/pthread_getcpuclockid.cpp", + "bionic/pthread_getschedparam.cpp", + "bionic/pthread_gettid_np.cpp", + "bionic/pthread_internal.cpp", + "bionic/pthread_join.cpp", + "bionic/pthread_key.cpp", + "bionic/pthread_kill.cpp", + "bionic/pthread_mutex.cpp", + "bionic/pthread_once.cpp", + "bionic/pthread_rwlock.cpp", + "bionic/pthread_sigqueue.cpp", + "bionic/pthread_self.cpp", + "bionic/pthread_setname_np.cpp", + "bionic/pthread_setschedparam.cpp", + "bionic/pthread_spinlock.cpp", + + // The following implementations depend on pthread data or implementation, + // so we can't include them in libc_ndk.a. + "bionic/__cxa_thread_atexit_impl.cpp", + "bionic/android_unsafe_frame_pointer_chase.cpp", + "bionic/atexit.cpp", + "bionic/fork.cpp", + ], + + cppflags: ["-Wold-style-cast"], + include_dirs: ["bionic/libstdc++/include"], + header_libs: ["bionic_libc_platform_headers"], + name: "libc_pthread", +} + +// ======================================================== +// libc_syscalls.a +// ======================================================== + +genrule { + name: "syscalls-arm.S", + out: ["syscalls-arm.S"], + srcs: ["SYSCALLS.TXT"], + tool_files: [":bionic-gensyscalls"], + cmd: "$(location :bionic-gensyscalls) arm $(in) > $(out)", +} + +genrule { + name: "syscalls-arm64.S", + out: ["syscalls-arm64.S"], + srcs: ["SYSCALLS.TXT"], + tool_files: [":bionic-gensyscalls"], + cmd: "$(location :bionic-gensyscalls) arm64 $(in) > $(out)", +} + +genrule { + name: "syscalls-x86.S", + out: ["syscalls-x86.S"], + srcs: ["SYSCALLS.TXT"], + tool_files: [":bionic-gensyscalls"], + cmd: "$(location :bionic-gensyscalls) x86 $(in) > $(out)", +} + +genrule { + name: "syscalls-x86_64.S", + out: ["syscalls-x86_64.S"], + srcs: ["SYSCALLS.TXT"], + tool_files: [":bionic-gensyscalls"], + cmd: "$(location :bionic-gensyscalls) x86_64 $(in) > $(out)", +} + +cc_library_static { + defaults: ["libc_defaults"], + srcs: ["bionic/__set_errno.cpp"], + arch: { + arm: { + srcs: [":syscalls-arm.S"], + }, + arm64: { + srcs: [":syscalls-arm64.S"], + }, + x86: { + srcs: [":syscalls-x86.S"], + }, + x86_64: { + srcs: [":syscalls-x86_64.S"], + }, + }, + name: "libc_syscalls", +} + +// ======================================================== +// libc_aeabi.a +// This is an LP32 ARM-only library that needs to be built with -fno-builtin +// to avoid infinite recursion. For the other architectures we just build an +// empty library to keep this makefile simple. +// ======================================================== + +cc_library_static { + defaults: ["libc_defaults"], + arch: { + arm: { + srcs: ["arch-arm/bionic/__aeabi.c"], + }, + }, + name: "libc_aeabi", + cflags: ["-fno-builtin"], +} + +// ======================================================== +// libc_ndk.a +// Compatibility library for the NDK. This library contains +// all the parts of libc that are safe to statically link. +// We can't safely statically link things that can only run +// on a certain version of the OS. Examples include +// anything that talks to netd (a large portion of the DNS +// code) and anything that is dependent on the layout of a +// data structure that has changed across releases (such as +// pthread_t). +// ======================================================== + +cc_library_static { + name: "libc_ndk", + defaults: [ + "libc_defaults", + "libc_native_allocator_defaults", + ], + ramdisk_available: false, + srcs: libc_common_src_files + [ + "bionic/gwp_asan_wrappers.cpp", + "bionic/heap_tagging.cpp", + "bionic/malloc_common.cpp", + "bionic/malloc_limit.cpp", + ], + multilib: { + lib32: { + srcs: libc_common_src_files_32, + }, + }, + arch: { + arm: { + srcs: [ + "arch-arm/bionic/exidx_dynamic.c", + "arch-common/bionic/crtbegin_so.c", + "arch-arm/bionic/atexit_legacy.c", + "arch-common/bionic/crtend_so.S", + ], + whole_static_libs: ["libc_aeabi"], + }, + }, + + cflags: [ + "-fvisibility=hidden", + "-DLIBC_STATIC", + ], + + whole_static_libs: [ + "gwp_asan", + "libc_bionic_ndk", + "libc_bootstrap", + "libc_fortify", + "libc_freebsd", + "libc_freebsd_large_stack", + "libc_gdtoa", + "libc_netbsd", + "libc_openbsd_large_stack", + "libc_openbsd_ndk", + "libc_syscalls", + "libc_tzcode", + "libm", + "libstdc++", + ], +} + +// ======================================================== +// libc_nopthread.a +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + srcs: libc_common_src_files, + multilib: { + lib32: { + srcs: libc_common_src_files_32, + }, + }, + name: "libc_nopthread", + + whole_static_libs: [ + "libc_bionic", + "libc_bionic_ndk", + "libc_bootstrap", + "libc_dns", + "libc_fortify", + "libc_freebsd", + "libc_freebsd_large_stack", + "libc_gdtoa", + "libc_netbsd", + "libc_openbsd", + "libc_openbsd_large_stack", + "libc_openbsd_ndk", + "libc_syscalls", + "libc_tzcode", + "libstdc++", + ], + + arch: { + arm: { + whole_static_libs: ["libc_aeabi"], + }, + }, +} + +// ======================================================== +// libc_common.a +// ======================================================== + +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_common", + + whole_static_libs: [ + "libc_nopthread", + "libc_pthread", + ], +} + +// ======================================================== +// libc_static_dispatch.a +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_static_dispatch", + + arch: { + x86: { + srcs: ["arch-x86/static_function_dispatch.S"], + }, + arm: { + srcs: ["arch-arm/static_function_dispatch.S"], + }, + arm64: { + srcs: ["arch-arm64/static_function_dispatch.S"], + }, + }, +} + +// ======================================================== +// libc_dynamic_dispatch.a +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_dynamic_dispatch", + + cflags: [ + "-ffreestanding", + "-fno-stack-protector", + "-fno-jump-tables", + ], + arch: { + x86: { + srcs: ["arch-x86/dynamic_function_dispatch.cpp"], + }, + arm: { + srcs: ["arch-arm/dynamic_function_dispatch.cpp"], + }, + arm64: { + srcs: ["arch-arm64/dynamic_function_dispatch.cpp"], + }, + }, +} + +// ======================================================== +// libc_common_static.a For static binaries. +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_common_static", + + whole_static_libs: [ + "libc_common", + "libc_static_dispatch", + ], +} + +// ======================================================== +// libc_common_shared.a For shared libraries. +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + name: "libc_common_shared", + + whole_static_libs: [ + "libc_common", + "libc_dynamic_dispatch", + ], +} + +// Versions of dl_iterate_phdr and similar APIs used to lookup unwinding information in a static +// executable. +cc_library_static { + name: "libc_unwind_static", + defaults: ["libc_defaults"], + cflags: ["-DLIBC_STATIC"], + + srcs: ["bionic/dl_iterate_phdr_static.cpp"], + arch: { + // arm32-specific dl_unwind_find_exidx and __gnu_Unwind_Find_exidx APIs + arm: { + srcs: ["arch-arm/bionic/exidx_static.c"], + }, + }, +} + +// ======================================================== +// libc_nomalloc.a +// ======================================================== +// +// This is a version of the static C library used by the dynamic linker that exclude malloc. It also +// excludes functions selected using ifunc's (e.g. for string.h). Link in either +// libc_static_dispatch or libc_dynamic_dispatch to provide those functions. + +cc_library_static { + name: "libc_nomalloc", + defaults: ["libc_defaults"], + + whole_static_libs: [ + "libc_common", + "libc_init_static", + "libc_unwind_static", + ], +} + +filegroup { + name: "libc_sources_shared", + srcs: [ + "arch-common/bionic/crtbegin_so.c", + "arch-common/bionic/crtbrand.S", + "bionic/gwp_asan_wrappers.cpp", + "bionic/heap_tagging.cpp", + "bionic/icu.cpp", + "bionic/malloc_common.cpp", + "bionic/malloc_common_dynamic.cpp", + "bionic/android_profiling_dynamic.cpp", + "bionic/malloc_heapprofd.cpp", + "bionic/malloc_limit.cpp", + "bionic/ndk_cruft.cpp", + "bionic/ndk_cruft_data.cpp", + "bionic/NetdClient.cpp", + "arch-common/bionic/crtend_so.S", + ], +} + +filegroup { + name: "libc_sources_static", + srcs: [ + "bionic/gwp_asan_wrappers.cpp", + "bionic/heap_tagging.cpp", + "bionic/malloc_common.cpp", + "bionic/malloc_limit.cpp", + ], +} + +filegroup { + name: "libc_sources_shared_arm", + srcs: [ + "arch-arm/bionic/exidx_dynamic.c", + "arch-arm/bionic/atexit_legacy.c", + ], +} + +// ======================================================== +// libc.a + libc.so +// ======================================================== +cc_library { + defaults: [ + "libc_defaults", + "libc_native_allocator_defaults", + ], + name: "libc", + static_ndk_lib: true, + export_include_dirs: ["include"], + product_variables: { + platform_sdk_version: { + asflags: ["-DPLATFORM_SDK_VERSION=%d"], + }, + }, + static: { + srcs: [ ":libc_sources_static" ], + cflags: ["-DLIBC_STATIC"], + whole_static_libs: [ + "gwp_asan", + "libc_init_static", + "libc_common_static", + "libc_unwind_static", + ], + }, + shared: { + srcs: [ ":libc_sources_shared" ], + whole_static_libs: [ + "gwp_asan", + "libc_init_dynamic", + "libc_common_shared", + ], + }, + + required: [ + "tzdata", + "tz_version", // Version metadata for tzdata to help debugging. + ], + + // Do not pack libc.so relocations; see http://b/20645321 for details. + pack_relocations: false, + + // WARNING: The only libraries libc.so should depend on are libdl.so and ld-android.so! + // If you add other libraries, make sure to add -Wl,--exclude-libs=libgcc.a to the + // LOCAL_LDFLAGS for those libraries. This ensures that symbols that are pulled into + // those new libraries from libgcc.a are not declared external; if that were the case, + // then libc would not pull those symbols from libgcc.a as it should, instead relying + // on the external symbols from the dependent libraries. That would create a "cloaked" + // dependency on libgcc.a in libc though the libraries, which is not what you wanted! + + shared_libs: [ + "ld-android", + "libdl", + ], + static_libs: [ + "libdl_android", + ], + + nocrt: true, + + arch: { + arm: { + // TODO: This is to work around b/24465209. Remove after root cause is fixed. + pack_relocations: false, + ldflags: ["-Wl,--hash-style=both"], + + version_script: ":libc.arm.map", + + shared: { + srcs: [":libc_sources_shared_arm"], + // special for arm + cflags: ["-DCRT_LEGACY_WORKAROUND"], + }, + + // Arm 32 bit does not produce complete exidx unwind information + // so keep the .debug_frame which is relatively small and does + // include needed unwind information. + // See b/132992102 for details. + strip: { + keep_symbols_and_debug_frame: true, + }, + + whole_static_libs: [ "libunwind_llvm" ], + }, + arm64: { + version_script: ":libc.arm64.map", + + // Leave the symbols in the shared library so that stack unwinders can produce + // meaningful name resolution. + strip: { + keep_symbols: true, + }, + + whole_static_libs: [ "libgcc_stripped" ], + }, + x86: { + // TODO: This is to work around b/24465209. Remove after root cause is fixed. + pack_relocations: false, + ldflags: ["-Wl,--hash-style=both"], + + version_script: ":libc.x86.map", + + // Leave the symbols in the shared library so that stack unwinders can produce + // meaningful name resolution. + strip: { + keep_symbols: true, + }, + + whole_static_libs: [ "libgcc_stripped" ], + }, + x86_64: { + version_script: ":libc.x86_64.map", + + // Leave the symbols in the shared library so that stack unwinders can produce + // meaningful name resolution. + strip: { + keep_symbols: true, + }, + + whole_static_libs: [ "libgcc_stripped" ], + }, + }, + + stubs: { + symbol_file: "libc.map.txt", + versions: [ + "29", + "R", + "10000", + ], + }, + + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + ], + + // Sorting bss symbols by size usually results in less dirty pages at run + // time, because small symbols are grouped together. + sort_bss_symbols_by_size: true, +} + +genrule { + name: "libc.arm.map", + out: ["libc.arm.map"], + srcs: ["libc.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) arm $(in) $(out)", +} + +genrule { + name: "libc.arm64.map", + out: ["libc.arm64.map"], + srcs: ["libc.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) arm64 $(in) $(out)", +} + +genrule { + name: "libc.x86.map", + out: ["libc.x86.map"], + srcs: ["libc.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) x86 $(in) $(out)", +} + +genrule { + name: "libc.x86_64.map", + out: ["libc.x86_64.map"], + srcs: ["libc.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) x86_64 $(in) $(out)", +} + +// Headers that only other parts of the platform can include. +cc_library_headers { + name: "bionic_libc_platform_headers", + visibility: [ + "//art:__subpackages__", + "//bionic:__subpackages__", + "//frameworks:__subpackages__", + "//device/generic/goldfish-opengl:__subpackages__", + "//external/gwp_asan:__subpackages__", + "//external/perfetto:__subpackages__", + "//external/scudo:__subpackages__", + "//system/core/debuggerd:__subpackages__", + "//system/memory/libmemunreachable:__subpackages__", + ], + host_supported: true, + vendor_available: true, + ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + export_include_dirs: [ + "platform", + ], + system_shared_libs: [], + stl: "none", + sdk_version: "current", + + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + "com.android.art.release", // from libdexfile_external + "com.android.art.debug", // from libdexfile_external + ], +} + +// libc_headers for libasync_safe and libpropertyinfoparser +cc_library_headers { + name: "libc_headers", + + host_supported: true, + vendor_available: true, + ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + // used by most APEXes indirectly via libunwind_llvm + min_sdk_version: "apex_inherit", + visibility: [ + ":__subpackages__", // visible to bionic + // ... and only to these places (b/152668052) + "//external/gwp_asan", + "//external/libunwind_llvm", + "//system/core/property_service/libpropertyinfoparser", + "//system/extras/toolchain-extras", + ], + + no_libcrt: true, + stl: "none", + system_shared_libs: [], + + // The build system generally requires that any dependencies of a target + // with an sdk_version must have a lower sdk_version. By setting sdk_version + // to 1 we let targets with an sdk_version that need to depend on the libc + // headers but cannot depend on libc itself due to circular dependencies + // (such as libunwind_llvm) depend on the headers. Setting sdk_version to 1 + // is correct because the headers can support any sdk_version. + sdk_version: "1", + + export_include_dirs: [ + "include", + "kernel/uapi", + "kernel/android/uapi", + ], + + arch: { + arm: { + export_include_dirs: [ + "kernel/uapi/asm-arm", + ], + }, + arm64: { + export_include_dirs: [ + "kernel/uapi/asm-arm64", + ], + }, + x86: { + export_include_dirs: [ + "kernel/uapi/asm-x86", + ], + }, + x86_64: { + export_include_dirs: [ + "kernel/uapi/asm-x86", + ], + }, + }, +} + +// ======================================================== +// libstdc++.so and libstdc++.a. +// ======================================================== + +cc_library { + defaults: ["libc_defaults"], + include_dirs: ["bionic/libstdc++/include"], + srcs: [ + "bionic/__cxa_guard.cpp", + "bionic/__cxa_pure_virtual.cpp", + "bionic/new.cpp", + ], + name: "libstdc++", + static_ndk_lib: true, + static_libs: ["libasync_safe"], + + static: { + system_shared_libs: [], + }, + shared: { + system_shared_libs: ["libc"], + }, + + //TODO (dimitry): This is to work around b/24465209. Remove after root cause is fixed + arch: { + arm: { + // TODO: This is to work around b/24465209. Remove after root cause is fixed. + pack_relocations: false, + ldflags: ["-Wl,--hash-style=both"], + version_script: ":libstdc++.arm.map", + }, + arm64: { + version_script: ":libstdc++.arm64.map", + }, + x86: { + pack_relocations: false, + ldflags: ["-Wl,--hash-style=both"], + version_script: ":libstdc++.x86.map", + }, + x86_64: { + version_script: ":libstdc++.x86_64.map", + }, + }, +} + +genrule { + name: "libstdc++.arm.map", + out: ["libstdc++.arm.map"], + srcs: ["libstdc++.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) arm $(in) $(out)", +} + +genrule { + name: "libstdc++.arm64.map", + out: ["libstdc++.arm64.map"], + srcs: ["libstdc++.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) arm64 $(in) $(out)", +} + +genrule { + name: "libstdc++.x86.map", + out: ["libstdc++.x86.map"], + srcs: ["libstdc++.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) x86 $(in) $(out)", +} + +genrule { + name: "libstdc++.x86_64.map", + out: ["libstdc++.x86_64.map"], + srcs: ["libstdc++.map.txt"], + tool_files: [":bionic-generate-version-script"], + cmd: "$(location :bionic-generate-version-script) x86_64 $(in) $(out)", +} + +// ======================================================== +// crt object files. +// ======================================================== + +cc_defaults { + name: "crt_defaults", + defaults: ["linux_bionic_supported"], + vendor_available: true, + ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + // crt* objects are used by most cc_binary/cc_library in "anyapex" + min_sdk_version: "apex_inherit", + cflags: [ + "-Wno-gcc-compat", + "-Wall", + "-Werror", + ], + sanitize: { + never: true, + }, +} + +cc_defaults { + name: "crt_so_defaults", + defaults: ["crt_defaults"], + + arch: { + x86: { + cflags: ["-fPIC"], + }, + x86_64: { + cflags: ["-fPIC"], + }, + }, + stl: "none", +} + +cc_object { + name: "crtbrand", + // crtbrand.c needs and a #define for the platform SDK version. + local_include_dirs: ["include"], + product_variables: { + platform_sdk_version: { + asflags: ["-DPLATFORM_SDK_VERSION=%d"], + }, + }, + srcs: ["arch-common/bionic/crtbrand.S"], + + defaults: ["crt_so_defaults"], +} + +cc_object { + name: "crtbegin_so1", + local_include_dirs: ["include"], + srcs: ["arch-common/bionic/crtbegin_so.c"], + + defaults: ["crt_so_defaults"], +} + +cc_object { + name: "crtbegin_so", + + defaults: ["crt_so_defaults"], + objs: [ + "crtbegin_so1", + "crtbrand", + ], +} + +cc_object { + name: "crtend_so", + local_include_dirs: ["include"], + srcs: ["arch-common/bionic/crtend_so.S"], + + defaults: ["crt_so_defaults"], +} + +cc_object { + name: "crtbegin_static1", + local_include_dirs: ["include"], + srcs: ["arch-common/bionic/crtbegin.c"], + defaults: ["crt_defaults"], +} + +cc_object { + name: "crtbegin_static", + + objs: [ + "crtbegin_static1", + "crtbrand", + ], + defaults: ["crt_defaults"], +} + +cc_object { + name: "crtbegin_dynamic1", + local_include_dirs: ["include"], + srcs: ["arch-common/bionic/crtbegin.c"], + defaults: ["crt_defaults"], +} + +cc_object { + name: "crtbegin_dynamic", + + objs: [ + "crtbegin_dynamic1", + "crtbrand", + ], + target: { + linux_bionic: { + generated_sources: ["host_bionic_linker_asm"], + objs: [ + "linker_wrapper", + ], + }, + }, + defaults: ["crt_defaults"], +} + +cc_object { + // We rename crtend.o to crtend_android.o to avoid a + // name clash between gcc and bionic. + name: "crtend_android", + local_include_dirs: ["include"], + srcs: ["arch-common/bionic/crtend.S"], + + defaults: ["crt_defaults"], +} + +// ======================================================== +// NDK headers. +// ======================================================== + +versioned_ndk_headers { + name: "common_libc", + from: "include", + to: "", + license: "NOTICE", +} + +ndk_headers { + name: "libc_uapi", + from: "kernel/uapi", + to: "", + srcs: [ + "kernel/uapi/asm-generic/**/*.h", + "kernel/uapi/drm/**/*.h", + "kernel/uapi/linux/**/*.h", + "kernel/uapi/misc/**/*.h", + "kernel/uapi/mtd/**/*.h", + "kernel/uapi/rdma/**/*.h", + "kernel/uapi/scsi/**/*.h", + "kernel/uapi/sound/**/*.h", + "kernel/uapi/video/**/*.h", + "kernel/uapi/xen/**/*.h", + ], + license: "NOTICE", +} + +ndk_headers { + name: "libc_kernel_android_uapi_linux", + from: "kernel/android/uapi/linux", + to: "linux", + srcs: ["kernel/android/uapi/linux/**/*.h"], + license: "NOTICE", +} + +ndk_headers { + name: "libc_kernel_android_scsi", + from: "kernel/android/scsi/scsi", + to: "scsi", + srcs: ["kernel/android/scsi/**/*.h"], + license: "NOTICE", +} + +ndk_headers { + name: "libc_asm_arm", + from: "kernel/uapi/asm-arm", + to: "arm-linux-androideabi", + srcs: ["kernel/uapi/asm-arm/**/*.h"], + license: "NOTICE", +} + +ndk_headers { + name: "libc_asm_arm64", + from: "kernel/uapi/asm-arm64", + to: "aarch64-linux-android", + srcs: ["kernel/uapi/asm-arm64/**/*.h"], + license: "NOTICE", +} + +ndk_headers { + name: "libc_asm_x86", + from: "kernel/uapi/asm-x86", + to: "i686-linux-android", + srcs: ["kernel/uapi/asm-x86/**/*.h"], + license: "NOTICE", +} + +ndk_headers { + name: "libc_asm_x86_64", + from: "kernel/uapi/asm-x86", + to: "x86_64-linux-android", + srcs: ["kernel/uapi/asm-x86/**/*.h"], + license: "NOTICE", +} + +ndk_library { + name: "libc", + native_bridge_supported: true, + symbol_file: "libc.map.txt", + first_version: "9", +} + +llndk_library { + name: "libc", + symbol_file: "libc.map.txt", + export_headers_as_system: true, + export_preprocessed_headers: ["include"], + native_bridge_supported: true, + export_include_dirs: [ + "kernel/android/scsi", + "kernel/android/uapi", + "kernel/uapi", + ], + arch: { + arm: { + export_include_dirs: [ + "kernel/uapi/asm-arm", + ], + }, + arm64: { + export_include_dirs: [ + "kernel/uapi/asm-arm64", + ], + }, + x86: { + export_include_dirs: [ + "kernel/uapi/asm-x86", + ], + }, + x86_64: { + export_include_dirs: [ + "kernel/uapi/asm-x86", + ], + }, + }, +} + +ndk_library { + name: "libstdc++", + symbol_file: "libstdc++.map.txt", + first_version: "9", +} + +// Export these headers for toolbox to process +filegroup { + name: "kernel_input_headers", + srcs: [ + "kernel/uapi/linux/input.h", + "kernel/uapi/linux/input-event-codes.h", + ], +} + +// Generate a syscall name / number mapping. These objects are text files +// (thanks to the -dD -E flags) and not binary files. They will then be +// consumed by the genseccomp.py script and converted into C++ code. +cc_defaults { + name: "libseccomp_gen_syscall_nrs_defaults", + recovery_available: true, + srcs: ["seccomp/gen_syscall_nrs.cpp"], + cflags: [ + "-dD", + "-E", + "-Wall", + "-Werror", + "-nostdinc", + ], +} + +cc_object { + name: "libseccomp_gen_syscall_nrs_arm", + defaults: ["libseccomp_gen_syscall_nrs_defaults"], + local_include_dirs: [ + "kernel/uapi/asm-arm", + "kernel/uapi", + ], +} + +cc_object { + name: "libseccomp_gen_syscall_nrs_arm64", + defaults: ["libseccomp_gen_syscall_nrs_defaults"], + local_include_dirs: [ + "kernel/uapi/asm-arm64", + "kernel/uapi", + ], +} + +cc_object { + name: "libseccomp_gen_syscall_nrs_x86", + defaults: ["libseccomp_gen_syscall_nrs_defaults"], + srcs: ["seccomp/gen_syscall_nrs_x86.cpp"], + exclude_srcs: ["seccomp/gen_syscall_nrs.cpp"], + local_include_dirs: [ + "kernel/uapi/asm-x86", + "kernel/uapi", + ], +} + +cc_object { + name: "libseccomp_gen_syscall_nrs_x86_64", + defaults: ["libseccomp_gen_syscall_nrs_defaults"], + srcs: ["seccomp/gen_syscall_nrs_x86_64.cpp"], + exclude_srcs: ["seccomp/gen_syscall_nrs.cpp"], + local_include_dirs: [ + "kernel/uapi/asm-x86", + "kernel/uapi", + ], +} + +// Generate the C++ policy sources for app and system seccomp-bpf filters. +python_binary_host { + name: "genseccomp", + main: "tools/genseccomp.py", + + srcs: [ + "tools/genseccomp.py", + "tools/gensyscalls.py", + ], + + data: [ + "kernel/uapi/**/*.h", + ], + + version: { + py2: { + enabled: true, + }, + py3: { + enabled: false, + }, + }, +} + +python_binary_host { + name: "genfunctosyscallnrs", + main: "tools/genfunctosyscallnrs.py", + + srcs: [ + "tools/genseccomp.py", + "tools/genfunctosyscallnrs.py", + "tools/gensyscalls.py", + ], + + data: [ + "kernel/uapi/**/*.h", + ], + + version: { + py2: { + enabled: true, + }, + py3: { + enabled: false, + }, + }, +} + +cc_genrule { + name: "func_to_syscall_nrs", + recovery_available: true, + cmd: "$(location genfunctosyscallnrs) --out-dir=$(genDir) $(in)", + + tools: [ "genfunctosyscallnrs" ], + + srcs: [ + "SYSCALLS.TXT", + ":libseccomp_gen_syscall_nrs_arm", + ":libseccomp_gen_syscall_nrs_arm64", + ":libseccomp_gen_syscall_nrs_x86", + ":libseccomp_gen_syscall_nrs_x86_64", + ], + + out: [ + "func_to_syscall_nrs.h", + ], +} + +// SECCOMP_BLACKLIST_APP_ZYGOTE.TXT = SECCOMP_BLACKLIST_APP.txt - setresgid* +genrule { + name: "generate_app_zygote_blacklist", + out: ["SECCOMP_BLACKLIST_APP_ZYGOTE.TXT"], + srcs: ["SECCOMP_BLACKLIST_APP.TXT"], + cmd: "grep -v '^int[ \t]*setresgid' $(in) > $(out)", +} + +cc_genrule { + name: "libseccomp_policy_app_zygote_sources", + recovery_available: true, + cmd: "$(location genseccomp) --out-dir=$(genDir) --name-modifier=app_zygote $(in)", + + tools: [ "genseccomp" ], + + srcs: [ + "SYSCALLS.TXT", + "SECCOMP_WHITELIST_COMMON.TXT", + "SECCOMP_WHITELIST_APP.TXT", + "SECCOMP_BLACKLIST_COMMON.TXT", + "SECCOMP_PRIORITY.TXT", + ":generate_app_zygote_blacklist", + ":libseccomp_gen_syscall_nrs_arm", + ":libseccomp_gen_syscall_nrs_arm64", + ":libseccomp_gen_syscall_nrs_x86", + ":libseccomp_gen_syscall_nrs_x86_64", + ], + + out: [ + "arm64_app_zygote_policy.cpp", + "arm_app_zygote_policy.cpp", + "x86_64_app_zygote_policy.cpp", + "x86_app_zygote_policy.cpp", + ], +} + +cc_genrule { + name: "libseccomp_policy_app_sources", + recovery_available: true, + cmd: "$(location genseccomp) --out-dir=$(genDir) --name-modifier=app $(in)", + + tools: [ "genseccomp" ], + + srcs: [ + "SYSCALLS.TXT", + "SECCOMP_WHITELIST_COMMON.TXT", + "SECCOMP_WHITELIST_APP.TXT", + "SECCOMP_BLACKLIST_COMMON.TXT", + "SECCOMP_BLACKLIST_APP.TXT", + "SECCOMP_PRIORITY.TXT", + ":libseccomp_gen_syscall_nrs_arm", + ":libseccomp_gen_syscall_nrs_arm64", + ":libseccomp_gen_syscall_nrs_x86", + ":libseccomp_gen_syscall_nrs_x86_64", + ], + + out: [ + "arm64_app_policy.cpp", + "arm_app_policy.cpp", + "x86_64_app_policy.cpp", + "x86_app_policy.cpp", + ], +} + +cc_genrule { + name: "libseccomp_policy_system_sources", + recovery_available: true, + cmd: "$(location genseccomp) --out-dir=$(genDir) --name-modifier=system $(in)", + + tools: [ "genseccomp" ], + + srcs: [ + "SYSCALLS.TXT", + "SECCOMP_WHITELIST_COMMON.TXT", + "SECCOMP_WHITELIST_SYSTEM.TXT", + "SECCOMP_BLACKLIST_COMMON.TXT", + "SECCOMP_PRIORITY.TXT", + ":libseccomp_gen_syscall_nrs_arm", + ":libseccomp_gen_syscall_nrs_arm64", + ":libseccomp_gen_syscall_nrs_x86", + ":libseccomp_gen_syscall_nrs_x86_64", + ], + + out: [ + "arm64_system_policy.cpp", + "arm_system_policy.cpp", + "x86_64_system_policy.cpp", + "x86_system_policy.cpp", + ], +} + +cc_library { + name: "libseccomp_policy", + recovery_available: true, + generated_headers: ["func_to_syscall_nrs"], + generated_sources: [ + "libseccomp_policy_app_sources", + "libseccomp_policy_app_zygote_sources", + "libseccomp_policy_system_sources", + ], + + srcs: [ + "seccomp/seccomp_policy.cpp", + ], + + export_include_dirs: ["seccomp/include"], + cflags: [ + "-Wall", + "-Werror", + ], + shared: { + shared_libs: ["libbase"], + }, + static: { + static_libs: ["libbase"], + }, +} + +// This is a temporary library that will use scudo as the native memory +// allocator. To use it, add it as the first shared library. +cc_defaults { + name: "libc_scudo_wrapper_defaults", + srcs: [ + "bionic/gwp_asan_wrappers.cpp", + "bionic/heap_tagging.cpp", + "bionic/malloc_common.cpp", + "bionic/malloc_common_dynamic.cpp", + "bionic/malloc_heapprofd.cpp", + "bionic/malloc_limit.cpp", + "bionic/scudo_wrapper.cpp", + "bionic/__set_errno.cpp", + ], + cflags: [ + "-DUSE_SCUDO", + "-fno-emulated-tls", // Required for GWP-ASan. + ], + shared_libs: ["libscudo_wrapper"], + + header_libs: [ + "libc_headers", + "gwp_asan_headers", + ], + + static_libs: [ + "libasync_safe", + "gwp_asan", + ], + + arch: { + arm: { + srcs: [":syscalls-arm.S"], + }, + arm64: { + srcs: [":syscalls-arm64.S"], + }, + x86: { + srcs: [ + "arch-x86/bionic/__libc_init_sysinfo.cpp", + ":syscalls-x86.S", + ], + }, + x86_64: { + srcs: [":syscalls-x86_64.S"], + }, + }, + + // Mark this library as global so it overrides all the allocation + // definitions properly. + ldflags: ["-Wl,-z,global"], +} + +cc_library_shared { + name: "libc_scudo", + vendor_available: true, + stl: "none", + system_shared_libs: [], + + allow_undefined_symbols: true, + // Like libc, disable native coverage for libc_scudo. + native_coverage: false, + apex_available: [ + "//apex_available:platform", + "com.android.media.swcodec", + ], + min_sdk_version: "apex_inherit", +} + +subdirs = [ + "bionic/scudo", +] diff --git a/aosp/bionic/libc/MODULE_LICENSE_BSD b/aosp/bionic/libc/MODULE_LICENSE_BSD new file mode 100644 index 000000000..e69de29bb diff --git a/aosp/bionic/libc/NOTICE b/aosp/bionic/libc/NOTICE new file mode 100644 index 000000000..8245ff890 --- /dev/null +++ b/aosp/bionic/libc/NOTICE @@ -0,0 +1,6058 @@ + Copyright (c) 2014, ARM Limited + All rights Reserved. + Copyright (c) 2014, Linaro Ltd. + + 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. + * Neither the name of the company 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 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 + HOLDER 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. + +------------------------------------------------------------------- + + Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. + +------------------------------------------------------------------- + + Copyright (c) 1993 John Brezak + 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. The name of the author may be used to endorse or promote products + derived from this software without specific prior written permission. + +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. + +------------------------------------------------------------------- + + Copyright (c) 2009-2013 The Linux Foundation. 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. + * Neither the name of The Linux Foundation 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 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 HOLDER 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. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +Optimized by Bruce D. Evans. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +k_sinf.c and k_cosf.c merged by Steven G. Kargl. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +s_sin.c and s_cos.c merged by Steven G. Kargl. Descriptions of the +algorithms are contained in the original files. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +Optimized by Bruce D. Evans. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +k_sin.c and k_cos.c merged by Steven G. Kargl. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +Optimized by Bruce D. Evans. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + +Developed at SunSoft, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +k_sinl.c and k_cosl.c merged by Steven G. Kargl + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. +==================================================== + +The argument reduction and testing for exceptional cases was +written by Steven G. Kargl with input from Bruce D. Evans +and David A. Schultz. + +------------------------------------------------------------------- + +==================================================== +Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +==================================================== +Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +==================================================== +Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. +Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +Based on the UCB version with the ID appearing below. +This is ANSIish only when "multibyte character == plain character". + +Copyright (c) 1989, 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. + +------------------------------------------------------------------- + +Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: +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 project 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 PROJECT 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 PROJECT 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. + +------------------------------------------------------------------- + +Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") +Copyright (C) 1995-1999, 2001, 2003 Internet Software Consortium. + +Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") +Copyright (C) 1997-2001 Internet Software Consortium. + +Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (C) 2006 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. + +------------------------------------------------------------------- + +Copyright (C) 2006 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. + +------------------------------------------------------------------- + +Copyright (C) 2008 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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +Copyright (C) 2008 The Android Open Source Project +All rights reserved. +Copyright (c) 2013-2014, NVIDIA Corporation. 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. + +------------------------------------------------------------------- + +Copyright (C) 2009 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. + +------------------------------------------------------------------- + +Copyright (C) 2010 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. + +------------------------------------------------------------------- + +Copyright (C) 2010 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. + +------------------------------------------------------------------- + +Copyright (C) 2010 The Android Open Source Project +Copyright (c) 2008 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +Android adaptation and tweak by Jim Huang . + +------------------------------------------------------------------- + +Copyright (C) 2011 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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +Copyright (C) 2012 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. + +------------------------------------------------------------------- + +Copyright (C) 2013 Pietro Cerutti + +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 AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (C) 2013 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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +Copyright (C) 2013 The Android Open Source Project +All rights reserved. +Copyright (c) 2013-2014 NVIDIA Corporation. 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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +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: +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (C) 2015 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. + +------------------------------------------------------------------- + +Copyright (C) 2015 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. + +------------------------------------------------------------------- + +Copyright (C) 2016 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. + +------------------------------------------------------------------- + +Copyright (C) 2016 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. + +------------------------------------------------------------------- + +Copyright (C) 2017 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. + +------------------------------------------------------------------- + +Copyright (C) 2017 The Android Open Source Project +All rights reserved. + +Copyright (c) 2009-2011, Code Aurora Forum. 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. + +------------------------------------------------------------------- + +Copyright (C) 2017 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. + +------------------------------------------------------------------- + +Copyright (C) 2018 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. + +------------------------------------------------------------------- + +Copyright (C) 2019 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. + +------------------------------------------------------------------- + +Copyright (C) 2019 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. + +------------------------------------------------------------------- + +Copyright (C) 2019 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. + +------------------------------------------------------------------- + +Copyright (C) 2020 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. + +------------------------------------------------------------------- + +Copyright (c) 1980, 1983, 1988, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + + +Portions Copyright (c) 1993 by Digital Equipment Corporation. + +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, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1982, 1986, 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. + +------------------------------------------------------------------- + +Copyright (c) 1982, 1986, 1993 + The Regents of the University of California. All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1983, 1987, 1989 + 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. + +------------------------------------------------------------------- + +Copyright (c) 1983, 1989 + 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1983, 1989, 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. + +------------------------------------------------------------------- + +Copyright (c) 1983, 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. + +------------------------------------------------------------------- + +Copyright (c) 1985 + 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1985 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. + +------------------------------------------------------------------- + +Copyright (c) 1985, 1988, 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. + +Portions Copyright (c) 1993 by Digital Equipment Corporation. + +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, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1985, 1989, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1985, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1985, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1985, 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. + +------------------------------------------------------------------- + +Copyright (c) 1987 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. + +------------------------------------------------------------------- + +Copyright (c) 1987, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1987, 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. + +------------------------------------------------------------------- + +Copyright (c) 1988 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. + +------------------------------------------------------------------- + +Copyright (c) 1988 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. + +------------------------------------------------------------------- + +Copyright (c) 1988, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1988, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1988, 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. + +------------------------------------------------------------------- + +Copyright (c) 1989 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. + +------------------------------------------------------------------- + +Copyright (c) 1989 The Regents of the University of California. +All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 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. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Guido van Rossum. + +Copyright (c) 2011 The FreeBSD Foundation +All rights reserved. +Portions of this software were developed by David Chisnall +under sponsorship from the FreeBSD Foundation. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Guido van Rossum. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Roger L. Snyder. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1989, 1993 + The Regents of the University of California. All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990 Regents of the University of California. +All rights reserved. + +This code is derived from software contributed to Berkeley by +Chris Torek. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990 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. + +------------------------------------------------------------------- + +Copyright (c) 1990 The Regents of the University of California. +All rights reserved. + +This code is derived from software contributed to Berkeley by +Chris Torek. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990 The Regents of the University of California. +All rights reserved. + +This code is derived from software contributed to Berkeley by +William Jolitz. + +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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Chris Torek. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Donn Seeley at UUNET Technologies, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Donn Seeley at UUNET Technologies, Inc. + +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. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993 + The Regents of the University of California. All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993, 1994 + 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. + +------------------------------------------------------------------- + +Copyright (c) 1990, 1993, 1994 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Chris Torek. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1991 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. + +------------------------------------------------------------------- + +Copyright (c) 1991, 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. + +------------------------------------------------------------------- + +Copyright (c) 1991, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Berkeley Software Design, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1991, 1993 + The Regents of the University of California. All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +This code is derived from software contributed to Berkeley by +Hugh Smith at The University of Guelph. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1992 Henry Spencer. +Copyright (c) 1992, 1993 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Henry Spencer of the University of Toronto. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1992 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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 1993 + The Regents of the University of California. All rights reserved. + +This software was developed by the Computer Systems Engineering group +at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and +contributed to Berkeley. + +All advertising materials mentioning features or use of this software +must display the following acknowledgement: + This product includes software developed by the University of + California, Lawrence Berkeley Laboratory. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 1993 + The Regents of the University of California. All rights reserved. +(c) UNIX System Laboratories, Inc. +All or some portions of this file are derived from material licensed +to the University of California by American Telephone and Telegraph +Co. or Unix System Laboratories, Inc. and are reproduced herein with +the permission of UNIX System Laboratories, Inc. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 1993, 1994 + The Regents of the University of California. All rights reserved. + +This code is derived from software contributed to Berkeley by +Henry Spencer. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1992, 1993, 1994 Henry Spencer. + +This code is derived from software contributed to Berkeley by +Henry Spencer. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. 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. + +------------------------------------------------------------------- + +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. + +------------------------------------------------------------------- + +Copyright (c) 1993 Martin Birgmeier +All rights reserved. + +You may redistribute unmodified or modified versions of this source +code provided that the above copyright notice and this and the +following conditions are retained. + +This software is provided ``as is'', and comes with no warranties +of any kind. I shall in no event be liable for anything that happens +to anyone/anything when using this software. + +------------------------------------------------------------------- + +Copyright (c) 1994 SigmaSoft, Th. Lockert +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1996 by Internet Software Consortium. + +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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS +ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE +CONSORTIUM 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. + +------------------------------------------------------------------- + +Copyright (c) 1996, David Mazieres +Copyright (c) 2008, Damien Miller +Copyright (c) 2013, Markus Friedl + +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. + +------------------------------------------------------------------- + +Copyright (c) 1996, David Mazieres +Copyright (c) 2008, Damien Miller +Copyright (c) 2013, Markus Friedl +Copyright (c) 2014, Theo de Raadt + +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. + +------------------------------------------------------------------- + +Copyright (c) 1996-1998, 2008 Theo de Raadt +Copyright (c) 1997, 2008-2009 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 1997 Mark Brinicombe +Copyright (C) 2010 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: +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by Mark Brinicombe +4. 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 AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 1997 Niklas Hallqvist. 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. + +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. + +------------------------------------------------------------------- + +Copyright (c) 1997 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Neil A. Carson and Mark Brinicombe + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1997 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 1997 Todd C. Miller +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``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. + +------------------------------------------------------------------- + +Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. +All rights reserved. + +This code was contributed to The NetBSD Foundation by Klaus Klein. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the NetBSD + Foundation, Inc. and its contributors. +4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Luke Mewburn. + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Luke Mewburn; and by Jason R. Thorpe. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the NetBSD + Foundation, Inc. and its contributors. +4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1997, 2005 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 1998 Softweyr LLC. All rights reserved. + +strtok_r, from Berkeley strtok +Oct 13, 1998 by Wes Peters + +Copyright (c) 1988, 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 + notices, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notices, 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 SOFTWEYR LLC, 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 SOFTWEYR LLC, 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. + +------------------------------------------------------------------- + +Copyright (c) 1998 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Klaus Klein. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the NetBSD + Foundation, Inc. and its contributors. +4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 1998 Todd C. Miller +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``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. + +------------------------------------------------------------------- + +Copyright (c) 1998, 2015 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 1999 + David E. O'Brien +Copyright (c) 1988, 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. + +------------------------------------------------------------------- + +Copyright (c) 2000 Ben Harris. +Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: +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 project 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 PROJECT 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 PROJECT 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. + +------------------------------------------------------------------- + +Copyright (c) 2000 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Dieter Baron and Thomas Klausner. + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 2001 Wasabi Systems, Inc. +All rights reserved. + +Written by Frank van der Linden for Wasabi Systems, Inc. + +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. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed for the NetBSD Project by + Wasabi Systems, Inc. +4. The name of Wasabi Systems, Inc. may not be used to endorse + or promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC +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. + +------------------------------------------------------------------- + +Copyright (c) 2001-2011 The FreeBSD 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: +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2002 Daniel Hartmeier +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 HOLDERS 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. + +------------------------------------------------------------------- + +Copyright (c) 2002 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Christos Zoulas. + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 2002 Tim J. Robbins +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2002 Tim J. Robbins. +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2002 Todd C. Miller + +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. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +------------------------------------------------------------------- + +Copyright (c) 2002, 2003 Tim J. Robbins. +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2002-2004 Tim J. Robbins +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2002-2004 Tim J. Robbins. +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2003 Dag-Erling Smørgrav +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 + in this position and unchanged. +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +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. + +------------------------------------------------------------------- + +Copyright (c) 2003 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2003 Mike Barcroft +Copyright (c) 2002 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2003 Networks Associates Technology, Inc. +All rights reserved. + +Portions of this software were developed for the FreeBSD Project by +Jacques A. Vidrine, Safeport Network Services, and Network +Associates Laboratories, the Security Research Division of Network +Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 +("CBOSS"), as part of the DARPA CHATS research program. + +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2003 Todd C. Miller + +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. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +------------------------------------------------------------------- + +Copyright (c) 2003, 2004 Todd C. Miller + +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. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +------------------------------------------------------------------- + +Copyright (c) 2003, Steven G. Kargl +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 Stefan Farfeleder +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. + +THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1995,1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1995-1999 by Internet Software Consortium + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1995-1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996,1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1996-1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1997,1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Portions Copyright (c) 1996-1999 by Internet Software Consortium. + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2004, 2005 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2004-2005 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2004-2005 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2005 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2005 Tim J. Robbins. +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") +Copyright (c) 1995-1999 by Internet Software Consortium + +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 ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Copyright (c) 2005-2008 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2005-2011 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2005-2014 Rich Felker + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------- + +Copyright (c) 2007 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2007 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2007 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +Derived from s_modf.c, which has the following Copyright: +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +Copyright (c) 2007 Steven G. Kargl +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2007 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software written by Stephen L. Moshier. +It is redistributed by the NetBSD Foundation by permission of the author. + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 2007 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 2007, 2010-2013 Steven G. Kargl +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 unmodified, 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. + +s_sinl.c and s_cosl.c merged by Steven G. Kargl. + +------------------------------------------------------------------- + +Copyright (c) 2007-2008 Michael G Schwern + +This software originally derived from Paul Sheer's pivotal_gmtime_r.c. + +The MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------- + +Copyright (c) 2007-2008 Michael G Schwern + +This software originally derived from Paul Sheer's pivotal_gmtime_r.c. + +The MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Origin: http://code.google.com/p/y2038 +Modified for Bionic by the Android Open Source Project + +------------------------------------------------------------------- + +Copyright (c) 2007-2008 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2007-2013 Bruce D. Evans +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2008 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2008 Stephen L. Moshier + +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. + +------------------------------------------------------------------- + +Copyright (c) 2008 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 2008, Damien Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 2009 David Schultz +All rights reserved. + +Copyright (c) 2011 The FreeBSD Foundation +All rights reserved. +Portions of this software were developed by David Chisnall +under sponsorship from the FreeBSD Foundation. + +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2009 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2009 The NetBSD Foundation, Inc. + +This code is derived from software contributed to The NetBSD Foundation +by Roy Marples. + +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. + +------------------------------------------------------------------- + +Copyright (c) 2009-2013 Steven G. Kargl +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 unmodified, 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. + +Optimized by Bruce D. Evans. + +------------------------------------------------------------------- + +Copyright (c) 2010 The NetBSD Foundation, Inc. +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. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 2010 Todd C. Miller + +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. + +------------------------------------------------------------------- + +Copyright (c) 2010, 2011, 2012, 2013 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 David Chisnall +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 David Schultz +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 David Schultz +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 Ed Schouten + David Chisnall +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2011 Martin Pieuchot + +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. + +------------------------------------------------------------------- + +Copyright (c) 2011 The Android Open Source Project +Copyright (c) 2008 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +------------------------------------------------------------------- + +Copyright (c) 2011, 2012, 2013 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2011, VMware, Inc. +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. + * Neither the name of the VMware, Inc. 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 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 VMWARE, INC. 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. + +------------------------------------------------------------------- + +Copyright (c) 2012 Stephen Montgomery-Smith +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2012 Stephen Montgomery-Smith +Copyright (c) 2017 Mahdi Mokhtari +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2012, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. + +------------------------------------------------------------------- + +Copyright (c) 2012-2013, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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 + +------------------------------------------------------------------- + +Copyright (c) 2012-2014 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +------------------------------------------------------------------- + +Copyright (c) 2013 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +------------------------------------------------------------------- + +Copyright (c) 2013 Antoine Jacoutot + +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. + +------------------------------------------------------------------- + +Copyright (c) 2013 Bruce D. Evans +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 unmodified, 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. + +------------------------------------------------------------------- + +Copyright (c) 2013 The NetBSD Foundation, Inc. +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by Christos Zoulas. + +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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + +------------------------------------------------------------------- + +Copyright (c) 2013, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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 + +------------------------------------------------------------------- + +Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved. +Johnny Qiu +Shu Zhang + +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. + * Neither the name of The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +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. + +------------------------------------------------------------------- + +Copyright (c) 2013-2015, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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 + +------------------------------------------------------------------- + +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. + +------------------------------------------------------------------- + +Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. + +------------------------------------------------------------------- + +Copyright (c) 2015 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +------------------------------------------------------------------- + +Copyright (c) 2015 Joerg Sonnenberger . +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. + +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 HOLDERS 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. + +------------------------------------------------------------------- + +Copyright (c) 2015 Nuxi, https://nuxi.nl/ + +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c) 2017 ARM Ltd +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. The name of the company may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + +------------------------------------------------------------------- + +Copyright (c)1999 Citrus 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: +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c)2001 Citrus 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: +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright (c)2003 Citrus 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: +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 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 AUTHOR 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. + +------------------------------------------------------------------- + +Copyright 1989 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 + +------------------------------------------------------------------- + +Copyright 1997 Niels Provos +Copyright 2008 Damien Miller +All rights reserved. + +Theo de Raadt 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. + +------------------------------------------------------------------- + +From: @(#)s_ilogb.c 5.1 93/09/24 +==================================================== +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + +Developed at SunPro, a Sun Microsystems, Inc. business. +Permission to use, copy, modify, and distribute this +software is freely granted, provided that this notice +is preserved. + +------------------------------------------------------------------- + +Portions Copyright (C) 2004, 2005, 2008, 2009 Internet Systems Consortium, Inc. ("ISC") +Portions Copyright (C) 1996-2003 Internet Software Consortium. + +Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC 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. + +------------------------------------------------------------------- + +Portions Copyright (c) 1993 by Digital Equipment Corporation. + +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, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION 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. + +------------------------------------------------------------------- + +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute this +Software with or without fee, provided that the above copyright notice and +all paragraphs of this notice appear in all copies, and that the name of IBM +not be used in connection with the marketing of any product incorporating +the Software or modifications thereof, without specific, written prior +permission. + +To the extent it has a right to do so, IBM grants an immunity from suit +under its patents, if any, for the use, sale or manufacture of products to +the extent that such products are used for performing Domain Name System +dynamic updates in TCP/IP networks by means of the Software. No immunity is +granted for any product per se or for any other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING +OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN +IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + +------------------------------------------------------------------- + +Portions Copyright(C) 1995, Jason Downs. 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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(S) 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 1998 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 1998, 1999 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 1998, 2000 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 1998-2000 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 1998-2001 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + +The author of this software is David M. Gay. + +Copyright (C) 2000 by Lucent Technologies +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of Lucent or any of its entities +not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, 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. + +------------------------------------------------------------------- + diff --git a/aosp/bionic/libc/SECCOMP_BLACKLIST_APP.TXT b/aosp/bionic/libc/SECCOMP_BLACKLIST_APP.TXT new file mode 100644 index 000000000..40ca22275 --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_BLACKLIST_APP.TXT @@ -0,0 +1,49 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# The final seccomp whitelist is SYSCALLS.TXT - SECCOMP_BLACKLIST.TXT + SECCOMP_WHITELIST.TXT +# Any entry in the blacklist must be in the syscalls file and not be in the whitelist file +# +# This file is processed by a python script named genseccomp.py. + +# Note: Some privileged syscalls are still needed in app process after fork before uid change, +# including capset and setresuid. This is because the seccomp filter must be installed while +# the process still has CAP_SYS_ADMIN; changing the uid would remove that capability. + +# syscalls to modify IDs +int setgid:setgid32(gid_t) lp32 +int setgid:setgid(gid_t) lp64 +int setuid:setuid32(uid_t) lp32 +int setuid:setuid(uid_t) lp64 +int setregid:setregid32(gid_t, gid_t) lp32 +int setregid:setregid(gid_t, gid_t) lp64 +int setreuid:setreuid32(uid_t, uid_t) lp32 +int setreuid:setreuid(uid_t, uid_t) lp64 +int setresgid:setresgid32(gid_t, gid_t, gid_t) lp32 +int setresgid:setresgid(gid_t, gid_t, gid_t) lp64 +# setresuid is explicitly allowed, see above. +int setfsgid(gid_t) all +int setfsuid(uid_t) all +int setgroups:setgroups32(int, const gid_t*) lp32 +int setgroups:setgroups(int, const gid_t*) lp64 + +# syscalls to modify times +int adjtimex(struct timex*) all +int clock_adjtime(clockid_t, struct timex*) all +int clock_settime(clockid_t, const struct timespec*) all +int settimeofday(const struct timeval*, const struct timezone*) all + +int acct(const char* filepath) all +int klogctl:syslog(int, char*, int) all +int chroot(const char*) all + +# syscalls to change machine various configurations +int init_module(void*, unsigned long, const char*) all +int delete_module(const char*, unsigned int) all +int mount(const char*, const char*, const char*, unsigned long, const void*) all +int umount2(const char*, int) all +int swapon(const char*, int) all +int swapoff(const char*) all +int setdomainname(const char*, size_t) all +int sethostname(const char*, size_t) all +int __reboot:reboot(int, int, int, void*) all diff --git a/aosp/bionic/libc/SECCOMP_BLACKLIST_COMMON.TXT b/aosp/bionic/libc/SECCOMP_BLACKLIST_COMMON.TXT new file mode 100644 index 000000000..8ae21c197 --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_BLACKLIST_COMMON.TXT @@ -0,0 +1,10 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# The final seccomp whitelist is SYSCALLS.TXT - SECCOMP_BLACKLIST.TXT + SECCOMP_WHITELIST.TXT +# Any entry in the blacklist must be in the syscalls file and not be in the whitelist file +# +# This file is processed by a python script named genseccomp.py. + +int swapon(const char*, int) all +int swapoff(const char*) all diff --git a/aosp/bionic/libc/SECCOMP_PRIORITY.TXT b/aosp/bionic/libc/SECCOMP_PRIORITY.TXT new file mode 100644 index 000000000..fb5ad4a79 --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_PRIORITY.TXT @@ -0,0 +1,10 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# This file is processed by a python script named genseccomp.py. +# +# The syscalls below are prioritized above other syscalls when checking seccomp policy, in +# the order of appearance in this file. + +futex +ioctl \ No newline at end of file diff --git a/aosp/bionic/libc/SECCOMP_WHITELIST_APP.TXT b/aosp/bionic/libc/SECCOMP_WHITELIST_APP.TXT new file mode 100644 index 000000000..dc48715ae --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_WHITELIST_APP.TXT @@ -0,0 +1,58 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# This file is processed by a python script named genseccomp.py. + +# Needed for debugging 32-bit Chrome +int pipe:pipe(int pipefd[2]) lp32 + +# b/34651972 +int access:access(const char *pathname, int mode) lp32 +int stat64:stat64(const char*, struct stat64*) lp32 + +# b/34813887 +int open:open(const char *path, int oflag, ... ) lp32,x86_64 +int getdents:getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) lp32,x86_64 + +# b/34719286 +int eventfd:eventfd(unsigned int initval, int flags) lp32 + +# b/34817266 +int epoll_wait:epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) lp32 + +# b/34908783 +int epoll_create:epoll_create(int size) lp32 + +# b/34979910 +int creat:creat(const char *pathname, mode_t mode) lp32 +int unlink:unlink(const char *pathname) lp32 + +# b/35059702 +int lstat64:lstat64(const char*, struct stat64*) lp32 + +# b/35217603 +int fcntl:fcntl(int fd, int cmd, ... /* arg */ ) lp32 +pid_t fork:fork() lp32 +int poll:poll(struct pollfd *fds, nfds_t nfds, int timeout) lp32 + +# b/35906875 +int inotify_init() lp32 +uid_t getuid() lp32 + +# b/36435222 +int remap_file_pages(void *addr, size_t size, int prot, size_t pgoff, int flags) lp32 + +# b/36449658 +int rename(const char *oldpath, const char *newpath) lp32 + +# b/36726183. Note arm does not support mmap +void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) x86 + +# b/37769298 +int dup2(int oldfd, int newfd) lp32 + +# b/62779795 +int compat_select:_newselect(int n, unsigned long* inp, unsigned long* outp, unsigned long* exp, struct timeval* timeout) lp32 + +# b/62090571 +int mkdir(const char *pathname, mode_t mode) lp32 diff --git a/aosp/bionic/libc/SECCOMP_WHITELIST_COMMON.TXT b/aosp/bionic/libc/SECCOMP_WHITELIST_COMMON.TXT new file mode 100644 index 000000000..56f9d1d34 --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_WHITELIST_COMMON.TXT @@ -0,0 +1,76 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# This file is processed by a python script named genseccomp.py. + +# syscalls needed to boot android +int pivot_root:pivot_root(const char *new_root, const char *put_old) lp64 +int ioprio_get:ioprio_get(int which, int who) lp64 +int ioprio_set:ioprio_set(int which, int who, int ioprio) lp64 +pid_t gettid:gettid() all +int futex:futex(int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, int val3) all +int clone:clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ..) all +int sigreturn:sigreturn(unsigned long __unused) lp32 +int rt_sigreturn:rt_sigreturn(unsigned long __unused) all +int rt_tgsigqueueinfo:int rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *uinfo) all +int restart_syscall:int restart_syscall() all + +# vfork is used by java.lang.ProcessBuilder +pid_t vfork:vfork() arm,x86,x86_64 + +# Needed for performance tools +int perf_event_open:perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags) all + +# Needed for strace +int tkill:tkill(int tid, int sig) all + +# b/34763393 +int seccomp:seccomp(unsigned int operation, unsigned int flags, void *args) all + +# Needed by sanitizers (b/34606909, b/136777266). +int open:open(const char*, int, ...) arm,x86,x86_64 +int stat64:stat64(const char*, struct stat64*) arm,x86 +ssize_t readlink:readlink(const char*, char*, size_t) arm,x86,x86_64 + +# +# Useful new syscalls which we don't yet use in bionic. +# + +# Since Linux 2.5, not in glibc. +int io_setup(unsigned nr, aio_context_t *ctxp) all +int io_destroy(aio_context_t ctx) all +int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) all +int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event *events, struct timespec *timeout) all +int io_cancel(aio_context_t ctx, struct iocb *, struct io_event *result) all +# Since Linux 3.14, not in glibc. +int sched_getattr(pid_t pid, struct sched_attr* attr, unsigned int flags) all +int sched_setattr(pid_t pid, struct sched_attr* attr, unsigned int size, unsigned int flags) all +# Since Linux 3.19, not in glibc (and not really needed to implement fexecve). +int execveat(int dirfd, const char* pathname, char* const* argv, char* const* envp, int flags) all +# Since Linux 4.3, not in glibc. Probed for and conditionally used by ART. +int membarrier(int cmd, int flags) all +# Since Linux 4.5, glibc 2.27. +ssize_t copy_file_range(int fd_in, loff_t* off_in, int fd_out, loff_t* off_out, size_t len, unsigned int flags) all +# Since Linux 4.6, glibc 2.26. +ssize_t preadv2(int fd, const struct iovec* iov, int iovcnt, off_t offset, int flags) all +ssize_t pwritev2(int fd, const struct iovec* iov, int iovcnt, off_t offset, int flags) all +# Since Linux 5.1, not in glibc. +int clock_gettime64(clockid_t, timespec64*) lp32 +int clock_settime64(clockid_t, const timespec64*) lp32 +int clock_adjtime64(clockid_t, timex64*) lp32 +int clock_getres_time64(clockid_t, timespec64*) lp32 +int clock_nanosleep_time64(clockid_t, int, const timespec64*, timespec*) lp32 +int timer_gettime64(__kernel_timer_t, itimerspec64*) lp32 +int timer_settime64(__kernel_timer_t, int, const itimerspec64*, itimerspec64*) lp32 +int timerfd_gettime64(int, itimerspec64*) lp32 +int timerfd_settime64(int, int, const itimerspec64*, itimerspec64*) lp32 +int utimensat_time64(int, const char*, const timespec64[2], int) lp32 +int pselect6_time64(int, fd_set*, fd_set*, timespec64*, void*) lp32 +int ppoll_time64(pollfd*, unsigned int, timespec64*, const sigset64_t*, size_t) lp32 +int recvmmsg_time64(int, mmsghdr*, unsigned int, int, const timespec64*) lp32 +int semtimedop_time64(int, sembuf*, size_t, const timespec64*) lp32 +int rt_sigtimedwait_time64(const sigset64_t*, siginfo_t*, const timespec64*, size_t) lp32 +int futex_time64(int*, int, int, const timespec64*, int*, int) lp32 +int sched_rr_get_interval_time64(pid_t, timespec64*) lp32 +# Since Linux 5.3, not in glibc. +int pidfd_open(pid_t pid, unsigned int flags) all diff --git a/aosp/bionic/libc/SECCOMP_WHITELIST_SYSTEM.TXT b/aosp/bionic/libc/SECCOMP_WHITELIST_SYSTEM.TXT new file mode 100644 index 000000000..266fe30f7 --- /dev/null +++ b/aosp/bionic/libc/SECCOMP_WHITELIST_SYSTEM.TXT @@ -0,0 +1,6 @@ +# This file is used to populate seccomp's whitelist policy in combination with SYSCALLS.TXT. +# Note that the resultant policy is applied only to zygote spawned processes. +# +# This file is processed by a python script named genseccomp.py. + +int bpf(int cmd, union bpf_attr *attr, unsigned int size) all diff --git a/aosp/bionic/libc/SYSCALLS.TXT b/aosp/bionic/libc/SYSCALLS.TXT new file mode 100644 index 000000000..ddfeebc95 --- /dev/null +++ b/aosp/bionic/libc/SYSCALLS.TXT @@ -0,0 +1,360 @@ +# This file is used to automatically generate bionic's system call stubs. +# +# Each non-blank, non-comment line has the following format: +# +# return_type func_name[|alias_list][:syscall_name[:socketcall_id]]([parameter_list]) arch_list +# +# where: +# arch_list ::= "all" | arches +# arches ::= arch | arch "," arches +# arch ::= "arm" | "arm64" | "x86" | "x86_64" | "lp32" | "lp64" +# +# Note: +# - syscall_name corresponds to the name of the syscall, which may differ from +# the exported function name (example: the exit syscall is implemented by the _exit() +# function, which is not the same as the standard C exit() function which calls it) +# +# - alias_list is optional comma separated list of function aliases. +# +# - The call_id parameter, given that func_name and syscall_name have +# been provided, allows the user to specify dispatch style syscalls. +# For example, socket() syscall on i386 actually becomes: +# socketcall(__NR_socket, 1, *(rest of args on stack)). +# +# - Each parameter type is assumed to be stored in 32 bits. +# +# This file is processed by a python script named gensyscalls.py, run via +# genrules in Android.bp. + +int execve(const char*, char* const*, char* const*) all + +uid_t getuid:getuid32() lp32 +uid_t getuid:getuid() lp64 +gid_t getgid:getgid32() lp32 +gid_t getgid:getgid() lp64 +uid_t geteuid:geteuid32() lp32 +uid_t geteuid:geteuid() lp64 +gid_t getegid:getegid32() lp32 +gid_t getegid:getegid() lp64 +uid_t getresuid:getresuid32(uid_t* ruid, uid_t* euid, uid_t* suid) lp32 +uid_t getresuid:getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) lp64 +gid_t getresgid:getresgid32(gid_t* rgid, gid_t* egid, gid_t* sgid) lp32 +gid_t getresgid:getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) lp64 +ssize_t readahead(int, off64_t, size_t) all +int getgroups:getgroups32(int, gid_t*) lp32 +int getgroups:getgroups(int, gid_t*) lp64 +pid_t getpgid(pid_t) all +pid_t getppid() all +pid_t getsid(pid_t) all +pid_t setsid() all +int setgid:setgid32(gid_t) lp32 +int setgid:setgid(gid_t) lp64 +int setuid:setuid32(uid_t) lp32 +int setuid:setuid(uid_t) lp64 +int setreuid:setreuid32(uid_t, uid_t) lp32 +int setreuid:setreuid(uid_t, uid_t) lp64 +int setresuid:setresuid32(uid_t, uid_t, uid_t) lp32 +int setresuid:setresuid(uid_t, uid_t, uid_t) lp64 +int setresgid:setresgid32(gid_t, gid_t, gid_t) lp32 +int setresgid:setresgid(gid_t, gid_t, gid_t) lp64 +void* __brk:brk(void*) all +int kill(pid_t, int) all +int tgkill(pid_t tgid, pid_t tid, int sig) all +int __ptrace:ptrace(int request, int pid, void* addr, void* data) all + +# +int getrusage(int, struct rusage*) all +int __getpriority:getpriority(int, id_t) all +int setpriority(int, id_t, int) all +# On LP64, rlimit and rlimit64 are the same. +# On 32-bit systems we use prlimit64 to implement the rlimit64 functions. +int getrlimit:ugetrlimit(int, struct rlimit*) lp32 +int getrlimit|getrlimit64(int, struct rlimit*) lp64 +int setrlimit(int, const struct rlimit*) lp32 +int setrlimit|setrlimit64(int, const struct rlimit*) lp64 +int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*) lp64 +int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*) lp32 + +int setgroups:setgroups32(int, const gid_t*) lp32 +int setgroups:setgroups(int, const gid_t*) lp64 +int setpgid(pid_t, pid_t) all +int setregid:setregid32(gid_t, gid_t) lp32 +int setregid:setregid(gid_t, gid_t) lp64 +int chroot(const char*) all +int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long) all +long __arch_prctl:arch_prctl(int, unsigned long) x86_64 +int capget(cap_user_header_t header, cap_user_data_t data) all +int capset(cap_user_header_t header, const cap_user_data_t data) all +int sigaltstack(const stack_t*, stack_t*) all +int acct(const char* filepath) all + +# file descriptors +ssize_t read(int, void*, size_t) all +ssize_t write(int, const void*, size_t) all +ssize_t pread64(int, void*, size_t, off64_t) lp32 +ssize_t pread64|pread(int, void*, size_t, off_t) lp64 +ssize_t pwrite64(int, void*, size_t, off64_t) lp32 +ssize_t pwrite64|pwrite(int, void*, size_t, off_t) lp64 + +# On LP32, preadv/pwritev don't use off64_t --- they use pairs of 32-bit +# arguments to avoid problems on architectures like ARM where 64-bit arguments +# must be in a register pair starting with an even-numbered register. +# See linux/fs/read_write.c and https://lwn.net/Articles/311630/. +ssize_t __preadv64:preadv(int, const struct iovec*, int, long, long) lp32 +ssize_t preadv|preadv64(int, const struct iovec*, int, off_t) lp64 +ssize_t __pwritev64:pwritev(int, const struct iovec*, int, long, long) lp32 +ssize_t pwritev|pwritev64(int, const struct iovec*, int, off_t) lp64 + +int __close:close(int) all +pid_t __getpid:getpid() all +int memfd_create(const char*, unsigned) all +int munmap(void*, size_t) all +void* __mremap:mremap(void*, size_t, size_t, int, void*) all +int msync(const void*, size_t, int) all +int mprotect(const void*, size_t, int) all +int madvise(void*, size_t, int) all +int mlock(const void* addr, size_t len) all +int mlock2(const void* addr, size_t len, int flags) all +int munlock(const void* addr, size_t len) all +int mlockall(int flags) all +int munlockall() all +int mincore(void* start, size_t length, unsigned char* vec) all +int __ioctl:ioctl(int, int, void*) all +ssize_t readv(int, const struct iovec*, int) all +ssize_t writev(int, const struct iovec*, int) all +int __fcntl64:fcntl64(int, int, void*) lp32 +int __fcntl:fcntl(int, int, void*) lp64 +int flock(int, int) all +int __fchmod:fchmod(int, mode_t) all +int __pipe2:pipe2(int*, int) all +int __dup:dup(int) all +int __dup3:dup3(int, int, int) all +int fsync(int) all +int fdatasync(int) all +int fchown:fchown32(int, uid_t, gid_t) lp32 +int fchown:fchown(int, uid_t, gid_t) lp64 +void sync(void) all +int syncfs(int) all +int __fsetxattr:fsetxattr(int, const char*, const void*, size_t, int) all +ssize_t __fgetxattr:fgetxattr(int, const char*, void*, size_t) all +ssize_t __flistxattr:flistxattr(int, char*, size_t) all +int fremovexattr(int, const char*) all + +int __getdents64:getdents64(unsigned int, struct dirent*, unsigned int) all + +int __openat:openat(int, const char*, int, mode_t) all +int __faccessat:faccessat(int, const char*, int) all +int __fchmodat:fchmodat(int, const char*, mode_t) all +int fchownat(int, const char*, uid_t, gid_t, int) all +int fstatat64|fstatat:fstatat64(int, const char*, struct stat*, int) lp32 +int fstatat64|fstatat:newfstatat(int, const char*, struct stat*, int) arm64,x86_64 +int linkat(int, const char*, int, const char*, int) all +int mkdirat(int, const char*, mode_t) all +int mknodat(int, const char*, mode_t, dev_t) all +int readlinkat(int, const char*, char*, size_t) all +int renameat(int, const char*, int, const char*) all +int renameat2(int, const char*, int, const char*, unsigned) all +int symlinkat(const char*, int, const char*) all +int unlinkat(int, const char*, int) all +int utimensat(int, const char*, const struct timespec times[2], int) all + +# Paired off_t/off64_t system calls. On 64-bit systems, +# sizeof(off_t) == sizeof(off64_t), so there we emit two symbols that are +# aliases. On 32-bit systems, we have two different system calls. +# That means that every system call in this section should take three lines. +off_t lseek(int, off_t, int) lp32 +int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) lp32 +off_t lseek|lseek64(int, off_t, int) lp64 +int ftruncate64(int, off64_t) lp32 +int ftruncate|ftruncate64(int, off_t) lp64 +ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) lp32 +ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) lp32 +ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) lp64 +int truncate(const char*, off_t) lp32 +int truncate64(const char*, off64_t) lp32 +int truncate|truncate64(const char*, off_t) lp64 +# (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.) +void* __mmap2:mmap2(void*, size_t, int, int, int, long) lp32 +void* mmap|mmap64(void*, size_t, int, int, int, off_t) lp64 +# (fallocate only gets two lines because there is no 32-bit variant.) +int fallocate64:fallocate(int, int, off64_t, off64_t) lp32 +int fallocate|fallocate64(int, int, off_t, off_t) lp64 + +# posix_fadvise64 is awkward: arm has shuffled arguments, +# the POSIX functions don't set errno, and no architecture has posix_fadvise. +int __arm_fadvise64_64:arm_fadvise64_64(int, int, off64_t, off64_t) arm +int __fadvise64:fadvise64_64(int, off64_t, off64_t, int) x86 +int __fadvise64:fadvise64(int, off64_t, off64_t, int) lp64 + +int __fstatfs64:fstatfs64(int, size_t, struct statfs*) lp32 +int __fstatfs:fstatfs(int, struct statfs*) lp64 +int __statfs64:statfs64(const char*, size_t, struct statfs*) lp32 +int __statfs:statfs(const char*, struct statfs*) lp64 + +int fstat64|fstat:fstat64(int, struct stat*) lp32 +int fstat64|fstat:fstat(int, struct stat*) arm64,x86_64 + +# file system +int chdir(const char*) all +int mount(const char*, const char*, const char*, unsigned long, const void*) all +int umount2(const char*, int) all +int __getcwd:getcwd(char* buf, size_t size) all +int fchdir(int) all +int setxattr(const char*, const char*, const void*, size_t, int) all +int lsetxattr(const char*, const char*, const void*, size_t, int) all +ssize_t getxattr(const char*, const char*, void*, size_t) all +ssize_t lgetxattr(const char*, const char*, void*, size_t) all +ssize_t listxattr(const char*, char*, size_t) all +ssize_t llistxattr(const char*, char*, size_t) all +int removexattr(const char*, const char*) all +int lremovexattr(const char*, const char*) all +int statx(int, const char*, int, unsigned, struct statx*) all +int swapon(const char*, int) all +int swapoff(const char*) all + +# time +int settimeofday(const struct timeval*, const struct timezone*) all +clock_t times(struct tms*) all +int nanosleep(const struct timespec*, struct timespec*) all +int clock_settime(clockid_t, const struct timespec*) all +int __clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*) all +int getitimer(int, struct itimerval*) all +int setitimer(int, const struct itimerval*, struct itimerval*) all +int __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid) all +int __timer_settime:timer_settime(__kernel_timer_t, int, const struct itimerspec*, struct itimerspec*) all +int __timer_gettime:timer_gettime(__kernel_timer_t, struct itimerspec*) all +int __timer_getoverrun:timer_getoverrun(__kernel_timer_t) all +int __timer_delete:timer_delete(__kernel_timer_t) all +int timerfd_create(clockid_t, int) all +int timerfd_settime(int, int, const struct itimerspec*, struct itimerspec*) all +int timerfd_gettime(int, struct itimerspec*) all +int adjtimex(struct timex*) all +int clock_adjtime(clockid_t, struct timex*) all + +# signals +int __sigaction:sigaction(int, const struct sigaction*, struct sigaction*) lp32 +int __rt_sigaction:rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t) all +int __rt_sigpending:rt_sigpending(sigset64_t*, size_t) all +int __rt_sigprocmask:rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t) all +int __rt_sigsuspend:rt_sigsuspend(const sigset64_t*, size_t) all +int __rt_sigtimedwait:rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t) all +int __rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*) all +int __signalfd4:signalfd4(int, const sigset64_t*, size_t, int) all + +# sockets +int __socket:socket(int, int, int) arm,lp64 +int __socketpair:socketpair(int, int, int, int*) arm,lp64 +int bind(int, struct sockaddr*, socklen_t) arm,lp64 +int __connect:connect(int, struct sockaddr*, socklen_t) arm,lp64 +int listen(int, int) arm,lp64 +int __accept4:accept4(int, struct sockaddr*, socklen_t*, int) arm,lp64 +int getsockname(int, struct sockaddr*, socklen_t*) arm,lp64 +int getpeername(int, struct sockaddr*, socklen_t*) arm,lp64 +ssize_t __sendto:sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t) arm,lp64 +ssize_t recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*) arm,lp64 +int shutdown(int, int) arm,lp64 +int setsockopt(int, int, int, const void*, socklen_t) arm,lp64 +int getsockopt(int, int, int, void*, socklen_t*) arm,lp64 +ssize_t __recvmsg:recvmsg(int, struct msghdr*, unsigned int) arm,lp64 +ssize_t __sendmsg:sendmsg(int, const struct msghdr*, unsigned int) arm,lp64 +int __recvmmsg:recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,lp64 +int __sendmmsg:sendmmsg(int, struct mmsghdr*, unsigned int, int) arm,lp64 + +# sockets for x86. These are done as an "indexed" call to socketcall syscall. +int __socket:socketcall:1(int, int, int) x86 +int bind:socketcall:2(int, struct sockaddr*, int) x86 +int __connect:socketcall:3(int, struct sockaddr*, socklen_t) x86 +int listen:socketcall:4(int, int) x86 +int getsockname:socketcall:6(int, struct sockaddr*, socklen_t*) x86 +int getpeername:socketcall:7(int, struct sockaddr*, socklen_t*) x86 +int __socketpair:socketcall:8(int, int, int, int*) x86 +ssize_t __sendto:socketcall:11(int, const void*, size_t, int, const struct sockaddr*, socklen_t) x86 +ssize_t recvfrom:socketcall:12(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*) x86 +int shutdown:socketcall:13(int, int) x86 +int setsockopt:socketcall:14(int, int, int, const void*, socklen_t) x86 +int getsockopt:socketcall:15(int, int, int, void*, socklen_t*) x86 +int __sendmsg:socketcall:16(int, const struct msghdr*, unsigned int) x86 +int __recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86 +int __accept4:socketcall:18(int, struct sockaddr*, socklen_t*, int) x86 +int __recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86 +int __sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int) x86 + +# scheduler & real-time +int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param) all +int sched_getscheduler(pid_t pid) all +int sched_yield(void) all +int sched_setparam(pid_t pid, const struct sched_param* param) all +int sched_getparam(pid_t pid, struct sched_param* param) all +int sched_get_priority_max(int policy) all +int sched_get_priority_min(int policy) all +int sched_rr_get_interval(pid_t pid, struct timespec* interval) all +int sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set) all +int setns(int, int) all +int unshare(int) all +int __sched_getaffinity:sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set) all +int __getcpu:getcpu(unsigned*, unsigned*, void*) all + +# other +int uname(struct utsname*) all +mode_t umask(mode_t) all +int __reboot:reboot(int, int, int, void*) all +int init_module(void*, unsigned long, const char*) all +int delete_module(const char*, unsigned int) all +int klogctl:syslog(int, char*, int) all +int sysinfo(struct sysinfo*) all +int personality(unsigned long) all + +ssize_t tee(int, int, size_t, unsigned int) all +ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int) all +ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) all + +int __epoll_create1:epoll_create1(int) all +int epoll_ctl(int, int op, int, struct epoll_event*) all +int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset64_t*, size_t) all + +int __eventfd:eventfd2(unsigned int, int) all + +void _exit|_Exit:exit_group(int) all +void __exit:exit(int) all + +int inotify_init1(int) all +int inotify_add_watch(int, const char*, unsigned int) all +int inotify_rm_watch(int, unsigned int) all + +int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*) all +int __ppoll:ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t) all + +ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all +ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all + +int quotactl(int, const char*, int, char*) all + +int __set_tid_address:set_tid_address(int*) all + +int setfsgid(gid_t) all +int setfsuid(uid_t) all + +int setdomainname(const char*, size_t) all +int sethostname(const char*, size_t) all + +int __sync_file_range:sync_file_range(int, off64_t, off64_t, unsigned int) arm64,x86,x86_64 +int __sync_file_range2:sync_file_range2(int, unsigned int, off64_t, off64_t) arm + +pid_t wait4(pid_t, int*, int, struct rusage*) all +int __waitid:waitid(int, pid_t, siginfo_t*, int, void*) all + +# ARM-specific +int __set_tls:__ARM_NR_set_tls(void*) arm +int cacheflush:__ARM_NR_cacheflush(long start, long end, long flags) arm + +# x86-specific +int __set_thread_area:set_thread_area(void*) x86 + +# vdso stuff. +int __clock_getres:clock_getres(clockid_t, struct timespec*) all +int __clock_gettime:clock_gettime(clockid_t, struct timespec*) all +int __gettimeofday:gettimeofday(struct timeval*, struct timezone*) all + +# +ssize_t getrandom(void*, size_t, unsigned) all +int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) all \ No newline at end of file diff --git a/aosp/bionic/libc/arch-arm/bionic/__aeabi.c b/aosp/bionic/libc/arch-arm/bionic/__aeabi.c new file mode 100644 index 000000000..c82f56d23 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/__aeabi.c @@ -0,0 +1,183 @@ +/* + * 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. + */ + +// clang interprets -fno-builtin more loosely than you might expect, +// and thinks it's okay to still substitute builtins as long as they're +// named __aeabi_* rather than __builtin_*, which causes infinite +// recursion if we have the fortified memcpy visible in this file. +#undef _FORTIFY_SOURCE + +#include +#include + +extern int __cxa_atexit(void (*)(void*), void*, void*); + +// All of these are weak symbols to avoid multiple definition errors when +// linking with libstdc++-v3 or compiler-rt. + +/* The "C++ ABI for ARM" document states that static C++ constructors, + * which are called from the .init_array, should manually call + * __aeabi_atexit() to register static destructors explicitly. + * + * Note that 'dso_handle' is the address of a magic linker-generate + * variable from the shared object that contains the constructor/destructor + */ + +int __attribute__((weak)) +__aeabi_atexit_impl(void *object, void (*destructor) (void *), void *dso_handle) { + return __cxa_atexit(destructor, object, dso_handle); +} + +int __attribute__((weak)) +__aeabi_atexit_impl2(void *object, void (*destructor) (void *), void *dso_handle) { + return __cxa_atexit(destructor, object, dso_handle); +} + + +void __attribute__((weak)) __aeabi_memcpy8_impl(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memcpy4_impl(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memcpy_impl(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memcpy8_impl2(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memcpy4_impl2(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memcpy_impl2(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); +} + + +void __attribute__((weak)) __aeabi_memmove8_impl(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memmove4_impl(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memmove_impl(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memmove8_impl2(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memmove4_impl2(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, size_t n) { + memmove(dest, src, n); +} + +/* + * __aeabi_memset has the order of its second and third arguments reversed. + * This allows __aeabi_memclr to tail-call __aeabi_memset + */ + +void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) { + memset(dest, c, n); +} + +void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) { + memset(dest, c, n); +} + +void __attribute__((weak)) __aeabi_memset_impl(void *dest, size_t n, int c) { + memset(dest, c, n); +} + +void __attribute__((weak)) __aeabi_memset8_impl2(void *dest, size_t n, int c) { + memset(dest, c, n); +} + +void __attribute__((weak)) __aeabi_memset4_impl2(void *dest, size_t n, int c) { + memset(dest, c, n); +} + +void __attribute__((weak)) __aeabi_memset_impl2(void *dest, size_t n, int c) { + memset(dest, c, n); +} + + +void __attribute__((weak)) __aeabi_memclr8_impl(void *dest, size_t n) { + __aeabi_memset8_impl(dest, n, 0); +} + +void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) { + __aeabi_memset4_impl(dest, n, 0); +} + +void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) { + __aeabi_memset_impl(dest, n, 0); +} + +void __attribute__((weak)) __aeabi_memclr8_impl2(void *dest, size_t n) { + __aeabi_memset8_impl(dest, n, 0); +} + +void __attribute__((weak)) __aeabi_memclr4_impl2(void *dest, size_t n) { + __aeabi_memset4_impl(dest, n, 0); +} + +void __attribute__((weak)) __aeabi_memclr_impl2(void *dest, size_t n) { + __aeabi_memset_impl(dest, n, 0); +} + +#define __AEABI_SYMVERS(fn_name) \ +__asm__(".symver " #fn_name "_impl, " #fn_name "@@LIBC_N"); \ +__asm__(".symver " #fn_name "_impl2, " #fn_name "@LIBC_PRIVATE") + +__AEABI_SYMVERS(__aeabi_atexit); +__AEABI_SYMVERS(__aeabi_memcpy8); +__AEABI_SYMVERS(__aeabi_memcpy4); +__AEABI_SYMVERS(__aeabi_memcpy); +__AEABI_SYMVERS(__aeabi_memmove8); +__AEABI_SYMVERS(__aeabi_memmove4); +__AEABI_SYMVERS(__aeabi_memmove); +__AEABI_SYMVERS(__aeabi_memset8); +__AEABI_SYMVERS(__aeabi_memset4); +__AEABI_SYMVERS(__aeabi_memset); +__AEABI_SYMVERS(__aeabi_memclr8); +__AEABI_SYMVERS(__aeabi_memclr4); +__AEABI_SYMVERS(__aeabi_memclr); + +#undef __AEABI_SYMVERS diff --git a/aosp/bionic/libc/arch-arm/bionic/__aeabi_read_tp.S b/aosp/bionic/libc/arch-arm/bionic/__aeabi_read_tp.S new file mode 100644 index 000000000..f6f975707 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/__aeabi_read_tp.S @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 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 + +// For arm32 and -mtp=soft, the compiler uses this function to read the thread +// pointer for ELF TLS accesses. With -mtp=cp15, the compiler inlines the call +// instead. GCC defaults to -mtp=auto, which inlines this function with +// -march=armv7-a. Clang does not yet implement -mtp=auto, and instead defaults +// to -mtp=soft. +// - https://bugs.llvm.org/show_bug.cgi?id=38394. +// - https://reviews.llvm.org/D34878?id=114573. +// +// This function must preserve every register except r0, ip, lr, and cpsr. +// +// See "Run-time ABI for the ARM Architecture" +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0043d/IHI0043D_rtabi.pdf +// +ENTRY(__aeabi_read_tp) + // __get_tls() + mrc p15, 0, r0, c13, c0, 3 + bx lr +END(__aeabi_read_tp) diff --git a/aosp/bionic/libc/arch-arm/bionic/__bionic_clone.S b/aosp/bionic/libc/arch-arm/bionic/__bionic_clone.S new file mode 100644 index 000000000..6669b93a2 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/__bionic_clone.S @@ -0,0 +1,69 @@ +/* + * 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 + +// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg); +ENTRY_PRIVATE(__bionic_clone) + mov ip, sp + # save registers to parent stack + stmfd sp!, {r4, r5, r6, r7} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset r6, 8 + .cfi_rel_offset r7, 12 + + # load extra parameters + ldmfd ip, {r4, r5, r6} + + # Push 'fn' and 'arg' onto the child stack. + stmdb r1!, {r5, r6} + + # Make the system call. + ldr r7, =__NR_clone + swi #0 + + # Are we the child? + movs r0, r0 + beq .L_bc_child + + # In the parent, reload saved registers then either return or set errno. + ldmfd sp!, {r4, r5, r6, r7} + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno_internal + +.L_bc_child: + # Setting lr to 0 will make the unwinder stop at __start_thread. + mov lr, #0 + # Call __start_thread with the 'fn' and 'arg' we stored on the child stack. + pop {r0, r1} + b __start_thread +END(__bionic_clone) diff --git a/aosp/bionic/libc/arch-arm/bionic/__restore.S b/aosp/bionic/libc/arch-arm/bionic/__restore.S new file mode 100644 index 000000000..8c1e41d53 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/__restore.S @@ -0,0 +1,63 @@ +/* + * 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 + +// gdb is smart enough to unwind through signal frames with just the regular +// CFI information but libgcc and libunwind both need extra help. We do this +// by using .fnstart/.fnend and inserting a nop before both __restore and +// __restore_rt (but covered by the .fnstart/.fnend) so that although they're +// not inside the functions from objdump's point of view, an unwinder that +// blindly looks at the previous instruction (but is then smart enough to check +// the unwind information to find out where it landed) gets the right answer. +// Make sure not to have both DWARF and ARM unwind information, so only +// use the ARM unwind information. + +// We need to place .fnstart ourselves (but we may as well keep the free .fnend). +#undef __bionic_asm_custom_entry +#define __bionic_asm_custom_entry(f) + + .fnstart + .save {r0-r15} + .pad #32 + nop +ENTRY_PRIVATE_NO_DWARF(__restore) + // This function must have exactly this instruction sequence. + mov r7, #__NR_sigreturn + swi #0 +END_NO_DWARF(__restore) + + .fnstart + .save {r0-r15} + .pad #160 + nop +ENTRY_PRIVATE_NO_DWARF(__restore_rt) + // This function must have exactly this instruction sequence. + mov r7, #__NR_rt_sigreturn + swi #0 +END_NO_DWARF(__restore_rt) diff --git a/aosp/bionic/libc/arch-arm/bionic/_exit_with_stack_teardown.S b/aosp/bionic/libc/arch-arm/bionic/_exit_with_stack_teardown.S new file mode 100644 index 000000000..1a67fedfc --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/_exit_with_stack_teardown.S @@ -0,0 +1,41 @@ +/* + * 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 + +// void _exit_with_stack_teardown(void* stackBase, size_t stackSize) +ENTRY_PRIVATE(_exit_with_stack_teardown) + ldr r7, =__NR_munmap + swi #0 + // If munmap failed, we ignore the failure and exit anyway. + + mov r0, #0 + ldr r7, =__NR_exit + swi #0 + // The exit syscall does not return. +END(_exit_with_stack_teardown) diff --git a/aosp/bionic/libc/arch-arm/bionic/atexit_legacy.c b/aosp/bionic/libc/arch-arm/bionic/atexit_legacy.c new file mode 100644 index 000000000..7254017cc --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/atexit_legacy.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 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 +#include + +#include + +/* + * This source file should only be included by libc.so, its purpose is + * to support legacy ARM binaries by exporting a publicly visible + * implementation of atexit(). + */ + +extern int __cxa_atexit(void (*func)(void *), void *arg, void *dso); + +/* + * Register a function to be performed at exit. + */ +int +atexit(void (*func)(void)) +{ + /* + * Exit functions queued by this version of atexit will not be called + * on dlclose(), and when they are called (at program exit), the + * calling library may have been dlclose()'d, causing the program to + * crash. + */ + static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n"; + + async_safe_format_log(ANDROID_LOG_WARN, "libc", warning); + fprintf(stderr, warning); + + return (__cxa_atexit((void (*)(void *))func, NULL, NULL)); +} diff --git a/aosp/bionic/libc/arch-arm/bionic/atomics_arm.c b/aosp/bionic/libc/arch-arm/bionic/atomics_arm.c new file mode 100644 index 000000000..d69eaff9e --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/atomics_arm.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 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. + */ + + +/* The purpose of this file is to export a small set of atomic-related + * functions from the C library, to ensure binary ABI compatibility for + * the NDK. + * + * These functions were initially exposed by the NDK through , + * which was unfortunate because their implementation didn't provide any + * memory barriers at all. + * + * This wasn't a problem for the platform code that used them, because it + * used explicit barrier instructions around them. On the other hand, it means + * that any NDK-generated machine code that linked against them would not + * perform correctly when running on multi-core devices. + * + * To fix this, the platform code was first modified to not use any of these + * functions (everything is now inlined through assembly statements, see + * libc/private/bionic_arm_inline.h and the headers it includes. + * + * The functions here are thus only for the benefit of NDK applications, + * and now includes full memory barriers to prevent any random memory ordering + * issue from cropping. + * + * Note that we also provide an updated header that defines + * always_inlined versions of the functions that use the GCC builtin + * intrinsics to perform the same thing. + * + * NOTE: There is no need for a similar file for non-ARM platforms. + */ + +/* DO NOT INCLUDE HERE ! */ + +int +__atomic_cmpxchg(int old, int _new, volatile int *ptr) +{ + /* We must return 0 on success */ + return __sync_val_compare_and_swap(ptr, old, _new) != old; +} + +int +__atomic_swap(int _new, volatile int *ptr) +{ + int prev; + do { + prev = *ptr; + } while (__sync_val_compare_and_swap(ptr, prev, _new) != prev); + return prev; +} + +int +__atomic_dec(volatile int *ptr) +{ + return __sync_fetch_and_sub (ptr, 1); +} + +int +__atomic_inc(volatile int *ptr) +{ + return __sync_fetch_and_add (ptr, 1); +} diff --git a/aosp/bionic/libc/arch-arm/bionic/bpabi.c b/aosp/bionic/libc/arch-arm/bionic/bpabi.c new file mode 100644 index 000000000..5c9cd99c6 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/bpabi.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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. + */ + +extern long long __divdi3(long long, long long); +extern unsigned long long __udivdi3(unsigned long long, unsigned long long); + +long long __gnu_ldivmod_helper(long long a, long long b, long long* remainder) { + long long quotient = __divdi3(a, b); + *remainder = a - b * quotient; + return quotient; +} + +unsigned long long __gnu_uldivmod_helper(unsigned long long a, unsigned long long b, + unsigned long long* remainder) { + unsigned long long quotient = __udivdi3(a, b); + *remainder = a - b * quotient; + return quotient; +} diff --git a/aosp/bionic/libc/arch-arm/bionic/exidx_dynamic.c b/aosp/bionic/libc/arch-arm/bionic/exidx_dynamic.c new file mode 100644 index 000000000..60ac8af58 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/exidx_dynamic.c @@ -0,0 +1,49 @@ +/* + * 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 + +/* For a given PC, find the .so that it belongs to. + * Returns the base address of the .ARM.exidx section + * for that .so, and the number of 8-byte entries + * in that section (via *pcount). + * + * libgcc declares __gnu_Unwind_Find_exidx() as a weak symbol, with + * the expectation that libc will define it and call through to + * a differently-named function in the dynamic linker. + */ +_Unwind_Ptr __gnu_Unwind_Find_exidx_impl(_Unwind_Ptr pc, int *pcount) { + return dl_unwind_find_exidx(pc, pcount); +} + +_Unwind_Ptr __gnu_Unwind_Find_exidx_impl2(_Unwind_Ptr pc, int *pcount) { + return dl_unwind_find_exidx(pc, pcount); +} + +__asm__(".symver __gnu_Unwind_Find_exidx_impl,__gnu_Unwind_Find_exidx@LIBC_PRIVATE"); +__asm__(".symver __gnu_Unwind_Find_exidx_impl2,__gnu_Unwind_Find_exidx@@LIBC_N"); diff --git a/aosp/bionic/libc/arch-arm/bionic/exidx_static.c b/aosp/bionic/libc/arch-arm/bionic/exidx_static.c new file mode 100644 index 000000000..9830c54de --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/exidx_static.c @@ -0,0 +1,53 @@ +/* + * 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 + +/* Find the .ARM.exidx section (which in the case of a static executable + * can be identified through its start and end symbols), and return its + * beginning and number of entries to the caller. Note that for static + * executables we do not need to use the value of the PC to find the + * EXIDX section. + */ + +struct exidx_entry { + uint32_t key; + uint32_t value; +}; + +extern struct exidx_entry __exidx_end; +extern struct exidx_entry __exidx_start; + +_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc __attribute__((unused)), int* pcount) { + *pcount = (&__exidx_end - &__exidx_start); + return (_Unwind_Ptr)&__exidx_start; +} + +_Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount) { + return dl_unwind_find_exidx(pc, pcount); +} diff --git a/aosp/bionic/libc/arch-arm/bionic/kuser_helper_on.S b/aosp/bionic/libc/arch-arm/bionic/kuser_helper_on.S new file mode 100644 index 000000000..cff2073b7 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/kuser_helper_on.S @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 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. + */ + + .section .note.android.kuser_helper_on,"a",%note + .balign 4 + .type kuser_helper_on, %object +kuser_helper_on: + .long 2f-1f // int32_t namesz + .long 3f-2f // int32_t descsz + .long 3 // int32_t type +1:.ascii "Android\0" // char name[] +2:.long 1 // int32_t on +3: + .size kuser_helper_on, .-kuser_helper_on diff --git a/aosp/bionic/libc/arch-arm/bionic/libcrt_compat.c b/aosp/bionic/libc/arch-arm/bionic/libcrt_compat.c new file mode 100644 index 000000000..ce77a5dea --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/libcrt_compat.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2016 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. + */ + +extern char __adddf3; +extern char __addsf3; +extern char __aeabi_cdcmpeq; +extern char __aeabi_cdcmple; +extern char __aeabi_cdrcmple; +extern char __aeabi_cfcmpeq; +extern char __aeabi_cfcmple; +extern char __aeabi_cfrcmple; +extern char __aeabi_d2f; +extern char __aeabi_d2iz; +extern char __aeabi_d2uiz; +extern char __aeabi_dadd; +extern char __aeabi_dcmpeq; +extern char __aeabi_dcmpge; +extern char __aeabi_dcmpgt; +extern char __aeabi_dcmple; +extern char __aeabi_dcmplt; +extern char __aeabi_dcmpun; +extern char __aeabi_ddiv; +extern char __aeabi_dmul; +extern char __aeabi_drsub; +extern char __aeabi_dsub; +extern char __aeabi_f2d; +extern char __aeabi_f2iz; +extern char __aeabi_f2uiz; +extern char __aeabi_fadd; +extern char __aeabi_fcmpeq; +extern char __aeabi_fcmpge; +extern char __aeabi_fcmpgt; +extern char __aeabi_fcmple; +extern char __aeabi_fcmplt; +extern char __aeabi_fcmpun; +extern char __aeabi_fdiv; +extern char __aeabi_fmul; +extern char __aeabi_frsub; +extern char __aeabi_fsub; +extern char __aeabi_i2d; +extern char __aeabi_i2f; +extern char __aeabi_idiv; +extern char __aeabi_idivmod; +extern char __aeabi_l2d; +extern char __aeabi_l2f; +extern char __aeabi_lasr; +extern char __aeabi_ldivmod; +extern char __aeabi_llsl; +extern char __aeabi_llsr; +extern char __aeabi_lmul; +extern char __aeabi_ui2d; +extern char __aeabi_ui2f; +extern char __aeabi_uidiv; +extern char __aeabi_uidivmod; +extern char __aeabi_ul2d; +extern char __aeabi_ul2f; +extern char __aeabi_uldivmod; +extern char __aeabi_unwind_cpp_pr0; +extern char __aeabi_unwind_cpp_pr1; +extern char __cmpdf2; +extern char __cmpsf2; +extern char __divdf3; +extern char __divsf3; +extern char __eqdf2; +extern char __eqsf2; +extern char __extendsfdf2; +extern char __fixdfsi; +extern char __fixsfsi; +extern char __fixunsdfsi; +extern char __floatdidf; +extern char __floatdisf; +extern char __floatsidf; +extern char __floatsisf; +extern char __floatundidf; +extern char __floatundisf; +extern char __floatunsidf; +extern char __floatunsisf; +extern char __gedf2; +extern char __gesf2; +extern char __gtdf2; +extern char __gtsf2; +extern char __gnu_ldivmod_helper; +extern char __gnu_uldivmod_helper; +extern char __ledf2; +extern char __lesf2; +extern char __ltdf2; +extern char __ltsf2; +extern char __muldf3; +extern char __muldi3; +extern char __mulsf3; +extern char __nedf2; +extern char __nesf2; +extern char __popcount_tab; +extern char __popcountsi2; +extern char __subdf3; +extern char __subsf3; +extern char __truncdfsf2; +extern char __udivdi3; +extern char __unorddf2; +extern char __unordsf2; + +void* __bionic_libcrt_compat_symbols[] = { + &__adddf3, + &__addsf3, + &__aeabi_cdcmpeq, + &__aeabi_cdcmple, + &__aeabi_cdrcmple, + &__aeabi_cfcmpeq, + &__aeabi_cfcmple, + &__aeabi_cfrcmple, + &__aeabi_d2f, + &__aeabi_d2iz, + &__aeabi_d2uiz, + &__aeabi_dadd, + &__aeabi_dcmpeq, + &__aeabi_dcmpge, + &__aeabi_dcmpgt, + &__aeabi_dcmple, + &__aeabi_dcmplt, + &__aeabi_dcmpun, + &__aeabi_ddiv, + &__aeabi_dmul, + &__aeabi_drsub, + &__aeabi_dsub, + &__aeabi_f2d, + &__aeabi_f2iz, + &__aeabi_f2uiz, + &__aeabi_fadd, + &__aeabi_fcmpeq, + &__aeabi_fcmpge, + &__aeabi_fcmpgt, + &__aeabi_fcmple, + &__aeabi_fcmplt, + &__aeabi_fcmpun, + &__aeabi_fdiv, + &__aeabi_fmul, + &__aeabi_frsub, + &__aeabi_fsub, + &__aeabi_i2d, + &__aeabi_i2f, + &__aeabi_idiv, + &__aeabi_idivmod, + &__aeabi_l2d, + &__aeabi_l2f, + &__aeabi_lasr, + &__aeabi_ldivmod, + &__aeabi_llsl, + &__aeabi_llsr, + &__aeabi_lmul, + &__aeabi_ui2d, + &__aeabi_ui2f, + &__aeabi_uidiv, + &__aeabi_uidivmod, + &__aeabi_ul2d, + &__aeabi_ul2f, + &__aeabi_uldivmod, + &__aeabi_unwind_cpp_pr0, + &__aeabi_unwind_cpp_pr1, + &__cmpdf2, + &__cmpsf2, + &__divdf3, + &__divsf3, + &__eqdf2, + &__eqsf2, + &__extendsfdf2, + &__fixdfsi, + &__fixsfsi, + &__fixunsdfsi, + &__floatdidf, + &__floatdisf, + &__floatsidf, + &__floatsisf, + &__floatundidf, + &__floatundisf, + &__floatunsidf, + &__floatunsisf, + &__gedf2, + &__gesf2, + &__gtdf2, + &__gtsf2, + &__gnu_ldivmod_helper, + &__gnu_uldivmod_helper, + &__ledf2, + &__lesf2, + &__ltdf2, + &__ltsf2, + &__muldf3, + &__muldi3, + &__mulsf3, + &__nedf2, + &__nesf2, + &__popcount_tab, + &__popcountsi2, + &__subdf3, + &__subsf3, + &__truncdfsf2, + &__udivdi3, + &__unorddf2, + &__unordsf2, +}; diff --git a/aosp/bionic/libc/arch-arm/bionic/popcount_tab.c b/aosp/bionic/libc/arch-arm/bionic/popcount_tab.c new file mode 100644 index 000000000..eb2faa9c7 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/popcount_tab.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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. + */ + +// Export this to maintain ABI compatibilty with libgcc, since compiler-rt +// doesn't use a table-driven implementation of __popcount. +const unsigned char __popcount_tab[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, + 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, + 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, + 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, + 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, + 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, + 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; diff --git a/aosp/bionic/libc/arch-arm/bionic/setjmp.S b/aosp/bionic/libc/arch-arm/bionic/setjmp.S new file mode 100644 index 000000000..5fbcaf39f --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/setjmp.S @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1997 Mark Brinicombe + * Copyright (C) 2010 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: + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Brinicombe + * 4. 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 AUTHOR 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 AUTHOR 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 + +// According to the ARM AAPCS document, we only need to save +// the following registers: +// +// Core r4-r11, sp, lr +// AAPCS 5.1.1: +// A subroutine must preserve the contents of the registers r4-r8, r10, r11 +// and SP (and r9 in PCS variants that designate r9 as v6). +// +// VFP d8-d15 +// AAPCS 5.1.2.1: +// Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine +// calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved +// (and can be used for passing arguments or returning results in standard +// procedure-call variants). Registers d16-d31 (q8-q15), if present, do +// not need to be preserved. +// +// FPSCR saved because glibc does. + +// The internal structure of a jmp_buf is totally private. +// Current layout (changes from release to release): +// +// word name description +// 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit +// 1 sigmask 64-bit signal mask (not used with _setjmp / _longjmp) +// 2 " " +// 3 reserved (unused to allow float_base to be maximally aligned; +// this avoids software emulation of unaligned loads/stores) +// 4 float_base base of float registers (d8 to d15) +// 20 float_state floating-point status and control register +// 21 core_base base of core registers (r4-r11, r13-r14) +// 31 checksum checksum of all of the core registers, to give better error messages +// 32 reserved reserved entries (room to grow) +// ... +// 63 " " + +#define _JB_SIGFLAG 0 +#define _JB_SIGMASK (_JB_SIGFLAG + 1) +#define _JB_FLOAT_BASE (_JB_SIGMASK + 3) +#define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2) +#define _JB_CORE_BASE (_JB_FLOAT_STATE+1) +#define _JB_CHECKSUM (_JB_CORE_BASE+10) + +ENTRY(setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(setjmp) + mov r1, #1 + b sigsetjmp +END(setjmp) + +ENTRY(_setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_setjmp) + mov r1, #0 + b sigsetjmp +END(_setjmp) + +#define MANGLE_REGISTERS 1 +#define USE_CHECKSUM 1 + +.macro m_mangle_registers reg +#if MANGLE_REGISTERS + eor r4, r4, \reg + eor r5, r5, \reg + eor r6, r6, \reg + eor r7, r7, \reg + eor r8, r8, \reg + eor r9, r9, \reg + eor r10, r10, \reg + eor r11, r11, \reg + eor r13, r13, \reg + eor r14, r14, \reg +#endif +.endm + +.macro m_unmangle_registers reg + m_mangle_registers \reg +.endm + +.macro m_calculate_checksum dst, src, scratch + mov \dst, #0 + .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 + ldr \scratch, [\src, #(\i * 4)] + eor \dst, \dst, \scratch + .endr +.endm + +// int sigsetjmp(sigjmp_buf env, int save_signal_mask); +ENTRY(sigsetjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp) + stmfd sp!, {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov r0, r1 + bl __bionic_setjmp_cookie_get + mov r1, r0 + + ldmfd sp, {r0} + + // Save the setjmp cookie for later. + bic r2, r1, #1 + stmfd sp!, {r2} + .cfi_adjust_cfa_offset 4 + + // Record the setjmp cookie and whether or not we're saving the signal mask. + str r1, [r0, #(_JB_SIGFLAG * 4)] + + // Do we need to save the signal mask? + tst r1, #1 + beq 1f + + // Align the stack. + sub sp, #4 + .cfi_adjust_cfa_offset 4 + + // Save the current signal mask. + add r2, r0, #(_JB_SIGMASK * 4) + mov r0, #2 // SIG_SETMASK + mov r1, #0 + bl sigprocmask64 + + // Unalign the stack. + add sp, #4 + .cfi_adjust_cfa_offset -4 + +1: + ldmfd sp!, {r2} + .cfi_adjust_cfa_offset -4 + ldmfd sp!, {r0, lr} + .cfi_adjust_cfa_offset -8 + .cfi_restore r0 + .cfi_restore lr + + // Save core registers. + add r1, r0, #(_JB_CORE_BASE * 4) + m_mangle_registers r2 + + // ARM deprecates using sp in the register list for stmia. + stmia r1, {r4-r11, lr} + str sp, [r1, #(9 * 4)] + m_unmangle_registers r2 + + // Save floating-point registers. + add r1, r0, #(_JB_FLOAT_BASE * 4) + vstmia r1, {d8-d15} + + // Save floating-point state. + fmrx r1, fpscr + str r1, [r0, #(_JB_FLOAT_STATE * 4)] + +#if USE_CHECKSUM + // Calculate the checksum. + m_calculate_checksum r12, r0, r2 + str r12, [r0, #(_JB_CHECKSUM * 4)] +#endif + + mov r0, #0 + bx lr +END(sigsetjmp) + +// void siglongjmp(sigjmp_buf env, int value); +ENTRY(siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(siglongjmp) + stmfd sp!, {r0, r1, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r1, 4 + .cfi_rel_offset lr, 8 + +#if USE_CHECKSUM + // Check the checksum before doing anything. + m_calculate_checksum r12, r0, r3 + ldr r2, [r0, #(_JB_CHECKSUM * 4)] + + teq r2, r12 + bne __bionic_setjmp_checksum_mismatch +#endif + + // Fetch the signal flag. + ldr r1, [r0, #(_JB_SIGFLAG * 4)] + + // Do we need to restore the signal mask? + ands r1, r1, #1 + beq 1f + + // Restore the signal mask. + mov r2, #0 + add r1, r0, #(_JB_SIGMASK * 4) + mov r0, #2 // SIG_SETMASK + bl sigprocmask64 + +1: + ldmfd sp!, {r0, r1, lr} + .cfi_adjust_cfa_offset -12 + .cfi_restore r0 + .cfi_restore r1 + .cfi_restore lr + + // Restore floating-point registers. + add r2, r0, #(_JB_FLOAT_BASE * 4) + vldmia r2, {d8-d15} + + // Restore floating-point state. + ldr r2, [r0, #(_JB_FLOAT_STATE * 4)] + fmxr fpscr, r2 + + // Load the cookie. + ldr r3, [r0, #(_JB_SIGFLAG * 4)] + bic r3, r3, #1 + + // Restore core registers. + add r2, r0, #(_JB_CORE_BASE * 4) + + // ARM deprecates using sp in the register list for ldmia. + ldmia r2, {r4-r11, lr} + ldr sp, [r2, #(9 * 4)] + m_unmangle_registers r3 + + // Save the return value/address and check the setjmp cookie. + stmfd sp!, {r1, lr} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset lr, 4 + mov r0, r3 + bl __bionic_setjmp_cookie_check + + // Restore return value/address. + ldmfd sp!, {r0, lr} + .cfi_adjust_cfa_offset -8 + .cfi_restore lr + + teq r0, #0 + moveq r0, #1 + bx lr +END(siglongjmp) + +ALIAS_SYMBOL(longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp) +ALIAS_SYMBOL(_longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp) diff --git a/aosp/bionic/libc/arch-arm/bionic/syscall.S b/aosp/bionic/libc/arch-arm/bionic/syscall.S new file mode 100644 index 000000000..d0df37977 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/syscall.S @@ -0,0 +1,51 @@ +/* + * 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 + +ENTRY(syscall) + mov ip, sp + stmfd sp!, {r4, r5, r6, r7} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset r6, 8 + .cfi_rel_offset r7, 12 + mov r7, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + ldmfd ip, {r3, r4, r5, r6} + swi #0 + ldmfd sp!, {r4, r5, r6, r7} + .cfi_def_cfa_offset 0 + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno_internal +END(syscall) diff --git a/aosp/bionic/libc/arch-arm/bionic/vfork.S b/aosp/bionic/libc/arch-arm/bionic/vfork.S new file mode 100644 index 000000000..a964be53a --- /dev/null +++ b/aosp/bionic/libc/arch-arm/bionic/vfork.S @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 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 +#include + +ENTRY(vfork) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork) + // r3 = &__get_tls()[TLS_SLOT_THREAD_ID] + mrc p15, 0, r3, c13, c0, 3 + ldr r3, [r3, #(TLS_SLOT_THREAD_ID * 4)] + + // Set cached_pid_ to 0, vforked_ to 1, and stash the previous value. + mov r0, #0x80000000 + ldr r1, [r3, #12] + str r0, [r3, #12] + + mov ip, r7 + ldr r7, =__NR_vfork + swi #0 + mov r7, ip + + teq r0, #0 + bxeq lr + + // rc != 0: reset cached_pid_ and vforked_. + str r1, [r3, #12] + cmn r0, #(MAX_ERRNO + 1) + + bxls lr + neg r0, r0 + b __set_errno_internal +END(vfork) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S new file mode 100644 index 000000000..69e405fc9 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S @@ -0,0 +1,203 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_a15) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r1, r0 + sub r3, r3, #1 + b .L_finish + +.L_zero_in_first_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_finish + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_finish + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_finish + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_finish + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_finish + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_finish + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} + .cfi_adjust_cfa_offset -8 + .cfi_restore r4 + .cfi_restore r5 + +#include "memcpy_base.S" + + // Undo the above cfi directives + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 +END(__strcat_chk_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S new file mode 100644 index 000000000..ddde30e98 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S @@ -0,0 +1,165 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_a15) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r0, r1 + sub r3, r3, #1 + b .L_check_size + +.L_zero_in_first_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_check_size + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_check_size + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_check_size + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_check_size + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_check_size + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_check_size + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + +#include "memcpy_base.S" + +END(__strcpy_chk_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy.S new file mode 100644 index 000000000..a9dfaff0f --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy.S @@ -0,0 +1,75 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .text + .syntax unified + .fpu neon + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Prototype: void *memcpy (void *dst, const void *src, size_t count). +ENTRY(__memcpy_a15) + pld [r1, #64] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + +#include "memcpy_base.S" +END(__memcpy_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy_base.S new file mode 100644 index 000000000..1d152bbc1 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memcpy_base.S @@ -0,0 +1,154 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +.L_memcpy_base: + // Assumes that n >= 0, and dst, src are valid pointers. + // For any sizes less than 832 use the neon code that doesn't + // care about the src alignment. This avoids any checks + // for src alignment, and offers the best improvement since + // smaller sized copies are dominated by the overhead of + // the pre and post main loop. + // For larger copies, if src and dst cannot both be aligned to + // word boundaries, use the neon code. + // For all other copies, align dst to a double word boundary + // and copy using LDRD/STRD instructions. + + cmp r2, #16 + blo .L_copy_less_than_16_unknown_align + +.L_copy_unknown_alignment: + // Unknown alignment of src and dst. + // Assumes that the first few bytes have already been prefetched. + + // Align destination to 128 bits. The mainloop store instructions + // require this alignment or they will throw an exception. + rsb r3, r0, #0 + ands r3, r3, #0xF + beq 2f + + // Copy up to 15 bytes (count in r3). + sub r2, r2, r3 + movs ip, r3, lsl #31 + + itt mi + ldrbmi lr, [r1], #1 + strbmi lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1], #1 + strbcs ip, [r0], #1 + strbcs lr, [r0], #1 + + movs ip, r3, lsl #29 + bge 1f + // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after. + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]! +1: bcc 2f + // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after. + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! + +2: // Make sure we have at least 64 bytes to copy. + subs r2, r2, #64 + blo 2f + +1: // The main loop copies 64 bytes at a time. + vld1.8 {d0 - d3}, [r1]! + vld1.8 {d4 - d7}, [r1]! + pld [r1, #(64*4)] + subs r2, r2, #64 + vst1.8 {d0 - d3}, [r0, :128]! + vst1.8 {d4 - d7}, [r0, :128]! + bhs 1b + +2: // Fix-up the remaining count and make sure we have >= 32 bytes left. + adds r2, r2, #32 + blo 3f + + // 32 bytes. These cache lines were already preloaded. + vld1.8 {d0 - d3}, [r1]! + sub r2, r2, #32 + vst1.8 {d0 - d3}, [r0, :128]! +3: // Less than 32 left. + add r2, r2, #32 + tst r2, #0x10 + beq .L_copy_less_than_16_unknown_align + // Copies 16 bytes, destination 128 bits aligned. + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0, :128]! + +.L_copy_less_than_16_unknown_align: + // Copy up to 15 bytes (count in r2). + movs ip, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: bge 2f + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! + +2: // Copy 0 to 4 bytes. + lsls r2, r2, #31 + itt ne + ldrbne lr, [r1], #1 + strbne lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1] + strbcs ip, [r0], #1 + strbcs lr, [r0] + + pop {r0, pc} diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memmove.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memmove.S new file mode 100644 index 000000000..92eba8d06 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memmove.S @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * Copyright (c) 2013-2014 NVIDIA Corporation. 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 + + .text + .syntax unified + .fpu neon + +#define CACHE_LINE_SIZE (64) +#define MEMCPY_BLOCK_SIZE_SMALL (32768) +#define MEMCPY_BLOCK_SIZE_MID (1048576) +#define PREFETCH_DISTANCE_NEAR (CACHE_LINE_SIZE*4) +#define PREFETCH_DISTANCE_MID (CACHE_LINE_SIZE*4) +#define PREFETCH_DISTANCE_FAR (CACHE_LINE_SIZE*16) + +ENTRY(memmove_a15) + cmp r2, #0 + cmpne r0, r1 + bxeq lr + subs r3, r0, r1 + bls .L_jump_to_memcpy + cmp r2, r3 + bhi .L_reversed_memcpy + +.L_jump_to_memcpy: + b __memcpy + +.L_reversed_memcpy: + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + add r0, r0, r2 + add r1, r1, r2 + + /* preload next cache line */ + pld [r1, #-CACHE_LINE_SIZE] + pld [r1, #-CACHE_LINE_SIZE*2] + +.L_reversed_memcpy_align_dest: + /* Deal with very small blocks (< 32bytes) asap */ + cmp r2, #32 + blo .L_reversed_memcpy_lt_32bytes + /* no need to align if len < 128 bytes */ + cmp r2, #128 + blo .L_reversed_memcpy_lt_128bytes + /* align destination to 64 bytes (1 cache line) */ + ands r3, r0, #0x3f + beq .L_reversed_memcpy_dispatch + sub r2, r2, r3 +0: /* copy 1 byte */ + movs ip, r3, lsl #31 + ldrbmi ip, [r1, #-1]! + strbmi ip, [r0, #-1]! +1: /* copy 2 bytes */ + ldrbcs ip, [r1, #-1]! + strbcs ip, [r0, #-1]! + ldrbcs ip, [r1, #-1]! + strbcs ip, [r0, #-1]! +2: /* copy 4 bytes */ + movs ip, r3, lsl #29 + bpl 3f + sub r1, r1, #4 + sub r0, r0, #4 + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1] + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32] +3: /* copy 8 bytes */ + bcc 4f + sub r1, r1, #8 + sub r0, r0, #8 + vld1.8 {d0}, [r1] + vst1.8 {d0}, [r0, :64] +4: /* copy 16 bytes */ + movs ip, r3, lsl #27 + bpl 5f + sub r1, r1, #16 + sub r0, r0, #16 + vld1.8 {q0}, [r1] + vst1.8 {q0}, [r0, :128] +5: /* copy 32 bytes */ + bcc .L_reversed_memcpy_dispatch + sub r1, r1, #32 + sub r0, r0, #32 + vld1.8 {q0, q1}, [r1] + vst1.8 {q0, q1}, [r0, :256] + +.L_reversed_memcpy_dispatch: + /* preload more cache lines */ + pld [r1, #-CACHE_LINE_SIZE*3] + pld [r1, #-CACHE_LINE_SIZE*4] + + cmp r2, #MEMCPY_BLOCK_SIZE_SMALL + blo .L_reversed_memcpy_neon_pld_near + cmp r2, #MEMCPY_BLOCK_SIZE_MID + blo .L_reversed_memcpy_neon_pld_mid + b .L_reversed_memcpy_neon_pld_far + +.L_reversed_memcpy_neon_pld_near: + /* less than 128 bytes? */ + subs r2, r2, #128 + blo 1f + sub r1, r1, #32 + sub r0, r0, #32 + mov r3, #-32 + .align 4 +0: + /* copy 128 bytes in each loop */ + subs r2, r2, #128 + + /* preload to cache */ + pld [r1, #-(PREFETCH_DISTANCE_NEAR+CACHE_LINE_SIZE*2)+32] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + + /* preload to cache */ + pld [r1, #-(PREFETCH_DISTANCE_NEAR+CACHE_LINE_SIZE*2)+32] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + + bhs 0b + add r1, r1, #32 + add r0, r0, #32 +1: + adds r2, r2, #128 + bne .L_reversed_memcpy_lt_128bytes + pop {r0, pc} + +.L_reversed_memcpy_neon_pld_mid: + subs r2, r2, #128 + sub r1, r1, #32 + sub r0, r0, #32 + mov r3, #-32 + .align 4 +0: + /* copy 128 bytes in each loop */ + subs r2, r2, #128 + + /* preload to cache */ + pld [r1, #-(PREFETCH_DISTANCE_MID+CACHE_LINE_SIZE)+32] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + + /* preload to cache */ + pld [r1, #-(PREFETCH_DISTANCE_MID+CACHE_LINE_SIZE)+32] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + vld1.8 {q0, q1}, [r1], r3 + vst1.8 {q0, q1}, [r0, :256], r3 + + bhs 0b + add r1, r1, #32 + add r0, r0, #32 +1: + adds r2, r2, #128 + bne .L_reversed_memcpy_lt_128bytes + pop {r0, pc} + +.L_reversed_memcpy_neon_pld_far: + sub r2, r2, #128 + sub r0, r0, #128 + sub r1, r1, #128 + .align 4 +0: + /* copy 128 bytes in each loop */ + subs r2, r2, #128 + + /* preload to cache */ + pld [r1, #-(PREFETCH_DISTANCE_FAR+CACHE_LINE_SIZE*2)+128] + pld [r1, #-(PREFETCH_DISTANCE_FAR+CACHE_LINE_SIZE)+128] + /* read */ + vld1.8 {q0, q1}, [r1]! + vld1.8 {q2, q3}, [r1]! + vld1.8 {q8, q9}, [r1]! + vld1.8 {q10, q11}, [r1]! + /* write */ + vst1.8 {q0, q1}, [r0, :256]! + vst1.8 {q2, q3}, [r0, :256]! + vst1.8 {q8, q9}, [r0, :256]! + vst1.8 {q10, q11}, [r0, :256]! + + sub r0, r0, #256 + sub r1, r1, #256 + bhs 0b + add r0, r0, #128 + add r1, r1, #128 +1: + adds r2, r2, #128 + bne .L_reversed_memcpy_lt_128bytes + pop {r0, pc} + +.L_reversed_memcpy_lt_128bytes: +6: /* copy 64 bytes */ + movs ip, r2, lsl #26 + bcc 5f + sub r1, r1, #32 + sub r0, r0, #32 + vld1.8 {q0, q1}, [r1] + vst1.8 {q0, q1}, [r0] + sub r1, r1, #32 + sub r0, r0, #32 + vld1.8 {q0, q1}, [r1] + vst1.8 {q0, q1}, [r0] +5: /* copy 32 bytes */ + bpl 4f + sub r1, r1, #32 + sub r0, r0, #32 + vld1.8 {q0, q1}, [r1] + vst1.8 {q0, q1}, [r0] +.L_reversed_memcpy_lt_32bytes: +4: /* copy 16 bytes */ + movs ip, r2, lsl #28 + bcc 3f + sub r1, r1, #16 + sub r0, r0, #16 + vld1.8 {q0}, [r1] + vst1.8 {q0}, [r0] +3: /* copy 8 bytes */ + bpl 2f + sub r1, r1, #8 + sub r0, r0, #8 + vld1.8 {d0}, [r1] + vst1.8 {d0}, [r0] +2: /* copy 4 bytes */ + ands ip, r2, #0x4 + beq 1f + sub r1, r1, #4 + sub r0, r0, #4 + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1] + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0] +1: /* copy 2 bytes */ + movs ip, r2, lsl #31 + ldrbcs ip, [r1, #-1]! + strbcs ip, [r0, #-1]! + ldrbcs ip, [r1, #-1]! + strbcs ip, [r0, #-1]! +0: /* copy 1 byte */ + ldrbmi ip, [r1, #-1]! + strbmi ip, [r0, #-1]! + + pop {r0, pc} + +END(memmove_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memset.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memset.S new file mode 100644 index 000000000..ead881e49 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/memset.S @@ -0,0 +1,174 @@ +/* + * 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 + + /* + * Optimized memset() for ARM. + * + * memset() returns its first argument. + */ + + .fpu neon + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +ENTRY(__memset_chk_a15) + cmp r2, r3 + bls memset + + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + + bl __memset_chk_fail +END(__memset_chk_a15) + +ENTRY(memset_a15) + stmfd sp!, {r0} + .cfi_def_cfa_offset 4 + .cfi_rel_offset r0, 0 + + // The new algorithm is slower for copies < 16 so use the old + // neon code in that case. + cmp r2, #16 + blo .L_set_less_than_16_unknown_align + + // Use strd which requires an even and odd register so move the + // values so that: + // r0 and r1 contain the memset value + // r2 is the number of bytes to set + // r3 is the destination pointer + mov r3, r0 + + // Copy the byte value in every byte of r1. + mov r1, r1, lsl #24 + orr r1, r1, r1, lsr #8 + orr r1, r1, r1, lsr #16 + +.L_check_alignment: + // Align destination to a double word to avoid the strd crossing + // a cache line boundary. + ands ip, r3, #7 + bne .L_do_double_word_align + +.L_double_word_aligned: + mov r0, r1 + + subs r2, #64 + blo .L_set_less_than_64 + +1: // Main loop sets 64 bytes at a time. + .irp offset, #0, #8, #16, #24, #32, #40, #48, #56 + strd r0, r1, [r3, \offset] + .endr + + add r3, #64 + subs r2, #64 + bge 1b + +.L_set_less_than_64: + // Restore r2 to the count of bytes left to set. + add r2, #64 + lsls ip, r2, #27 + bcc .L_set_less_than_32 + // Set 32 bytes. + .irp offset, #0, #8, #16, #24 + strd r0, r1, [r3, \offset] + .endr + add r3, #32 + +.L_set_less_than_32: + bpl .L_set_less_than_16 + // Set 16 bytes. + .irp offset, #0, #8 + strd r0, r1, [r3, \offset] + .endr + add r3, #16 + +.L_set_less_than_16: + // Less than 16 bytes to set. + lsls ip, r2, #29 + bcc .L_set_less_than_8 + + // Set 8 bytes. + strd r0, r1, [r3], #8 + +.L_set_less_than_8: + bpl .L_set_less_than_4 + // Set 4 bytes + str r1, [r3], #4 + +.L_set_less_than_4: + lsls ip, r2, #31 + it ne + strbne r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3] + + ldmfd sp!, {r0} + bx lr + +.L_do_double_word_align: + rsb ip, ip, #8 + sub r2, r2, ip + movs r0, ip, lsl #31 + it mi + strbmi r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + + // Dst is at least word aligned by this point. + cmp ip, #4 + blo .L_double_word_aligned + str r1, [r3], #4 + b .L_double_word_aligned + +.L_set_less_than_16_unknown_align: + // Set up to 15 bytes. + vdup.8 d0, r1 + movs ip, r2, lsl #29 + bcc 1f + vst1.8 {d0}, [r0]! +1: bge 2f + vst1.32 {d0[0]}, [r0]! +2: movs ip, r2, lsl #31 + it mi + strbmi r1, [r0], #1 + itt cs + strbcs r1, [r0], #1 + strbcs r1, [r0], #1 + ldmfd sp!, {r0} + bx lr +END(memset_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/stpcpy.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/stpcpy.S new file mode 100644 index 000000000..740523b5d --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/stpcpy.S @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#define STPCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcat.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcat.S new file mode 100644 index 000000000..260926a0a --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcat.S @@ -0,0 +1,575 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .syntax unified + + .thumb + .thumb_func + + .macro m_push + push {r0, r4, r5, lr} + .endm // m_push + + .macro m_pop + pop {r0, r4, r5, pc} + .endm // m_pop + + .macro m_scan_byte + ldrb r3, [r0] + cbz r3, .L_strcat_r0_scan_done + add r0, #1 + .endm // m_scan_byte + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +ENTRY(strcat_a15) + // Quick check to see if src is empty. + ldrb r2, [r1] + pld [r1, #0] + cbnz r2, .L_strcat_continue + bx lr + +.L_strcat_continue: + // To speed up really small dst strings, unroll checking the first 4 bytes. + m_push + m_scan_byte + m_scan_byte + m_scan_byte + m_scan_byte + + ands r3, r0, #7 + beq .L_strcat_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_strcat_align_to_32 + + ldrb r5, [r0] + cbz r5, .L_strcat_r0_scan_done + add r0, r0, #1 + +.L_strcat_align_to_32: + bcc .L_strcat_align_to_64 + + ldrb r2, [r0] + cbz r2, .L_strcat_r0_scan_done + add r0, r0, #1 + ldrb r4, [r0] + cbz r4, .L_strcat_r0_scan_done + add r0, r0, #1 + +.L_strcat_align_to_64: + tst r3, #4 + beq .L_strcat_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcat_zero_in_second_register + b .L_strcat_mainloop + +.L_strcat_r0_scan_done: + // For short copies, hard-code checking the first 8 bytes since this + // new code doesn't win until after about 8 bytes. + m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r5, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r2, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.L_strcpy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.L_strcpy_continue + +.L_strcpy_finish: + m_pop + +.L_strcpy_continue: + ands r3, r0, #7 + beq .L_strcpy_check_src_align + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_strcpy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + +.L_strcpy_align_to_32: + bcc .L_strcpy_align_to_64 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + +.L_strcpy_align_to_64: + tst r3, #4 + beq .L_strcpy_check_src_align + // Read one byte at a time since we don't know the src alignment + // and we don't want to read into a different page. + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .L_strcpy_complete + +.L_strcpy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .L_strcpy_unaligned_copy + + .p2align 2 +.L_strcpy_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_mainloop + +.L_strcpy_complete: + m_pop + +.L_strcpy_zero_in_first_register: + lsls lr, ip, #17 + bne .L_strcpy_copy1byte + bcs .L_strcpy_copy2bytes + lsls ip, ip, #1 + bne .L_strcpy_copy3bytes + +.L_strcpy_copy4bytes: + // Copy 4 bytes to the destiniation. + str r2, [r0] + m_pop + +.L_strcpy_copy1byte: + strb r2, [r0] + m_pop + +.L_strcpy_copy2bytes: + strh r2, [r0] + m_pop + +.L_strcpy_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_pop + +.L_strcpy_zero_in_second_register: + lsls lr, ip, #17 + bne .L_strcpy_copy5bytes + bcs .L_strcpy_copy6bytes + lsls ip, ip, #1 + bne .L_strcpy_copy7bytes + + // Copy 8 bytes to the destination. + strd r2, r3, [r0] + m_pop + +.L_strcpy_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] + m_pop + +.L_strcpy_copy6bytes: + str r2, [r0], #4 + strh r3, [r0] + m_pop + +.L_strcpy_copy7bytes: + str r2, [r0], #4 + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_pop + +.L_strcpy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.L_strcpy_unaligned_branchtable: + .byte 0 + .byte ((.L_strcpy_unalign7 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign6 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign5 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign4 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign3 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign2 - .L_strcpy_unaligned_branchtable)/2) + .byte ((.L_strcpy_unalign1 - .L_strcpy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.L_strcpy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .L_strcpy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .L_strcpy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .L_strcpy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 + beq .L_strcpy_unalign_return + b .L_strcpy_unalign7 + +.L_strcpy_unalign7_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] +.L_strcpy_unalign_return: + m_pop + +.L_strcpy_unalign7_copy6bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0], #1 + m_pop + +.L_strcpy_unalign7_copy7bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0], #1 + m_pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.L_strcpy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .L_strcpy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .L_strcpy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .L_strcpy_copy7bytes + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 + beq .L_strcpy_unalign_return + b .L_strcpy_unalign6 + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.L_strcpy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .L_strcpy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_unalign5 + +.L_strcpy_unalign_copy5bytes: + str r2, [r0], #4 + strb r4, [r0] + m_pop + +.L_strcpy_unalign_copy6bytes: + str r2, [r0], #4 + strb r4, [r0], #1 + strb r5, [r0] + m_pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.L_strcpy_unalign4: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + ldr r3, [r1], #4 + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.L_strcpy_unalign3: + ldrb r2, [r1] + cbz r2, .L_strcpy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .L_strcpy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .L_strcpy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .L_strcpy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_unalign3 + +.L_strcpy_unalign3_copy1byte: + strb r2, [r0] + m_pop + +.L_strcpy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_pop + +.L_strcpy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.L_strcpy_unalign2: + ldrb r2, [r1] + cbz r2, .L_strcpy_unalign_copy1byte + ldrb r4, [r1, #1] + cbz r4, .L_strcpy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .L_strcpy_copy3bytes + lsrs ip, r2, #24 + beq .L_strcpy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.L_strcpy_unalign1: + ldrb r2, [r1] + cbz r2, .L_strcpy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcpy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .L_strcpy_unalign1 + +.L_strcpy_unalign_copy1byte: + strb r2, [r0] + m_pop + +.L_strcpy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r4, [r0] + m_pop + + .p2align 2 +.L_strcat_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_strcat_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_strcat_zero_in_second_register + b .L_strcat_mainloop + +.L_strcat_zero_in_first_register: + // Prefetch the src now, it's going to be used soon. + pld [r1, #0] + lsls lr, ip, #17 + bne .L_strcat_sub8 + bcs .L_strcat_sub7 + lsls ip, ip, #1 + bne .L_strcat_sub6 + + sub r0, r0, #5 + b .L_strcat_r0_scan_done + +.L_strcat_sub8: + sub r0, r0, #8 + b .L_strcat_r0_scan_done + +.L_strcat_sub7: + sub r0, r0, #7 + b .L_strcat_r0_scan_done + +.L_strcat_sub6: + sub r0, r0, #6 + b .L_strcat_r0_scan_done + +.L_strcat_zero_in_second_register: + // Prefetch the src now, it's going to be used soon. + pld [r1, #0] + lsls lr, ip, #17 + bne .L_strcat_sub4 + bcs .L_strcat_sub3 + lsls ip, ip, #1 + bne .L_strcat_sub2 + + sub r0, r0, #1 + b .L_strcat_r0_scan_done + +.L_strcat_sub4: + sub r0, r0, #4 + b .L_strcat_r0_scan_done + +.L_strcat_sub3: + sub r0, r0, #3 + b .L_strcat_r0_scan_done + +.L_strcat_sub2: + sub r0, r0, #2 + b .L_strcat_r0_scan_done +END(strcat_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S new file mode 100644 index 000000000..467201b78 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2012-2014 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + +#ifdef __ARMEB__ +#define S2LO lsl +#define S2LOEQ lsleq +#define S2HI lsr +#define MSB 0x000000ff +#define LSB 0xff000000 +#define BYTE0_OFFSET 24 +#define BYTE1_OFFSET 16 +#define BYTE2_OFFSET 8 +#define BYTE3_OFFSET 0 +#else /* not __ARMEB__ */ +#define S2LO lsr +#define S2LOEQ lsreq +#define S2HI lsl +#define BYTE0_OFFSET 0 +#define BYTE1_OFFSET 8 +#define BYTE2_OFFSET 16 +#define BYTE3_OFFSET 24 +#define MSB 0xff000000 +#define LSB 0x000000ff +#endif /* not __ARMEB__ */ + +/* Parameters and result. */ +#define src1 r0 +#define src2 r1 +#define result r0 /* Overlaps src1. */ + +/* Internal variables. */ +#define tmp1 r4 +#define tmp2 r5 +#define const_m1 r12 + +/* Additional internal variables for 64-bit aligned data. */ +#define data1a r2 +#define data1b r3 +#define data2a r6 +#define data2b r7 +#define syndrome_a tmp1 +#define syndrome_b tmp2 + +/* Additional internal variables for 32-bit aligned data. */ +#define data1 r2 +#define data2 r3 +#define syndrome tmp2 + + /* Implementation of strcmp for ARMv7 when DSP instructions are + available. Use ldrd to support wider loads, provided the data + is sufficiently aligned. Use saturating arithmetic to optimize + the compares. */ + + /* Build Options: + STRCMP_NO_PRECHECK: Don't run a quick pre-check of the first + byte in the string. If comparing completely random strings + the pre-check will save time, since there is a very high + probability of a mismatch in the first character: we save + significant overhead if this is the common case. However, + if strings are likely to be identical (eg because we're + verifying a hit in a hash table), then this check is largely + redundant. */ + + +.syntax unified +.thumb + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + + /* Macro to compute and return the result value for word-aligned + cases. */ + .macro strcmp_epilogue_aligned synd d1 d2 restore_r6 +#ifdef __ARM_BIG_ENDIAN + /* If data1 contains a zero byte, then syndrome will contain a 1 in + bit 7 of that byte. Otherwise, the highest set bit in the + syndrome will highlight the first different bit. It is therefore + sufficient to extract the eight bits starting with the syndrome + bit. */ + clz tmp1, \synd + lsl r1, \d2, tmp1 + .if \restore_r6 + ldrd r6, r7, [sp, #8] + .endif + .cfi_restore 6 + .cfi_restore 7 + lsl \d1, \d1, tmp1 + .cfi_remember_state + lsr result, \d1, #24 + ldrd r4, r5, [sp], #16 + .cfi_restore 4 + .cfi_restore 5 + sub result, result, r1, lsr #24 + bx lr +#else + /* To use the big-endian trick we'd have to reverse all three words. + that's slower than this approach. */ + rev \synd, \synd + clz tmp1, \synd + bic tmp1, tmp1, #7 + lsr r1, \d2, tmp1 + .cfi_remember_state + .if \restore_r6 + ldrd r6, r7, [sp, #8] + .endif + .cfi_restore 6 + .cfi_restore 7 + lsr \d1, \d1, tmp1 + and result, \d1, #255 + and r1, r1, #255 + ldrd r4, r5, [sp], #16 + .cfi_restore 4 + .cfi_restore 5 + sub result, result, r1 + + bx lr +#endif + .endm + + .text + .p2align 5 +.Lstrcmp_start_addr: +#ifndef STRCMP_NO_PRECHECK +.Lfastpath_exit: + sub r0, r2, r3 + bx lr + nop +#endif + +ENTRY(strcmp_a15) +#ifndef STRCMP_NO_PRECHECK + ldrb r2, [src1] + ldrb r3, [src2] + cmp r2, #1 + it cs + cmpcs r2, r3 + bne .Lfastpath_exit +#endif + .cfi_sections .debug_frame + strd r4, r5, [sp, #-16]! + .cfi_def_cfa_offset 16 + .cfi_offset 4, -16 + .cfi_offset 5, -12 + orr tmp1, src1, src2 + strd r6, r7, [sp, #8] + .cfi_offset 6, -8 + .cfi_offset 7, -4 + mvn const_m1, #0 + lsl r2, tmp1, #29 + cbz r2, .Lloop_aligned8 + +.Lnot_aligned: + eor tmp1, src1, src2 + tst tmp1, #7 + bne .Lmisaligned8 + + /* Deal with mutual misalignment by aligning downwards and then + masking off the unwanted loaded data to prevent a difference. */ + and tmp1, src1, #7 + bic src1, src1, #7 + and tmp2, tmp1, #3 + bic src2, src2, #7 + lsl tmp2, tmp2, #3 /* Bytes -> bits. */ + ldrd data1a, data1b, [src1], #16 + tst tmp1, #4 + ldrd data2a, data2b, [src2], #16 + /* In thumb code we can't use MVN with a register shift, but + we do have ORN. */ + S2HI tmp1, const_m1, tmp2 + orn data1a, data1a, tmp1 + orn data2a, data2a, tmp1 + beq .Lstart_realigned8 + orn data1b, data1b, tmp1 + mov data1a, const_m1 + orn data2b, data2b, tmp1 + mov data2a, const_m1 + b .Lstart_realigned8 + + /* Unwind the inner loop by a factor of 2, giving 16 bytes per + pass. */ + .p2align 5,,12 /* Don't start in the tail bytes of a cache line. */ + .p2align 2 /* Always word aligned. */ +.Lloop_aligned8: + ldrd data1a, data1b, [src1], #16 + ldrd data2a, data2b, [src2], #16 +.Lstart_realigned8: + uadd8 syndrome_b, data1a, const_m1 /* Only want GE bits, */ + eor syndrome_a, data1a, data2a + sel syndrome_a, syndrome_a, const_m1 + cbnz syndrome_a, .Ldiff_in_a + uadd8 syndrome_b, data1b, const_m1 /* Only want GE bits. */ + eor syndrome_b, data1b, data2b + sel syndrome_b, syndrome_b, const_m1 + cbnz syndrome_b, .Ldiff_in_b + + ldrd data1a, data1b, [src1, #-8] + ldrd data2a, data2b, [src2, #-8] + uadd8 syndrome_b, data1a, const_m1 /* Only want GE bits, */ + eor syndrome_a, data1a, data2a + sel syndrome_a, syndrome_a, const_m1 + uadd8 syndrome_b, data1b, const_m1 /* Only want GE bits. */ + eor syndrome_b, data1b, data2b + sel syndrome_b, syndrome_b, const_m1 + /* Can't use CBZ for backwards branch. */ + orrs syndrome_b, syndrome_b, syndrome_a /* Only need if s_a == 0 */ + beq .Lloop_aligned8 + +.Ldiff_found: + cbnz syndrome_a, .Ldiff_in_a + +.Ldiff_in_b: + strcmp_epilogue_aligned syndrome_b, data1b, data2b 1 + +.Ldiff_in_a: + .cfi_restore_state + strcmp_epilogue_aligned syndrome_a, data1a, data2a 1 + + .cfi_restore_state +.Lmisaligned8: + tst tmp1, #3 + bne .Lmisaligned4 + ands tmp1, src1, #3 + bne .Lmutual_align4 + + /* Unrolled by a factor of 2, to reduce the number of post-increment + operations. */ +.Lloop_aligned4: + ldr data1, [src1], #8 + ldr data2, [src2], #8 +.Lstart_realigned4: + uadd8 syndrome, data1, const_m1 /* Only need GE bits. */ + eor syndrome, data1, data2 + sel syndrome, syndrome, const_m1 + cbnz syndrome, .Laligned4_done + ldr data1, [src1, #-4] + ldr data2, [src2, #-4] + uadd8 syndrome, data1, const_m1 + eor syndrome, data1, data2 + sel syndrome, syndrome, const_m1 + cmp syndrome, #0 + beq .Lloop_aligned4 + +.Laligned4_done: + strcmp_epilogue_aligned syndrome, data1, data2, 0 + +.Lmutual_align4: + .cfi_restore_state + /* Deal with mutual misalignment by aligning downwards and then + masking off the unwanted loaded data to prevent a difference. */ + lsl tmp1, tmp1, #3 /* Bytes -> bits. */ + bic src1, src1, #3 + ldr data1, [src1], #8 + bic src2, src2, #3 + ldr data2, [src2], #8 + + /* In thumb code we can't use MVN with a register shift, but + we do have ORN. */ + S2HI tmp1, const_m1, tmp1 + orn data1, data1, tmp1 + orn data2, data2, tmp1 + b .Lstart_realigned4 + +.Lmisaligned4: + ands tmp1, src1, #3 + beq .Lsrc1_aligned + sub src2, src2, tmp1 + bic src1, src1, #3 + lsls tmp1, tmp1, #31 + ldr data1, [src1], #4 + beq .Laligned_m2 + bcs .Laligned_m1 + +#ifdef STRCMP_NO_PRECHECK + ldrb data2, [src2, #1] + uxtb tmp1, data1, ror #BYTE1_OFFSET + subs tmp1, tmp1, data2 + bne .Lmisaligned_exit + cbz data2, .Lmisaligned_exit + +.Laligned_m2: + ldrb data2, [src2, #2] + uxtb tmp1, data1, ror #BYTE2_OFFSET + subs tmp1, tmp1, data2 + bne .Lmisaligned_exit + cbz data2, .Lmisaligned_exit + +.Laligned_m1: + ldrb data2, [src2, #3] + uxtb tmp1, data1, ror #BYTE3_OFFSET + subs tmp1, tmp1, data2 + bne .Lmisaligned_exit + add src2, src2, #4 + cbnz data2, .Lsrc1_aligned +#else /* STRCMP_NO_PRECHECK */ + /* If we've done the pre-check, then we don't need to check the + first byte again here. */ + ldrb data2, [src2, #2] + uxtb tmp1, data1, ror #BYTE2_OFFSET + subs tmp1, tmp1, data2 + bne .Lmisaligned_exit + cbz data2, .Lmisaligned_exit + +.Laligned_m2: + ldrb data2, [src2, #3] + uxtb tmp1, data1, ror #BYTE3_OFFSET + subs tmp1, tmp1, data2 + bne .Lmisaligned_exit + cbnz data2, .Laligned_m1 +#endif + +.Lmisaligned_exit: + .cfi_remember_state + mov result, tmp1 + ldr r4, [sp], #16 + .cfi_restore 4 + bx lr + +#ifndef STRCMP_NO_PRECHECK +.Laligned_m1: + add src2, src2, #4 +#endif +.Lsrc1_aligned: + .cfi_restore_state + /* src1 is word aligned, but src2 has no common alignment + with it. */ + ldr data1, [src1], #4 + lsls tmp1, src2, #31 /* C=src2[1], Z=src2[0]. */ + + bic src2, src2, #3 + ldr data2, [src2], #4 + bhi .Loverlap1 /* C=1, Z=0 => src2[1:0] = 0b11. */ + bcs .Loverlap2 /* C=1, Z=1 => src2[1:0] = 0b10. */ + + /* (overlap3) C=0, Z=0 => src2[1:0] = 0b01. */ +.Loverlap3: + bic tmp1, data1, #MSB + uadd8 syndrome, data1, const_m1 + eors syndrome, tmp1, data2, S2LO #8 + sel syndrome, syndrome, const_m1 + bne 4f + cbnz syndrome, 5f + ldr data2, [src2], #4 + eor tmp1, tmp1, data1 + cmp tmp1, data2, S2HI #24 + bne 6f + ldr data1, [src1], #4 + b .Loverlap3 +4: + S2LO data2, data2, #8 + b .Lstrcmp_tail + +5: + bics syndrome, syndrome, #MSB + bne .Lstrcmp_done_equal + + /* We can only get here if the MSB of data1 contains 0, so + fast-path the exit. */ + ldrb result, [src2] + .cfi_remember_state + ldrd r4, r5, [sp], #16 + .cfi_restore 4 + .cfi_restore 5 + /* R6/7 Not used in this sequence. */ + .cfi_restore 6 + .cfi_restore 7 + neg result, result + bx lr + +6: + .cfi_restore_state + S2LO data1, data1, #24 + and data2, data2, #LSB + b .Lstrcmp_tail + + .p2align 5,,12 /* Ensure at least 3 instructions in cache line. */ +.Loverlap2: + and tmp1, data1, const_m1, S2LO #16 + uadd8 syndrome, data1, const_m1 + eors syndrome, tmp1, data2, S2LO #16 + sel syndrome, syndrome, const_m1 + bne 4f + cbnz syndrome, 5f + ldr data2, [src2], #4 + eor tmp1, tmp1, data1 + cmp tmp1, data2, S2HI #16 + bne 6f + ldr data1, [src1], #4 + b .Loverlap2 +4: + S2LO data2, data2, #16 + b .Lstrcmp_tail +5: + ands syndrome, syndrome, const_m1, S2LO #16 + bne .Lstrcmp_done_equal + + ldrh data2, [src2] + S2LO data1, data1, #16 +#ifdef __ARM_BIG_ENDIAN + lsl data2, data2, #16 +#endif + b .Lstrcmp_tail + +6: + S2LO data1, data1, #16 + and data2, data2, const_m1, S2LO #16 + b .Lstrcmp_tail + + .p2align 5,,12 /* Ensure at least 3 instructions in cache line. */ +.Loverlap1: + and tmp1, data1, #LSB + uadd8 syndrome, data1, const_m1 + eors syndrome, tmp1, data2, S2LO #24 + sel syndrome, syndrome, const_m1 + bne 4f + cbnz syndrome, 5f + ldr data2, [src2], #4 + eor tmp1, tmp1, data1 + cmp tmp1, data2, S2HI #8 + bne 6f + ldr data1, [src1], #4 + b .Loverlap1 +4: + S2LO data2, data2, #24 + b .Lstrcmp_tail +5: + tst syndrome, #LSB + bne .Lstrcmp_done_equal + ldr data2, [src2] +6: + S2LO data1, data1, #8 + bic data2, data2, #MSB + b .Lstrcmp_tail + +.Lstrcmp_done_equal: + mov result, #0 + .cfi_remember_state + ldrd r4, r5, [sp], #16 + .cfi_restore 4 + .cfi_restore 5 + /* R6/7 not used in this sequence. */ + .cfi_restore 6 + .cfi_restore 7 + bx lr + +.Lstrcmp_tail: + .cfi_restore_state +#ifndef __ARM_BIG_ENDIAN + rev data1, data1 + rev data2, data2 + /* Now everything looks big-endian... */ +#endif + uadd8 tmp1, data1, const_m1 + eor tmp1, data1, data2 + sel syndrome, tmp1, const_m1 + clz tmp1, syndrome + lsl data1, data1, tmp1 + lsl data2, data2, tmp1 + lsr result, data1, #24 + ldrd r4, r5, [sp], #16 + .cfi_restore 4 + .cfi_restore 5 + /* R6/7 not used in this sequence. */ + .cfi_restore 6 + .cfi_restore 7 + sub result, result, data2, lsr #24 + bx lr +END(strcmp_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcpy.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcpy.S new file mode 100644 index 000000000..951face01 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strcpy.S @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#define STRCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/string_copy.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/string_copy.S new file mode 100644 index 000000000..affbc3b20 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/string_copy.S @@ -0,0 +1,520 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +#if !defined(STPCPY) && !defined(STRCPY) +#error "Either STPCPY or STRCPY must be defined." +#endif + +#include + + .syntax unified + + .thumb + .thumb_func + +#if defined(STPCPY) + .macro m_push + push {r4, r5, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset lr, 8 + .endm // m_push +#else + .macro m_push + push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 + .endm // m_push +#endif + +#if defined(STPCPY) + .macro m_pop + pop {r4, r5, pc} + .endm // m_pop +#else + .macro m_pop + pop {r0, r4, r5, pc} + .endm // m_pop +#endif + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +#if defined(STPCPY) +ENTRY(stpcpy_a15) +#else +ENTRY(strcpy_a15) +#endif + // For short copies, hard-code checking the first 8 bytes since this + // new code doesn't win until after about 8 bytes. + m_push + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue + +.Lstringcopy_finish: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_pop + +.Lstringcopy_continue: + pld [r1, #0] + ands r3, r0, #7 + beq .Lstringcopy_check_src_align + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstringcopy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_32: + bcc .Lstringcopy_align_to_64 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_64: + tst r3, #4 + beq .Lstringcopy_check_src_align + // Read one byte at a time since we don't have any idea about the alignment + // of the source and we don't want to read into a different page. + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .Lstringcopy_unaligned_copy + + .p2align 2 +.Lstringcopy_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_mainloop + +.Lstringcopy_complete: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_pop + +.Lstringcopy_zero_in_first_register: + lsls lr, ip, #17 + bne .Lstringcopy_copy1byte + bcs .Lstringcopy_copy2bytes + lsls ip, ip, #1 + bne .Lstringcopy_copy3bytes + +.Lstringcopy_copy4bytes: + // Copy 4 bytes to the destiniation. +#if defined(STPCPY) + str r2, [r0], #3 +#else + str r2, [r0] +#endif + m_pop + +.Lstringcopy_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_copy2bytes: +#if defined(STPCPY) + strh r2, [r0], #1 +#else + strh r2, [r0] +#endif + m_pop + +.Lstringcopy_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_pop + +.Lstringcopy_zero_in_second_register: + lsls lr, ip, #17 + bne .Lstringcopy_copy5bytes + bcs .Lstringcopy_copy6bytes + lsls ip, ip, #1 + bne .Lstringcopy_copy7bytes + + // Copy 8 bytes to the destination. + strd r2, r3, [r0] +#if defined(STPCPY) + add r0, r0, #7 +#endif + m_pop + +.Lstringcopy_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] + m_pop + +.Lstringcopy_copy6bytes: + str r2, [r0], #4 +#if defined(STPCPY) + strh r3, [r0], #1 +#else + strh r3, [r0] +#endif + m_pop + +.Lstringcopy_copy7bytes: + str r2, [r0], #4 + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_pop + +.Lstringcopy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.Lstringcopy_unaligned_branchtable: + .byte 0 + .byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.Lstringcopy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .Lstringcopy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .Lstringcopy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign7 + +.Lstringcopy_unalign7_copy5bytes: + str r2, [r0], #4 + strb r3, [r0] +.Lstringcopy_unalign_return: + m_pop + +.Lstringcopy_unalign7_copy6bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0] + m_pop + +.Lstringcopy_unalign7_copy7bytes: + str r2, [r0], #4 + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0] + m_pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.Lstringcopy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .Lstringcopy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .Lstringcopy_copy7bytes + lsrs ip, r3, #24 + strd r2, r3, [r0], #8 +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign6 + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.Lstringcopy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign5 + +.Lstringcopy_unalign_copy5bytes: + str r2, [r0], #4 + strb r4, [r0] + m_pop + +.Lstringcopy_unalign_copy6bytes: + str r2, [r0], #4 + strb r4, [r0], #1 + strb r5, [r0] + m_pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.Lstringcopy_unalign4: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldr r3, [r1], #4 + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.Lstringcopy_unalign3: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .Lstringcopy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .Lstringcopy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign3 + +.Lstringcopy_unalign3_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_pop + +.Lstringcopy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.Lstringcopy_unalign2: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .Lstringcopy_copy3bytes + lsrs ip, r2, #24 + beq .Lstringcopy_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.Lstringcopy_unalign1: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + strd r2, r3, [r0], #8 + b .Lstringcopy_unalign1 + +.Lstringcopy_unalign_copy1byte: + strb r2, [r0] + m_pop + +.Lstringcopy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r4, [r0] + m_pop +#if defined(STPCPY) +END(stpcpy_a15) +#else +END(strcpy_a15) +#endif diff --git a/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strlen.S b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strlen.S new file mode 100644 index 000000000..9c5ed2911 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a15/bionic/strlen.S @@ -0,0 +1,165 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .syntax unified + + .thumb + .thumb_func + +ENTRY(strlen_a15) + pld [r0, #0] + mov r1, r0 + + ands r3, r0, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_return + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_return + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_return + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_return: + sub r0, r1, r0 + sub r0, r0, #1 + bx lr + +.L_zero_in_first_register: + sub r0, r1, r0 + lsls r3, ip, #17 + bne .L_sub8_and_return + bcs .L_sub7_and_return + lsls ip, ip, #1 + bne .L_sub6_and_return + + sub r0, r0, #5 + bx lr + +.L_sub8_and_return: + sub r0, r0, #8 + bx lr + +.L_sub7_and_return: + sub r0, r0, #7 + bx lr + +.L_sub6_and_return: + sub r0, r0, #6 + bx lr + +.L_zero_in_second_register: + sub r0, r1, r0 + lsls r3, ip, #17 + bne .L_sub4_and_return + bcs .L_sub3_and_return + lsls ip, ip, #1 + bne .L_sub2_and_return + + sub r0, r0, #1 + bx lr + +.L_sub4_and_return: + sub r0, r0, #4 + bx lr + +.L_sub3_and_return: + sub r0, r0, #3 + bx lr + +.L_sub2_and_return: + sub r0, r0, #2 + bx lr +END(strlen_a15) diff --git a/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S new file mode 100644 index 000000000..72be243ce --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcat_chk.S @@ -0,0 +1,203 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_a53) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r1, r0 + sub r3, r3, #1 + b .L_finish + +.L_zero_in_first_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_finish + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_finish + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_finish + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_finish + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_finish + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_finish + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} + .cfi_adjust_cfa_offset -8 + .cfi_restore r4 + .cfi_restore r5 + +#include "memcpy_base.S" + + // Undo the above cfi directives + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 +END(__strcat_chk_a53) diff --git a/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S new file mode 100644 index 000000000..49228842b --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/__strcpy_chk.S @@ -0,0 +1,165 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_a53) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r0, r1 + sub r3, r3, #1 + b .L_check_size + +.L_zero_in_first_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_check_size + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_check_size + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_check_size + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_check_size + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_check_size + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_check_size + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + +#include "memcpy_base.S" + +END(__strcpy_chk_a53) diff --git a/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy.S new file mode 100644 index 000000000..ea748bd00 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy.S @@ -0,0 +1,75 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .text + .syntax unified + .fpu neon + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Prototype: void *memcpy (void *dst, const void *src, size_t count). +ENTRY(__memcpy_a53) + pld [r1, #64] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + +#include "memcpy_base.S" +END(__memcpy_a53) diff --git a/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy_base.S new file mode 100644 index 000000000..2749fc83d --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a53/bionic/memcpy_base.S @@ -0,0 +1,143 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +.L_memcpy_base: + // Assumes that n >= 0, and dst, src are valid pointers. + cmp r2, #16 + blo .L_copy_less_than_16_unknown_align + +.L_copy_unknown_alignment: + // Unknown alignment of src and dst. + // Assumes that the first few bytes have already been prefetched. + + // Align destination to 128 bits. The mainloop store instructions + // require this alignment or they will throw an exception. + rsb r3, r0, #0 + ands r3, r3, #0xF + beq 2f + + // Copy up to 15 bytes (count in r3). + sub r2, r2, r3 + movs ip, r3, lsl #31 + + itt mi + ldrbmi lr, [r1], #1 + strbmi lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1], #1 + strbcs ip, [r0], #1 + strbcs lr, [r0], #1 + + movs ip, r3, lsl #29 + bge 1f + // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after. + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]! +1: bcc 2f + // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after. + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! + +2: // Make sure we have at least 64 bytes to copy. + subs r2, r2, #64 + blo 2f + +1: // The main loop copies 64 bytes at a time. + vld1.8 {d0 - d3}, [r1]! + vld1.8 {d4 - d7}, [r1]! + subs r2, r2, #64 + vstmia r0!, {d0 - d7} + pld [r1, #(64*10)] + bhs 1b + +2: // Fix-up the remaining count and make sure we have >= 32 bytes left. + adds r2, r2, #32 + blo 3f + + // 32 bytes. These cache lines were already preloaded. + vld1.8 {d0 - d3}, [r1]! + sub r2, r2, #32 + vst1.8 {d0 - d3}, [r0, :128]! +3: // Less than 32 left. + add r2, r2, #32 + tst r2, #0x10 + beq .L_copy_less_than_16_unknown_align + // Copies 16 bytes, destination 128 bits aligned. + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0, :128]! + +.L_copy_less_than_16_unknown_align: + // Copy up to 15 bytes (count in r2). + movs ip, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: bge 2f + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! + +2: // Copy 0 to 4 bytes. + lsls r2, r2, #31 + itt ne + ldrbne lr, [r1], #1 + strbne lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1] + strbcs ip, [r0], #1 + strbcs lr, [r0] + + pop {r0, pc} diff --git a/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcat_chk.S new file mode 100644 index 000000000..eec1005df --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcat_chk.S @@ -0,0 +1,198 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_a55) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r1, r0 + sub r3, r3, #1 + b .L_finish + +.L_zero_in_first_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_finish + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_finish + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_finish + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_finish + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_finish + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_finish + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} +END(__strcat_chk_a55) + +#define MEMCPY_BASE __strcat_chk_a55_memcpy_base +#define MEMCPY_BASE_ALIGNED __strcat_chk_a55_memcpy_base_aligned + +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcpy_chk.S new file mode 100644 index 000000000..dfcc58983 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/__strcpy_chk.S @@ -0,0 +1,168 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_a55) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r0, r1 + sub r3, r3, #1 + b .L_check_size + +.L_zero_in_first_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_check_size + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_check_size + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_check_size + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_check_size + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_check_size + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_check_size + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + + // Fall through into the memcpy_base function. +END(__strcpy_chk_a55) + +#define MEMCPY_BASE __strcpy_chk_a55_memcpy_base +#define MEMCPY_BASE_ALIGNED __strcpy_chk_a55_memcpy_base_aligned +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy.S new file mode 100644 index 000000000..ac9675f7b --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy.S @@ -0,0 +1,78 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +// Prototype: void *memcpy (void *dst, const void *src, size_t count). + +#include + + .text + .syntax unified + .fpu neon + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +ENTRY(__memcpy_a55) + pld [r1, #64] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 +END(__memcpy_a55) + +#define MEMCPY_BASE __memcpy_base_a55 +#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_a55 +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy_base.S new file mode 100644 index 000000000..2abb48671 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a55/bionic/memcpy_base.S @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * Copyright (c) 2013-2014, NVIDIA Corporation. 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. + */ + +#define CACHE_LINE_SIZE (64) +#define PREFETCH_DISTANCE (CACHE_LINE_SIZE*6) + +ENTRY_PRIVATE(MEMCPY_BASE) + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + cmp r2, #0 + beq .L_memcpy_done + cmp r0, r1 + beq .L_memcpy_done + + /* preload next cache line */ + pld [r1, #CACHE_LINE_SIZE*1] + + /* Deal with very small blocks (< 32bytes) asap */ + cmp r2, #32 + blo .L_memcpy_lt_32bytes + /* no need to align if len < 128 bytes */ + cmp r2, #128 + blo .L_memcpy_lt_128bytes + + /* large copy, align dest to 64 byte boundry */ + pld [r1, #CACHE_LINE_SIZE*2] + rsb r3, r0, #0 + ands r3, r3, #0x3F + pld [r1, #CACHE_LINE_SIZE*3] + beq .L_memcpy_dispatch + sub r2, r2, r3 + /* copy 1 byte */ + movs ip, r3, lsl #31 + itt mi + ldrbmi ip, [r1], #1 + strbmi ip, [r0], #1 + /* copy 2 bytes */ + itt cs + ldrhcs ip, [r1], #2 + strhcs ip, [r0], #2 + /* copy 4 bytes */ + movs ip, r3, lsl #29 + itt mi + ldrmi ip, [r1], #4 + strmi ip, [r0], #4 + /* copy 8 bytes */ + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! +1: /* copy 16 bytes */ + movs ip, r3, lsl #27 + bpl 1f + vld1.8 {q0}, [r1]! + vst1.8 {q0}, [r0, :128]! +1: /* copy 32 bytes */ + bcc .L_memcpy_dispatch + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + +.L_memcpy_dispatch: + // pre-decrement by 128 to detect nearly-done condition easily, but + // also need to check if we have less than 128 bytes left at this + // point due to alignment code above + subs r2, r2, #128 + blo .L_memcpy_lt_128presub + + // Denver does better if both source and dest are aligned so + // we'll special-case that even though the code is virually identical + tst r1, #0xF + bne .L_memcpy_neon_unalign_src_pld + + // DRAM memcpy should be throttled slightly to get full bandwidth + // + cmp r2, #32768 + bhi .L_memcpy_neon_unalign_src_pld + .align 4 +1: + /* copy 128 bytes in each loop */ + subs r2, r2, #128 + + /* preload a cache line */ + pld [r1, #PREFETCH_DISTANCE] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1, :128]! + vst1.8 {q0, q1}, [r0, :256]! + vld1.8 {q0, q1}, [r1, :128]! + vst1.8 {q0, q1}, [r0, :256]! + /* preload a cache line */ + pld [r1, #PREFETCH_DISTANCE] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1, :128]! + vst1.8 {q0, q1}, [r0, :256]! + vld1.8 {q0, q1}, [r1, :128]! + vst1.8 {q0, q1}, [r0, :256]! + + bhs 1b + adds r2, r2, #128 + bne .L_memcpy_lt_128bytes_align + pop {r0, pc} + + .align 4 +.L_memcpy_neon_unalign_src_pld: +1: + /* copy 128 bytes in each loop */ + subs r2, r2, #128 + + /* preload a cache line */ + pld [r1, #PREFETCH_DISTANCE] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + /* preload a cache line */ + pld [r1, #PREFETCH_DISTANCE] + /* copy a cache line */ + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + + bhs 1b + adds r2, r2, #128 + bne .L_memcpy_lt_128bytes_align + pop {r0, pc} + +.L_memcpy_lt_128presub: + add r2, r2, #128 +.L_memcpy_lt_128bytes_align: + /* copy 64 bytes */ + movs ip, r2, lsl #26 + bcc 1f + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! +1: /* copy 32 bytes */ + bpl 1f + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0, :256]! +1: /* copy 16 bytes */ + movs ip, r2, lsl #28 + bcc 1f + vld1.8 {q0}, [r1]! + vst1.8 {q0}, [r0, :128]! +1: /* copy 8 bytes */ + bpl 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! +1: /* copy 4 bytes */ + tst r2, #4 + itt ne + ldrne ip, [r1], #4 + strne ip, [r0], #4 + /* copy 2 bytes */ + movs ip, r2, lsl #31 + itt cs + ldrhcs ip, [r1], #2 + strhcs ip, [r0], #2 + /* copy 1 byte */ + itt mi + ldrbmi ip, [r1] + strbmi ip, [r0] + + pop {r0, pc} + +.L_memcpy_lt_128bytes: + /* copy 64 bytes */ + movs ip, r2, lsl #26 + bcc 1f + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0]! + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0]! +1: /* copy 32 bytes */ + bpl .L_memcpy_lt_32bytes + vld1.8 {q0, q1}, [r1]! + vst1.8 {q0, q1}, [r0]! +.L_memcpy_lt_32bytes: + /* copy 16 bytes */ + movs ip, r2, lsl #28 + bcc 1f + vld1.8 {q0}, [r1]! + vst1.8 {q0}, [r0]! +1: /* copy 8 bytes */ + bpl 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: /* copy 4 bytes */ + tst r2, #4 + itt ne + ldrne ip, [r1], #4 + strne ip, [r0], #4 + /* copy 2 bytes */ + movs ip, r2, lsl #31 + itt cs + ldrhcs ip, [r1], #2 + strhcs ip, [r0], #2 + /* copy 1 byte */ + itt mi + ldrbmi ip, [r1] + strbmi ip, [r0] + +.L_memcpy_done: + pop {r0, pc} +END(MEMCPY_BASE) diff --git a/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S new file mode 100644 index 000000000..36bda6b0e --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcat_chk.S @@ -0,0 +1,203 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_a7) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r1, r0 + sub r3, r3, #1 + b .L_finish + +.L_zero_in_first_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_finish + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_finish + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_finish + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_finish + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_finish + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_finish + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} + .cfi_adjust_cfa_offset -8 + .cfi_restore r4 + .cfi_restore r5 + +#include "memcpy_base.S" + + // Undo the above cfi directives + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 +END(__strcat_chk_a7) diff --git a/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S new file mode 100644 index 000000000..edbabc776 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/__strcpy_chk.S @@ -0,0 +1,165 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_a7) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r0, r1 + sub r3, r3, #1 + b .L_check_size + +.L_zero_in_first_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_check_size + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_check_size + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_check_size + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_check_size + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_check_size + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_check_size + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + +#include "memcpy_base.S" + +END(__strcpy_chk_a7) diff --git a/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy.S new file mode 100644 index 000000000..2f32d2e7e --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy.S @@ -0,0 +1,75 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .text + .syntax unified + .fpu neon + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Prototype: void *memcpy (void *dst, const void *src, size_t count). +ENTRY(__memcpy_a7) + pld [r1, #64] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + +#include "memcpy_base.S" +END(__memcpy_a7) diff --git a/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy_base.S new file mode 100644 index 000000000..4ff982b0f --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memcpy_base.S @@ -0,0 +1,176 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +.L_memcpy_base: + // Assumes that n >= 0, and dst, src are valid pointers. + // For any sizes less than 832 use the neon code that doesn't + // care about the src alignment. This avoids any checks + // for src alignment, and offers the best improvement since + // smaller sized copies are dominated by the overhead of + // the pre and post main loop. + // For larger copies, if src and dst cannot both be aligned to + // word boundaries, use the neon code. + // For all other copies, align dst to a double word boundary + // and copy using LDRD/STRD instructions. + + cmp r2, #16 + blo .L_copy_less_than_16_unknown_align + +.L_copy_unknown_alignment: + // Unknown alignment of src and dst. + // Assumes that the first few bytes have already been prefetched. + + // Align destination to 128 bits. The mainloop store instructions + // require this alignment or they will throw an exception. + rsb r3, r0, #0 + ands r3, r3, #0xF + beq 2f + + // Copy up to 15 bytes (count in r3). + sub r2, r2, r3 + movs ip, r3, lsl #31 + + itt mi + ldrbmi lr, [r1], #1 + strbmi lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1], #1 + strbcs ip, [r0], #1 + strbcs lr, [r0], #1 + + movs ip, r3, lsl #29 + bge 1f + // Copies 4 bytes, dst 32 bits aligned before, at least 64 bits after. + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0, :32]! +1: bcc 2f + // Copies 8 bytes, dst 64 bits aligned before, at least 128 bits after. + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! + +2: cmp r2, #256 + ble .L_copy_loop + + // Make sure DST is 64 BYTE aligned. + rsb r3, r0, #0 + ands r3, r3, #0x30 + beq .L_copy_loop + + sub r2, r2, r3 + cmp r3, #0x10 + beq .L_copy_16 + + vld1.8 {d0 - d3}, [r1]! + vst1.8 {d0 - d3}, [r0, :128]! + ands r3, r3, #0x10 + beq .L_copy_loop + +.L_copy_16: + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0, :128]! + +.L_copy_loop: + // Make sure we have at least 64 bytes to copy. + subs r2, r2, #64 + blo 2f + +1: // The main loop copies 64 bytes at a time. + vld1.8 {d0 - d3}, [r1]! + vst1.8 {d0 - d3}, [r0, :128]! + pld [r1, #(64*4)] + subs r2, r2, #64 + vld1.8 {d4 - d7}, [r1]! + vst1.8 {d4 - d7}, [r0, :128]! + bhs 1b + +2: // Fix-up the remaining count and make sure we have >= 32 bytes left. + adds r2, r2, #32 + blo 3f + + // 32 bytes. These cache lines were already preloaded. + vld1.8 {d0 - d3}, [r1]! + sub r2, r2, #32 + vst1.8 {d0 - d3}, [r0, :128]! +3: // Less than 32 left. + add r2, r2, #32 + tst r2, #0x10 + beq .L_copy_less_than_16_unknown_align + // Copies 16 bytes, destination 128 bits aligned. + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0, :128]! + +.L_copy_less_than_16_unknown_align: + // Copy up to 15 bytes (count in r2). + movs ip, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: bge 2f + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! + +2: // Copy 0 to 4 bytes. + lsls r2, r2, #31 + itt ne + ldrbne lr, [r1], #1 + strbne lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1] + strbcs ip, [r0], #1 + strbcs lr, [r0] + + pop {r0, pc} diff --git a/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memset.S b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memset.S new file mode 100644 index 000000000..d7d3b34e0 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a7/bionic/memset.S @@ -0,0 +1,163 @@ +/* + * 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 + + /* + * Optimized memset() for ARM. + * + * memset() returns its first argument. + */ + + .fpu neon + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +ENTRY(__memset_chk_a7) + cmp r2, r3 + bls memset + + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + + bl __memset_chk_fail +END(__memset_chk_a7) + +ENTRY(memset_a7) + mov r3, r0 + // At this point only d0, d1 are going to be used below. + vdup.8 q0, r1 + cmp r2, #16 + blo .L_set_less_than_16_unknown_align + +.L_check_alignment: + // Align destination to a double word to avoid the store crossing + // a cache line boundary. + ands ip, r3, #7 + bne .L_do_double_word_align + +.L_double_word_aligned: + // Duplicate since the less than 64 can use d2, d3. + vmov q1, q0 + subs r2, #64 + blo .L_set_less_than_64 + + // Duplicate the copy value so that we can store 64 bytes at a time. + vmov q2, q0 + vmov q3, q0 + +1: // Main loop stores 64 bytes at a time. + subs r2, #64 + vstmia r3!, {d0 - d7} + bge 1b + +.L_set_less_than_64: + // Restore r2 to the count of bytes left to set. + add r2, #64 + lsls ip, r2, #27 + bcc .L_set_less_than_32 + // Set 32 bytes. + vstmia r3!, {d0 - d3} + +.L_set_less_than_32: + bpl .L_set_less_than_16 + // Set 16 bytes. + vstmia r3!, {d0, d1} + +.L_set_less_than_16: + // Less than 16 bytes to set. + lsls ip, r2, #29 + bcc .L_set_less_than_8 + + // Set 8 bytes. + vstmia r3!, {d0} + +.L_set_less_than_8: + bpl .L_set_less_than_4 + // Set 4 bytes + vst1.32 {d0[0]}, [r3]! + +.L_set_less_than_4: + lsls ip, r2, #31 + it ne + strbne r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3] + bx lr + +.L_do_double_word_align: + rsb ip, ip, #8 + sub r2, r2, ip + + // Do this comparison now, otherwise we'll need to save a + // register to the stack since we've used all available + // registers. + cmp ip, #4 + blo 1f + + // Need to do a four byte copy. + movs ip, ip, lsl #31 + it mi + strbmi r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + vst1.32 {d0[0]}, [r3]! + b .L_double_word_aligned + +1: + // No four byte copy. + movs ip, ip, lsl #31 + it mi + strbmi r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + b .L_double_word_aligned + +.L_set_less_than_16_unknown_align: + // Set up to 15 bytes. + movs ip, r2, lsl #29 + bcc 1f + vst1.8 {d0}, [r3]! +1: bge 2f + vst1.32 {d0[0]}, [r3]! +2: movs ip, r2, lsl #31 + it mi + strbmi r1, [r3], #1 + itt cs + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + bx lr +END(memset_a7) diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S new file mode 100644 index 000000000..d20283e98 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S @@ -0,0 +1,202 @@ +/* + * 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 + + .syntax unified + .fpu neon + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_a9) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + + ands r3, r0, #7 + bne .L_align_src + + .p2align 2 +.L_mainloop: + ldmia r1!, {r2, r3} + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_zero_in_first_register: + sub r3, r1, r0 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq .L_check_byte1_reg1 + + sub r3, r3, #8 + b .L_finish + +.L_check_byte1_reg1: + bcc .L_check_byte2_reg1 + + sub r3, r3, #7 + b .L_finish + +.L_check_byte2_reg1: + // Check for zero in byte 2. + tst ip, #0x800000 + it ne + subne r3, r3, #6 + bne .L_finish + sub r3, r3, #5 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq .L_check_byte1_reg2 + + sub r3, r3, #4 + b .L_finish + +.L_check_byte1_reg2: + bcc .L_check_byte2_reg2 + + sub r3, r3, #3 + b .L_finish + +.L_check_byte2_reg2: + // Check for zero in byte 2. + tst ip, #0x800000 + it ne + subne r3, r3, #2 + bne .L_finish + sub r3, r3, #1 + b .L_finish + +.L_align_src: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_done + +.L_align_to_32: + bcc .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_done + ldrb r2, [r1], #1 + cbz r2, .L_done + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_done: + sub r3, r1, r0 + sub r3, r3, #1 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} + + // Fall through into the memcpy_base function. +END(__strcat_chk_a9) + +#define MEMCPY_BASE __strcat_chk_a9_memcpy_base +#define MEMCPY_BASE_ALIGNED __strcat_chk_a9_memcpy_base_aligned +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S new file mode 100644 index 000000000..1f0a774b8 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S @@ -0,0 +1,170 @@ +/* + * 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 + + .syntax unified + .fpu neon + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_a9) + pld [r0, #0] + push {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r0, #7 + bne .L_align_src + + .p2align 2 +.L_mainloop: + ldmia r0!, {r2, r3} + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_zero_in_first_register: + sub r3, r0, r1 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq .L_check_byte1_reg1 + + sub r3, r3, #8 + b .L_check_size + +.L_check_byte1_reg1: + bcc .L_check_byte2_reg1 + + sub r3, r3, #7 + b .L_check_size + +.L_check_byte2_reg1: + // Check for zero in byte 2. + tst ip, #0x800000 + it ne + subne r3, r3, #6 + bne .L_check_size + sub r3, r3, #5 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq .L_check_byte1_reg2 + + sub r3, r3, #4 + b .L_check_size + +.L_check_byte1_reg2: + bcc .L_check_byte2_reg2 + + sub r3, r3, #3 + b .L_check_size + +.L_check_byte2_reg2: + // Check for zero in byte 2. + tst ip, #0x800000 + it ne + subne r3, r3, #2 + bne .L_check_size + sub r3, r3, #1 + b .L_check_size + +.L_align_src: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_done + +.L_align_to_32: + bcc .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_done + ldrb r2, [r0], #1 + cbz r2, .L_done + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r2, [r0], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_done: + sub r3, r0, r1 + sub r3, r3, #1 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + + // Fall through into the memcpy_base function. +END(__strcpy_chk_a9) + +#define MEMCPY_BASE __strcpy_chk_a9_memcpy_base +#define MEMCPY_BASE_ALIGNED __strcpy_chk_a9_memcpy_base_aligned +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy.S new file mode 100644 index 000000000..e78a7daa9 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy.S @@ -0,0 +1,53 @@ +/* + * 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 + +/* + * This code assumes it is running on a processor that supports all arm v7 + * instructions, that supports neon instructions, and that has a 32 byte + * cache line. + */ + + .syntax unified + .fpu neon + .thumb + .thumb_func + +ENTRY(__memcpy_a9) + pld [r1, #0] + stmfd sp!, {r0, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + pld [r1, #64] +END(__memcpy_a9) + +#define MEMCPY_BASE __memcpy_base_a9 +#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned_a9 +#include "memcpy_base.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy_base.S new file mode 100644 index 000000000..39da7ffcf --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memcpy_base.S @@ -0,0 +1,228 @@ +/* + * 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. + */ + +/* + * This code assumes it is running on a processor that supports all arm v7 + * instructions, that supports neon instructions, and that has a 32 byte + * cache line. + */ + + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +ENTRY_PRIVATE(MEMCPY_BASE) + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + // Check so divider is at least 16 bytes, needed for alignment code. + cmp r2, #16 + blo 5f + + /* check if buffers are aligned. If so, run arm-only version */ + eor r3, r0, r1 + ands r3, r3, #0x3 + beq MEMCPY_BASE_ALIGNED + + /* Check the upper size limit for Neon unaligned memory access in memcpy */ + cmp r2, #224 + blo 3f + + /* align destination to 16 bytes for the write-buffer */ + rsb r3, r0, #0 + ands r3, r3, #0xF + beq 3f + + /* copy up to 15-bytes (count in r3) */ + sub r2, r2, r3 + movs ip, r3, lsl #31 + itt mi + ldrbmi lr, [r1], #1 + strbmi lr, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1], #1 + strbcs ip, [r0], #1 + strbcs lr, [r0], #1 + movs ip, r3, lsl #29 + bge 1f + // copies 4 bytes, destination 32-bits aligned + vld1.32 {d0[0]}, [r1]! + vst1.32 {d0[0]}, [r0, :32]! +1: bcc 2f + // copies 8 bytes, destination 64-bits aligned + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0, :64]! +2: + /* preload immediately the next cache line, which we may need */ + pld [r1, #0] + pld [r1, #(32 * 2)] +3: + /* make sure we have at least 64 bytes to copy */ + subs r2, r2, #64 + blo 2f + + /* preload all the cache lines we need */ + pld [r1, #(32 * 4)] + pld [r1, #(32 * 6)] + +1: /* The main loop copies 64 bytes at a time */ + vld1.8 {d0 - d3}, [r1]! + vld1.8 {d4 - d7}, [r1]! + pld [r1, #(32 * 6)] + subs r2, r2, #64 + vst1.8 {d0 - d3}, [r0]! + vst1.8 {d4 - d7}, [r0]! + bhs 1b + +2: /* fix-up the remaining count and make sure we have >= 32 bytes left */ + add r2, r2, #64 + subs r2, r2, #32 + blo 4f + +3: /* 32 bytes at a time. These cache lines were already preloaded */ + vld1.8 {d0 - d3}, [r1]! + subs r2, r2, #32 + vst1.8 {d0 - d3}, [r0]! + bhs 3b + +4: /* less than 32 left */ + add r2, r2, #32 + tst r2, #0x10 + beq 5f + // copies 16 bytes, 128-bits aligned + vld1.8 {d0, d1}, [r1]! + vst1.8 {d0, d1}, [r0]! +5: /* copy up to 15-bytes (count in r2) */ + movs ip, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: bge 2f + vld1.32 {d0[0]}, [r1]! + vst1.32 {d0[0]}, [r0]! +2: movs ip, r2, lsl #31 + itt mi + ldrbmi r3, [r1], #1 + strbmi r3, [r0], #1 + itttt cs + ldrbcs ip, [r1], #1 + ldrbcs lr, [r1], #1 + strbcs ip, [r0], #1 + strbcs lr, [r0], #1 + + ldmfd sp!, {r0, pc} +END(MEMCPY_BASE) + +ENTRY_PRIVATE(MEMCPY_BASE_ALIGNED) + .cfi_def_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + /* Simple arm-only copy loop to handle aligned copy operations */ + stmfd sp!, {r4-r8} + .cfi_adjust_cfa_offset 20 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset r6, 8 + .cfi_rel_offset r7, 12 + .cfi_rel_offset r8, 16 + pld [r1, #(32 * 4)] + + /* Check alignment */ + rsb r3, r1, #0 + ands r3, #3 + beq 2f + + /* align source to 32 bits. We need to insert 2 instructions between + * a ldr[b|h] and str[b|h] because byte and half-word instructions + * stall 2 cycles. + */ + movs r12, r3, lsl #31 + sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */ + itt mi + ldrbmi r3, [r1], #1 + strbmi r3, [r0], #1 + itttt cs + ldrbcs r4, [r1], #1 + ldrbcs r5, [r1], #1 + strbcs r4, [r0], #1 + strbcs r5, [r0], #1 + +2: + subs r2, r2, #64 + blt 4f + +3: /* Main copy loop, copying 64 bytes at a time */ + pld [r1, #(32 * 8)] + ldmia r1!, {r3, r4, r5, r6, r7, r8, r12, lr} + stmia r0!, {r3, r4, r5, r6, r7, r8, r12, lr} + ldmia r1!, {r3, r4, r5, r6, r7, r8, r12, lr} + stmia r0!, {r3, r4, r5, r6, r7, r8, r12, lr} + subs r2, r2, #64 + bge 3b + +4: /* Check if there are > 32 bytes left */ + adds r2, r2, #64 + subs r2, r2, #32 + blt 5f + + /* Copy 32 bytes */ + ldmia r1!, {r3, r4, r5, r6, r7, r8, r12, lr} + stmia r0!, {r3, r4, r5, r6, r7, r8, r12, lr} + subs r2, #32 + +5: /* Handle any remaining bytes */ + adds r2, #32 + beq 6f + + movs r12, r2, lsl #28 + itt cs + ldmiacs r1!, {r3, r4, r5, r6} /* 16 bytes */ + stmiacs r0!, {r3, r4, r5, r6} + itt mi + ldmiami r1!, {r7, r8} /* 8 bytes */ + stmiami r0!, {r7, r8} + movs r12, r2, lsl #30 + itt cs + ldrcs r3, [r1], #4 /* 4 bytes */ + strcs r3, [r0], #4 + itt mi + ldrhmi r4, [r1], #2 /* 2 bytes */ + strhmi r4, [r0], #2 + tst r2, #0x1 + itt ne + ldrbne r3, [r1] /* last byte */ + strbne r3, [r0] +6: + ldmfd sp!, {r4-r8} + ldmfd sp!, {r0, pc} +END(MEMCPY_BASE_ALIGNED) diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memset.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memset.S new file mode 100644 index 000000000..cf66e86c9 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/memset.S @@ -0,0 +1,161 @@ +/* + * 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 + +/* + * This code assumes it is running on a processor that supports all arm v7 + * instructions and that supports neon instructions. + */ + + .fpu neon + .syntax unified + +ENTRY(__memset_chk_a9) + cmp r2, r3 + bls memset + + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + + bl __memset_chk_fail +END(__memset_chk_a9) + +/* memset() returns its first argument. */ +ENTRY(memset_a9) + // The neon memset only wins for less than 132. + cmp r2, #132 + bhi .L_memset_large_copy + + mov r3, r0 + vdup.8 q0, r1 + + /* make sure we have at least 32 bytes to write */ + subs r2, r2, #32 + blo 2f + vmov q1, q0 + +1: /* The main loop writes 32 bytes at a time */ + subs r2, r2, #32 + vst1.8 {d0 - d3}, [r3]! + bhs 1b + +2: /* less than 32 left */ + add r2, r2, #32 + tst r2, #0x10 + beq 3f + + // writes 16 bytes, 128-bits aligned + vst1.8 {d0, d1}, [r3]! +3: /* write up to 15-bytes (count in r2) */ + movs ip, r2, lsl #29 + bcc 1f + vst1.8 {d0}, [r3]! +1: bge 2f + vst1.32 {d0[0]}, [r3]! +2: movs ip, r2, lsl #31 + strbmi r1, [r3], #1 + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + bx lr + +.L_memset_large_copy: + /* compute the offset to align the destination + * offset = (4-(src&3))&3 = -src & 3 + */ + stmfd sp!, {r0, r4-r7, lr} + .cfi_def_cfa_offset 24 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset r6, 12 + .cfi_rel_offset r7, 16 + .cfi_rel_offset lr, 20 + + rsb r3, r0, #0 + ands r3, r3, #3 + cmp r3, r2 + movhi r3, r2 + + /* splat r1 */ + mov r1, r1, lsl #24 + orr r1, r1, r1, lsr #8 + orr r1, r1, r1, lsr #16 + + movs r12, r3, lsl #31 + strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */ + strbcs r1, [r0], #1 + strbmi r1, [r0], #1 + subs r2, r2, r3 + popls {r0, r4-r7, pc} /* return */ + + /* align the destination to a cache-line */ + mov r12, r1 + mov lr, r1 + mov r4, r1 + mov r5, r1 + mov r6, r1 + mov r7, r1 + + rsb r3, r0, #0 + ands r3, r3, #0x1C + beq 3f + cmp r3, r2 + andhi r3, r2, #0x1C + sub r2, r2, r3 + + /* conditionally writes 0 to 7 words (length in r3) */ + movs r3, r3, lsl #28 + stmcs r0!, {r1, lr} + stmcs r0!, {r1, lr} + stmmi r0!, {r1, lr} + movs r3, r3, lsl #2 + strcs r1, [r0], #4 + +3: + subs r2, r2, #32 + mov r3, r1 + bmi 2f +1: subs r2, r2, #32 + stmia r0!, {r1,r3,r4,r5,r6,r7,r12,lr} + bhs 1b +2: add r2, r2, #32 + + /* conditionally stores 0 to 31 bytes */ + movs r2, r2, lsl #28 + stmcs r0!, {r1,r3,r12,lr} + stmmi r0!, {r1, lr} + movs r2, r2, lsl #2 + strcs r1, [r0], #4 + strhmi r1, [r0], #2 + movs r2, r2, lsl #2 + strbcs r1, [r0] + ldmfd sp!, {r0, r4-r7, pc} +END(memset_a9) diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/stpcpy.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/stpcpy.S new file mode 100644 index 000000000..740523b5d --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/stpcpy.S @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#define STPCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcat.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcat.S new file mode 100644 index 000000000..430748f25 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcat.S @@ -0,0 +1,559 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + + .thumb + .thumb_func + + .macro m_push + push {r0, r4, r5, lr} + .endm // m_push + + .macro m_ret inst + \inst {r0, r4, r5, pc} + .endm // m_ret + + .macro m_scan_byte + ldrb r3, [r0] + cbz r3, .Lstrcat_r0_scan_done + add r0, #1 + .endm // m_scan_byte + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +ENTRY(strcat_a9) + // Quick check to see if src is empty. + ldrb r2, [r1] + pld [r1, #0] + cbnz r2, .Lstrcat_continue + bx lr + +.Lstrcat_continue: + // To speed up really small dst strings, unroll checking the first 4 bytes. + m_push + m_scan_byte + m_scan_byte + m_scan_byte + m_scan_byte + + ands r3, r0, #7 + bne .Lstrcat_align_src + + .p2align 2 +.Lstrcat_mainloop: + ldmia r0!, {r2, r3} + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcat_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcat_zero_in_second_register + b .Lstrcat_mainloop + +.Lstrcat_zero_in_first_register: + sub r0, r0, #4 + +.Lstrcat_zero_in_second_register: + // Check for zero in byte 0. + tst ip, #0x80 + it ne + subne r0, r0, #4 + bne .Lstrcat_r0_scan_done + // Check for zero in byte 1. + tst ip, #0x8000 + it ne + subne r0, r0, #3 + bne .Lstrcat_r0_scan_done + // Check for zero in byte 2. + tst ip, #0x800000 + it ne + subne r0, r0, #2 + it eq + // Zero is in byte 3. + subeq r0, r0, #1 + +.Lstrcat_r0_scan_done: + // Unroll the first 8 bytes that will be copied. + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstrcpy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstrcpy_continue + +.Lstrcpy_finish: + m_ret inst=pop + +.Lstrcpy_continue: + pld [r1, #0] + ands r3, r0, #7 + bne .Lstrcpy_align_dst + +.Lstrcpy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .Lstrcpy_unaligned_copy + + .p2align 2 +.Lstrcpy_mainloop: + ldmia r1!, {r2, r3} + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_mainloop + +.Lstrcpy_zero_in_first_register: + lsls lr, ip, #17 + itt ne + strbne r2, [r0] + m_ret inst=popne + itt cs + strhcs r2, [r0] + m_ret inst=popcs + lsls ip, ip, #1 + itt eq + streq r2, [r0] + m_ret inst=popeq + strh r2, [r0], #2 + lsr r3, r2, #16 + strb r3, [r0] + m_ret inst=pop + +.Lstrcpy_zero_in_second_register: + lsls lr, ip, #17 + ittt ne + stmiane r0!, {r2} + strbne r3, [r0] + m_ret inst=popne + ittt cs + strcs r2, [r0], #4 + strhcs r3, [r0] + m_ret inst=popcs + lsls ip, ip, #1 + itt eq + stmiaeq r0, {r2, r3} + m_ret inst=popeq + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r4, r3, #16 + strb r4, [r0] + m_ret inst=pop + +.Lstrcpy_align_dst: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstrcpy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstrcpy_complete + +.Lstrcpy_align_to_32: + bcc .Lstrcpy_align_to_64 + + ldrb r4, [r1], #1 + strb r4, [r0], #1 + cmp r4, #0 + it eq + m_ret inst=popeq + ldrb r5, [r1], #1 + strb r5, [r0], #1 + cmp r5, #0 + it eq + m_ret inst=popeq + +.Lstrcpy_align_to_64: + tst r3, #4 + beq .Lstrcpy_check_src_align + // Read one byte at a time since we don't know the src alignment + // and we don't want to read into a different page. + ldrb r4, [r1], #1 + strb r4, [r0], #1 + cbz r4, .Lstrcpy_complete + ldrb r5, [r1], #1 + strb r5, [r0], #1 + cbz r5, .Lstrcpy_complete + ldrb r4, [r1], #1 + strb r4, [r0], #1 + cbz r4, .Lstrcpy_complete + ldrb r5, [r1], #1 + strb r5, [r0], #1 + cbz r5, .Lstrcpy_complete + b .Lstrcpy_check_src_align + +.Lstrcpy_complete: + m_ret inst=pop + +.Lstrcpy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.Lstrcpy_unaligned_branchtable: + .byte 0 + .byte ((.Lstrcpy_unalign7 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign6 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign5 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign4 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign3 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign2 - .Lstrcpy_unaligned_branchtable)/2) + .byte ((.Lstrcpy_unalign1 - .Lstrcpy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.Lstrcpy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .Lstrcpy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .Lstrcpy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .Lstrcpy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + stmia r0!, {r2, r3} + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign7 + +.Lstrcpy_unalign7_copy5bytes: + stmia r0!, {r2} + strb r3, [r0] +.Lstrcpy_unalign_return: + m_ret inst=pop + +.Lstrcpy_unalign7_copy6bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0], #1 + m_ret inst=pop + +.Lstrcpy_unalign7_copy7bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0], #1 + m_ret inst=pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.Lstrcpy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstrcpy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .Lstrcpy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .Lstrcpy_unalign6_copy7bytes + lsrs ip, r3, #24 + stmia r0!, {r2, r3} + beq .Lstrcpy_unalign_return + b .Lstrcpy_unalign6 + +.Lstrcpy_unalign6_copy7bytes: + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.Lstrcpy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstrcpy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_unalign5 + +.Lstrcpy_unalign_copy5bytes: + stmia r0!, {r2} + strb r4, [r0] + m_ret inst=pop + +.Lstrcpy_unalign_copy6bytes: + stmia r0!, {r2} + strb r4, [r0], #1 + strb r5, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.Lstrcpy_unalign4: + ldmia r1!, {r2} + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + ldmia r1!, {r3} + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.Lstrcpy_unalign3: + ldrb r2, [r1] + cbz r2, .Lstrcpy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstrcpy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .Lstrcpy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .Lstrcpy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_unalign3 + +.Lstrcpy_unalign3_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstrcpy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstrcpy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.Lstrcpy_unalign2: + ldrb r2, [r1] + cbz r2, .Lstrcpy_unalign_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstrcpy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .Lstrcpy_unalign_copy3bytes + lsrs ip, r2, #24 + beq .Lstrcpy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.Lstrcpy_unalign1: + ldrb r2, [r1] + cbz r2, .Lstrcpy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcpy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstrcpy_unalign1 + +.Lstrcpy_unalign_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstrcpy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstrcpy_unalign_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_ret inst=pop + +.Lstrcpy_unalign_copy4bytes: + stmia r0, {r2} + m_ret inst=pop + +.Lstrcat_align_src: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstrcat_align_to_32 + ldrb r2, [r0], #1 + cbz r2, .Lstrcat_r0_update + +.Lstrcat_align_to_32: + bcc .Lstrcat_align_to_64 + ldrb r2, [r0], #1 + cbz r2, .Lstrcat_r0_update + ldrb r2, [r0], #1 + cbz r2, .Lstrcat_r0_update + +.Lstrcat_align_to_64: + tst r3, #4 + beq .Lstrcat_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstrcat_zero_in_second_register + b .Lstrcat_mainloop + +.Lstrcat_r0_update: + sub r0, r0, #1 + b .Lstrcat_r0_scan_done +END(strcat_a9) diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcpy.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcpy.S new file mode 100644 index 000000000..951face01 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strcpy.S @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#define STRCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/string_copy.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/string_copy.S new file mode 100644 index 000000000..3605b7a57 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/string_copy.S @@ -0,0 +1,546 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +#if !defined(STPCPY) && !defined(STRCPY) +#error "Either STPCPY or STRCPY must be defined." +#endif + +#include + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +#if defined(STPCPY) + .macro m_push + push {r4, r5, lr} + .cfi_def_cfa_offset 12 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + .cfi_rel_offset lr, 8 + .endm // m_push +#else + .macro m_push + push {r0, r4, r5, lr} + .cfi_def_cfa_offset 16 + .cfi_rel_offset r0, 0 + .cfi_rel_offset r4, 4 + .cfi_rel_offset r5, 8 + .cfi_rel_offset lr, 12 + .endm // m_push +#endif + +#if defined(STPCPY) + .macro m_ret inst + \inst {r4, r5, pc} + .endm // m_ret +#else + .macro m_ret inst + \inst {r0, r4, r5, pc} + .endm // m_ret +#endif + + .macro m_copy_byte reg, cmd, label + ldrb \reg, [r1], #1 + strb \reg, [r0], #1 + \cmd \reg, \label + .endm // m_copy_byte + +#if defined(STPCPY) +ENTRY(stpcpy_a9) +#else +ENTRY(strcpy_a9) +#endif + // Unroll the first 8 bytes that will be copied. + m_push + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r2, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r3, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r4, cmd=cbz, label=.Lstringcopy_finish + m_copy_byte reg=r5, cmd=cbnz, label=.Lstringcopy_continue + +.Lstringcopy_finish: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_ret inst=pop + +.Lstringcopy_continue: + pld [r1, #0] + ands r3, r0, #7 + bne .Lstringcopy_align_dst + +.Lstringcopy_check_src_align: + // At this point dst is aligned to a double word, check if src + // is also aligned to a double word. + ands r3, r1, #7 + bne .Lstringcopy_unaligned_copy + + .p2align 2 +.Lstringcopy_mainloop: + ldmia r1!, {r2, r3} + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_mainloop + +.Lstringcopy_zero_in_first_register: + lsls lr, ip, #17 + itt ne + strbne r2, [r0] + m_ret inst=popne + itt cs +#if defined(STPCPY) + strhcs r2, [r0], #1 +#else + strhcs r2, [r0] +#endif + m_ret inst=popcs + lsls ip, ip, #1 + itt eq +#if defined(STPCPY) + streq r2, [r0], #3 +#else + streq r2, [r0] +#endif + m_ret inst=popeq + strh r2, [r0], #2 + lsr r3, r2, #16 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_zero_in_second_register: + lsls lr, ip, #17 + ittt ne + stmiane r0!, {r2} + strbne r3, [r0] + m_ret inst=popne + ittt cs + strcs r2, [r0], #4 +#if defined(STPCPY) + strhcs r3, [r0], #1 +#else + strhcs r3, [r0] +#endif + m_ret inst=popcs + lsls ip, ip, #1 +#if defined(STPCPY) + ittt eq +#else + itt eq +#endif + stmiaeq r0, {r2, r3} +#if defined(STPCPY) + addeq r0, r0, #7 +#endif + m_ret inst=popeq + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r4, r3, #16 + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_align_dst: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .Lstringcopy_align_to_32 + + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + +.Lstringcopy_align_to_32: + bcc .Lstringcopy_align_to_64 + + ldrb r4, [r1], #1 + strb r4, [r0], #1 + cmp r4, #0 +#if defined(STPCPY) + itt eq + subeq r0, r0, #1 +#else + it eq +#endif + m_ret inst=popeq + ldrb r5, [r1], #1 + strb r5, [r0], #1 + cmp r5, #0 +#if defined(STPCPY) + itt eq + subeq r0, r0, #1 +#else + it eq +#endif + m_ret inst=popeq + +.Lstringcopy_align_to_64: + tst r3, #4 + beq .Lstringcopy_check_src_align + // Read one byte at a time since we don't have any idea about the alignment + // of the source and we don't want to read into a different page. + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + ldrb r2, [r1], #1 + strb r2, [r0], #1 + cbz r2, .Lstringcopy_complete + b .Lstringcopy_check_src_align + +.Lstringcopy_complete: +#if defined(STPCPY) + sub r0, r0, #1 +#endif + m_ret inst=pop + +.Lstringcopy_unaligned_copy: + // Dst is aligned to a double word, while src is at an unknown alignment. + // There are 7 different versions of the unaligned copy code + // to prevent overreading the src. The mainloop of every single version + // will store 64 bits per loop. The difference is how much of src can + // be read without potentially crossing a page boundary. + tbb [pc, r3] +.Lstringcopy_unaligned_branchtable: + .byte 0 + .byte ((.Lstringcopy_unalign7 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign6 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign5 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign4 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign3 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign2 - .Lstringcopy_unaligned_branchtable)/2) + .byte ((.Lstringcopy_unalign1 - .Lstringcopy_unaligned_branchtable)/2) + + .p2align 2 + // Can read 7 bytes before possibly crossing a page. +.Lstringcopy_unalign7: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r3, [r1] + cbz r3, .Lstringcopy_unalign7_copy5bytes + ldrb r4, [r1, #1] + cbz r4, .Lstringcopy_unalign7_copy6bytes + ldrb r5, [r1, #2] + cbz r5, .Lstringcopy_unalign7_copy7bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + lsrs ip, r3, #24 + stmia r0!, {r2, r3} +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign7 + +.Lstringcopy_unalign7_copy5bytes: + stmia r0!, {r2} + strb r3, [r0] +.Lstringcopy_unalign_return: + m_ret inst=pop + +.Lstringcopy_unalign7_copy6bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_unalign7_copy7bytes: + stmia r0!, {r2} + strb r3, [r0], #1 + strb r4, [r0], #1 + strb r5, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 6 bytes before possibly crossing a page. +.Lstringcopy_unalign6: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + ldrb r5, [r1, #1] + cbz r5, .Lstringcopy_unalign_copy6bytes + + ldr r3, [r1], #4 + pld [r1, #64] + + tst r3, #0xff0000 + beq .Lstringcopy_unalign6_copy7bytes + lsrs ip, r3, #24 + stmia r0!, {r2, r3} +#if defined(STPCPY) + beq .Lstringcopy_finish +#else + beq .Lstringcopy_unalign_return +#endif + b .Lstringcopy_unalign6 + +.Lstringcopy_unalign6_copy7bytes: + stmia r0!, {r2} + strh r3, [r0], #2 + lsr r3, #16 + strb r3, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 5 bytes before possibly crossing a page. +.Lstringcopy_unalign5: + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldrb r4, [r1] + cbz r4, .Lstringcopy_unalign_copy5bytes + + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign5 + +.Lstringcopy_unalign_copy5bytes: + stmia r0!, {r2} + strb r4, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy6bytes: + stmia r0!, {r2} + strb r4, [r0], #1 + strb r5, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 4 bytes before possibly crossing a page. +.Lstringcopy_unalign4: + ldmia r1!, {r2} + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + ldmia r1!, {r3} + pld [r1, #64] + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign4 + + .p2align 2 + // Can read 3 bytes before possibly crossing a page. +.Lstringcopy_unalign3: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign3_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign3_copy2bytes + ldrb r4, [r1, #2] + cbz r4, .Lstringcopy_unalign3_copy3bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + lsrs lr, r2, #24 + beq .Lstringcopy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign3 + +.Lstringcopy_unalign3_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign3_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_unalign3_copy3bytes: + strb r2, [r0], #1 + strb r3, [r0], #1 + strb r4, [r0] + m_ret inst=pop + + .p2align 2 + // Can read 2 bytes before possibly crossing a page. +.Lstringcopy_unalign2: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + ldrb r3, [r1, #1] + cbz r3, .Lstringcopy_unalign_copy2bytes + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + pld [r1, #64] + + tst r2, #0xff0000 + beq .Lstringcopy_unalign_copy3bytes + lsrs ip, r2, #24 + beq .Lstringcopy_unalign_copy4bytes + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign2 + + .p2align 2 + // Can read 1 byte before possibly crossing a page. +.Lstringcopy_unalign1: + ldrb r2, [r1] + cbz r2, .Lstringcopy_unalign_copy1byte + + ldr r2, [r1], #4 + ldr r3, [r1], #4 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .Lstringcopy_zero_in_second_register + + stmia r0!, {r2, r3} + b .Lstringcopy_unalign1 + +.Lstringcopy_unalign_copy1byte: + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy2bytes: + strb r2, [r0], #1 + strb r3, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy3bytes: + strh r2, [r0], #2 + lsr r2, #16 + strb r2, [r0] + m_ret inst=pop + +.Lstringcopy_unalign_copy4bytes: + stmia r0, {r2} +#if defined(STPCPY) + add r0, r0, #3 +#endif + m_ret inst=pop +#if defined(STPCPY) +END(stpcpy_a9) +#else +END(strcpy_a9) +#endif diff --git a/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strlen.S b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strlen.S new file mode 100644 index 000000000..ffebc9dea --- /dev/null +++ b/aosp/bionic/libc/arch-arm/cortex-a9/bionic/strlen.S @@ -0,0 +1,171 @@ +/* + * 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. + */ +/* + * Copyright (c) 2013 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + + .thumb + .thumb_func + +ENTRY(strlen_a9) + pld [r0, #0] + mov r1, r0 + + ands r3, r0, #7 + bne align_src + + .p2align 2 +mainloop: + ldmia r1!, {r2, r3} + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne zero_in_second_register + b mainloop + +zero_in_first_register: + sub r0, r1, r0 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq check_byte1_reg1 + + sub r0, r0, #8 + bx lr + +check_byte1_reg1: + bcc check_byte2_reg1 + + sub r0, r0, #7 + bx lr + +check_byte2_reg1: + // Check for zero in byte 2. + tst ip, #0x800000 + itt ne + subne r0, r0, #6 + bxne lr + sub r0, r0, #5 + bx lr + +zero_in_second_register: + sub r0, r1, r0 + // Check for zero in byte 0. + lsls r2, ip, #17 + beq check_byte1_reg2 + + sub r0, r0, #4 + bx lr + +check_byte1_reg2: + bcc check_byte2_reg2 + + sub r0, r0, #3 + bx lr + +check_byte2_reg2: + // Check for zero in byte 2. + tst ip, #0x800000 + itt ne + subne r0, r0, #2 + bxne lr + sub r0, r0, #1 + bx lr + +align_src: + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq align_to_32 + + ldrb r2, [r1], #1 + cbz r2, done + +align_to_32: + bcc align_to_64 + + ldrb r2, [r1], #1 + cbz r2, done + ldrb r2, [r1], #1 + cbz r2, done + +align_to_64: + tst r3, #4 + beq mainloop + ldr r2, [r1], #4 + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne zero_in_second_register + b mainloop + +done: + sub r0, r1, r0 + sub r0, r0, #1 + bx lr +END(strlen_a9) diff --git a/aosp/bionic/libc/arch-arm/dynamic_function_dispatch.cpp b/aosp/bionic/libc/arch-arm/dynamic_function_dispatch.cpp new file mode 100644 index 000000000..1d2f38ff5 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/dynamic_function_dispatch.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2018 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 +#include + +#include + +extern "C" { + +enum CpuVariant { + kUnknown = 0, + kGeneric, + kCortexA7, + kCortexA9, + kCortexA53, + kCortexA55, + kKrait, + kKryo, +}; + +static constexpr int MAX_CPU_NAME_LEN = 12; +struct CpuVariantNames { + alignas(alignof(int)) char name[MAX_CPU_NAME_LEN]; + CpuVariant variant; +}; + +static constexpr CpuVariantNames cpu_variant_names[] = { + {"cortex-a76", kCortexA55}, + {"kryo385", kCortexA55}, + {"cortex-a75", kCortexA55}, + {"kryo", kKryo}, + {"cortex-a73", kCortexA55}, + {"cortex-a55", kCortexA55}, + {"cortex-a53", kCortexA53}, + {"krait", kKrait}, + {"cortex-a9", kCortexA9}, + {"cortex-a7", kCortexA7}, + // kUnknown indicates the end of this array. + {"", kUnknown}, +}; + +static long ifunc_open(const char* pathname) { + register long r0 __asm__("r0") = AT_FDCWD; + register long r1 __asm__("r1") = reinterpret_cast(pathname); + register long r2 __asm__("r2") = O_RDONLY; + register long r3 __asm__("r3") = 0; + register long r7 __asm__("r7") = __NR_openat; + __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7)); + return r0; +} + +static ssize_t ifunc_read(int fd, void* buf, size_t count) { + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = reinterpret_cast(buf); + register long r2 __asm__("r2") = count; + register long r7 __asm__("r7") = __NR_read; + __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory"); + return r0; +} + +static int ifunc_close(int fd) { + register long r0 __asm__("r0") = fd; + register long r7 __asm__("r7") = __NR_close; + __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7)); + return r0; +} + +static bool is_same_name(const char* a, const char* b) { + static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, ""); + const int* ia = reinterpret_cast(a); + const int* ib = reinterpret_cast(b); + for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) { + if (ia[i] != ib[i]) { + return false; + } + } + return true; +} + +static CpuVariant init_cpu_variant() { + int fd = ifunc_open("/dev/cpu_variant:arm"); + if (fd < 0) return kGeneric; + + alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {}; + + int bytes_read, total_read = 0; + while (total_read < MAX_CPU_NAME_LEN - 1 && + (bytes_read = ifunc_read(fd, name + total_read, + MAX_CPU_NAME_LEN - 1 - total_read)) > 0) { + total_read += bytes_read; + } + ifunc_close(fd); + + if (bytes_read != 0) { + // The file is too big. We haven't reach the end. Or maybe there is an + // error when reading. + return kGeneric; + } + name[total_read] = 0; + + const CpuVariantNames* cpu_variant = cpu_variant_names; + while (cpu_variant->variant != kUnknown) { + if (is_same_name(cpu_variant->name, name)) { + return cpu_variant->variant; + } + cpu_variant++; + } + return kGeneric; +} + +static CpuVariant get_cpu_variant() { + static CpuVariant cpu_variant = kUnknown; + if (cpu_variant == kUnknown) { + cpu_variant = init_cpu_variant(); + } + return cpu_variant; +} + +typedef void* memmove_func(void* __dst, const void* __src, size_t __n); +DEFINE_IFUNC_FOR(memmove) { + RETURN_FUNC(memmove_func, memmove_a15); +} + +typedef void* memcpy_func(void*, const void*, size_t); +DEFINE_IFUNC_FOR(memcpy) { + return memmove_resolver(hwcap); +} + +typedef void* __memcpy_func(void*, const void*, size_t); +DEFINE_IFUNC_FOR(__memcpy) { + switch(get_cpu_variant()) { + case kCortexA7: + RETURN_FUNC(__memcpy_func, __memcpy_a7); + case kCortexA9: + RETURN_FUNC(__memcpy_func, __memcpy_a9); + case kKrait: + RETURN_FUNC(__memcpy_func, __memcpy_krait); + case kCortexA53: + RETURN_FUNC(__memcpy_func, __memcpy_a53); + case kCortexA55: + RETURN_FUNC(__memcpy_func, __memcpy_a55); + case kKryo: + RETURN_FUNC(__memcpy_func, __memcpy_kryo); + default: + RETURN_FUNC(__memcpy_func, __memcpy_a15); + } +} + +typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2); +DEFINE_IFUNC_FOR(__memset_chk) { + switch(get_cpu_variant()) { + case kCortexA7: + case kCortexA53: + case kCortexA55: + case kKryo: + RETURN_FUNC(__memset_chk_func, __memset_chk_a7); + case kCortexA9: + RETURN_FUNC(__memset_chk_func, __memset_chk_a9); + case kKrait: + RETURN_FUNC(__memset_chk_func, __memset_chk_krait); + default: + RETURN_FUNC(__memset_chk_func, __memset_chk_a15); + } +} + +typedef void* memset_func(void* __dst, int __ch, size_t __n); +DEFINE_IFUNC_FOR(memset) { + switch(get_cpu_variant()) { + case kCortexA7: + case kCortexA53: + case kCortexA55: + case kKryo: + RETURN_FUNC(memset_func, memset_a7); + case kCortexA9: + RETURN_FUNC(memset_func, memset_a9); + case kKrait: + RETURN_FUNC(memset_func, memset_krait); + default: + RETURN_FUNC(memset_func, memset_a15); + } +} + +typedef char* strcpy_func(char* __dst, const char* __src); +DEFINE_IFUNC_FOR(strcpy) { + switch(get_cpu_variant()) { + case kCortexA9: + RETURN_FUNC(strcpy_func, strcpy_a9); + default: + RETURN_FUNC(strcpy_func, strcpy_a15); + } +} + +typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len); +DEFINE_IFUNC_FOR(__strcpy_chk) { + switch(get_cpu_variant()) { + case kCortexA7: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7); + case kCortexA9: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9); + case kKrait: + case kKryo: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait); + case kCortexA53: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53); + case kCortexA55: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55); + default: + RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15); + } +} + +typedef char* stpcpy_func(char* __dst, const char* __src); +DEFINE_IFUNC_FOR(stpcpy) { + switch(get_cpu_variant()) { + case kCortexA9: + RETURN_FUNC(stpcpy_func, stpcpy_a9); + default: + RETURN_FUNC(stpcpy_func, stpcpy_a15); + } +} + +typedef char* strcat_func(char* __dst, const char* __src); +DEFINE_IFUNC_FOR(strcat) { + switch(get_cpu_variant()) { + case kCortexA9: + RETURN_FUNC(strcat_func, strcat_a9); + default: + RETURN_FUNC(strcat_func, strcat_a15); + } +} + +typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size); +DEFINE_IFUNC_FOR(__strcat_chk) { + switch(get_cpu_variant()) { + case kCortexA7: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7); + case kCortexA9: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9); + case kKrait: + case kKryo: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait); + case kCortexA53: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53); + case kCortexA55: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55); + default: + RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15); + } +} + +typedef int strcmp_func(const char* __lhs, const char* __rhs); +DEFINE_IFUNC_FOR(strcmp) { + RETURN_FUNC(strcmp_func, strcmp_a15); +} + +typedef size_t strlen_func(const char* __s); +DEFINE_IFUNC_FOR(strlen) { + switch(get_cpu_variant()) { + case kCortexA9: + RETURN_FUNC(strlen_func, strlen_a9); + default: + RETURN_FUNC(strlen_func, strlen_a15); + } +} + +} // extern "C" diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/__memcpy_chk.S b/aosp/bionic/libc/arch-arm/generic/bionic/__memcpy_chk.S new file mode 100644 index 000000000..7ee2a8f09 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/__memcpy_chk.S @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 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 + + .syntax unified + +ENTRY(__memcpy_chk) + cmp r2, r3 + bls memcpy + + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + + bl __memcpy_chk_fail +END(__memcpy_chk) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/memcmp.S b/aosp/bionic/libc/arch-arm/generic/bionic/memcmp.S new file mode 100644 index 000000000..9fd72e9ea --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/memcmp.S @@ -0,0 +1,343 @@ +/* + * 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 + + +#ifdef HAVE_32_BYTE_CACHE_LINE +#define CACHE_LINE_SIZE 32 +#else +#define CACHE_LINE_SIZE 64 +#endif + +/* + * Optimized memcmp() for Cortex-A9. + */ + +.syntax unified + +ENTRY(memcmp) + pld [r0, #(CACHE_LINE_SIZE * 0)] + pld [r0, #(CACHE_LINE_SIZE * 1)] + + /* take of the case where length is 0 or the buffers are the same */ + cmp r0, r1 + moveq r0, #0 + bxeq lr + + pld [r1, #(CACHE_LINE_SIZE * 0)] + pld [r1, #(CACHE_LINE_SIZE * 1)] + + /* make sure we have at least 8+4 bytes, this simplify things below + * and avoid some overhead for small blocks + */ + cmp r2, #(8+4) + bmi 10f +/* + * Neon optimization + * Comparing 32 bytes at a time + */ +#if defined(__ARM_NEON__) + subs r2, r2, #32 + blo 3f + + /* preload all the cache lines we need. */ + pld [r0, #(CACHE_LINE_SIZE * 2)] + pld [r1, #(CACHE_LINE_SIZE * 2)] + +1: /* The main loop compares 32 bytes at a time */ + vld1.8 {d0 - d3}, [r0]! + pld [r0, #(CACHE_LINE_SIZE * 2)] + vld1.8 {d4 - d7}, [r1]! + pld [r1, #(CACHE_LINE_SIZE * 2)] + + /* Start subtracting the values and merge results */ + vsub.i8 q0, q2 + vsub.i8 q1, q3 + vorr q2, q0, q1 + vorr d4, d5 + vmov r3, ip, d4 + /* Check if there are any differences among the 32 bytes */ + orrs r3, ip + bne 2f + subs r2, r2, #32 + bhs 1b + b 3f +2: + /* Check if the difference was in the first or last 16 bytes */ + sub r0, #32 + vorr d0, d1 + sub r1, #32 + vmov r3, ip, d0 + orrs r3, ip + /* if the first 16 bytes are equal, we only have to rewind 16 bytes */ + ittt eq + subeq r2, #16 + addeq r0, #16 + addeq r1, #16 + +3: /* fix-up the remaining count */ + add r2, r2, #32 + + cmp r2, #(8+4) + bmi 10f +#endif + + /* save registers */ + stmfd sp!, {r4, lr} + .cfi_def_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset lr, 4 + + /* since r0 hold the result, move the first source + * pointer somewhere else + */ + mov r4, r0 + + /* align first pointer to word boundary + * offset = -src & 3 + */ + rsb r3, r4, #0 + ands r3, r3, #3 + beq 0f + + /* align first pointer */ + sub r2, r2, r3 +1: ldrb r0, [r4], #1 + ldrb ip, [r1], #1 + subs r0, r0, ip + bne 9f + subs r3, r3, #1 + bne 1b + + +0: /* here the first pointer is aligned, and we have at least 4 bytes + * to process. + */ + + /* see if the pointers are congruent */ + eor r0, r4, r1 + ands r0, r0, #3 + bne 5f + + /* congruent case, 32 bytes per iteration + * We need to make sure there are at least 32+4 bytes left + * because we effectively read ahead one word, and we could + * read past the buffer (and segfault) if we're not careful. + */ + + ldr ip, [r1] + subs r2, r2, #(32 + 4) + bmi 1f + +0: pld [r4, #(CACHE_LINE_SIZE * 2)] + pld [r1, #(CACHE_LINE_SIZE * 2)] + ldr r0, [r4], #4 + ldr lr, [r1, #4]! + eors r0, r0, ip + ldreq r0, [r4], #4 + ldreq ip, [r1, #4]! + eorseq r0, r0, lr + ldreq r0, [r4], #4 + ldreq lr, [r1, #4]! + eorseq r0, r0, ip + ldreq r0, [r4], #4 + ldreq ip, [r1, #4]! + eorseq r0, r0, lr + ldreq r0, [r4], #4 + ldreq lr, [r1, #4]! + eorseq r0, r0, ip + ldreq r0, [r4], #4 + ldreq ip, [r1, #4]! + eorseq r0, r0, lr + ldreq r0, [r4], #4 + ldreq lr, [r1, #4]! + eorseq r0, r0, ip + ldreq r0, [r4], #4 + ldreq ip, [r1, #4]! + eorseq r0, r0, lr + bne 2f + subs r2, r2, #32 + bhs 0b + + /* do we have at least 4 bytes left? */ +1: adds r2, r2, #(32 - 4 + 4) + bmi 4f + + /* finish off 4 bytes at a time */ +3: ldr r0, [r4], #4 + ldr ip, [r1], #4 + eors r0, r0, ip + bne 2f + subs r2, r2, #4 + bhs 3b + + /* are we done? */ +4: adds r2, r2, #4 + moveq r0, #0 + beq 9f + + /* finish off the remaining bytes */ + b 8f + +2: /* the last 4 bytes are different, restart them */ + sub r4, r4, #4 + sub r1, r1, #4 + mov r2, #4 + + /* process the last few bytes */ +8: ldrb r0, [r4], #1 + ldrb ip, [r1], #1 + // stall + subs r0, r0, ip + bne 9f + subs r2, r2, #1 + bne 8b + +9: /* restore registers and return */ + ldmfd sp!, {r4, pc} + +10: /* process less than 12 bytes */ + cmp r2, #0 + moveq r0, #0 + bxeq lr + mov r3, r0 +11: + ldrb r0, [r3], #1 + ldrb ip, [r1], #1 + subs r0, ip + bxne lr + subs r2, r2, #1 + bne 11b + bx lr + +5: /*************** non-congruent case ***************/ + and r0, r1, #3 + cmp r0, #2 + bne 4f + + /* here, offset is 2 (16-bits aligned, special cased) */ + + /* make sure we have at least 16 bytes to process */ + subs r2, r2, #16 + addmi r2, r2, #16 + bmi 8b + + /* align the unaligned pointer */ + bic r1, r1, #3 + ldr lr, [r1], #4 + +6: pld [r1, #(CACHE_LINE_SIZE * 2)] + pld [r4, #(CACHE_LINE_SIZE * 2)] + mov ip, lr, lsr #16 + ldr lr, [r1], #4 + ldr r0, [r4], #4 + orr ip, ip, lr, lsl #16 + eors r0, r0, ip + moveq ip, lr, lsr #16 + ldreq lr, [r1], #4 + ldreq r0, [r4], #4 + orreq ip, ip, lr, lsl #16 + eorseq r0, r0, ip + moveq ip, lr, lsr #16 + ldreq lr, [r1], #4 + ldreq r0, [r4], #4 + orreq ip, ip, lr, lsl #16 + eorseq r0, r0, ip + moveq ip, lr, lsr #16 + ldreq lr, [r1], #4 + ldreq r0, [r4], #4 + orreq ip, ip, lr, lsl #16 + eorseq r0, r0, ip + bne 7f + subs r2, r2, #16 + bhs 6b + sub r1, r1, #2 + /* are we done? */ + adds r2, r2, #16 + moveq r0, #0 + beq 9b + /* finish off the remaining bytes */ + b 8b + +7: /* fix up the 2 pointers and fallthrough... */ + sub r1, r1, #(4+2) + sub r4, r4, #4 + mov r2, #4 + b 8b + + +4: /*************** offset is 1 or 3 (less optimized) ***************/ + + stmfd sp!, {r5, r6, r7} + + // r5 = rhs + // r6 = lhs + // r7 = scratch + + mov r5, r0, lsl #3 /* r5 = right shift */ + rsb r6, r5, #32 /* r6 = left shift */ + + /* align the unaligned pointer */ + bic r1, r1, #3 + ldr r7, [r1], #4 + sub r2, r2, #8 + +6: mov ip, r7, lsr r5 + ldr r7, [r1], #4 + ldr r0, [r4], #4 + orr ip, ip, r7, lsl r6 + eors r0, r0, ip + moveq ip, r7, lsr r5 + ldreq r7, [r1], #4 + ldreq r0, [r4], #4 + orreq ip, ip, r7, lsl r6 + eorseq r0, r0, ip + bne 7f + subs r2, r2, #8 + bhs 6b + + sub r1, r1, r6, lsr #3 + ldmfd sp!, {r5, r6, r7} + + /* are we done? */ + adds r2, r2, #8 + moveq r0, #0 + beq 9b + + /* finish off the remaining bytes */ + b 8b + +7: /* fix up the 2 pointers and fallthrough... */ + sub r1, r1, #4 + sub r1, r1, r6, lsr #3 + sub r4, r4, #4 + mov r2, #4 + ldmfd sp!, {r5, r6, r7} + b 8b +END(memcmp) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/memmove.S b/aosp/bionic/libc/arch-arm/generic/bionic/memmove.S new file mode 100644 index 000000000..0cf82d14f --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/memmove.S @@ -0,0 +1,471 @@ +/* $OpenBSD: _memcpy.S,v 1.6 2016/08/06 19:16:09 guenther Exp $ */ +/* $NetBSD: _memcpy.S,v 1.4 2003/04/05 23:08:52 bjh21 Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Neil A. Carson and Mark Brinicombe + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 + + .syntax unified + +/* + * This is one fun bit of code ... + * Some easy listening music is suggested while trying to understand this + * code e.g. Iron Maiden + * + * For anyone attempting to understand it : + * + * The core code is implemented here with simple stubs for memcpy() + * memmove() and bcopy(). + * + * All local labels are prefixed with Lmemcpy_ + * Following the prefix a label starting f is used in the forward copy code + * while a label using b is used in the backwards copy code + * The source and destination addresses determine whether a forward or + * backward copy is performed. + * Separate bits of code are used to deal with the following situations + * for both the forward and backwards copy. + * unaligned source address + * unaligned destination address + * Separate copy routines are used to produce an optimised result for each + * of these cases. + * The copy code will use LDM/STM instructions to copy up to 32 bytes at + * a time where possible. + * + * Note: r12 (aka ip) can be trashed during the function along with + * r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out. + * Additional registers are preserved prior to use i.e. r4, r5 & lr + * + * Apologies for the state of the comments ;-) + */ + +ENTRY_PRIVATE(bsd_safe_memcpy) + /* Determine copy direction */ + cmp r1, r0 + bcc .Lmemcpy_backwards + + moveq r0, #0 /* Quick abort for len=0 */ + moveq pc, lr + + stmdb sp!, {r0, lr} /* memcpy() returns dest addr */ + subs r2, r2, #4 + blt .Lmemcpy_fl4 /* less than 4 bytes */ + ands r12, r0, #3 + bne .Lmemcpy_fdestul /* oh unaligned destination addr */ + ands r12, r1, #3 + bne .Lmemcpy_fsrcul /* oh unaligned source addr */ + +.Lmemcpy_ft8: + /* We have aligned source and destination */ + subs r2, r2, #8 + blt .Lmemcpy_fl12 /* less than 12 bytes (4 from above) */ + subs r2, r2, #0x14 + blt .Lmemcpy_fl32 /* less than 32 bytes (12 from above) */ + stmdb sp!, {r4} /* borrow r4 */ + + /* blat 32 bytes at a time */ + /* XXX for really big copies perhaps we should use more registers */ +.Lmemcpy_floop32: + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge .Lmemcpy_floop32 + + cmn r2, #0x10 + ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ + stmiage r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + ldmia sp!, {r4} /* return r4 */ + +.Lmemcpy_fl32: + adds r2, r2, #0x14 + + /* blat 12 bytes at a time */ +.Lmemcpy_floop12: + ldmiage r1!, {r3, r12, lr} + stmiage r0!, {r3, r12, lr} + subsge r2, r2, #0x0c + bge .Lmemcpy_floop12 + +.Lmemcpy_fl12: + adds r2, r2, #8 + blt .Lmemcpy_fl4 + + subs r2, r2, #4 + ldrlt r3, [r1], #4 + strlt r3, [r0], #4 + ldmiage r1!, {r3, r12} + stmiage r0!, {r3, r12} + subge r2, r2, #4 + +.Lmemcpy_fl4: + /* less than 4 bytes to go */ + adds r2, r2, #4 + ldmiaeq sp!, {r0, pc} /* done */ + + /* copy the crud byte at a time */ + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrbge r3, [r1], #1 + strbge r3, [r0], #1 + ldrbgt r3, [r1], #1 + strbgt r3, [r0], #1 + ldmia sp!, {r0, pc} + + /* erg - unaligned destination */ +.Lmemcpy_fdestul: + rsb r12, r12, #4 + cmp r12, #2 + + /* align destination with byte copies */ + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrbge r3, [r1], #1 + strbge r3, [r0], #1 + ldrbgt r3, [r1], #1 + strbgt r3, [r0], #1 + subs r2, r2, r12 + blt .Lmemcpy_fl4 /* less the 4 bytes */ + + ands r12, r1, #3 + beq .Lmemcpy_ft8 /* we have an aligned source */ + + /* erg - unaligned source */ + /* This is where it gets nasty ... */ +.Lmemcpy_fsrcul: + bic r1, r1, #3 + ldr lr, [r1], #4 + cmp r12, #2 + bgt .Lmemcpy_fsrcul3 + beq .Lmemcpy_fsrcul2 + cmp r2, #0x0c + blt .Lmemcpy_fsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul1loop16: + mov r3, lr, lsr #8 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r12, lsl #24 + mov r12, r12, lsr #8 + orr r12, r12, lr, lsl #24 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul1loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul1l4 + +.Lmemcpy_fsrcul1loop4: + mov r12, lr, lsr #8 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #24 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul1loop4 + +.Lmemcpy_fsrcul1l4: + sub r1, r1, #3 + b .Lmemcpy_fl4 + +.Lmemcpy_fsrcul2: + cmp r2, #0x0c + blt .Lmemcpy_fsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul2loop16: + mov r3, lr, lsr #16 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r12, lsl #16 + mov r12, r12, lsr #16 + orr r12, r12, lr, lsl #16 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul2loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul2l4 + +.Lmemcpy_fsrcul2loop4: + mov r12, lr, lsr #16 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #16 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul2loop4 + +.Lmemcpy_fsrcul2l4: + sub r1, r1, #2 + b .Lmemcpy_fl4 + +.Lmemcpy_fsrcul3: + cmp r2, #0x0c + blt .Lmemcpy_fsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +.Lmemcpy_fsrcul3loop16: + mov r3, lr, lsr #24 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r12, lsl #8 + mov r12, r12, lsr #24 + orr r12, r12, lr, lsl #8 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge .Lmemcpy_fsrcul3loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt .Lmemcpy_fsrcul3l4 + +.Lmemcpy_fsrcul3loop4: + mov r12, lr, lsr #24 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #8 + str r12, [r0], #4 + subs r2, r2, #4 + bge .Lmemcpy_fsrcul3loop4 + +.Lmemcpy_fsrcul3l4: + sub r1, r1, #1 + b .Lmemcpy_fl4 + +.Lmemcpy_backwards: + add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt .Lmemcpy_bl4 /* less than 4 bytes */ + ands r12, r0, #3 + bne .Lmemcpy_bdestul /* oh unaligned destination addr */ + ands r12, r1, #3 + bne .Lmemcpy_bsrcul /* oh unaligned source addr */ + +.Lmemcpy_bt8: + /* We have aligned source and destination */ + subs r2, r2, #8 + blt .Lmemcpy_bl12 /* less than 12 bytes (4 from above) */ + stmdb sp!, {r4, lr} + subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */ + blt .Lmemcpy_bl32 + + /* blat 32 bytes at a time */ + /* XXX for really big copies perhaps we should use more registers */ +.Lmemcpy_bloop32: + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge .Lmemcpy_bloop32 + +.Lmemcpy_bl32: + cmn r2, #0x10 + ldmdbge r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ + stmdbge r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + adds r2, r2, #0x14 + ldmdbge r1!, {r3, r12, lr} /* blat a remaining 12 bytes */ + stmdbge r0!, {r3, r12, lr} + subge r2, r2, #0x0c + ldmia sp!, {r4, lr} + +.Lmemcpy_bl12: + adds r2, r2, #8 + blt .Lmemcpy_bl4 + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + strlt r3, [r0, #-4]! + ldmdbge r1!, {r3, r12} + stmdbge r0!, {r3, r12} + subge r2, r2, #4 + +.Lmemcpy_bl4: + /* less than 4 bytes to go */ + adds r2, r2, #4 + moveq pc, lr /* done */ + + /* copy the crud byte at a time */ + cmp r2, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrbge r3, [r1, #-1]! + strbge r3, [r0, #-1]! + ldrbgt r3, [r1, #-1]! + strbgt r3, [r0, #-1]! + mov pc, lr + + /* erg - unaligned destination */ +.Lmemcpy_bdestul: + cmp r12, #2 + + /* align destination with byte copies */ + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrbge r3, [r1, #-1]! + strbge r3, [r0, #-1]! + ldrbgt r3, [r1, #-1]! + strbgt r3, [r0, #-1]! + subs r2, r2, r12 + blt .Lmemcpy_bl4 /* less than 4 bytes to go */ + ands r12, r1, #3 + beq .Lmemcpy_bt8 /* we have an aligned source */ + + /* erg - unaligned source */ + /* This is where it gets nasty ... */ +.Lmemcpy_bsrcul: + bic r1, r1, #3 + ldr r3, [r1, #0] + cmp r12, #2 + blt .Lmemcpy_bsrcul1 + beq .Lmemcpy_bsrcul2 + cmp r2, #0x0c + blt .Lmemcpy_bsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul3loop16: + mov lr, r3, lsl #8 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #24 + mov r12, r12, lsl #8 + orr r12, r12, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul3loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul3l4 + +.Lmemcpy_bsrcul3loop4: + mov r12, r3, lsl #8 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #24 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul3loop4 + +.Lmemcpy_bsrcul3l4: + add r1, r1, #3 + b .Lmemcpy_bl4 + +.Lmemcpy_bsrcul2: + cmp r2, #0x0c + blt .Lmemcpy_bsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul2loop16: + mov lr, r3, lsl #16 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #16 + mov r12, r12, lsl #16 + orr r12, r12, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul2loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul2l4 + +.Lmemcpy_bsrcul2loop4: + mov r12, r3, lsl #16 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #16 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul2loop4 + +.Lmemcpy_bsrcul2l4: + add r1, r1, #2 + b .Lmemcpy_bl4 + +.Lmemcpy_bsrcul1: + cmp r2, #0x0c + blt .Lmemcpy_bsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +.Lmemcpy_bsrcul1loop32: + mov lr, r3, lsl #24 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #8 + mov r12, r12, lsl #24 + orr r12, r12, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge .Lmemcpy_bsrcul1loop32 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt .Lmemcpy_bsrcul1l4 + +.Lmemcpy_bsrcul1loop4: + mov r12, r3, lsl #24 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #8 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge .Lmemcpy_bsrcul1loop4 + +.Lmemcpy_bsrcul1l4: + add r1, r1, #1 + b .Lmemcpy_bl4 +END(bsd_safe_memcpy) + +ENTRY(memmove_generic) + stmfd sp!, {r0, lr} + bl bsd_safe_memcpy + ldmfd sp!, {r0, pc} +END(memmove_generic) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/memset.S b/aosp/bionic/libc/arch-arm/generic/bionic/memset.S new file mode 100644 index 000000000..e70002f02 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/memset.S @@ -0,0 +1,111 @@ +/* + * 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 + + /* + * Optimized memset() for ARM. + * + * memset() returns its first argument. + */ + + .syntax unified + +ENTRY(__memset_chk_generic) + cmp r2, r3 + bls memset + + bl __memset_chk_fail +END(__memset_chk_generic) + +ENTRY(memset_generic) + /* compute the offset to align the destination + * offset = (4-(src&3))&3 = -src & 3 + */ + .save {r0, r4-r7, lr} + stmfd sp!, {r0, r4-r7, lr} + rsb r3, r0, #0 + ands r3, r3, #3 + cmp r3, r2 + movhi r3, r2 + + /* splat r1 */ + mov r1, r1, lsl #24 + orr r1, r1, r1, lsr #8 + orr r1, r1, r1, lsr #16 + + movs r12, r3, lsl #31 + strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */ + strbcs r1, [r0], #1 + strbmi r1, [r0], #1 + subs r2, r2, r3 + popls {r0, r4-r7, pc} /* return */ + + /* align the destination to a cache-line */ + mov r12, r1 + mov lr, r1 + mov r4, r1 + mov r5, r1 + mov r6, r1 + mov r7, r1 + + rsb r3, r0, #0 + ands r3, r3, #0x1C + beq 3f + cmp r3, r2 + andhi r3, r2, #0x1C + sub r2, r2, r3 + + /* conditionally writes 0 to 7 words (length in r3) */ + movs r3, r3, lsl #28 + stmcs r0!, {r1, lr} + stmcs r0!, {r1, lr} + stmmi r0!, {r1, lr} + movs r3, r3, lsl #2 + strcs r1, [r0], #4 + +3: + subs r2, r2, #32 + mov r3, r1 + bmi 2f +1: subs r2, r2, #32 + stmia r0!, {r1,r3,r4,r5,r6,r7,r12,lr} + bhs 1b +2: add r2, r2, #32 + + /* conditionally stores 0 to 31 bytes */ + movs r2, r2, lsl #28 + stmcs r0!, {r1,r3,r12,lr} + stmmi r0!, {r1, lr} + movs r2, r2, lsl #2 + strcs r1, [r0], #4 + strhmi r1, [r0], #2 + movs r2, r2, lsl #2 + strbcs r1, [r0] + ldmfd sp!, {r0, r4-r7, pc} +END(memset_generic) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/stpcpy.c b/aosp/bionic/libc/arch-arm/generic/bionic/stpcpy.c new file mode 100644 index 000000000..0aabaa5da --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/stpcpy.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define stpcpy stpcpy_generic +#include diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/strcat.c b/aosp/bionic/libc/arch-arm/generic/bionic/strcat.c new file mode 100644 index 000000000..8e70531d0 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/strcat.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define strcat strcat_generic +#include diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/strcmp.S b/aosp/bionic/libc/arch-arm/generic/bionic/strcmp.S new file mode 100644 index 000000000..03225a006 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/strcmp.S @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2011 The Android Open Source Project + * Copyright (c) 2008 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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 + + .text + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +#ifdef __ARMEB__ +#define SHFT2LSB lsl +#define SHFT2LSBEQ lsleq +#define SHFT2MSB lsr +#define SHFT2MSBEQ lsreq +#define MSB 0x000000ff +#define LSB 0xff000000 +#else +#define SHFT2LSB lsr +#define SHFT2LSBEQ lsreq +#define SHFT2MSB lsl +#define SHFT2MSBEQ lsleq +#define MSB 0xff000000 +#define LSB 0x000000ff +#endif + +#define magic1(REG) REG +#define magic2(REG) REG, lsl #7 + +ENTRY(strcmp_generic) + pld [r0, #0] + pld [r1, #0] + eor r2, r0, r1 + tst r2, #3 + + /* Strings not at same byte offset from a word boundary. */ + bne .Lstrcmp_unaligned + ands r2, r0, #3 + bic r0, r0, #3 + bic r1, r1, #3 + ldr ip, [r0], #4 + it eq + ldreq r3, [r1], #4 + beq 1f + + /* Although s1 and s2 have identical initial alignment, they are + * not currently word aligned. Rather than comparing bytes, + * make sure that any bytes fetched from before the addressed + * bytes are forced to 0xff. Then they will always compare + * equal. + */ + eor r2, r2, #3 + lsl r2, r2, #3 + mvn r3, #MSB + SHFT2LSB r2, r3, r2 + ldr r3, [r1], #4 + orr ip, ip, r2 + orr r3, r3, r2 +1: + /* Load the 'magic' constant 0x01010101. */ + str r4, [sp, #-4]! + mov r4, #1 + orr r4, r4, r4, lsl #8 + orr r4, r4, r4, lsl #16 + .p2align 2 +4: + pld [r0, #8] + pld [r1, #8] + sub r2, ip, magic1(r4) + cmp ip, r3 + itttt eq + + /* check for any zero bytes in first word */ + biceq r2, r2, ip + tsteq r2, magic2(r4) + ldreq ip, [r0], #4 + ldreq r3, [r1], #4 + beq 4b +2: + /* There's a zero or a different byte in the word */ + SHFT2MSB r0, ip, #24 + SHFT2LSB ip, ip, #8 + cmp r0, #1 + it cs + cmpcs r0, r3, SHFT2MSB #24 + it eq + SHFT2LSBEQ r3, r3, #8 + beq 2b + /* On a big-endian machine, r0 contains the desired byte in bits + * 0-7; on a little-endian machine they are in bits 24-31. In + * both cases the other bits in r0 are all zero. For r3 the + * interesting byte is at the other end of the word, but the + * other bits are not necessarily zero. We need a signed result + * representing the differnece in the unsigned bytes, so for the + * little-endian case we can't just shift the interesting bits up. + */ +#ifdef __ARMEB__ + sub r0, r0, r3, lsr #24 +#else + and r3, r3, #255 + /* No RSB instruction in Thumb2 */ +#ifdef __thumb2__ + lsr r0, r0, #24 + sub r0, r0, r3 +#else + rsb r0, r3, r0, lsr #24 +#endif +#endif + ldr r4, [sp], #4 + bx lr + +.Lstrcmp_unaligned: + wp1 .req r0 + wp2 .req r1 + b1 .req r2 + w1 .req r4 + w2 .req r5 + t1 .req ip + @ r3 is scratch + + /* First of all, compare bytes until wp1(sp1) is word-aligned. */ +1: + tst wp1, #3 + beq 2f + ldrb r2, [wp1], #1 + ldrb r3, [wp2], #1 + cmp r2, #1 + it cs + cmpcs r2, r3 + beq 1b + sub r0, r2, r3 + bx lr + +2: + str r5, [sp, #-4]! + str r4, [sp, #-4]! + mov b1, #1 + orr b1, b1, b1, lsl #8 + orr b1, b1, b1, lsl #16 + + and t1, wp2, #3 + bic wp2, wp2, #3 + ldr w1, [wp1], #4 + ldr w2, [wp2], #4 + cmp t1, #2 + beq 2f + bhi 3f + + /* Critical inner Loop: Block with 3 bytes initial overlap */ + .p2align 2 +1: + bic t1, w1, #MSB + cmp t1, w2, SHFT2LSB #8 + sub r3, w1, b1 + bic r3, r3, w1 + bne 4f + ands r3, r3, b1, lsl #7 + it eq + ldreq w2, [wp2], #4 + bne 5f + eor t1, t1, w1 + cmp t1, w2, SHFT2MSB #24 + bne 6f + ldr w1, [wp1], #4 + b 1b +4: + SHFT2LSB w2, w2, #8 + b 8f + +5: +#ifdef __ARMEB__ + /* The syndrome value may contain false ones if the string ends + * with the bytes 0x01 0x00 + */ + tst w1, #0xff000000 + itt ne + tstne w1, #0x00ff0000 + tstne w1, #0x0000ff00 + beq 7f +#else + bics r3, r3, #0xff000000 + bne 7f +#endif + ldrb w2, [wp2] + SHFT2LSB t1, w1, #24 +#ifdef __ARMEB__ + lsl w2, w2, #24 +#endif + b 8f + +6: + SHFT2LSB t1, w1, #24 + and w2, w2, #LSB + b 8f + + /* Critical inner Loop: Block with 2 bytes initial overlap */ + .p2align 2 +2: + SHFT2MSB t1, w1, #16 + sub r3, w1, b1 + SHFT2LSB t1, t1, #16 + bic r3, r3, w1 + cmp t1, w2, SHFT2LSB #16 + bne 4f + ands r3, r3, b1, lsl #7 + it eq + ldreq w2, [wp2], #4 + bne 5f + eor t1, t1, w1 + cmp t1, w2, SHFT2MSB #16 + bne 6f + ldr w1, [wp1], #4 + b 2b + +5: +#ifdef __ARMEB__ + /* The syndrome value may contain false ones if the string ends + * with the bytes 0x01 0x00 + */ + tst w1, #0xff000000 + it ne + tstne w1, #0x00ff0000 + beq 7f +#else + lsls r3, r3, #16 + bne 7f +#endif + ldrh w2, [wp2] + SHFT2LSB t1, w1, #16 +#ifdef __ARMEB__ + lsl w2, w2, #16 +#endif + b 8f + +6: + SHFT2MSB w2, w2, #16 + SHFT2LSB t1, w1, #16 +4: + SHFT2LSB w2, w2, #16 + b 8f + + /* Critical inner Loop: Block with 1 byte initial overlap */ + .p2align 2 +3: + and t1, w1, #LSB + cmp t1, w2, SHFT2LSB #24 + sub r3, w1, b1 + bic r3, r3, w1 + bne 4f + ands r3, r3, b1, lsl #7 + it eq + ldreq w2, [wp2], #4 + bne 5f + eor t1, t1, w1 + cmp t1, w2, SHFT2MSB #8 + bne 6f + ldr w1, [wp1], #4 + b 3b +4: + SHFT2LSB w2, w2, #24 + b 8f +5: + /* The syndrome value may contain false ones if the string ends + * with the bytes 0x01 0x00 + */ + tst w1, #LSB + beq 7f + ldr w2, [wp2], #4 +6: + SHFT2LSB t1, w1, #8 + bic w2, w2, #MSB + b 8f +7: + mov r0, #0 + ldr r4, [sp], #4 + ldr r5, [sp], #4 + bx lr + +8: + and r2, t1, #LSB + and r0, w2, #LSB + cmp r0, #1 + it cs + cmpcs r0, r2 + itt eq + SHFT2LSBEQ t1, t1, #8 + SHFT2LSBEQ w2, w2, #8 + beq 8b + sub r0, r2, r0 + ldr r4, [sp], #4 + ldr r5, [sp], #4 + bx lr +END(strcmp_generic) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/strcpy.S b/aosp/bionic/libc/arch-arm/generic/bionic/strcpy.S new file mode 100644 index 000000000..89bd69913 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/strcpy.S @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (c) 2008 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + * + * Android adaptation and tweak by Jim Huang . + */ + +#include + +.syntax unified + +// To avoid warning about deprecated instructions, add an explicit +// arch. The code generated is exactly the same. +.arch armv7-a + +ENTRY(strcpy_generic) + pld [r1, #0] + eor r2, r0, r1 + mov ip, r0 + tst r2, #3 + bne 4f + tst r1, #3 + bne 3f +5: + str r5, [sp, #-4]! + mov r5, #0x01 + orr r5, r5, r5, lsl #8 + orr r5, r5, r5, lsl #16 + + str r4, [sp, #-4]! + tst r1, #4 + ldr r3, [r1], #4 + beq 2f + sub r2, r3, r5 + bics r2, r2, r3 + tst r2, r5, lsl #7 + itt eq + streq r3, [ip], #4 + ldreq r3, [r1], #4 + bne 1f + /* Inner loop. We now know that r1 is 64-bit aligned, so we + can safely fetch up to two words. This allows us to avoid + load stalls. */ + .p2align 2 +2: + pld [r1, #8] + ldr r4, [r1], #4 + sub r2, r3, r5 + bics r2, r2, r3 + tst r2, r5, lsl #7 + sub r2, r4, r5 + bne 1f + str r3, [ip], #4 + bics r2, r2, r4 + tst r2, r5, lsl #7 + itt eq + ldreq r3, [r1], #4 + streq r4, [ip], #4 + beq 2b + mov r3, r4 +1: +#ifdef __ARMEB__ + rors r3, r3, #24 +#endif + strb r3, [ip], #1 + tst r3, #0xff +#ifdef __ARMEL__ + ror r3, r3, #8 +#endif + bne 1b + ldr r4, [sp], #4 + ldr r5, [sp], #4 + bx lr + + /* Strings have the same offset from word alignment, but it's + not zero. */ +3: + tst r1, #1 + beq 1f + ldrb r2, [r1], #1 + strb r2, [ip], #1 + cmp r2, #0 + it eq + bxeq lr +1: + tst r1, #2 + beq 5b + ldrh r2, [r1], #2 +#ifdef __ARMEB__ + tst r2, #0xff00 + iteet ne + strhne r2, [ip], #2 + lsreq r2, r2, #8 + strbeq r2, [ip] + tstne r2, #0xff +#else + tst r2, #0xff + itet ne + strhne r2, [ip], #2 + strbeq r2, [ip] + tstne r2, #0xff00 +#endif + bne 5b + bx lr + + /* src and dst do not have a common word-alignement. Fall back to + byte copying. */ +4: + ldrb r2, [r1], #1 + strb r2, [ip], #1 + cmp r2, #0 + bne 4b + bx lr +END(strcpy_generic) diff --git a/aosp/bionic/libc/arch-arm/generic/bionic/strlen.c b/aosp/bionic/libc/arch-arm/generic/bionic/strlen.c new file mode 100644 index 000000000..43d9e514c --- /dev/null +++ b/aosp/bionic/libc/arch-arm/generic/bionic/strlen.c @@ -0,0 +1,129 @@ +/* + * 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 +#include + +size_t strlen_generic(const char *s) +{ + __builtin_prefetch(s); + __builtin_prefetch(s+32); + + union { + const char *b; + const uint32_t *w; + uintptr_t i; + } u; + + // these are some scratch variables for the asm code below + uint32_t v, t; + + // initialize the string length to zero + size_t l = 0; + + // align the pointer to a 32-bit word boundary + u.b = s; + while (u.i & 0x3) { + if (__builtin_expect(*u.b++ == 0, 0)) { + goto done; + } + l++; + } + + // loop for each word, testing if it contains a zero byte + // if so, exit the loop and update the length. + // We need to process 32 bytes per loop to schedule PLD properly + // and achieve the maximum bus speed. + asm( + "ldr %[v], [%[s]], #4 \n" + "sub %[l], %[l], %[s] \n" + "0: \n" + "pld [%[s], #64] \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" +#if !defined(__OPTIMIZE_SIZE__) + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" + "sub %[t], %[v], %[mask], lsr #7\n" + "and %[t], %[t], %[mask] \n" + "bics %[t], %[t], %[v] \n" + "bne 1f \n" + "ldr %[v], [%[s]], #4 \n" +#endif + "b 0b \n" + "1: \n" + "add %[l], %[l], %[s] \n" + "tst %[v], #0xFF \n" + "beq 2f \n" + "add %[l], %[l], #1 \n" + "tst %[v], #0xFF00 \n" + "beq 2f \n" + "add %[l], %[l], #1 \n" + "tst %[v], #0xFF0000 \n" + "it ne \n" + "addne %[l], %[l], #1 \n" + "2: \n" + : [l]"=&r"(l), [v]"=&r"(v), [t]"=&r"(t), [s]"=&r"(u.b) + : "%[l]"(l), "%[s]"(u.b), [mask]"r"(0x80808080UL) + : "cc" + ); + +done: + return l; +} diff --git a/aosp/bionic/libc/arch-arm/krait/bionic/__strcat_chk.S b/aosp/bionic/libc/arch-arm/krait/bionic/__strcat_chk.S new file mode 100644 index 000000000..9d4bffbfe --- /dev/null +++ b/aosp/bionic/libc/arch-arm/krait/bionic/__strcat_chk.S @@ -0,0 +1,203 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of src string, then get the source of the dst string. +// Check that the two lengths together don't exceed the threshold, then +// do a memcpy of the data. +ENTRY(__strcat_chk_krait) + pld [r0, #0] + push {r0, lr} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + push {r4, r5} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 + + mov lr, r2 + + // Save the dst register to r5 + mov r5, r0 + + // Zero out r4 + eor r4, r4, r4 + + // r1 contains the address of the string to count. +.L_strlen_start: + mov r0, r1 + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r1], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r1], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r1], #8 + + pld [r1, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r1, r0 + sub r3, r3, #1 + b .L_finish + +.L_zero_in_first_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_finish + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_finish + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_finish + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_finish + +.L_zero_in_second_register: + sub r3, r1, r0 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_finish + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_finish + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_finish + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_finish: + cmp r4, #0 + bne .L_strlen_done + + // Time to get the dst string length. + mov r1, r5 + + // Save the original source address to r5. + mov r5, r0 + + // Save the current length (adding 1 for the terminator). + add r4, r3, #1 + b .L_strlen_start + + // r0 holds the pointer to the dst string. + // r3 holds the dst string length. + // r4 holds the src string length + 1. +.L_strlen_done: + add r2, r3, r4 + cmp r2, lr + itt hi + movhi r0, lr + bhi __strcat_chk_fail + + // Set up the registers for the memcpy code. + mov r1, r5 + pld [r1, #64] + mov r2, r4 + add r0, r0, r3 + pop {r4, r5} + .cfi_adjust_cfa_offset -8 + .cfi_restore r4 + .cfi_restore r5 + +#include "memcpy_base.S" + + // Undo the above cfi directives. + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r4, 0 + .cfi_rel_offset r5, 4 +END(__strcat_chk_krait) diff --git a/aosp/bionic/libc/arch-arm/krait/bionic/__strcpy_chk.S b/aosp/bionic/libc/arch-arm/krait/bionic/__strcpy_chk.S new file mode 100644 index 000000000..969e112cc --- /dev/null +++ b/aosp/bionic/libc/arch-arm/krait/bionic/__strcpy_chk.S @@ -0,0 +1,165 @@ +/* + * 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 + + .syntax unified + + .thumb + .thumb_func + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +// Get the length of the source string first, then do a memcpy of the data +// instead of a strcpy. +ENTRY(__strcpy_chk_krait) + pld [r0, #0] + push {r0, lr} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + + mov lr, r2 + mov r0, r1 + + ands r3, r1, #7 + beq .L_mainloop + + // Align to a double word (64 bits). + rsb r3, r3, #8 + lsls ip, r3, #31 + beq .L_align_to_32 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_32: + bcc .L_align_to_64 + ands ip, r3, #2 + beq .L_align_to_64 + + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + ldrb r2, [r0], #1 + cbz r2, .L_update_count_and_finish + +.L_align_to_64: + tst r3, #4 + beq .L_mainloop + ldr r3, [r0], #4 + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + + .p2align 2 +.L_mainloop: + ldrd r2, r3, [r0], #8 + + pld [r0, #64] + + sub ip, r2, #0x01010101 + bic ip, ip, r2 + ands ip, ip, #0x80808080 + bne .L_zero_in_first_register + + sub ip, r3, #0x01010101 + bic ip, ip, r3 + ands ip, ip, #0x80808080 + bne .L_zero_in_second_register + b .L_mainloop + +.L_update_count_and_finish: + sub r3, r0, r1 + sub r3, r3, #1 + b .L_check_size + +.L_zero_in_first_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub8_and_finish + bcs .L_sub7_and_finish + lsls ip, ip, #1 + bne .L_sub6_and_finish + + sub r3, r3, #5 + b .L_check_size + +.L_sub8_and_finish: + sub r3, r3, #8 + b .L_check_size + +.L_sub7_and_finish: + sub r3, r3, #7 + b .L_check_size + +.L_sub6_and_finish: + sub r3, r3, #6 + b .L_check_size + +.L_zero_in_second_register: + sub r3, r0, r1 + lsls r2, ip, #17 + bne .L_sub4_and_finish + bcs .L_sub3_and_finish + lsls ip, ip, #1 + bne .L_sub2_and_finish + + sub r3, r3, #1 + b .L_check_size + +.L_sub4_and_finish: + sub r3, r3, #4 + b .L_check_size + +.L_sub3_and_finish: + sub r3, r3, #3 + b .L_check_size + +.L_sub2_and_finish: + sub r3, r3, #2 + +.L_check_size: + pld [r1, #0] + pld [r1, #64] + ldr r0, [sp] + + // Add 1 for copy length to get the string terminator. + add r2, r3, #1 + + cmp r2, lr + itt hi + movhi r0, r2 + bhi __strcpy_chk_fail + +#include "memcpy_base.S" + +END(__strcpy_chk_krait) diff --git a/aosp/bionic/libc/arch-arm/krait/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/krait/bionic/memcpy.S new file mode 100644 index 000000000..6618b3ad0 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/krait/bionic/memcpy.S @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/* Assumes neon instructions and a cache line size of 32 bytes. */ + +#include + +/* + * This code assumes it is running on a processor that supports all arm v7 + * instructions, that supports neon instructions, and that has a 32 byte + * cache line. + */ + + .text + .syntax unified + .fpu neon + .thumb + .thumb_func + +ENTRY(__memcpy_krait) + pld [r1, #64] + stmfd sp!, {r0, lr} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r0, 0 + .cfi_rel_offset lr, 4 + +#include "memcpy_base.S" +END(__memcpy_krait) diff --git a/aosp/bionic/libc/arch-arm/krait/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm/krait/bionic/memcpy_base.S new file mode 100644 index 000000000..5b4b70d5c --- /dev/null +++ b/aosp/bionic/libc/arch-arm/krait/bionic/memcpy_base.S @@ -0,0 +1,193 @@ +/*************************************************************************** + Copyright (c) 2009-2013 The Linux Foundation. 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. + * Neither the name of The Linux Foundation 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 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 HOLDER 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. + ***************************************************************************/ + +/* Assumes neon instructions and a cache line size of 64 bytes. */ + +#define PLDOFFS (10) +#define PLDTHRESH (PLDOFFS) +#define BBTHRESH (4096/64) +#define PLDSIZE (64) + +#if (PLDOFFS < 1) +#error Routine does not support offsets less than 1 +#endif + +#if (PLDTHRESH < PLDOFFS) +#error PLD threshold must be greater than or equal to the PLD offset +#endif + + .text + .syntax unified + .fpu neon + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + +.L_memcpy_base: + cmp r2, #4 + blt .L_neon_lt4 + cmp r2, #16 + blt .L_neon_lt16 + cmp r2, #32 + blt .L_neon_16 + cmp r2, #64 + blt .L_neon_copy_32_a + + mov r12, r2, lsr #6 + cmp r12, #PLDTHRESH + ble .L_neon_copy_64_loop_nopld + + push {r9, r10} + .cfi_adjust_cfa_offset 8 + .cfi_rel_offset r9, 0 + .cfi_rel_offset r10, 4 + + cmp r12, #BBTHRESH + ble .L_neon_prime_pump + + add lr, r0, #0x400 + add r9, r1, #(PLDOFFS*PLDSIZE) + sub lr, lr, r9 + lsl lr, lr, #21 + lsr lr, lr, #21 + add lr, lr, #(PLDOFFS*PLDSIZE) + cmp r12, lr, lsr #6 + ble .L_neon_prime_pump + + itt gt + movgt r9, #(PLDOFFS) + rsbsgt r9, r9, lr, lsr #6 + ble .L_neon_prime_pump + + add r10, r1, lr + bic r10, #0x3F + + sub r12, r12, lr, lsr #6 + + cmp r9, r12 + itee le + suble r12, r12, r9 + movgt r9, r12 + movgt r12, #0 + + pld [r1, #((PLDOFFS-1)*PLDSIZE)] +.L_neon_copy_64_loop_outer_doublepld: + pld [r1, #((PLDOFFS)*PLDSIZE)] + vld1.32 {q0, q1}, [r1]! + vld1.32 {q2, q3}, [r1]! + ldr r3, [r10] + subs r9, r9, #1 + vst1.32 {q0, q1}, [r0]! + vst1.32 {q2, q3}, [r0]! + add r10, #64 + bne .L_neon_copy_64_loop_outer_doublepld + cmp r12, #0 + beq .L_neon_pop_before_nopld + + cmp r12, #(512*1024/64) + blt .L_neon_copy_64_loop_outer + +.L_neon_copy_64_loop_ddr: + vld1.32 {q0, q1}, [r1]! + vld1.32 {q2, q3}, [r1]! + pld [r10] + subs r12, r12, #1 + vst1.32 {q0, q1}, [r0]! + vst1.32 {q2, q3}, [r0]! + add r10, #64 + bne .L_neon_copy_64_loop_ddr + b .L_neon_pop_before_nopld + +.L_neon_prime_pump: + mov lr, #(PLDOFFS*PLDSIZE) + add r10, r1, #(PLDOFFS*PLDSIZE) + bic r10, #0x3F + sub r12, r12, #PLDOFFS + ldr r3, [r10, #(-1*PLDSIZE)] + +.L_neon_copy_64_loop_outer: + vld1.32 {q0, q1}, [r1]! + vld1.32 {q2, q3}, [r1]! + ldr r3, [r10] + subs r12, r12, #1 + vst1.32 {q0, q1}, [r0]! + vst1.32 {q2, q3}, [r0]! + add r10, #64 + bne .L_neon_copy_64_loop_outer + +.L_neon_pop_before_nopld: + mov r12, lr, lsr #6 + pop {r9, r10} + .cfi_adjust_cfa_offset -8 + .cfi_restore r9 + .cfi_restore r10 + +.L_neon_copy_64_loop_nopld: + vld1.32 {q8, q9}, [r1]! + vld1.32 {q10, q11}, [r1]! + subs r12, r12, #1 + vst1.32 {q8, q9}, [r0]! + vst1.32 {q10, q11}, [r0]! + bne .L_neon_copy_64_loop_nopld + ands r2, r2, #0x3f + beq .L_neon_exit + +.L_neon_copy_32_a: + movs r3, r2, lsl #27 + bcc .L_neon_16 + vld1.32 {q0,q1}, [r1]! + vst1.32 {q0,q1}, [r0]! + +.L_neon_16: + bpl .L_neon_lt16 + vld1.32 {q8}, [r1]! + vst1.32 {q8}, [r0]! + ands r2, r2, #0x0f + beq .L_neon_exit + +.L_neon_lt16: + movs r3, r2, lsl #29 + bcc 1f + vld1.8 {d0}, [r1]! + vst1.8 {d0}, [r0]! +1: + bge .L_neon_lt4 + vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [r1]! + vst4.8 {d0[0], d1[0], d2[0], d3[0]}, [r0]! + +.L_neon_lt4: + movs r2, r2, lsl #31 + itt cs + ldrhcs r3, [r1], #2 + strhcs r3, [r0], #2 + itt mi + ldrbmi r3, [r1] + strbmi r3, [r0] + +.L_neon_exit: + pop {r0, pc} diff --git a/aosp/bionic/libc/arch-arm/krait/bionic/memset.S b/aosp/bionic/libc/arch-arm/krait/bionic/memset.S new file mode 100644 index 000000000..675ab53bc --- /dev/null +++ b/aosp/bionic/libc/arch-arm/krait/bionic/memset.S @@ -0,0 +1,85 @@ +/* + * 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 + +/* + * This code assumes it is running on a processor that supports all arm v7 + * instructions, that supports neon instructions, and that supports + * unaligned neon instruction accesses to memory. + */ + + .fpu neon + .syntax unified + +ENTRY(__memset_chk_krait) + cmp r2, r3 + bls memset + + // Preserve lr for backtrace. + push {lr} + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 + + bl __memset_chk_fail +END(__memset_chk_krait) + +/* memset() returns its first argument. */ +ENTRY(memset_krait) + mov r3, r0 + vdup.8 q0, r1 + + /* make sure we have at least 32 bytes to write */ + subs r2, r2, #32 + blo 2f + vmov q1, q0 + +1: /* The main loop writes 32 bytes at a time */ + subs r2, r2, #32 + vst1.8 {d0 - d3}, [r3]! + bhs 1b + +2: /* less than 32 left */ + add r2, r2, #32 + tst r2, #0x10 + beq 3f + + // writes 16 bytes, 128-bits aligned + vst1.8 {d0, d1}, [r3]! +3: /* write up to 15-bytes (count in r2) */ + movs ip, r2, lsl #29 + bcc 1f + vst1.8 {d0}, [r3]! +1: bge 2f + vst1.32 {d0[0]}, [r3]! +2: movs ip, r2, lsl #31 + strbmi r1, [r3], #1 + strbcs r1, [r3], #1 + strbcs r1, [r3], #1 + bx lr +END(memset_krait) diff --git a/aosp/bionic/libc/arch-arm/kryo/bionic/memcpy.S b/aosp/bionic/libc/arch-arm/kryo/bionic/memcpy.S new file mode 100644 index 000000000..250f7bc61 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/kryo/bionic/memcpy.S @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * All rights reserved. + * + * Copyright (c) 2009-2011, Code Aurora Forum. 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 + +#define PLDOFFS (16) +#define PLDSIZE (128) /* L2 cache line size */ + + .syntax unified + + // To avoid warning about deprecated instructions, add an explicit + // arch. The code generated is exactly the same. + .arch armv7-a + + .code 32 +ENTRY(__memcpy_kryo) + push {r0} + .cfi_def_cfa_offset 4 + .cfi_rel_offset r0, 0 + cmp r2, #4 + blt .Lneon_lt4 + cmp r2, #16 + blt .Lneon_lt16 + cmp r2, #32 + blt .Lneon_16 + cmp r2, #128 + blt .Lneon_copy_32_a + /* Copy blocks of 128-bytes (word-aligned) at a time*/ + /* Code below is optimized for PLDSIZE=128 only */ + mov r12, r2, lsr #7 + cmp r12, #PLDOFFS + ble .Lneon_copy_128_loop_nopld + sub r12, #PLDOFFS + pld [r1, #(PLDOFFS-1)*PLDSIZE] +.Lneon_copy_128_loop_outer: + pld [r1, #(PLDOFFS*PLDSIZE)] + pld [r1, #(PLDOFFS)*(PLDSIZE)+64] + vld1.32 {q0, q1}, [r1]! + vld1.32 {q2, q3}, [r1]! + vld1.32 {q8, q9}, [r1]! + vld1.32 {q10, q11}, [r1]! + subs r12, r12, #1 + vst1.32 {q0, q1}, [r0]! + vst1.32 {q2, q3}, [r0]! + vst1.32 {q8, q9}, [r0]! + vst1.32 {q10, q11}, [r0]! + bne .Lneon_copy_128_loop_outer + mov r12, #PLDOFFS +.Lneon_copy_128_loop_nopld: + vld1.32 {q0, q1}, [r1]! + vld1.32 {q2, q3}, [r1]! + vld1.32 {q8, q9}, [r1]! + vld1.32 {q10, q11}, [r1]! + subs r12, r12, #1 + vst1.32 {q0, q1}, [r0]! + vst1.32 {q2, q3}, [r0]! + vst1.32 {q8, q9}, [r0]! + vst1.32 {q10, q11}, [r0]! + bne .Lneon_copy_128_loop_nopld + ands r2, r2, #0x7f + beq .Lneon_exit + cmp r2, #32 + blt .Lneon_16 + nop + /* Copy blocks of 32-bytes (word aligned) at a time*/ +.Lneon_copy_32_a: + mov r12, r2, lsr #5 +.Lneon_copy_32_loop_a: + vld1.32 {q0,q1}, [r1]! + subs r12, r12, #1 + vst1.32 {q0,q1}, [r0]! + bne .Lneon_copy_32_loop_a + ands r2, r2, #0x1f + beq .Lneon_exit +.Lneon_16: + subs r2, r2, #16 + blt .Lneon_lt16 + vld1.32 {q8}, [r1]! + vst1.32 {q8}, [r0]! + beq .Lneon_exit +.Lneon_lt16: + movs r12, r2, lsl #29 + bcc .Lneon_skip8 + ldr r3, [r1], #4 + ldr r12, [r1], #4 + str r3, [r0], #4 + str r12, [r0], #4 +.Lneon_skip8: + bpl .Lneon_lt4 + ldr r3, [r1], #4 + str r3, [r0], #4 +.Lneon_lt4: + movs r2, r2, lsl #31 + bcc .Lneon_lt2 + ldrh r3, [r1], #2 + strh r3, [r0], #2 +.Lneon_lt2: + bpl .Lneon_exit + ldrb r12, [r1] + strb r12, [r0] +.Lneon_exit: + pop {r0} + bx lr + +END(__memcpy_kryo) diff --git a/aosp/bionic/libc/arch-arm/static_function_dispatch.S b/aosp/bionic/libc/arch-arm/static_function_dispatch.S new file mode 100644 index 000000000..a8235c242 --- /dev/null +++ b/aosp/bionic/libc/arch-arm/static_function_dispatch.S @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 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 + +#define FUNCTION_DELEGATE(name, impl) \ +ENTRY(name); \ + b impl; \ +END(name) + +FUNCTION_DELEGATE(memmove, memmove_generic) +FUNCTION_DELEGATE(memcpy, memmove_generic) +FUNCTION_DELEGATE(memset, memset_generic) +FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic) +FUNCTION_DELEGATE(strcpy, strcpy_generic) +FUNCTION_DELEGATE(__strcpy_chk, __strcpy_chk_generic) +FUNCTION_DELEGATE(stpcpy, stpcpy_generic) +FUNCTION_DELEGATE(strcat, strcat_generic) +FUNCTION_DELEGATE(__strcat_chk, __strcat_chk_generic) +FUNCTION_DELEGATE(strcmp, strcmp_generic) +FUNCTION_DELEGATE(strlen, strlen_generic) diff --git a/aosp/bionic/libc/arch-arm64/bionic/__bionic_clone.S b/aosp/bionic/libc/arch-arm64/bionic/__bionic_clone.S new file mode 100644 index 000000000..c3ff0e50c --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/__bionic_clone.S @@ -0,0 +1,59 @@ +/* + * 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 + +// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg); + +ENTRY_PRIVATE(__bionic_clone) + # Push 'fn' and 'arg' onto the child stack. + stp x5, x6, [x1, #-16]! + + # Make the system call. + mov x8, __NR_clone + svc #0 + + # Are we the child? + cbz x0, .L_bc_child + + # Set errno if something went wrong. + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno_internal + + ret + +.L_bc_child: + # We're in the child now. Set the end of the frame record chain. + mov x29, #0 + # Setting x30 to 0 will make the unwinder stop at __start_thread. + mov x30, #0 + # Call __start_thread with the 'fn' and 'arg' we stored on the child stack. + ldp x0, x1, [sp], #16 + b __start_thread +END(__bionic_clone) diff --git a/aosp/bionic/libc/arch-arm64/bionic/__set_tls.c b/aosp/bionic/libc/arch-arm64/bionic/__set_tls.c new file mode 100644 index 000000000..0d88d111d --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/__set_tls.c @@ -0,0 +1,33 @@ +/* + * 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 + +__LIBC_HIDDEN__ void __set_tls(void* tls) { + asm("msr tpidr_el0, %0" : : "r" (tls)); +} diff --git a/aosp/bionic/libc/arch-arm64/bionic/_exit_with_stack_teardown.S b/aosp/bionic/libc/arch-arm64/bionic/_exit_with_stack_teardown.S new file mode 100644 index 000000000..6a7b1e561 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/_exit_with_stack_teardown.S @@ -0,0 +1,41 @@ +/* + * 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 + +// void _exit_with_stack_teardown(void* stackBase, size_t stackSize) +ENTRY_PRIVATE(_exit_with_stack_teardown) + mov w8, __NR_munmap + svc #0 + // If munmap failed, we ignore the failure and exit anyway. + + mov x0, #0 + mov w8, __NR_exit + svc #0 + // The exit syscall does not return. +END(_exit_with_stack_teardown) diff --git a/aosp/bionic/libc/arch-arm64/bionic/setjmp.S b/aosp/bionic/libc/arch-arm64/bionic/setjmp.S new file mode 100644 index 000000000..a2b23702a --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/setjmp.S @@ -0,0 +1,299 @@ +/* + * 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 +#include + +// According to AARCH64 PCS document we need to save the following +// registers: +// +// Core x19 - x30, sp (see section 5.1.1) +// VFP d8 - d15 (see section 5.1.2) +// +// NOTE: All the registers saved here will have 64 bit vales. +// AAPCS mandates that the higher part of q registers do not need to +// be saved by the callee. +// +// The internal structure of a jmp_buf is totally private. +// Current layout (changes from release to release): +// +// word name description +// 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit +// 1 sigmask signal mask (not used with _setjmp / _longjmp) +// 2 core_base base of core registers (x18-x30, sp) +// (We only store the low bits of x18 to avoid leaking the +// shadow call stack address into memory.) +// 16 float_base base of float registers (d8-d15) +// 24 checksum checksum of core registers +// 25 reserved reserved entries (room to grow) +// 32 + +#define _JB_SIGFLAG 0 +#define _JB_SIGMASK (_JB_SIGFLAG + 1) +#define _JB_X30_SP (_JB_SIGMASK + 1) +#define _JB_X28_X29 (_JB_X30_SP + 2) +#define _JB_X26_X27 (_JB_X28_X29 + 2) +#define _JB_X24_X25 (_JB_X26_X27 + 2) +#define _JB_X22_X23 (_JB_X24_X25 + 2) +#define _JB_X20_X21 (_JB_X22_X23 + 2) +#define _JB_SCS_X19 (_JB_X20_X21 + 2) +#define _JB_D14_D15 (_JB_SCS_X19 + 2) +#define _JB_D12_D13 (_JB_D14_D15 + 2) +#define _JB_D10_D11 (_JB_D12_D13 + 2) +#define _JB_D8_D9 (_JB_D10_D11 + 2) +#define _JB_CHECKSUM (_JB_D8_D9 + 2) + +#define SCS_MASK (SCS_SIZE - 1) +#define MANGLE_REGISTERS 1 +#define USE_CHECKSUM 1 + +.macro m_mangle_registers reg, sp_reg +#if MANGLE_REGISTERS + eor x3, x3, \reg + eor x19, x19, \reg + eor x20, x20, \reg + eor x21, x21, \reg + eor x22, x22, \reg + eor x23, x23, \reg + eor x24, x24, \reg + eor x25, x25, \reg + eor x26, x26, \reg + eor x27, x27, \reg + eor x28, x28, \reg + eor x29, x29, \reg + eor x30, x30, \reg + eor \sp_reg, \sp_reg, \reg +#endif +.endm + +.macro m_calculate_checksum dst, src, scratch + mov \dst, #0 + .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 + ldr \scratch, [\src, #(\i * 8)] + eor \dst, \dst, \scratch + .endr +.endm + +.macro m_unmangle_registers reg, sp_reg + m_mangle_registers \reg, sp_reg=\sp_reg +.endm + +ENTRY(setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(setjmp) + mov w1, #1 + b sigsetjmp +END(setjmp) + +ENTRY(_setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_setjmp) + mov w1, #0 + b sigsetjmp +END(_setjmp) + +// int sigsetjmp(sigjmp_buf env, int save_signal_mask); +ENTRY(sigsetjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp) + stp x0, x30, [sp, #-16]! + .cfi_def_cfa_offset 16 + .cfi_rel_offset x0, 0 + .cfi_rel_offset x30, 8 + + // Get the cookie and store it along with the signal flag. + mov x0, x1 + bl __bionic_setjmp_cookie_get + mov x1, x0 + ldr x0, [sp, #0] + str x1, [x0, #(_JB_SIGFLAG * 8)] + + // Do we need to save the signal mask? + tbz w1, #0, 1f + + // Save the cookie for later. + stp x1, xzr, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + + // Save current signal mask. + // The 'how' argument is ignored if new_mask is NULL. + mov x1, #0 // NULL. + add x2, x0, #(_JB_SIGMASK * 8) // old_mask. + bl sigprocmask + + ldp x1, xzr, [sp], #16 + .cfi_adjust_cfa_offset -16 + +1: + // Restore original x0 and lr. + ldp x0, x30, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x0 + .cfi_restore x30 + + // Mask off the signal flag bit. + bic x1, x1, #1 + + // Mask off the high bits of the shadow call stack pointer. + and x3, x18, #SCS_MASK + + // Save core registers. + mov x10, sp + m_mangle_registers x1, sp_reg=x10 + stp x30, x10, [x0, #(_JB_X30_SP * 8)] + stp x28, x29, [x0, #(_JB_X28_X29 * 8)] + stp x26, x27, [x0, #(_JB_X26_X27 * 8)] + stp x24, x25, [x0, #(_JB_X24_X25 * 8)] + stp x22, x23, [x0, #(_JB_X22_X23 * 8)] + stp x20, x21, [x0, #(_JB_X20_X21 * 8)] + stp x3, x19, [x0, #(_JB_SCS_X19 * 8)] + m_unmangle_registers x1, sp_reg=x10 + + // Save floating point registers. + stp d14, d15, [x0, #(_JB_D14_D15 * 8)] + stp d12, d13, [x0, #(_JB_D12_D13 * 8)] + stp d10, d11, [x0, #(_JB_D10_D11 * 8)] + stp d8, d9, [x0, #(_JB_D8_D9 * 8)] + +#if USE_CHECKSUM + // Calculate the checksum. + m_calculate_checksum x12, x0, x2 + str x12, [x0, #(_JB_CHECKSUM * 8)] +#endif + + mov w0, #0 + ret +END(sigsetjmp) + +// void siglongjmp(sigjmp_buf env, int value); +ENTRY(siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(siglongjmp) +#if USE_CHECKSUM + // Check the checksum before doing anything. + m_calculate_checksum x12, x0, x2 + ldr x2, [x0, #(_JB_CHECKSUM * 8)] + + cmp x2, x12 + bne __bionic_setjmp_checksum_mismatch +#endif + +#if __has_feature(hwaddress_sanitizer) + stp x0, x30, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset x0, 0 + .cfi_rel_offset x30, 8 + mov x19, x1 // Save 'value'. + + // load and unmangle destination SP + ldr x2, [x0, #(_JB_SIGFLAG * 8)] + bic x2, x2, #1 + ldr x0, [x0, #(_JB_X30_SP * 8 + 8)] + eor x0, x0, x2 + bl __hwasan_handle_longjmp + + mov x1, x19 // Restore 'value'. + // Restore original x0 and lr. + ldp x0, x30, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x0 + .cfi_restore x30 +#endif + + // Do we need to restore the signal mask? + ldr x2, [x0, #(_JB_SIGFLAG * 8)] + tbz w2, #0, 1f + + stp x0, x30, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset x0, 0 + .cfi_rel_offset x30, 8 + + // Restore signal mask. + mov x19, x1 // Save 'value'. + + mov x2, x0 + mov x0, #2 // SIG_SETMASK + add x1, x2, #(_JB_SIGMASK * 8) // new_mask. + mov x2, #0 // NULL. + bl sigprocmask + mov x1, x19 // Restore 'value'. + + // Restore original x0 and lr. + ldp x0, x30, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x0 + .cfi_restore x30 + + ldr x2, [x0, #(_JB_SIGFLAG * 8)] +1: + // Restore core registers. + bic x2, x2, #1 + ldp x30, x10, [x0, #(_JB_X30_SP * 8)] + ldp x28, x29, [x0, #(_JB_X28_X29 * 8)] + ldp x26, x27, [x0, #(_JB_X26_X27 * 8)] + ldp x24, x25, [x0, #(_JB_X24_X25 * 8)] + ldp x22, x23, [x0, #(_JB_X22_X23 * 8)] + ldp x20, x21, [x0, #(_JB_X20_X21 * 8)] + ldp x3, x19, [x0, #(_JB_SCS_X19 * 8)] + m_unmangle_registers x2, sp_reg=x10 + mov sp, x10 + + // Restore the low bits of the shadow call stack pointer. + and x18, x18, #~SCS_MASK + orr x18, x3, x18 + + stp x0, x1, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset x0, 0 + .cfi_rel_offset x1, 8 + stp x30, xzr, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset x30, 0 + ldr x0, [x0, #(_JB_SIGFLAG * 8)] + bl __bionic_setjmp_cookie_check + ldp x30, xzr, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x30 + ldp x0, x1, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x0 + .cfi_restore x1 + + // Restore floating point registers. + ldp d14, d15, [x0, #(_JB_D14_D15 * 8)] + ldp d12, d13, [x0, #(_JB_D12_D13 * 8)] + ldp d10, d11, [x0, #(_JB_D10_D11 * 8)] + ldp d8, d9, [x0, #(_JB_D8_D9 * 8)] + + // Set return value. + cmp w1, wzr + csinc w0, w1, wzr, ne + ret +END(siglongjmp) + +ALIAS_SYMBOL(longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp) +ALIAS_SYMBOL(_longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp) diff --git a/aosp/bionic/libc/arch-arm64/bionic/syscall.S b/aosp/bionic/libc/arch-arm64/bionic/syscall.S new file mode 100644 index 000000000..8389f9830 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/syscall.S @@ -0,0 +1,49 @@ +/* + * 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 + +ENTRY(syscall) + /* Move syscall No. from x0 to x8 */ + mov x8, x0 + /* Move syscall parameters from x1 thru x6 to x0 thru x5 */ + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + svc #0 + + /* check if syscall returned successfully */ + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno_internal + + ret +END(syscall) diff --git a/aosp/bionic/libc/arch-arm64/bionic/vfork.S b/aosp/bionic/libc/arch-arm64/bionic/vfork.S new file mode 100644 index 000000000..5cfb8b0cc --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/bionic/vfork.S @@ -0,0 +1,87 @@ +/* + * 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 +#include +#include + +// Must match the defines in linux/sched.h +#define CLONE_VM 0x00000100 +#define CLONE_VFORK 0x00004000 + +ENTRY(vfork) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork) + // x9 = __get_tls()[TLS_SLOT_THREAD_ID] + mrs x9, tpidr_el0 + ldr x9, [x9, #(TLS_SLOT_THREAD_ID * 8)] + + // Set cached_pid_ to 0, vforked_ to 1, and stash the previous value. + mov w0, #0x80000000 + ldr w10, [x9, #20] + str w0, [x9, #20] + + mov x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD) + mov x1, xzr + mov x2, xzr + mov x3, xzr + mov x4, xzr + + mov x8, __NR_clone + svc #0 + + cbz x0, .L_exit + + // rc != 0: reset cached_pid_ and vforked_. + str w10, [x9, #20] + cmn x0, #(MAX_ERRNO + 1) + cneg x0, x0, hi + b.hi __set_errno_internal + +#if __has_feature(hwaddress_sanitizer) + cbz x0, .L_exit + + // Clean up stack shadow in the parent process. + // https://github.com/google/sanitizers/issues/925 + stp x0, x30, [sp, #-16]! + .cfi_adjust_cfa_offset 16 + .cfi_rel_offset x0, 0 + .cfi_rel_offset x30, 8 + + add x0, sp, #16 + bl __hwasan_handle_vfork + + ldp x0, x30, [sp], #16 + .cfi_adjust_cfa_offset -16 + .cfi_restore x0 + .cfi_restore x30 + +#endif + +.L_exit: + ret +END(vfork) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/memchr.S b/aosp/bionic/libc/arch-arm64/default/bionic/memchr.S new file mode 100644 index 000000000..7fbcc8fd4 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/memchr.S @@ -0,0 +1,164 @@ +/* + * + Copyright (c) 2014, ARM Limited + All rights Reserved. + Copyright (c) 2014, Linaro Ltd. + + 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. + * Neither the name of the company 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + * Neon Available. + */ + +#include + +/* Arguments and results. */ +#define srcin x0 +#define chrin w1 +#define cntin x2 + +#define result x0 + +#define src x3 +#define tmp x4 +#define wtmp2 w5 +#define synd x6 +#define soff x9 +#define cntrem x10 + +#define vrepchr v0 +#define vdata1 v1 +#define vdata2 v2 +#define vhas_chr1 v3 +#define vhas_chr2 v4 +#define vrepmask v5 +#define vend v6 + +/* + * Core algorithm: + * + * For each 32-byte chunk we calculate a 64-bit syndrome value, with two bits + * per byte. For each tuple, bit 0 is set if the relevant byte matched the + * requested character and bit 1 is not used (faster than using a 32bit + * syndrome). Since the bits in the syndrome reflect exactly the order in which + * things occur in the original string, counting trailing zeros allows to + * identify exactly which byte has matched. + */ + +ENTRY(memchr_default) + /* + * Magic constant 0x40100401 allows us to identify which lane matches + * the requested byte. + */ + cbz cntin, .Lzero_length + mov wtmp2, #0x0401 + movk wtmp2, #0x4010, lsl #16 + dup vrepchr.16b, chrin + /* Work with aligned 32-byte chunks */ + bic src, srcin, #31 + dup vrepmask.4s, wtmp2 + ands soff, srcin, #31 + and cntrem, cntin, #31 + b.eq .Lloop + + /* + * Input string is not 32-byte aligned. We calculate the syndrome + * value for the aligned 32 bytes block containing the first bytes + * and mask the irrelevant part. + */ + + ld1 {vdata1.16b, vdata2.16b}, [src], #32 + sub tmp, soff, #32 + adds cntin, cntin, tmp + cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b + cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b + and vhas_chr1.16b, vhas_chr1.16b, vrepmask.16b + and vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b + addp vend.16b, vhas_chr1.16b, vhas_chr2.16b /* 256->128 */ + addp vend.16b, vend.16b, vend.16b /* 128->64 */ + mov synd, vend.d[0] + /* Clear the soff*2 lower bits */ + lsl tmp, soff, #1 + lsr synd, synd, tmp + lsl synd, synd, tmp + /* The first block can also be the last */ + b.ls .Lmasklast + /* Have we found something already? */ + cbnz synd, .Ltail + +.Lloop: + ld1 {vdata1.16b, vdata2.16b}, [src], #32 + subs cntin, cntin, #32 + cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b + cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b + /* If we're out of data we finish regardless of the result */ + b.ls .Lend + /* Use a fast check for the termination condition */ + orr vend.16b, vhas_chr1.16b, vhas_chr2.16b + addp vend.2d, vend.2d, vend.2d + mov synd, vend.d[0] + /* We're not out of data, loop if we haven't found the character */ + cbz synd, .Lloop + +.Lend: + /* Termination condition found, let's calculate the syndrome value */ + and vhas_chr1.16b, vhas_chr1.16b, vrepmask.16b + and vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b + addp vend.16b, vhas_chr1.16b, vhas_chr2.16b /* 256->128 */ + addp vend.16b, vend.16b, vend.16b /* 128->64 */ + mov synd, vend.d[0] + /* Only do the clear for the last possible block */ + b.hi .Ltail + +.Lmasklast: + /* Clear the (32 - ((cntrem + soff) % 32)) * 2 upper bits */ + add tmp, cntrem, soff + and tmp, tmp, #31 + sub tmp, tmp, #32 + neg tmp, tmp, lsl #1 + lsl synd, synd, tmp + lsr synd, synd, tmp + +.Ltail: + /* Count the trailing zeros using bit reversing */ + rbit synd, synd + /* Compensate the last post-increment */ + sub src, src, #32 + /* Check that we have found a character */ + cmp synd, #0 + /* And count the leading zeros */ + clz synd, synd + /* Compute the potential result */ + add result, src, synd, lsr #1 + /* Select result or NULL */ + csel result, xzr, result, eq + ret + +.Lzero_length: + mov result, xzr + ret +END(memchr_default) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/strchr.S b/aosp/bionic/libc/arch-arm64/default/bionic/strchr.S new file mode 100644 index 000000000..f8cb724cc --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/strchr.S @@ -0,0 +1,153 @@ +/* + * + Copyright (c) 2014, ARM Limited + All rights Reserved. + Copyright (c) 2014, Linaro Ltd. + + 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. + * Neither the name of the company 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + * Neon Available. + */ + +#include + +/* Arguments and results. */ +#define srcin x0 +#define chrin w1 + +#define result x0 + +#define src x2 +#define tmp1 x3 +#define wtmp2 w4 +#define tmp3 x5 + +#define vrepchr v0 +#define vdata1 v1 +#define vdata2 v2 +#define vhas_nul1 v3 +#define vhas_nul2 v4 +#define vhas_chr1 v5 +#define vhas_chr2 v6 +#define vrepmask_0 v7 +#define vrepmask_c v16 +#define vend1 v17 +#define vend2 v18 + +/* Core algorithm. + + For each 32-byte hunk we calculate a 64-bit syndrome value, with + two bits per byte (LSB is always in bits 0 and 1, for both big + and little-endian systems). For each tuple, bit 0 is set iff + the relevant byte matched the requested character; bit 1 is set + iff the relevant byte matched the NUL end of string (we trigger + off bit0 for the special case of looking for NUL). Since the bits + in the syndrome reflect exactly the order in which things occur + in the original string a count_trailing_zeros() operation will + identify exactly which byte is causing the termination, and why. */ + +/* Locals and temporaries. */ + +ENTRY(strchr_default) + /* Magic constant 0x40100401 to allow us to identify which lane + matches the requested byte. Magic constant 0x80200802 used + similarly for NUL termination. */ + mov wtmp2, #0x0401 + movk wtmp2, #0x4010, lsl #16 + dup vrepchr.16b, chrin + bic src, srcin, #31 /* Work with aligned 32-byte hunks. */ + dup vrepmask_c.4s, wtmp2 + ands tmp1, srcin, #31 + add vrepmask_0.4s, vrepmask_c.4s, vrepmask_c.4s /* equiv: lsl #1 */ + b.eq .Lloop + + /* Input string is not 32-byte aligned. Rather than forcing + the padding bytes to a safe value, we calculate the syndrome + for all the bytes, but then mask off those bits of the + syndrome that are related to the padding. */ + ld1 {vdata1.16b, vdata2.16b}, [src], #32 + neg tmp1, tmp1 + cmeq vhas_nul1.16b, vdata1.16b, #0 + cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b + cmeq vhas_nul2.16b, vdata2.16b, #0 + cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b + and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b + and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b + and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b + and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b + orr vend1.16b, vhas_nul1.16b, vhas_chr1.16b + orr vend2.16b, vhas_nul2.16b, vhas_chr2.16b + lsl tmp1, tmp1, #1 + addp vend1.16b, vend1.16b, vend2.16b // 256->128 + mov tmp3, #~0 + addp vend1.16b, vend1.16b, vend2.16b // 128->64 + lsr tmp1, tmp3, tmp1 + + mov tmp3, vend1.d[0] + bic tmp1, tmp3, tmp1 // Mask padding bits. + cbnz tmp1, .Ltail + +.Lloop: + ld1 {vdata1.16b, vdata2.16b}, [src], #32 + cmeq vhas_nul1.16b, vdata1.16b, #0 + cmeq vhas_chr1.16b, vdata1.16b, vrepchr.16b + cmeq vhas_nul2.16b, vdata2.16b, #0 + cmeq vhas_chr2.16b, vdata2.16b, vrepchr.16b + /* Use a fast check for the termination condition. */ + orr vend1.16b, vhas_nul1.16b, vhas_chr1.16b + orr vend2.16b, vhas_nul2.16b, vhas_chr2.16b + orr vend1.16b, vend1.16b, vend2.16b + addp vend1.2d, vend1.2d, vend1.2d + mov tmp1, vend1.d[0] + cbz tmp1, .Lloop + + /* Termination condition found. Now need to establish exactly why + we terminated. */ + and vhas_nul1.16b, vhas_nul1.16b, vrepmask_0.16b + and vhas_nul2.16b, vhas_nul2.16b, vrepmask_0.16b + and vhas_chr1.16b, vhas_chr1.16b, vrepmask_c.16b + and vhas_chr2.16b, vhas_chr2.16b, vrepmask_c.16b + orr vend1.16b, vhas_nul1.16b, vhas_chr1.16b + orr vend2.16b, vhas_nul2.16b, vhas_chr2.16b + addp vend1.16b, vend1.16b, vend2.16b // 256->128 + addp vend1.16b, vend1.16b, vend2.16b // 128->64 + + mov tmp1, vend1.d[0] +.Ltail: + /* Count the trailing zeros, by bit reversing... */ + rbit tmp1, tmp1 + /* Re-bias source. */ + sub src, src, #32 + clz tmp1, tmp1 /* And counting the leading zeros. */ + /* Tmp1 is even if the target charager was found first. Otherwise + we've found the end of string and we weren't looking for NUL. */ + tst tmp1, #1 + add result, src, tmp1, lsr #1 + csel result, result, xzr, eq + ret +END(strchr_default) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/strcmp.S b/aosp/bionic/libc/arch-arm64/default/bionic/strcmp.S new file mode 100644 index 000000000..dfac7c42c --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/strcmp.S @@ -0,0 +1,192 @@ +/* Copyright (c) 2012, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + */ + +#include + +#define L(label) .L ## label + +#define REP8_01 0x0101010101010101 +#define REP8_7f 0x7f7f7f7f7f7f7f7f +#define REP8_80 0x8080808080808080 + +/* Parameters and result. */ +#define src1 x0 +#define src2 x1 +#define result x0 + +/* Internal variables. */ +#define data1 x2 +#define data1w w2 +#define data2 x3 +#define data2w w3 +#define has_nul x4 +#define diff x5 +#define syndrome x6 +#define tmp1 x7 +#define tmp2 x8 +#define tmp3 x9 +#define zeroones x10 +#define pos x11 + + /* Start of performance-critical section -- one 64B cache line. */ +ENTRY(strcmp_default) +.p2align 6 + eor tmp1, src1, src2 + mov zeroones, #REP8_01 + tst tmp1, #7 + b.ne L(misaligned8) + ands tmp1, src1, #7 + b.ne L(mutual_align) + /* NUL detection works on the principle that (X - 1) & (~X) & 0x80 + (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and + can be done in parallel across the entire word. */ +L(loop_aligned): + ldr data1, [src1], #8 + ldr data2, [src2], #8 +L(start_realigned): + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + eor diff, data1, data2 /* Non-zero if differences found. */ + bic has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ + orr syndrome, diff, has_nul + cbz syndrome, L(loop_aligned) + /* End of performance-critical section -- one 64B cache line. */ + +L(end): +#ifndef __AARCH64EB__ + rev syndrome, syndrome + rev data1, data1 + /* The MS-non-zero bit of the syndrome marks either the first bit + that is different, or the top bit of the first zero byte. + Shifting left now will bring the critical information into the + top bits. */ + clz pos, syndrome + rev data2, data2 + lsl data1, data1, pos + lsl data2, data2, pos + /* But we need to zero-extend (char is unsigned) the value and then + perform a signed 32-bit subtraction. */ + lsr data1, data1, #56 + sub result, data1, data2, lsr #56 + ret +#else + /* For big-endian we cannot use the trick with the syndrome value + as carry-propagation can corrupt the upper bits if the trailing + bytes in the string contain 0x01. */ + /* However, if there is no NUL byte in the dword, we can generate + the result directly. We can't just subtract the bytes as the + MSB might be significant. */ + cbnz has_nul, 1f + cmp data1, data2 + cset result, ne + cneg result, result, lo + ret +1: + /* Re-compute the NUL-byte detection, using a byte-reversed value. */ + rev tmp3, data1 + sub tmp1, tmp3, zeroones + orr tmp2, tmp3, #REP8_7f + bic has_nul, tmp1, tmp2 + rev has_nul, has_nul + orr syndrome, diff, has_nul + clz pos, syndrome + /* The MS-non-zero bit of the syndrome marks either the first bit + that is different, or the top bit of the first zero byte. + Shifting left now will bring the critical information into the + top bits. */ + lsl data1, data1, pos + lsl data2, data2, pos + /* But we need to zero-extend (char is unsigned) the value and then + perform a signed 32-bit subtraction. */ + lsr data1, data1, #56 + sub result, data1, data2, lsr #56 + ret +#endif + +L(mutual_align): + /* Sources are mutually aligned, but are not currently at an + alignment boundary. Round down the addresses and then mask off + the bytes that preceed the start point. */ + bic src1, src1, #7 + bic src2, src2, #7 + lsl tmp1, tmp1, #3 /* Bytes beyond alignment -> bits. */ + ldr data1, [src1], #8 + neg tmp1, tmp1 /* Bits to alignment -64. */ + ldr data2, [src2], #8 + mov tmp2, #~0 +#ifdef __AARCH64EB__ + /* Big-endian. Early bytes are at MSB. */ + lsl tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ +#else + /* Little-endian. Early bytes are at LSB. */ + lsr tmp2, tmp2, tmp1 /* Shift (tmp1 & 63). */ +#endif + orr data1, data1, tmp2 + orr data2, data2, tmp2 + b L(start_realigned) + +L(misaligned8): + /* Align SRC1 to 8 bytes and then compare 8 bytes at a time, always + checking to make sure that we don't access beyond page boundary in + SRC2. */ + tst src1, #7 + b.eq L(loop_misaligned) +L(do_misaligned): + ldrb data1w, [src1], #1 + ldrb data2w, [src2], #1 + cmp data1w, #1 + ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ + b.ne L(done) + tst src1, #7 + b.ne L(do_misaligned) + +L(loop_misaligned): + /* Test if we are within the last dword of the end of a 4K page. If + yes then jump back to the misaligned loop to copy a byte at a time. */ + and tmp1, src2, #0xff8 + eor tmp1, tmp1, #0xff8 + cbz tmp1, L(do_misaligned) + ldr data1, [src1], #8 + ldr data2, [src2], #8 + + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + eor diff, data1, data2 /* Non-zero if differences found. */ + bic has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ + orr syndrome, diff, has_nul + cbz syndrome, L(loop_misaligned) + b L(end) + +L(done): + sub result, data1, data2 + ret +END(strcmp_default) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/strlen.S b/aosp/bionic/libc/arch-arm64/default/bionic/strlen.S new file mode 100644 index 000000000..07c5294c2 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/strlen.S @@ -0,0 +1,227 @@ +/* Copyright (c) 2013-2015, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. */ + +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses, min page size 4k. + */ + +#include + +/* To test the page crossing code path more thoroughly, compile with + -DTEST_PAGE_CROSS - this will force all calls through the slower + entry path. This option is not intended for production use. */ + +/* Arguments and results. */ +#define srcin x0 +#define len x0 + +/* Locals and temporaries. */ +#define src x1 +#define data1 x2 +#define data2 x3 +#define has_nul1 x4 +#define has_nul2 x5 +#define tmp1 x4 +#define tmp2 x5 +#define tmp3 x6 +#define tmp4 x7 +#define zeroones x8 + +#define L(l) .L ## l + + /* NUL detection works on the principle that (X - 1) & (~X) & 0x80 + (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and + can be done in parallel across the entire word. A faster check + (X - 1) & 0x80 is zero for non-NUL ASCII characters, but gives + false hits for characters 129..255. */ + +#define REP8_01 0x0101010101010101 +#define REP8_7f 0x7f7f7f7f7f7f7f7f +#define REP8_80 0x8080808080808080 + +#ifdef TEST_PAGE_CROSS +# define MIN_PAGE_SIZE 15 +#else +# define MIN_PAGE_SIZE 4096 +#endif + + /* Since strings are short on average, we check the first 16 bytes + of the string for a NUL character. In order to do an unaligned ldp + safely we have to do a page cross check first. If there is a NUL + byte we calculate the length from the 2 8-byte words using + conditional select to reduce branch mispredictions (it is unlikely + strlen will be repeatedly called on strings with the same length). + + If the string is longer than 16 bytes, we align src so don't need + further page cross checks, and process 32 bytes per iteration + using the fast NUL check. If we encounter non-ASCII characters, + fallback to a second loop using the full NUL check. + + If the page cross check fails, we read 16 bytes from an aligned + address, remove any characters before the string, and continue + in the main loop using aligned loads. Since strings crossing a + page in the first 16 bytes are rare (probability of + 16/MIN_PAGE_SIZE ~= 0.4%), this case does not need to be optimized. + + AArch64 systems have a minimum page size of 4k. We don't bother + checking for larger page sizes - the cost of setting up the correct + page size is just not worth the extra gain from a small reduction in + the cases taking the slow path. Note that we only care about + whether the first fetch, which may be misaligned, crosses a page + boundary. */ + +ENTRY(strlen_default) + and tmp1, srcin, MIN_PAGE_SIZE - 1 + mov zeroones, REP8_01 + cmp tmp1, MIN_PAGE_SIZE - 16 + b.gt L(page_cross) + ldp data1, data2, [srcin] +#ifdef __AARCH64EB__ + /* For big-endian, carry propagation (if the final byte in the + string is 0x01) means we cannot use has_nul1/2 directly. + Since we expect strings to be small and early-exit, + byte-swap the data now so has_null1/2 will be correct. */ + rev data1, data1 + rev data2, data2 +#endif + sub tmp1, data1, zeroones + orr tmp2, data1, REP8_7f + sub tmp3, data2, zeroones + orr tmp4, data2, REP8_7f + bics has_nul1, tmp1, tmp2 + bic has_nul2, tmp3, tmp4 + ccmp has_nul2, 0, 0, eq + beq L(main_loop_entry) + + /* Enter with C = has_nul1 == 0. */ + csel has_nul1, has_nul1, has_nul2, cc + mov len, 8 + rev has_nul1, has_nul1 + clz tmp1, has_nul1 + csel len, xzr, len, cc + add len, len, tmp1, lsr 3 + ret + + /* The inner loop processes 32 bytes per iteration and uses the fast + NUL check. If we encounter non-ASCII characters, use a second + loop with the accurate NUL check. */ + .p2align 4 +L(main_loop_entry): + bic src, srcin, 15 + sub src, src, 16 +L(main_loop): + ldp data1, data2, [src, 32]! +.Lpage_cross_entry: + sub tmp1, data1, zeroones + sub tmp3, data2, zeroones + orr tmp2, tmp1, tmp3 + tst tmp2, zeroones, lsl 7 + bne 1f + ldp data1, data2, [src, 16] + sub tmp1, data1, zeroones + sub tmp3, data2, zeroones + orr tmp2, tmp1, tmp3 + tst tmp2, zeroones, lsl 7 + beq L(main_loop) + add src, src, 16 +1: + /* The fast check failed, so do the slower, accurate NUL check. */ + orr tmp2, data1, REP8_7f + orr tmp4, data2, REP8_7f + bics has_nul1, tmp1, tmp2 + bic has_nul2, tmp3, tmp4 + ccmp has_nul2, 0, 0, eq + beq L(nonascii_loop) + + /* Enter with C = has_nul1 == 0. */ +L(tail): +#ifdef __AARCH64EB__ + /* For big-endian, carry propagation (if the final byte in the + string is 0x01) means we cannot use has_nul1/2 directly. The + easiest way to get the correct byte is to byte-swap the data + and calculate the syndrome a second time. */ + csel data1, data1, data2, cc + rev data1, data1 + sub tmp1, data1, zeroones + orr tmp2, data1, REP8_7f + bic has_nul1, tmp1, tmp2 +#else + csel has_nul1, has_nul1, has_nul2, cc +#endif + sub len, src, srcin + rev has_nul1, has_nul1 + add tmp2, len, 8 + clz tmp1, has_nul1 + csel len, len, tmp2, cc + add len, len, tmp1, lsr 3 + ret + +L(nonascii_loop): + ldp data1, data2, [src, 16]! + sub tmp1, data1, zeroones + orr tmp2, data1, REP8_7f + sub tmp3, data2, zeroones + orr tmp4, data2, REP8_7f + bics has_nul1, tmp1, tmp2 + bic has_nul2, tmp3, tmp4 + ccmp has_nul2, 0, 0, eq + bne L(tail) + ldp data1, data2, [src, 16]! + sub tmp1, data1, zeroones + orr tmp2, data1, REP8_7f + sub tmp3, data2, zeroones + orr tmp4, data2, REP8_7f + bics has_nul1, tmp1, tmp2 + bic has_nul2, tmp3, tmp4 + ccmp has_nul2, 0, 0, eq + beq L(nonascii_loop) + b L(tail) + + /* Load 16 bytes from [srcin & ~15] and force the bytes that precede + srcin to 0x7f, so we ignore any NUL bytes before the string. + Then continue in the aligned loop. */ +L(page_cross): + bic src, srcin, 15 + ldp data1, data2, [src] + lsl tmp1, srcin, 3 + mov tmp4, -1 +#ifdef __AARCH64EB__ + /* Big-endian. Early bytes are at MSB. */ + lsr tmp1, tmp4, tmp1 /* Shift (tmp1 & 63). */ +#else + /* Little-endian. Early bytes are at LSB. */ + lsl tmp1, tmp4, tmp1 /* Shift (tmp1 & 63). */ +#endif + orr tmp1, tmp1, REP8_80 + orn data1, data1, tmp1 + orn tmp2, data2, tmp1 + tst srcin, 8 + csel data1, data1, tmp4, eq + csel data2, data2, tmp2, eq + b L(page_cross_entry) + +END(strlen_default) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/strncmp.S b/aosp/bionic/libc/arch-arm64/default/bionic/strncmp.S new file mode 100644 index 000000000..5432b738e --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/strncmp.S @@ -0,0 +1,280 @@ +/* Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + */ + +#include + +#define REP8_01 0x0101010101010101 +#define REP8_7f 0x7f7f7f7f7f7f7f7f +#define REP8_80 0x8080808080808080 + +/* Parameters and result. */ +#define src1 x0 +#define src2 x1 +#define limit x2 +#define result x0 + +/* Internal variables. */ +#define data1 x3 +#define data1w w3 +#define data2 x4 +#define data2w w4 +#define has_nul x5 +#define diff x6 +#define syndrome x7 +#define tmp1 x8 +#define tmp2 x9 +#define tmp3 x10 +#define zeroones x11 +#define pos x12 +#define limit_wd x13 +#define mask x14 +#define endloop x15 +#define count mask + + .text + .p2align 6 + .rep 7 + nop /* Pad so that the loop below fits a cache line. */ + .endr +ENTRY(strncmp_default) + cbz limit, .Lret0 + eor tmp1, src1, src2 + mov zeroones, #REP8_01 + tst tmp1, #7 + and count, src1, #7 + b.ne .Lmisaligned8 + cbnz count, .Lmutual_align + /* Calculate the number of full and partial words -1. */ + sub limit_wd, limit, #1 /* limit != 0, so no underflow. */ + lsr limit_wd, limit_wd, #3 /* Convert to Dwords. */ + + /* NUL detection works on the principle that (X - 1) & (~X) & 0x80 + (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and + can be done in parallel across the entire word. */ + /* Start of performance-critical section -- one 64B cache line. */ +.Lloop_aligned: + ldr data1, [src1], #8 + ldr data2, [src2], #8 +.Lstart_realigned: + subs limit_wd, limit_wd, #1 + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + eor diff, data1, data2 /* Non-zero if differences found. */ + csinv endloop, diff, xzr, pl /* Last Dword or differences. */ + bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ + ccmp endloop, #0, #0, eq + b.eq .Lloop_aligned + /* End of performance-critical section -- one 64B cache line. */ + + /* Not reached the limit, must have found the end or a diff. */ + tbz limit_wd, #63, .Lnot_limit + + /* Limit % 8 == 0 => all bytes significant. */ + ands limit, limit, #7 + b.eq .Lnot_limit + + lsl limit, limit, #3 /* Bits -> bytes. */ + mov mask, #~0 +#ifdef __AARCH64EB__ + lsr mask, mask, limit +#else + lsl mask, mask, limit +#endif + bic data1, data1, mask + bic data2, data2, mask + + /* Make sure that the NUL byte is marked in the syndrome. */ + orr has_nul, has_nul, mask + +.Lnot_limit: + orr syndrome, diff, has_nul + +#ifndef __AARCH64EB__ + rev syndrome, syndrome + rev data1, data1 + /* The MS-non-zero bit of the syndrome marks either the first bit + that is different, or the top bit of the first zero byte. + Shifting left now will bring the critical information into the + top bits. */ + clz pos, syndrome + rev data2, data2 + lsl data1, data1, pos + lsl data2, data2, pos + /* But we need to zero-extend (char is unsigned) the value and then + perform a signed 32-bit subtraction. */ + lsr data1, data1, #56 + sub result, data1, data2, lsr #56 + ret +#else + /* For big-endian we cannot use the trick with the syndrome value + as carry-propagation can corrupt the upper bits if the trailing + bytes in the string contain 0x01. */ + /* However, if there is no NUL byte in the dword, we can generate + the result directly. We can't just subtract the bytes as the + MSB might be significant. */ + cbnz has_nul, 1f + cmp data1, data2 + cset result, ne + cneg result, result, lo + ret +1: + /* Re-compute the NUL-byte detection, using a byte-reversed value. */ + rev tmp3, data1 + sub tmp1, tmp3, zeroones + orr tmp2, tmp3, #REP8_7f + bic has_nul, tmp1, tmp2 + rev has_nul, has_nul + orr syndrome, diff, has_nul + clz pos, syndrome + /* The MS-non-zero bit of the syndrome marks either the first bit + that is different, or the top bit of the first zero byte. + Shifting left now will bring the critical information into the + top bits. */ + lsl data1, data1, pos + lsl data2, data2, pos + /* But we need to zero-extend (char is unsigned) the value and then + perform a signed 32-bit subtraction. */ + lsr data1, data1, #56 + sub result, data1, data2, lsr #56 + ret +#endif + +.Lmutual_align: + /* Sources are mutually aligned, but are not currently at an + alignment boundary. Round down the addresses and then mask off + the bytes that precede the start point. + We also need to adjust the limit calculations, but without + overflowing if the limit is near ULONG_MAX. */ + bic src1, src1, #7 + bic src2, src2, #7 + ldr data1, [src1], #8 + neg tmp3, count, lsl #3 /* 64 - bits(bytes beyond align). */ + ldr data2, [src2], #8 + mov tmp2, #~0 + sub limit_wd, limit, #1 /* limit != 0, so no underflow. */ +#ifdef __AARCH64EB__ + /* Big-endian. Early bytes are at MSB. */ + lsl tmp2, tmp2, tmp3 /* Shift (count & 63). */ +#else + /* Little-endian. Early bytes are at LSB. */ + lsr tmp2, tmp2, tmp3 /* Shift (count & 63). */ +#endif + and tmp3, limit_wd, #7 + lsr limit_wd, limit_wd, #3 + /* Adjust the limit. Only low 3 bits used, so overflow irrelevant. */ + add limit, limit, count + add tmp3, tmp3, count + orr data1, data1, tmp2 + orr data2, data2, tmp2 + add limit_wd, limit_wd, tmp3, lsr #3 + b .Lstart_realigned + + .p2align 6 + /* Don't bother with dwords for up to 16 bytes. */ +.Lmisaligned8: + cmp limit, #16 + b.hs .Ltry_misaligned_words + +.Lbyte_loop: + /* Perhaps we can do better than this. */ + ldrb data1w, [src1], #1 + ldrb data2w, [src2], #1 + subs limit, limit, #1 + ccmp data1w, #1, #0, hi /* NZCV = 0b0000. */ + ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ + b.eq .Lbyte_loop +.Ldone: + sub result, data1, data2 + ret + /* Align the SRC1 to a dword by doing a bytewise compare and then do + the dword loop. */ +.Ltry_misaligned_words: + lsr limit_wd, limit, #3 + cbz count, .Ldo_misaligned + + neg count, count + and count, count, #7 + sub limit, limit, count + lsr limit_wd, limit, #3 + +.Lpage_end_loop: + ldrb data1w, [src1], #1 + ldrb data2w, [src2], #1 + cmp data1w, #1 + ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ + b.ne .Ldone + subs count, count, #1 + b.hi .Lpage_end_loop + +.Ldo_misaligned: + /* Prepare ourselves for the next page crossing. Unlike the aligned + loop, we fetch 1 less dword because we risk crossing bounds on + SRC2. */ + mov count, #8 + subs limit_wd, limit_wd, #1 + b.lo .Ldone_loop +.Lloop_misaligned: + and tmp2, src2, #0xff8 + eor tmp2, tmp2, #0xff8 + cbz tmp2, .Lpage_end_loop + + ldr data1, [src1], #8 + ldr data2, [src2], #8 + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + eor diff, data1, data2 /* Non-zero if differences found. */ + bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ + ccmp diff, #0, #0, eq + b.ne .Lnot_limit + subs limit_wd, limit_wd, #1 + b.pl .Lloop_misaligned + +.Ldone_loop: + /* We found a difference or a NULL before the limit was reached. */ + and limit, limit, #7 + cbz limit, .Lnot_limit + /* Read the last word. */ + sub src1, src1, 8 + sub src2, src2, 8 + ldr data1, [src1, limit] + ldr data2, [src2, limit] + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + eor diff, data1, data2 /* Non-zero if differences found. */ + bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ + ccmp diff, #0, #0, eq + b.ne .Lnot_limit + +.Lret0: + mov result, #0 + ret +END(strncmp_default) diff --git a/aosp/bionic/libc/arch-arm64/default/bionic/strnlen.S b/aosp/bionic/libc/arch-arm64/default/bionic/strnlen.S new file mode 100644 index 000000000..169453207 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/default/bionic/strnlen.S @@ -0,0 +1,174 @@ +/* Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + */ + +#include + +/* Arguments and results. */ +#define srcin x0 +#define len x0 +#define limit x1 + +/* Locals and temporaries. */ +#define src x2 +#define data1 x3 +#define data2 x4 +#define data2a x5 +#define has_nul1 x6 +#define has_nul2 x7 +#define tmp1 x8 +#define tmp2 x9 +#define tmp3 x10 +#define tmp4 x11 +#define zeroones x12 +#define pos x13 +#define limit_wd x14 + +#define REP8_01 0x0101010101010101 +#define REP8_7f 0x7f7f7f7f7f7f7f7f +#define REP8_80 0x8080808080808080 + + .text + .p2align 6 +.Lstart: + /* Pre-pad to ensure critical loop begins an icache line. */ + .rep 7 + nop + .endr + /* Put this code here to avoid wasting more space with pre-padding. */ +.Lhit_limit: + mov len, limit + ret + +ENTRY(strnlen_default) + cbz limit, .Lhit_limit + mov zeroones, #REP8_01 + bic src, srcin, #15 + ands tmp1, srcin, #15 + b.ne .Lmisaligned + /* Calculate the number of full and partial words -1. */ + sub limit_wd, limit, #1 /* Limit != 0, so no underflow. */ + lsr limit_wd, limit_wd, #4 /* Convert to Qwords. */ + + /* NUL detection works on the principle that (X - 1) & (~X) & 0x80 + (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and + can be done in parallel across the entire word. */ + /* The inner loop deals with two Dwords at a time. This has a + slightly higher start-up cost, but we should win quite quickly, + especially on cores with a high number of issue slots per + cycle, as we get much better parallelism out of the operations. */ + + /* Start of critial section -- keep to one 64Byte cache line. */ +.Lloop: + ldp data1, data2, [src], #16 +.Lrealigned: + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + sub tmp3, data2, zeroones + orr tmp4, data2, #REP8_7f + bic has_nul1, tmp1, tmp2 + bic has_nul2, tmp3, tmp4 + subs limit_wd, limit_wd, #1 + orr tmp1, has_nul1, has_nul2 + ccmp tmp1, #0, #0, pl /* NZCV = 0000 */ + b.eq .Lloop + /* End of critical section -- keep to one 64Byte cache line. */ + + orr tmp1, has_nul1, has_nul2 + cbz tmp1, .Lhit_limit /* No null in final Qword. */ + + /* We know there's a null in the final Qword. The easiest thing + to do now is work out the length of the string and return + MIN (len, limit). */ + + sub len, src, srcin + cbz has_nul1, .Lnul_in_data2 +#ifdef __AARCH64EB__ + mov data2, data1 +#endif + sub len, len, #8 + mov has_nul2, has_nul1 +.Lnul_in_data2: +#ifdef __AARCH64EB__ + /* For big-endian, carry propagation (if the final byte in the + string is 0x01) means we cannot use has_nul directly. The + easiest way to get the correct byte is to byte-swap the data + and calculate the syndrome a second time. */ + rev data2, data2 + sub tmp1, data2, zeroones + orr tmp2, data2, #REP8_7f + bic has_nul2, tmp1, tmp2 +#endif + sub len, len, #8 + rev has_nul2, has_nul2 + clz pos, has_nul2 + add len, len, pos, lsr #3 /* Bits to bytes. */ + cmp len, limit + csel len, len, limit, ls /* Return the lower value. */ + ret + +.Lmisaligned: + /* Deal with a partial first word. + We're doing two things in parallel here; + 1) Calculate the number of words (but avoiding overflow if + limit is near ULONG_MAX) - to do this we need to work out + limit + tmp1 - 1 as a 65-bit value before shifting it; + 2) Load and mask the initial data words - we force the bytes + before the ones we are interested in to 0xff - this ensures + early bytes will not hit any zero detection. */ + sub limit_wd, limit, #1 + neg tmp4, tmp1 + cmp tmp1, #8 + + and tmp3, limit_wd, #15 + lsr limit_wd, limit_wd, #4 + mov tmp2, #~0 + + ldp data1, data2, [src], #16 + lsl tmp4, tmp4, #3 /* Bytes beyond alignment -> bits. */ + add tmp3, tmp3, tmp1 + +#ifdef __AARCH64EB__ + /* Big-endian. Early bytes are at MSB. */ + lsl tmp2, tmp2, tmp4 /* Shift (tmp1 & 63). */ +#else + /* Little-endian. Early bytes are at LSB. */ + lsr tmp2, tmp2, tmp4 /* Shift (tmp1 & 63). */ +#endif + add limit_wd, limit_wd, tmp3, lsr #4 + + orr data1, data1, tmp2 + orr data2a, data2, tmp2 + + csinv data1, data1, xzr, le + csel data2, data2, data2a, le + b .Lrealigned +END(strnlen_default) diff --git a/aosp/bionic/libc/arch-arm64/dynamic_function_dispatch.cpp b/aosp/bionic/libc/arch-arm64/dynamic_function_dispatch.cpp new file mode 100644 index 000000000..37abea429 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/dynamic_function_dispatch.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include + +extern "C" { + +static bool supports_mte(unsigned long hwcap2) { +#ifdef ANDROID_EXPERIMENTAL_MTE + return hwcap2 & HWCAP2_MTE; +#else + (void)hwcap2; + return false; +#endif +} + +typedef void* memchr_func(const void*, int, size_t); +DEFINE_IFUNC_FOR(memchr) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(memchr_func, memchr_mte); + } else { + RETURN_FUNC(memchr_func, memchr_default); + } +} + +typedef char* strchr_func(const char*, int); +DEFINE_IFUNC_FOR(strchr) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(strchr_func, strchr_mte); + } else { + RETURN_FUNC(strchr_func, strchr_default); + } +} + +typedef int strcmp_func(const char*, const char*); +DEFINE_IFUNC_FOR(strcmp) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(strcmp_func, strcmp_mte); + } else { + RETURN_FUNC(strcmp_func, strcmp_default); + } +} + +typedef size_t strlen_func(const char*); +DEFINE_IFUNC_FOR(strlen) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(strlen_func, strlen_mte); + } else { + RETURN_FUNC(strlen_func, strlen_default); + } +} + +typedef int strncmp_func(const char*, const char*, int); +DEFINE_IFUNC_FOR(strncmp) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(strncmp_func, strncmp_mte); + } else { + RETURN_FUNC(strncmp_func, strncmp_default); + } +} + +typedef size_t strnlen_func(const char*, int); +DEFINE_IFUNC_FOR(strnlen) { + if (supports_mte(arg->_hwcap2)) { + RETURN_FUNC(strnlen_func, strnlen_mte); + } else { + RETURN_FUNC(strnlen_func, strnlen_default); + } +} + +} // extern "C" diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/__memcpy_chk.S b/aosp/bionic/libc/arch-arm64/generic/bionic/__memcpy_chk.S new file mode 100644 index 000000000..a6eeca477 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/__memcpy_chk.S @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 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 + +ENTRY(__memcpy_chk) + cmp x2, x3 + // Direct b.ls memcpy may not have enough range + b.hi .L_memcpy_chk_fail + b memcpy + +.L_memcpy_chk_fail: + // Preserve for accurate backtrace. + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + + bl __memcpy_chk_fail +END(__memcpy_chk) diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/memcmp.S b/aosp/bionic/libc/arch-arm64/generic/bionic/memcmp.S new file mode 100644 index 000000000..bff54aea3 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/memcmp.S @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2017 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses. + */ + +#include + +#define L(l) .L ## l + +/* Parameters and result. */ +#define src1 x0 +#define src2 x1 +#define limit x2 +#define result w0 + +/* Internal variables. */ +#define data1 x3 +#define data1w w3 +#define data1h x4 +#define data2 x5 +#define data2w w5 +#define data2h x6 +#define tmp1 x7 +#define tmp2 x8 + +/* Small inputs of less than 8 bytes are handled separately. This allows the + main code to be speed up using unaligned loads since there are now at least + 8 bytes to be compared. If the first 8 bytes are equal, align src1. + This ensures each iteration does at most one unaligned access even if both + src1 and src2 are unaligned, and mutually aligned inputs behave as if + aligned. After the main loop, process the last 16 bytes using unaligned + accesses. */ + +ENTRY(memcmp) +.p2align 6 + subs limit, limit, 8 + b.lo L(less8) + + /* Limit >= 8, so check first 8 bytes using unaligned loads. */ + ldr data1, [src1], 8 + ldr data2, [src2], 8 + cmp data1, data2 + b.ne L(return) + + subs limit, limit, 8 + b.gt L(more16) + + ldr data1, [src1, limit] + ldr data2, [src2, limit] + b L(return) + +L(more16): + ldr data1, [src1], 8 + ldr data2, [src2], 8 + cmp data1, data2 + bne L(return) + + /* Jump directly to comparing the last 16 bytes for 32 byte (or less) + strings. */ + subs limit, limit, 16 + b.ls L(last_bytes) + + /* We overlap loads between 0-32 bytes at either side of SRC1 when we + try to align, so limit it only to strings larger than 128 bytes. */ + cmp limit, 96 + b.ls L(loop16) + + /* Align src1 and adjust src2 with bytes not yet done. */ + and tmp1, src1, 15 + add limit, limit, tmp1 + sub src1, src1, tmp1 + sub src2, src2, tmp1 + + /* Loop performing 16 bytes per iteration using aligned src1. + Limit is pre-decremented by 16 and must be larger than zero. + Exit if <= 16 bytes left to do or if the data is not equal. */ + .p2align 4 +L(loop16): + ldp data1, data1h, [src1], 16 + ldp data2, data2h, [src2], 16 + subs limit, limit, 16 + ccmp data1, data2, 0, hi + ccmp data1h, data2h, 0, eq + b.eq L(loop16) + + cmp data1, data2 + bne L(return) + mov data1, data1h + mov data2, data2h + cmp data1, data2 + bne L(return) + + /* Compare last 1-16 bytes using unaligned access. */ +L(last_bytes): + add src1, src1, limit + add src2, src2, limit + ldp data1, data1h, [src1] + ldp data2, data2h, [src2] + cmp data1, data2 + bne L(return) + mov data1, data1h + mov data2, data2h + cmp data1, data2 + + /* Compare data bytes and set return value to 0, -1 or 1. */ +L(return): +#ifndef __AARCH64EB__ + rev data1, data1 + rev data2, data2 +#endif + cmp data1, data2 +L(ret_eq): + cset result, ne + cneg result, result, lo + ret + + .p2align 4 + /* Compare up to 8 bytes. Limit is [-8..-1]. */ +L(less8): + adds limit, limit, 4 + b.lo L(less4) + ldr data1w, [src1], 4 + ldr data2w, [src2], 4 + cmp data1w, data2w + b.ne L(return) + sub limit, limit, 4 +L(less4): + adds limit, limit, 4 + beq L(ret_eq) +L(byte_loop): + ldrb data1w, [src1], 1 + ldrb data2w, [src2], 1 + subs limit, limit, 1 + ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */ + b.eq L(byte_loop) + sub result, data1w, data2w + ret + +END(memcmp) diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy.S b/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy.S new file mode 100644 index 000000000..baadb9204 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy.S @@ -0,0 +1,35 @@ +/* + * 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. + */ + +// Prototype: void *memcpy (void *dst, const void *src, size_t count). + +#include + +ENTRY(__memcpy) + #include "memcpy_base.S" +END(__memcpy) diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy_base.S b/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy_base.S new file mode 100644 index 000000000..f85062408 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/memcpy_base.S @@ -0,0 +1,217 @@ +/* Copyright (c) 2012-2013, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. */ + +/* + * Copyright (c) 2015 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses. + * + */ + +#include + +#define dstin x0 +#define src x1 +#define count x2 +#define dst x3 +#define srcend x4 +#define dstend x5 +#define A_l x6 +#define A_lw w6 +#define A_h x7 +#define A_hw w7 +#define B_l x8 +#define B_lw w8 +#define B_h x9 +#define C_l x10 +#define C_h x11 +#define D_l x12 +#define D_h x13 +#define E_l src +#define E_h count +#define F_l srcend +#define F_h dst +#define tmp1 x9 + +#define L(l) .L ## l + +/* Copies are split into 3 main cases: small copies of up to 16 bytes, + medium copies of 17..96 bytes which are fully unrolled. Large copies + of more than 96 bytes align the destination and use an unrolled loop + processing 64 bytes per iteration. + Small and medium copies read all data before writing, allowing any + kind of overlap, and memmove tailcalls memcpy for these cases as + well as non-overlapping copies. +*/ + + prfm PLDL1KEEP, [src] + add srcend, src, count + add dstend, dstin, count + cmp count, 16 + b.ls L(copy16) + cmp count, 96 + b.hi L(copy_long) + + /* Medium copies: 17..96 bytes. */ + sub tmp1, count, 1 + ldp A_l, A_h, [src] + tbnz tmp1, 6, L(copy96) + ldp D_l, D_h, [srcend, -16] + tbz tmp1, 5, 1f + ldp B_l, B_h, [src, 16] + ldp C_l, C_h, [srcend, -32] + stp B_l, B_h, [dstin, 16] + stp C_l, C_h, [dstend, -32] +1: + stp A_l, A_h, [dstin] + stp D_l, D_h, [dstend, -16] + ret + + .p2align 4 + + /* Small copies: 0..16 bytes. */ +L(copy16): + cmp count, 8 + b.lo 1f + ldr A_l, [src] + ldr A_h, [srcend, -8] + str A_l, [dstin] + str A_h, [dstend, -8] + ret + .p2align 4 +1: + tbz count, 2, 1f + ldr A_lw, [src] + ldr A_hw, [srcend, -4] + str A_lw, [dstin] + str A_hw, [dstend, -4] + ret + + /* Copy 0..3 bytes. Use a branchless sequence that copies the same + byte 3 times if count==1, or the 2nd byte twice if count==2. */ +1: + cbz count, 2f + lsr tmp1, count, 1 + ldrb A_lw, [src] + ldrb A_hw, [srcend, -1] + ldrb B_lw, [src, tmp1] + strb A_lw, [dstin] + strb B_lw, [dstin, tmp1] + strb A_hw, [dstend, -1] +2: ret + + .p2align 4 + /* Copy 64..96 bytes. Copy 64 bytes from the start and + 32 bytes from the end. */ +L(copy96): + ldp B_l, B_h, [src, 16] + ldp C_l, C_h, [src, 32] + ldp D_l, D_h, [src, 48] + ldp E_l, E_h, [srcend, -32] + ldp F_l, F_h, [srcend, -16] + stp A_l, A_h, [dstin] + stp B_l, B_h, [dstin, 16] + stp C_l, C_h, [dstin, 32] + stp D_l, D_h, [dstin, 48] + stp E_l, E_h, [dstend, -32] + stp F_l, F_h, [dstend, -16] + ret + + /* Align DST to 16 byte alignment so that we don't cross cache line + boundaries on both loads and stores. There are at least 96 bytes + to copy, so copy 16 bytes unaligned and then align. The loop + copies 64 bytes per iteration and prefetches one iteration ahead. */ + + .p2align 4 +L(copy_long): + and tmp1, dstin, 15 + bic dst, dstin, 15 + ldp D_l, D_h, [src] + sub src, src, tmp1 + add count, count, tmp1 /* Count is now 16 too large. */ + ldp A_l, A_h, [src, 16] + stp D_l, D_h, [dstin] + ldp B_l, B_h, [src, 32] + ldp C_l, C_h, [src, 48] + ldp D_l, D_h, [src, 64]! + subs count, count, 128 + 16 /* Test and readjust count. */ + b.ls 2f +1: + stp A_l, A_h, [dst, 16] + ldp A_l, A_h, [src, 16] + stp B_l, B_h, [dst, 32] + ldp B_l, B_h, [src, 32] + stp C_l, C_h, [dst, 48] + ldp C_l, C_h, [src, 48] + stp D_l, D_h, [dst, 64]! + ldp D_l, D_h, [src, 64]! + subs count, count, 64 + b.hi 1b + + /* Write the last full set of 64 bytes. The remainder is at most 64 + bytes, so it is safe to always copy 64 bytes from the end even if + there is just 1 byte left. */ +2: + ldp E_l, E_h, [srcend, -64] + stp A_l, A_h, [dst, 16] + ldp A_l, A_h, [srcend, -48] + stp B_l, B_h, [dst, 32] + ldp B_l, B_h, [srcend, -32] + stp C_l, C_h, [dst, 48] + ldp C_l, C_h, [srcend, -16] + stp D_l, D_h, [dst, 64] + stp E_l, E_h, [dstend, -64] + stp A_l, A_h, [dstend, -48] + stp B_l, B_h, [dstend, -32] + stp C_l, C_h, [dstend, -16] + ret diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/memmove.S b/aosp/bionic/libc/arch-arm64/generic/bionic/memmove.S new file mode 100644 index 000000000..335b7d6ce --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/memmove.S @@ -0,0 +1,155 @@ +/* Copyright (c) 2013, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. */ + +/* + * Copyright (c) 2015 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses, wchar_t is 4 bytes + */ + +#include + +/* Parameters and result. */ +#define dstin x0 +#define src x1 +#define count x2 +#define srcend x3 +#define dstend x4 +#define tmp1 x5 +#define A_l x6 +#define A_h x7 +#define B_l x8 +#define B_h x9 +#define C_l x10 +#define C_h x11 +#define D_l x12 +#define D_h x13 +#define E_l count +#define E_h tmp1 + +/* All memmoves up to 96 bytes are done by memcpy as it supports overlaps. + Larger backwards copies are also handled by memcpy. The only remaining + case is forward large copies. The destination is aligned, and an + unrolled loop processes 64 bytes per iteration. +*/ + +#if defined(WMEMMOVE) +ENTRY(wmemmove) + lsl count, count, #2 +#else +ENTRY(memmove) +#endif + sub tmp1, dstin, src + cmp count, 96 + ccmp tmp1, count, 2, hi + b.hs __memcpy + + cbz tmp1, 3f + add dstend, dstin, count + add srcend, src, count + + /* Align dstend to 16 byte alignment so that we don't cross cache line + boundaries on both loads and stores. There are at least 96 bytes + to copy, so copy 16 bytes unaligned and then align. The loop + copies 64 bytes per iteration and prefetches one iteration ahead. */ + + and tmp1, dstend, 15 + ldp D_l, D_h, [srcend, -16] + sub srcend, srcend, tmp1 + sub count, count, tmp1 + ldp A_l, A_h, [srcend, -16] + stp D_l, D_h, [dstend, -16] + ldp B_l, B_h, [srcend, -32] + ldp C_l, C_h, [srcend, -48] + ldp D_l, D_h, [srcend, -64]! + sub dstend, dstend, tmp1 + subs count, count, 128 + b.ls 2f + nop +1: + stp A_l, A_h, [dstend, -16] + ldp A_l, A_h, [srcend, -16] + stp B_l, B_h, [dstend, -32] + ldp B_l, B_h, [srcend, -32] + stp C_l, C_h, [dstend, -48] + ldp C_l, C_h, [srcend, -48] + stp D_l, D_h, [dstend, -64]! + ldp D_l, D_h, [srcend, -64]! + subs count, count, 64 + b.hi 1b + + /* Write the last full set of 64 bytes. The remainder is at most 64 + bytes, so it is safe to always copy 64 bytes from the start even if + there is just 1 byte left. */ +2: + ldp E_l, E_h, [src, 48] + stp A_l, A_h, [dstend, -16] + ldp A_l, A_h, [src, 32] + stp B_l, B_h, [dstend, -32] + ldp B_l, B_h, [src, 16] + stp C_l, C_h, [dstend, -48] + ldp C_l, C_h, [src] + stp D_l, D_h, [dstend, -64] + stp E_l, E_h, [dstin, 48] + stp A_l, A_h, [dstin, 32] + stp B_l, B_h, [dstin, 16] + stp C_l, C_h, [dstin] +3: ret + +#if defined(WMEMMOVE) +END(wmemmove) +#else +END(memmove) + +ALIAS_SYMBOL(memcpy, memmove) +#endif diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/memset.S b/aosp/bionic/libc/arch-arm64/generic/bionic/memset.S new file mode 100644 index 000000000..12fc09db8 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/memset.S @@ -0,0 +1,251 @@ +/* Copyright (c) 2012-2013, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. */ + +/* + * Copyright (c) 2015 ARM Ltd + * 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. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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. + */ + +/* Assumptions: + * + * ARMv8-a, AArch64, unaligned accesses + * + */ + +#include + +/* By default we assume that the DC instruction can be used to zero + data blocks more efficiently. In some circumstances this might be + unsafe, for example in an asymmetric multiprocessor environment with + different DC clear lengths (neither the upper nor lower lengths are + safe to use). + + If code may be run in a virtualized environment, then define + MAYBE_VIRT. This will cause the code to cache the system register + values rather than re-reading them each call. */ + +#define dstin x0 +#define val x1 +#define valw w1 +#define count x2 +#define dst x3 +#define dstend x4 +#define tmp1 x5 +#define tmp1w w5 +#define tmp2 x6 +#define tmp2w w6 +#define zva_len x7 +#define zva_lenw w7 + +#define L(l) .L ## l + +ENTRY(__memset_chk) + cmp count, dst + bls memset + + // Preserve for accurate backtrace. + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_rel_offset x29, 0 + .cfi_rel_offset x30, 8 + + bl __memset_chk_fail +END(__memset_chk) + +ENTRY(memset) + + dup v0.16B, valw + add dstend, dstin, count + + cmp count, 96 + b.hi L(set_long) + cmp count, 16 + b.hs L(set_medium) + mov val, v0.D[0] + + /* Set 0..15 bytes. */ + tbz count, 3, 1f + str val, [dstin] + str val, [dstend, -8] + ret + nop +1: tbz count, 2, 2f + str valw, [dstin] + str valw, [dstend, -4] + ret +2: cbz count, 3f + strb valw, [dstin] + tbz count, 1, 3f + strh valw, [dstend, -2] +3: ret + + /* Set 17..96 bytes. */ +L(set_medium): + str q0, [dstin] + tbnz count, 6, L(set96) + str q0, [dstend, -16] + tbz count, 5, 1f + str q0, [dstin, 16] + str q0, [dstend, -32] +1: ret + + .p2align 4 + /* Set 64..96 bytes. Write 64 bytes from the start and + 32 bytes from the end. */ +L(set96): + str q0, [dstin, 16] + stp q0, q0, [dstin, 32] + stp q0, q0, [dstend, -32] + ret + + .p2align 3 + nop +L(set_long): + and valw, valw, 255 + bic dst, dstin, 15 + str q0, [dstin] + cmp count, 256 + ccmp valw, 0, 0, cs + b.eq L(try_zva) +L(no_zva): + sub count, dstend, dst /* Count is 16 too large. */ + add dst, dst, 16 + sub count, count, 64 + 16 /* Adjust count and bias for loop. */ +1: stp q0, q0, [dst], 64 + stp q0, q0, [dst, -32] +L(tail64): + subs count, count, 64 + b.hi 1b +2: stp q0, q0, [dstend, -64] + stp q0, q0, [dstend, -32] + ret + + .p2align 3 +L(try_zva): + mrs tmp1, dczid_el0 + tbnz tmp1w, 4, L(no_zva) + and tmp1w, tmp1w, 15 + cmp tmp1w, 4 /* ZVA size is 64 bytes. */ + b.ne L(zva_128) + + /* Write the first and last 64 byte aligned block using stp rather + than using DC ZVA. This is faster on some cores. + */ +L(zva_64): + str q0, [dst, 16] + stp q0, q0, [dst, 32] + bic dst, dst, 63 + stp q0, q0, [dst, 64] + stp q0, q0, [dst, 96] + sub count, dstend, dst /* Count is now 128 too large. */ + sub count, count, 128+64+64 /* Adjust count and bias for loop. */ + add dst, dst, 128 + nop +1: dc zva, dst + add dst, dst, 64 + subs count, count, 64 + b.hi 1b + stp q0, q0, [dst, 0] + stp q0, q0, [dst, 32] + stp q0, q0, [dstend, -64] + stp q0, q0, [dstend, -32] + ret + + .p2align 3 +L(zva_128): + cmp tmp1w, 5 /* ZVA size is 128 bytes. */ + b.ne L(zva_other) + + str q0, [dst, 16] + stp q0, q0, [dst, 32] + stp q0, q0, [dst, 64] + stp q0, q0, [dst, 96] + bic dst, dst, 127 + sub count, dstend, dst /* Count is now 128 too large. */ + sub count, count, 128+128 /* Adjust count and bias for loop. */ + add dst, dst, 128 +1: dc zva, dst + add dst, dst, 128 + subs count, count, 128 + b.hi 1b + stp q0, q0, [dstend, -128] + stp q0, q0, [dstend, -96] + stp q0, q0, [dstend, -64] + stp q0, q0, [dstend, -32] + ret + +L(zva_other): + mov tmp2w, 4 + lsl zva_lenw, tmp2w, tmp1w + add tmp1, zva_len, 64 /* Max alignment bytes written. */ + cmp count, tmp1 + blo L(no_zva) + + sub tmp2, zva_len, 1 + add tmp1, dst, zva_len + add dst, dst, 16 + subs count, tmp1, dst /* Actual alignment bytes to write. */ + bic tmp1, tmp1, tmp2 /* Aligned dc zva start address. */ + beq 2f +1: stp q0, q0, [dst], 64 + stp q0, q0, [dst, -32] + subs count, count, 64 + b.hi 1b +2: mov dst, tmp1 + sub count, dstend, tmp1 /* Remaining bytes to write. */ + subs count, count, zva_len + b.lo 4f +3: dc zva, dst + add dst, dst, zva_len + subs count, count, zva_len + b.hs 3b +4: add count, count, zva_len + b L(tail64) + +END(memset) diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/stpcpy.S b/aosp/bionic/libc/arch-arm64/generic/bionic/stpcpy.S new file mode 100644 index 000000000..e4a799387 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/stpcpy.S @@ -0,0 +1,29 @@ +/* + * 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. + */ +#define STPCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/strcpy.S b/aosp/bionic/libc/arch-arm64/generic/bionic/strcpy.S new file mode 100644 index 000000000..260c32138 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/strcpy.S @@ -0,0 +1,29 @@ +/* + * 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. + */ +#define STRCPY +#include "string_copy.S" diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/string_copy.S b/aosp/bionic/libc/arch-arm64/generic/bionic/string_copy.S new file mode 100644 index 000000000..2bf969d60 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/string_copy.S @@ -0,0 +1,245 @@ +/* + * 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. + */ + +/* + Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + */ + +#if !defined(STPCPY) && !defined(STRCPY) +#error "Either STPCPY or STRCPY must be defined." +#endif + +#include + +/* Arguments and results. */ +#if defined(STPCPY) +#define dst x0 +#elif defined(STRCPY) +#define dstin x0 +#endif +#define src x1 + +/* Locals and temporaries. */ +#if defined(STRCPY) +#define dst x2 +#endif +#define data1 x3 +#define data1_w w3 +#define data2 x4 +#define data2_w w4 +#define has_nul1 x5 +#define has_nul1_w w5 +#define has_nul2 x6 +#define tmp1 x7 +#define tmp2 x8 +#define tmp3 x9 +#define tmp4 x10 +#define zeroones x11 +#define zeroones_w w11 +#define pos x12 + +#define REP8_01 0x0101010101010101 +#define REP8_7f 0x7f7f7f7f7f7f7f7f +#define REP8_80 0x8080808080808080 + +#if defined(STPCPY) +ENTRY(stpcpy) +#elif defined(STRCPY) +ENTRY(strcpy) +#endif + mov zeroones, #REP8_01 +#if defined(STRCPY) + mov dst, dstin +#endif + ands tmp1, src, #15 + b.ne .Lmisaligned + // NUL detection works on the principle that (X - 1) & (~X) & 0x80 + // (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and + // can be done in parallel across the entire word. + // The inner loop deals with two Dwords at a time. This has a + // slightly higher start-up cost, but we should win quite quickly, + // especially on cores with a high number of issue slots per + // cycle, as we get much better parallelism out of the operations. +.Lloop: + ldp data1, data2, [src], #16 + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + bic has_nul1, tmp1, tmp2 + cbnz has_nul1, .Lnul_in_data1 + sub tmp3, data2, zeroones + orr tmp4, data2, #REP8_7f + bic has_nul2, tmp3, tmp4 + cbnz has_nul2, .Lnul_in_data2 + // No NUL in either register, copy it in a single instruction. + stp data1, data2, [dst], #16 + b .Lloop + +.Lnul_in_data1: + rev has_nul1, has_nul1 + clz pos, has_nul1 + add tmp1, pos, #0x8 + + tbz tmp1, #6, 1f +#if defined(STPCPY) + str data1, [dst], #7 +#elif defined(STRCPY) + str data1, [dst] +#endif + ret +1: + tbz tmp1, #5, 1f + str data1_w, [dst], #4 + lsr data1, data1, #32 +1: + tbz tmp1, #4, 1f + strh data1_w, [dst], #2 + lsr data1, data1, #16 +1: + tbz tmp1, #3, 1f + strb data1_w, [dst] +#if defined(STPCPY) + ret +#endif +1: +#if defined(STPCPY) + // Back up one so that dst points to the '\0' string terminator. + sub dst, dst, #1 +#endif + ret + +.Lnul_in_data2: + str data1, [dst], #8 + rev has_nul2, has_nul2 + clz pos, has_nul2 + add tmp1, pos, #0x8 + + tbz tmp1, #6, 1f +#if defined(STPCPY) + str data2, [dst], #7 +#elif defined(STRCPY) + str data2, [dst] +#endif + ret +1: + tbz tmp1, #5, 1f + str data2_w, [dst], #4 + lsr data2, data2, #32 +1: + tbz tmp1, #4, 1f + strh data2_w, [dst], #2 + lsr data2, data2, #16 +1: + tbz tmp1, #3, 1f + strb data2_w, [dst] +#if defined(STPCPY) + ret +#endif +1: +#if defined(STPCPY) + // Back up one so that dst points to the '\0' string terminator. + sub dst, dst, #1 +#endif + ret + +.Lmisaligned: + tbz src, #0, 1f + ldrb data1_w, [src], #1 + strb data1_w, [dst], #1 + cbnz data1_w, 1f +#if defined(STPCPY) + // Back up one so that dst points to the '\0' string terminator. + sub dst, dst, #1 +#endif + ret +1: + tbz src, #1, 1f + ldrb data1_w, [src], #1 + strb data1_w, [dst], #1 + cbz data1_w, .Ldone + ldrb data2_w, [src], #1 + strb data2_w, [dst], #1 + cbnz data2_w, 1f +.Ldone: +#if defined(STPCPY) + // Back up one so that dst points to the '\0' string terminator. + sub dst, dst, #1 +#endif + ret +1: + tbz src, #2, 1f + ldr data1_w, [src], #4 + // Check for a zero. + sub has_nul1_w, data1_w, zeroones_w + bic has_nul1_w, has_nul1_w, data1_w + ands has_nul1_w, has_nul1_w, #0x80808080 + b.ne .Lnul_in_data1 + str data1_w, [dst], #4 +1: + tbz src, #3, .Lloop + ldr data1, [src], #8 + // Check for a zero. + sub tmp1, data1, zeroones + orr tmp2, data1, #REP8_7f + bics has_nul1, tmp1, tmp2 + b.ne .Lnul_in_data1 + str data1, [dst], #8 + b .Lloop +#if defined(STPCPY) +END(stpcpy) +#elif defined(STRCPY) +END(strcpy) +#endif diff --git a/aosp/bionic/libc/arch-arm64/generic/bionic/wmemmove.S b/aosp/bionic/libc/arch-arm64/generic/bionic/wmemmove.S new file mode 100644 index 000000000..e4f67f759 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/generic/bionic/wmemmove.S @@ -0,0 +1,30 @@ +/* Copyright (c) 2014, Linaro Limited + 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. + * Neither the name of the Linaro 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 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 + HOLDER 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. +*/ + +#define WMEMMOVE +#include "memmove.S" +#undef WMEMMOVE diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/memchr.c b/aosp/bionic/libc/arch-arm64/mte/bionic/memchr.c new file mode 100644 index 000000000..33b2fc2c6 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/memchr.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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 + +#define memchr memchr_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/strchr.cpp b/aosp/bionic/libc/arch-arm64/mte/bionic/strchr.cpp new file mode 100644 index 000000000..7d394df0a --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/strchr.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 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. + */ + +#define strchr strchr_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/strcmp.c b/aosp/bionic/libc/arch-arm64/mte/bionic/strcmp.c new file mode 100644 index 000000000..0e134f025 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/strcmp.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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 + +#define strcmp strcmp_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/strlen.c b/aosp/bionic/libc/arch-arm64/mte/bionic/strlen.c new file mode 100644 index 000000000..de88320ce --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/strlen.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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 + +#define strlen strlen_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/strncmp.c b/aosp/bionic/libc/arch-arm64/mte/bionic/strncmp.c new file mode 100644 index 000000000..54d08e98e --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/strncmp.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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 + +#define strncmp strncmp_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/mte/bionic/strnlen.c b/aosp/bionic/libc/arch-arm64/mte/bionic/strnlen.c new file mode 100644 index 000000000..3dc251db3 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/mte/bionic/strnlen.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 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. + */ + +#define strnlen strnlen_mte +#include diff --git a/aosp/bionic/libc/arch-arm64/static_function_dispatch.S b/aosp/bionic/libc/arch-arm64/static_function_dispatch.S new file mode 100644 index 000000000..8e3a4c131 --- /dev/null +++ b/aosp/bionic/libc/arch-arm64/static_function_dispatch.S @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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 + +#define FUNCTION_DELEGATE(name, impl) \ +ENTRY(name); \ + b impl; \ +END(name) + +FUNCTION_DELEGATE(memchr, memchr_mte) +FUNCTION_DELEGATE(strchr, strchr_mte) +FUNCTION_DELEGATE(strcmp, strcmp_mte) +FUNCTION_DELEGATE(strlen, strlen_mte) +FUNCTION_DELEGATE(strncmp, strncmp_mte) +FUNCTION_DELEGATE(strnlen, strnlen_mte) diff --git a/aosp/bionic/libc/arch-common/bionic/__dso_handle.h b/aosp/bionic/libc/arch-common/bionic/__dso_handle.h new file mode 100644 index 000000000..fa4006025 --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/__dso_handle.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 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. + */ + + +#ifndef CRT_LEGACY_WORKAROUND +__attribute__((__visibility__("hidden"))) +#endif +void* __dso_handle = (void*) 0; diff --git a/aosp/bionic/libc/arch-common/bionic/__dso_handle_so.h b/aosp/bionic/libc/arch-common/bionic/__dso_handle_so.h new file mode 100644 index 000000000..2c0df7bc7 --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/__dso_handle_so.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * We would like __dso_handle to be: + * 1. A const so that if a DSO does not have any RW data, .data section can + * be omitted. + * 2. Of type void* so that no awkward type conversion is needed when + * &__dso_handle is passed to various functions, which all expect a void*. + * To achieve both, we do the following aliasing trick. + */ +static const void* const __dso_handle_const = &__dso_handle_const; +__attribute__((__visibility__("hidden"))) +__attribute__((alias("__dso_handle_const"))) extern void* __dso_handle; diff --git a/aosp/bionic/libc/arch-common/bionic/asm_multiarch.h b/aosp/bionic/libc/arch-common/bionic/asm_multiarch.h new file mode 100644 index 000000000..91cb8af4b --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/asm_multiarch.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifdef __LP64__ +# define ASM_PTR_SIZE(x) .quad x +# define ASM_ALIGN_TO_PTR_SIZE .balign 8 +#else +# define ASM_PTR_SIZE(x) .long x +# define ASM_ALIGN_TO_PTR_SIZE .balign 4 +#endif + diff --git a/aosp/bionic/libc/arch-common/bionic/atexit.h b/aosp/bionic/libc/arch-common/bionic/atexit.h new file mode 100644 index 000000000..90aa030ea --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/atexit.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 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 + +extern void* __dso_handle; + +extern int __cxa_atexit(void (*)(void*), void*, void*); + +__attribute__ ((visibility ("hidden"))) +void __atexit_handler_wrapper(void* func) { + if (func != NULL) { + (*(void (*)(void))func)(); + } +} + +__attribute__ ((visibility ("hidden"))) +int atexit(void (*func)(void)) { + return (__cxa_atexit(&__atexit_handler_wrapper, func, &__dso_handle)); +} diff --git a/aosp/bionic/libc/arch-common/bionic/crtbegin.c b/aosp/bionic/libc/arch-common/bionic/crtbegin.c new file mode 100644 index 000000000..b7043dcae --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/crtbegin.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 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 "../../bionic/libc_init_common.h" +#include +#include + +#define SECTION(name) __attribute__((__section__(name))) +SECTION(".preinit_array") void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1; +SECTION(".init_array") void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1; +SECTION(".fini_array") void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1; +#undef SECTION + +__used static void _start_main(void* raw_args) { + structors_array_t array; + array.preinit_array = &__PREINIT_ARRAY__; + array.init_array = &__INIT_ARRAY__; + array.fini_array = &__FINI_ARRAY__; + + __libc_init(raw_args, NULL, &main, &array); +} + +#define PRE ".text; .global _start; .type _start,%function; _start:" +#define POST "; .size _start, .-_start" + +#if defined(__aarch64__) +__asm__(PRE "mov x0,sp; b _start_main" POST); +#elif defined(__arm__) +__asm__(PRE "mov r0,sp; b _start_main" POST); +#elif defined(__i386__) +__asm__(PRE "movl %esp,%eax; andl $~0xf,%esp; subl $12,%esp; pushl %eax; calll _start_main" POST); +#elif defined(__x86_64__) +__asm__(PRE "movq %rsp,%rdi; andq $~0xf,%rsp; callq _start_main" POST); +#else +#error unsupported architecture +#endif + +#undef PRE +#undef POST + +// On arm32 and arm64, when targeting Q and up, overalign the TLS segment to +// (8 * sizeof(void*)), which reserves enough space between the thread pointer +// and the executable's TLS segment for Bionic's TLS slots. It has the side +// effect of placing a 0-sized TLS segment into Android executables that don't +// use TLS, but this should be harmless. +// +// To ensure that the .tdata input section isn't deleted (e.g. by +// --gc-sections), the .text input section (which contains _start) has a +// relocation to the .tdata input section. +#if __ANDROID_API__ >= 29 +#if defined(__arm__) +asm(" .section .tdata,\"awT\",%progbits\n" + " .p2align 5\n" + " .text\n" + " .reloc 0, R_ARM_NONE, .tdata\n"); +#elif defined(__aarch64__) +asm(" .section .tdata,\"awT\",@progbits\n" + " .p2align 6\n" + " .text\n" + " .reloc 0, R_AARCH64_NONE, .tdata\n"); +#endif +#endif + +#include "__dso_handle.h" +#include "atexit.h" +#include "pthread_atfork.h" +#ifdef __i386__ +# include "../../arch-x86/bionic/__stack_chk_fail_local.h" +#endif diff --git a/aosp/bionic/libc/arch-common/bionic/crtbegin_so.c b/aosp/bionic/libc/arch-common/bionic/crtbegin_so.c new file mode 100644 index 000000000..cf369cc82 --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/crtbegin_so.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 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. + */ + +extern void __cxa_finalize(void *); +extern void *__dso_handle; + +__attribute__((destructor)) +static void __on_dlclose(void) { + __cxa_finalize(&__dso_handle); +} + +/* Define a weak stub function here that will be overridden if the solib uses + * emutls. The function needs to be a definition, not just a declaration, + * because gold has a bug where it outputs weak+hidden symbols into the .dynsym + * table. */ +__attribute__((weak,visibility("hidden"))) +void __emutls_unregister_key(void) { +} + +/* Use a priority of 0 to run after any ordinary destructor function. The + * priority setting moves the function towards the front of the .fini_array + * section. */ +__attribute__((destructor(0))) +static void __on_dlclose_late(void) { + __emutls_unregister_key(); +} + +/* CRT_LEGACY_WORKAROUND should only be defined when building + * this file as part of the platform's C library. + * + * The C library already defines a function named 'atexit()' + * for backwards compatibility with older NDK-generated binaries. + * + * For newer ones, 'atexit' is actually embedded in the C + * runtime objects that are linked into the final ELF + * binary (shared library or executable), and will call + * __cxa_atexit() in order to un-register any atexit() + * handler when a library is unloaded. + * + * This function must be global *and* hidden. Only the + * code inside the same ELF binary should be able to access it. + */ + +#ifdef CRT_LEGACY_WORKAROUND +# include "__dso_handle.h" +#else +# include "__dso_handle_so.h" +# include "atexit.h" +#endif +#include "pthread_atfork.h" +#ifdef __i386__ +# include "../../arch-x86/bionic/__stack_chk_fail_local.h" +#endif diff --git a/aosp/bionic/libc/arch-common/bionic/crtbrand.S b/aosp/bionic/libc/arch-common/bionic/crtbrand.S new file mode 100644 index 000000000..34d648062 --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/crtbrand.S @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 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. + */ + + .section .note.android.ident,"a",%note + .balign 4 + .type abitag, %object +abitag: + .long 2f-1f // int32_t namesz + .long 3f-2f // int32_t descsz + .long 1 // int32_t type +#ifdef __ANDROID__ +1:.ascii "Android\0" // char name[] +2:.long PLATFORM_SDK_VERSION // int32_t android_api +#else +1:.ascii "LinuxBionic\0" // char name[] +2: +#endif +3: + .size abitag, .-abitag diff --git a/aosp/bionic/libc/arch-common/bionic/crtend.S b/aosp/bionic/libc/arch-common/bionic/crtend.S new file mode 100644 index 000000000..87d1120ab --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/crtend.S @@ -0,0 +1,55 @@ +/* + * 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 "asm_multiarch.h" + + .section .preinit_array, "aw" + ASM_ALIGN_TO_PTR_SIZE + ASM_PTR_SIZE(0) + + .section .init_array, "aw" + ASM_ALIGN_TO_PTR_SIZE + ASM_PTR_SIZE(0) + + .section .fini_array, "aw" + ASM_ALIGN_TO_PTR_SIZE + ASM_PTR_SIZE(0) + +#if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits +#endif +#if defined(__i386__) || defined(__x86_64__) + .section .eh_frame,"a",@progbits +#if defined(__i386__) + .balign 4 +#endif + .type __FRAME_END__, @object + .size __FRAME_END__, 4 +__FRAME_END__: + .zero 4 +#endif diff --git a/aosp/bionic/libc/arch-common/bionic/crtend_so.S b/aosp/bionic/libc/arch-common/bionic/crtend_so.S new file mode 100644 index 000000000..e7b8cac3e --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/crtend_so.S @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits +#endif +#if defined(__i386__) || defined(__x86_64__) + .section .eh_frame,"a",@progbits +#if defined(__i386__) + .balign 4 +#endif + .type __FRAME_END__, @object + .size __FRAME_END__, 4 +__FRAME_END__: + .zero 4 +#endif diff --git a/aosp/bionic/libc/arch-common/bionic/pthread_atfork.h b/aosp/bionic/libc/arch-common/bionic/pthread_atfork.h new file mode 100644 index 000000000..02e383d31 --- /dev/null +++ b/aosp/bionic/libc/arch-common/bionic/pthread_atfork.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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 + +// __register_atfork wasn't available until android-23. When using libc.a, we're +// using the latest library regardless of target API level. +#if defined(_FORCE_CRT_ATFORK) || __ANDROID_API__ >= 23 + +extern void* __dso_handle; + +extern int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void), void* dso); + +#ifndef _LIBC +// Libc used to export this in previous versions, therefore it needs +// to remain global for binary compatibility. +__attribute__ ((visibility ("hidden"))) +#endif +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { + return __register_atfork(prepare, parent, child, &__dso_handle); +} + +#endif diff --git a/aosp/bionic/libc/arch-x86/atom/string/cache.h b/aosp/bionic/libc/arch-x86/atom/string/cache.h new file mode 100644 index 000000000..823bb1e39 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/cache.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +/* Values are optimized for Atom */ +#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */ + +#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) +#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-memchr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-memchr-atom.S new file mode 100644 index 000000000..013af9b66 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-memchr-atom.S @@ -0,0 +1,556 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define ENTRANCE PUSH (%edi); +#define PARMS 8 +#define RETURN POP (%edi); ret; CFI_PUSH (%edi); + +#define STR1 PARMS +#define STR2 STR1+4 +#define LEN STR2+4 + + .text +ENTRY (memchr) + ENTRANCE + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + mov LEN(%esp), %edx + test %edx, %edx + jz L(return_null) + + punpcklbw %xmm1, %xmm1 + mov %ecx, %edi + punpcklbw %xmm1, %xmm1 + + and $63, %ecx + pshufd $0, %xmm1, %xmm1 + cmp $48, %ecx + ja L(crosscache) + + movdqu (%edi), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(match_case2_prolog) + + sub $16, %edx + jbe L(return_null) + lea 16(%edi), %edi + and $15, %ecx + and $-16, %edi + add %ecx, %edx + sub $64, %edx + jbe L(exit_loop) + jmp L(loop_prolog) + + .p2align 4 +L(crosscache): + and $15, %ecx + and $-16, %edi + movdqa (%edi), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + sar %cl, %eax + test %eax, %eax + + jnz L(match_case2_prolog1) + lea -16(%edx), %edx + add %ecx, %edx + jle L(return_null) + lea 16(%edi), %edi + sub $64, %edx + jbe L(exit_loop) + + .p2align 4 +L(loop_prolog): + movdqa (%edi), %xmm0 + pcmpeqb %xmm1, %xmm0 + xor %ecx, %ecx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 16(%edi), %xmm2 + pcmpeqb %xmm1, %xmm2 + lea 16(%ecx), %ecx + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 32(%edi), %xmm3 + pcmpeqb %xmm1, %xmm3 + lea 16(%ecx), %ecx + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 48(%edi), %xmm4 + pcmpeqb %xmm1, %xmm4 + lea 16(%ecx), %ecx + pmovmskb %xmm4, %eax + test %eax, %eax + jnz L(match_case1) + + lea 64(%edi), %edi + sub $64, %edx + jbe L(exit_loop) + + movdqa (%edi), %xmm0 + pcmpeqb %xmm1, %xmm0 + xor %ecx, %ecx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 16(%edi), %xmm2 + pcmpeqb %xmm1, %xmm2 + lea 16(%ecx), %ecx + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 32(%edi), %xmm3 + pcmpeqb %xmm1, %xmm3 + lea 16(%ecx), %ecx + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(match_case1) + + movdqa 48(%edi), %xmm4 + pcmpeqb %xmm1, %xmm4 + lea 16(%ecx), %ecx + pmovmskb %xmm4, %eax + test %eax, %eax + jnz L(match_case1) + + lea 64(%edi), %edi + mov %edi, %ecx + and $-64, %edi + and $63, %ecx + add %ecx, %edx + + .p2align 4 +L(align64_loop): + sub $64, %edx + jbe L(exit_loop) + movdqa (%edi), %xmm0 + movdqa 16(%edi), %xmm2 + movdqa 32(%edi), %xmm3 + movdqa 48(%edi), %xmm4 + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm1, %xmm2 + pcmpeqb %xmm1, %xmm3 + pcmpeqb %xmm1, %xmm4 + + pmaxub %xmm0, %xmm3 + pmaxub %xmm2, %xmm4 + pmaxub %xmm3, %xmm4 + add $64, %edi + pmovmskb %xmm4, %eax + + test %eax, %eax + jz L(align64_loop) + + sub $64, %edi + + pmovmskb %xmm0, %eax + xor %ecx, %ecx + test %eax, %eax + jnz L(match_case1) + + pmovmskb %xmm2, %eax + lea 16(%ecx), %ecx + test %eax, %eax + jnz L(match_case1) + + movdqa 32(%edi), %xmm3 + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %eax + lea 16(%ecx), %ecx + test %eax, %eax + jnz L(match_case1) + + pcmpeqb 48(%edi), %xmm1 + pmovmskb %xmm1, %eax + lea 16(%ecx), %ecx + + .p2align 4 +L(match_case1): + add %ecx, %edi + test %al, %al + jz L(match_case1_high) + mov %al, %cl + and $15, %cl + jz L(match_case1_8) + test $0x01, %al + jnz L(exit_case1_1) + test $0x02, %al + jnz L(exit_case1_2) + test $0x04, %al + jnz L(exit_case1_3) + lea 3(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_8): + test $0x10, %al + jnz L(exit_case1_5) + test $0x20, %al + jnz L(exit_case1_6) + test $0x40, %al + jnz L(exit_case1_7) + lea 7(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_high): + mov %ah, %ch + and $15, %ch + jz L(match_case1_high_8) + test $0x01, %ah + jnz L(exit_case1_9) + test $0x02, %ah + jnz L(exit_case1_10) + test $0x04, %ah + jnz L(exit_case1_11) + lea 11(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_high_8): + test $0x10, %ah + jnz L(exit_case1_13) + test $0x20, %ah + jnz L(exit_case1_14) + test $0x40, %ah + jnz L(exit_case1_15) + lea 15(%edi), %eax + RETURN + + .p2align 4 +L(exit_loop): + add $64, %edx + + movdqa (%edi), %xmm0 + pcmpeqb %xmm1, %xmm0 + xor %ecx, %ecx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(match_case2) + cmp $16, %edx + jbe L(return_null) + + movdqa 16(%edi), %xmm2 + pcmpeqb %xmm1, %xmm2 + lea 16(%ecx), %ecx + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(match_case2) + cmp $32, %edx + jbe L(return_null) + + movdqa 32(%edi), %xmm3 + pcmpeqb %xmm1, %xmm3 + lea 16(%ecx), %ecx + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(match_case2) + cmp $48, %edx + jbe L(return_null) + + pcmpeqb 48(%edi), %xmm1 + lea 16(%ecx), %ecx + pmovmskb %xmm1, %eax + test %eax, %eax + jnz L(match_case2) + + xor %eax, %eax + RETURN + + .p2align 4 +L(exit_case1_1): + mov %edi, %eax + RETURN + + .p2align 4 +L(exit_case1_2): + lea 1(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_3): + lea 2(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_5): + lea 4(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_6): + lea 5(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_7): + lea 6(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_9): + lea 8(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_10): + lea 9(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_11): + lea 10(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_13): + lea 12(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_14): + lea 13(%edi), %eax + RETURN + + .p2align 4 +L(exit_case1_15): + lea 14(%edi), %eax + RETURN + + .p2align 4 +L(match_case2): + sub %ecx, %edx +L(match_case2_prolog1): + add %ecx, %edi +L(match_case2_prolog): + test %al, %al + jz L(match_case2_high) + mov %al, %cl + and $15, %cl + jz L(match_case2_8) + test $0x01, %al + jnz L(exit_case2_1) + test $0x02, %al + jnz L(exit_case2_2) + test $0x04, %al + jnz L(exit_case2_3) + sub $4, %edx + jb L(return_null) + lea 3(%edi), %eax + RETURN + + .p2align 4 +L(match_case2_8): + test $0x10, %al + jnz L(exit_case2_5) + test $0x20, %al + jnz L(exit_case2_6) + test $0x40, %al + jnz L(exit_case2_7) + sub $8, %edx + jb L(return_null) + lea 7(%edi), %eax + RETURN + + .p2align 4 +L(match_case2_high): + mov %ah, %ch + and $15, %ch + jz L(match_case2_high_8) + test $0x01, %ah + jnz L(exit_case2_9) + test $0x02, %ah + jnz L(exit_case2_10) + test $0x04, %ah + jnz L(exit_case2_11) + sub $12, %edx + jb L(return_null) + lea 11(%edi), %eax + RETURN + + .p2align 4 +L(match_case2_high_8): + test $0x10, %ah + jnz L(exit_case2_13) + test $0x20, %ah + jnz L(exit_case2_14) + test $0x40, %ah + jnz L(exit_case2_15) + sub $16, %edx + jb L(return_null) + lea 15(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_1): + mov %edi, %eax + RETURN + + .p2align 4 +L(exit_case2_2): + sub $2, %edx + jb L(return_null) + lea 1(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_3): + sub $3, %edx + jb L(return_null) + lea 2(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_5): + sub $5, %edx + jb L(return_null) + lea 4(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_6): + sub $6, %edx + jb L(return_null) + lea 5(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_7): + sub $7, %edx + jb L(return_null) + lea 6(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_9): + sub $9, %edx + jb L(return_null) + lea 8(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_10): + sub $10, %edx + jb L(return_null) + lea 9(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_11): + sub $11, %edx + jb L(return_null) + lea 10(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_13): + sub $13, %edx + jb L(return_null) + lea 12(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_14): + sub $14, %edx + jb L(return_null) + lea 13(%edi), %eax + RETURN + + .p2align 4 +L(exit_case2_15): + sub $15, %edx + jb L(return_null) + lea 14(%edi), %eax + RETURN + .p2align 4 +L(return_null): + xor %eax, %eax + RETURN +END (memchr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-memrchr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-memrchr-atom.S new file mode 100644 index 000000000..1aa1a1a40 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-memrchr-atom.S @@ -0,0 +1,778 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 4 +#define STR1 PARMS +#define STR2 STR1+4 +#define LEN STR2+4 + + .text +ENTRY (memrchr) + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + mov LEN(%esp), %edx + + test %edx, %edx + jz L(return_null) + sub $16, %edx + jbe L(length_less16) + + punpcklbw %xmm1, %xmm1 + add %edx, %ecx + punpcklbw %xmm1, %xmm1 + + movdqu (%ecx), %xmm0 + pshufd $0, %xmm1, %xmm1 + pcmpeqb %xmm1, %xmm0 + + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(exit_dispatch) + + sub $64, %ecx + mov %ecx, %eax + and $15, %eax + jz L(loop_prolog) + + add $16, %ecx + add $16, %edx + and $-16, %ecx + sub %eax, %edx + + .p2align 4 +/* Loop start on aligned string. */ +L(loop_prolog): + sub $64, %edx + jbe L(exit_loop) + + movdqa 48(%ecx), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches48) + + movdqa 32(%ecx), %xmm2 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(matches32) + + movdqa 16(%ecx), %xmm3 + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(matches16) + + movdqa (%ecx), %xmm4 + pcmpeqb %xmm1, %xmm4 + pmovmskb %xmm4, %eax + test %eax, %eax + jnz L(exit_dispatch) + + sub $64, %ecx + sub $64, %edx + jbe L(exit_loop) + + movdqa 48(%ecx), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches48) + + movdqa 32(%ecx), %xmm2 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(matches32) + + movdqa 16(%ecx), %xmm3 + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(matches16) + + movdqa (%ecx), %xmm3 + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(exit_dispatch) + + mov %ecx, %eax + and $63, %eax + test %eax, %eax + jz L(align64_loop) + + add $64, %ecx + add $64, %edx + and $-64, %ecx + sub %eax, %edx + + .p2align 4 +L(align64_loop): + sub $64, %ecx + sub $64, %edx + jbe L(exit_loop) + + movdqa (%ecx), %xmm0 + movdqa 16(%ecx), %xmm2 + movdqa 32(%ecx), %xmm3 + movdqa 48(%ecx), %xmm4 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm1, %xmm2 + pcmpeqb %xmm1, %xmm3 + pcmpeqb %xmm1, %xmm4 + + pmaxub %xmm3, %xmm0 + pmaxub %xmm4, %xmm2 + pmaxub %xmm0, %xmm2 + pmovmskb %xmm2, %eax + + test %eax, %eax + jz L(align64_loop) + + pmovmskb %xmm4, %eax + test %eax, %eax + jnz L(matches48) + + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(matches32) + + movdqa 16(%ecx), %xmm2 + + pcmpeqb %xmm1, %xmm2 + pcmpeqb (%ecx), %xmm1 + + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(matches16) + + pmovmskb %xmm1, %eax + test %ah, %ah + jnz L(exit_dispatch_high) + mov %al, %dl + and $15 << 4, %dl + jnz L(exit_dispatch_8) + test $0x08, %al + jnz L(exit_4) + test $0x04, %al + jnz L(exit_3) + test $0x02, %al + jnz L(exit_2) + mov %ecx, %eax + ret + + .p2align 4 +L(exit_loop): + add $64, %edx + cmp $32, %edx + jbe L(exit_loop_32) + + movdqa 48(%ecx), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches48) + + movdqa 32(%ecx), %xmm2 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm2, %eax + test %eax, %eax + jnz L(matches32) + + movdqa 16(%ecx), %xmm3 + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %eax + test %eax, %eax + jnz L(matches16_1) + cmp $48, %edx + jbe L(return_null) + + pcmpeqb (%ecx), %xmm1 + pmovmskb %xmm1, %eax + test %eax, %eax + jnz L(matches0_1) + xor %eax, %eax + ret + + .p2align 4 +L(exit_loop_32): + movdqa 48(%ecx), %xmm0 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches48_1) + cmp $16, %edx + jbe L(return_null) + + pcmpeqb 32(%ecx), %xmm1 + pmovmskb %xmm1, %eax + test %eax, %eax + jnz L(matches32_1) + xor %eax, %eax + ret + + .p2align 4 +L(matches16): + lea 16(%ecx), %ecx + test %ah, %ah + jnz L(exit_dispatch_high) + mov %al, %dl + and $15 << 4, %dl + jnz L(exit_dispatch_8) + test $0x08, %al + jnz L(exit_4) + test $0x04, %al + jnz L(exit_3) + test $0x02, %al + jnz L(exit_2) + mov %ecx, %eax + ret + + .p2align 4 +L(matches32): + lea 32(%ecx), %ecx + test %ah, %ah + jnz L(exit_dispatch_high) + mov %al, %dl + and $15 << 4, %dl + jnz L(exit_dispatch_8) + test $0x08, %al + jnz L(exit_4) + test $0x04, %al + jnz L(exit_3) + test $0x02, %al + jnz L(exit_2) + mov %ecx, %eax + ret + + .p2align 4 +L(matches48): + lea 48(%ecx), %ecx + + .p2align 4 +L(exit_dispatch): + test %ah, %ah + jnz L(exit_dispatch_high) + mov %al, %dl + and $15 << 4, %dl + jnz L(exit_dispatch_8) + test $0x08, %al + jnz L(exit_4) + test $0x04, %al + jnz L(exit_3) + test $0x02, %al + jnz L(exit_2) + mov %ecx, %eax + ret + + .p2align 4 +L(exit_dispatch_8): + test $0x80, %al + jnz L(exit_8) + test $0x40, %al + jnz L(exit_7) + test $0x20, %al + jnz L(exit_6) + lea 4(%ecx), %eax + ret + + .p2align 4 +L(exit_dispatch_high): + mov %ah, %dh + and $15 << 4, %dh + jnz L(exit_dispatch_high_8) + test $0x08, %ah + jnz L(exit_12) + test $0x04, %ah + jnz L(exit_11) + test $0x02, %ah + jnz L(exit_10) + lea 8(%ecx), %eax + ret + + .p2align 4 +L(exit_dispatch_high_8): + test $0x80, %ah + jnz L(exit_16) + test $0x40, %ah + jnz L(exit_15) + test $0x20, %ah + jnz L(exit_14) + lea 12(%ecx), %eax + ret + + .p2align 4 +L(exit_2): + lea 1(%ecx), %eax + ret + + .p2align 4 +L(exit_3): + lea 2(%ecx), %eax + ret + + .p2align 4 +L(exit_4): + lea 3(%ecx), %eax + ret + + .p2align 4 +L(exit_6): + lea 5(%ecx), %eax + ret + + .p2align 4 +L(exit_7): + lea 6(%ecx), %eax + ret + + .p2align 4 +L(exit_8): + lea 7(%ecx), %eax + ret + + .p2align 4 +L(exit_10): + lea 9(%ecx), %eax + ret + + .p2align 4 +L(exit_11): + lea 10(%ecx), %eax + ret + + .p2align 4 +L(exit_12): + lea 11(%ecx), %eax + ret + + .p2align 4 +L(exit_14): + lea 13(%ecx), %eax + ret + + .p2align 4 +L(exit_15): + lea 14(%ecx), %eax + ret + + .p2align 4 +L(exit_16): + lea 15(%ecx), %eax + ret + + .p2align 4 +L(matches0_1): + lea -64(%edx), %edx + + test %ah, %ah + jnz L(exit_dispatch_1_high) + mov %al, %ah + and $15 << 4, %ah + jnz L(exit_dispatch_1_8) + test $0x08, %al + jnz L(exit_1_4) + test $0x04, %al + jnz L(exit_1_3) + test $0x02, %al + jnz L(exit_1_2) + + add $0, %edx + jl L(return_null) + mov %ecx, %eax + ret + + .p2align 4 +L(matches16_1): + lea -48(%edx), %edx + lea 16(%ecx), %ecx + + test %ah, %ah + jnz L(exit_dispatch_1_high) + mov %al, %ah + and $15 << 4, %ah + jnz L(exit_dispatch_1_8) + test $0x08, %al + jnz L(exit_1_4) + test $0x04, %al + jnz L(exit_1_3) + test $0x02, %al + jnz L(exit_1_2) + + add $0, %edx + jl L(return_null) + mov %ecx, %eax + ret + + .p2align 4 +L(matches32_1): + lea -32(%edx), %edx + lea 32(%ecx), %ecx + + test %ah, %ah + jnz L(exit_dispatch_1_high) + mov %al, %ah + and $15 << 4, %ah + jnz L(exit_dispatch_1_8) + test $0x08, %al + jnz L(exit_1_4) + test $0x04, %al + jnz L(exit_1_3) + test $0x02, %al + jnz L(exit_1_2) + + add $0, %edx + jl L(return_null) + mov %ecx, %eax + ret + + .p2align 4 +L(matches48_1): + lea -16(%edx), %edx + lea 48(%ecx), %ecx + + .p2align 4 +L(exit_dispatch_1): + test %ah, %ah + jnz L(exit_dispatch_1_high) + mov %al, %ah + and $15 << 4, %ah + jnz L(exit_dispatch_1_8) + test $0x08, %al + jnz L(exit_1_4) + test $0x04, %al + jnz L(exit_1_3) + test $0x02, %al + jnz L(exit_1_2) + + add $0, %edx + jl L(return_null) + mov %ecx, %eax + ret + + .p2align 4 +L(exit_dispatch_1_8): + test $0x80, %al + jnz L(exit_1_8) + test $0x40, %al + jnz L(exit_1_7) + test $0x20, %al + jnz L(exit_1_6) + + add $4, %edx + jl L(return_null) + lea 4(%ecx), %eax + ret + + .p2align 4 +L(exit_dispatch_1_high): + mov %ah, %al + and $15 << 4, %al + jnz L(exit_dispatch_1_high_8) + test $0x08, %ah + jnz L(exit_1_12) + test $0x04, %ah + jnz L(exit_1_11) + test $0x02, %ah + jnz L(exit_1_10) + + add $8, %edx + jl L(return_null) + lea 8(%ecx), %eax + ret + + .p2align 4 +L(exit_dispatch_1_high_8): + test $0x80, %ah + jnz L(exit_1_16) + test $0x40, %ah + jnz L(exit_1_15) + test $0x20, %ah + jnz L(exit_1_14) + + add $12, %edx + jl L(return_null) + lea 12(%ecx), %eax + ret + + .p2align 4 +L(exit_1_2): + add $1, %edx + jl L(return_null) + lea 1(%ecx), %eax + ret + + .p2align 4 +L(exit_1_3): + add $2, %edx + jl L(return_null) + lea 2(%ecx), %eax + ret + + .p2align 4 +L(exit_1_4): + add $3, %edx + jl L(return_null) + lea 3(%ecx), %eax + ret + + .p2align 4 +L(exit_1_6): + add $5, %edx + jl L(return_null) + lea 5(%ecx), %eax + ret + + .p2align 4 +L(exit_1_7): + add $6, %edx + jl L(return_null) + lea 6(%ecx), %eax + ret + + .p2align 4 +L(exit_1_8): + add $7, %edx + jl L(return_null) + lea 7(%ecx), %eax + ret + + .p2align 4 +L(exit_1_10): + add $9, %edx + jl L(return_null) + lea 9(%ecx), %eax + ret + + .p2align 4 +L(exit_1_11): + add $10, %edx + jl L(return_null) + lea 10(%ecx), %eax + ret + + .p2align 4 +L(exit_1_12): + add $11, %edx + jl L(return_null) + lea 11(%ecx), %eax + ret + + .p2align 4 +L(exit_1_14): + add $13, %edx + jl L(return_null) + lea 13(%ecx), %eax + ret + + .p2align 4 +L(exit_1_15): + add $14, %edx + jl L(return_null) + lea 14(%ecx), %eax + ret + + .p2align 4 +L(exit_1_16): + add $15, %edx + jl L(return_null) + lea 15(%ecx), %eax + ret + + .p2align 4 +L(return_null): + xor %eax, %eax + ret + + .p2align 4 +L(length_less16_offset0): + mov %dl, %cl + pcmpeqb (%eax), %xmm1 + + mov $1, %edx + sal %cl, %edx + sub $1, %edx + + mov %eax, %ecx + pmovmskb %xmm1, %eax + + and %edx, %eax + test %eax, %eax + jnz L(exit_dispatch) + + xor %eax, %eax + ret + + .p2align 4 +L(length_less16): + punpcklbw %xmm1, %xmm1 + add $16, %edx + punpcklbw %xmm1, %xmm1 + + mov %ecx, %eax + pshufd $0, %xmm1, %xmm1 + + and $15, %ecx + jz L(length_less16_offset0) + + PUSH (%edi) + + mov %cl, %dh + add %dl, %dh + and $-16, %eax + + sub $16, %dh + ja L(length_less16_part2) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edi + + sar %cl, %edi + add %ecx, %eax + mov %dl, %cl + + mov $1, %edx + sal %cl, %edx + sub $1, %edx + + and %edx, %edi + test %edi, %edi + jz L(ret_null) + + bsr %edi, %edi + add %edi, %eax + POP (%edi) + ret + + CFI_PUSH (%edi) + + .p2align 4 +L(length_less16_part2): + movdqa 16(%eax), %xmm2 + pcmpeqb %xmm1, %xmm2 + pmovmskb %xmm2, %edi + + mov %cl, %ch + + mov %dh, %cl + mov $1, %edx + sal %cl, %edx + sub $1, %edx + + and %edx, %edi + + test %edi, %edi + jnz L(length_less16_part2_return) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edi + + mov %ch, %cl + sar %cl, %edi + test %edi, %edi + jz L(ret_null) + + bsr %edi, %edi + add %edi, %eax + xor %ch, %ch + add %ecx, %eax + POP (%edi) + ret + + CFI_PUSH (%edi) + + .p2align 4 +L(length_less16_part2_return): + bsr %edi, %edi + lea 16(%eax, %edi), %eax + POP (%edi) + ret + + CFI_PUSH (%edi) + + .p2align 4 +L(ret_null): + xor %eax, %eax + POP (%edi) + ret + +END (memrchr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-memset-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-memset-atom.S new file mode 100644 index 000000000..016c49e58 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-memset-atom.S @@ -0,0 +1,842 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 + +#include "cache.h" + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#define CFI_PUSH(REG) \ + .cfi_adjust_cfa_offset 4; \ + .cfi_rel_offset REG, 0 + +#define CFI_POP(REG) \ + .cfi_adjust_cfa_offset -4; \ + .cfi_restore REG + +#define PUSH(REG) pushl REG; CFI_PUSH(REG) +#define POP(REG) popl REG; CFI_POP(REG) + +#define PARMS 8 /* Preserve EBX. */ +#define DST PARMS +#define CHR (DST+4) +#define LEN (CHR+4) +#define CHK_DST_LEN (LEN+4) +#define SETRTNVAL movl DST(%esp), %eax + +#define ENTRANCE PUSH(%ebx); +#define RETURN_END POP(%ebx); ret +#define RETURN RETURN_END; CFI_PUSH(%ebx) +#define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + /* We first load PC into EBX. */ \ + call __x86.get_pc_thunk.bx; \ + /* Get the address of the jump table. */ \ + add $(TABLE - .), %ebx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + add (%ebx,%ecx,4), %ebx; \ + add %ecx, %edx; \ + /* We loaded the jump table and adjusted EDX. Go. */ \ + jmp *%ebx + + .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + ALIGN(4) + .type __x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret + +ENTRY(__memset_chk_atom) + ENTRANCE + + movl LEN(%esp), %ecx + cmpl CHK_DST_LEN(%esp), %ecx + jna L(memset_length_loaded) + + POP(%ebx) // Undo ENTRANCE without returning. + jmp __memset_chk_fail +END(__memset_chk_atom) + + .section .text.sse2,"ax",@progbits + ALIGN(4) +ENTRY(memset_atom) + ENTRANCE + + movl LEN(%esp), %ecx +L(memset_length_loaded): + movzbl CHR(%esp), %eax + movb %al, %ah + /* Fill the whole EAX with pattern. */ + movl %eax, %edx + shl $16, %eax + or %edx, %eax + movl DST(%esp), %edx + cmp $32, %ecx + jae L(32bytesormore) + +L(write_less32bytes): + BRANCH_TO_JMPTBL_ENTRY(L(table_less_32bytes)) + + + .pushsection .rodata.sse2,"a",@progbits + ALIGN(2) +L(table_less_32bytes): + .int JMPTBL(L(write_0bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_1bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_2bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_3bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_4bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_5bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_6bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_7bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_8bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_9bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_10bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_11bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_12bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_13bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_14bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_15bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_16bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_17bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_18bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_19bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_20bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_21bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_22bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_23bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_24bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_25bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_26bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_27bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_28bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_29bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_30bytes), L(table_less_32bytes)) + .int JMPTBL(L(write_31bytes), L(table_less_32bytes)) + .popsection + + ALIGN(4) +L(write_28bytes): + movl %eax, -28(%edx) +L(write_24bytes): + movl %eax, -24(%edx) +L(write_20bytes): + movl %eax, -20(%edx) +L(write_16bytes): + movl %eax, -16(%edx) +L(write_12bytes): + movl %eax, -12(%edx) +L(write_8bytes): + movl %eax, -8(%edx) +L(write_4bytes): + movl %eax, -4(%edx) +L(write_0bytes): + SETRTNVAL + RETURN + + ALIGN(4) +L(write_29bytes): + movl %eax, -29(%edx) +L(write_25bytes): + movl %eax, -25(%edx) +L(write_21bytes): + movl %eax, -21(%edx) +L(write_17bytes): + movl %eax, -17(%edx) +L(write_13bytes): + movl %eax, -13(%edx) +L(write_9bytes): + movl %eax, -9(%edx) +L(write_5bytes): + movl %eax, -5(%edx) +L(write_1bytes): + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(write_30bytes): + movl %eax, -30(%edx) +L(write_26bytes): + movl %eax, -26(%edx) +L(write_22bytes): + movl %eax, -22(%edx) +L(write_18bytes): + movl %eax, -18(%edx) +L(write_14bytes): + movl %eax, -14(%edx) +L(write_10bytes): + movl %eax, -10(%edx) +L(write_6bytes): + movl %eax, -6(%edx) +L(write_2bytes): + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(write_31bytes): + movl %eax, -31(%edx) +L(write_27bytes): + movl %eax, -27(%edx) +L(write_23bytes): + movl %eax, -23(%edx) +L(write_19bytes): + movl %eax, -19(%edx) +L(write_15bytes): + movl %eax, -15(%edx) +L(write_11bytes): + movl %eax, -11(%edx) +L(write_7bytes): + movl %eax, -7(%edx) +L(write_3bytes): + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +/* ECX > 32 and EDX is 4 byte aligned. */ +L(32bytesormore): + /* Fill xmm0 with the pattern. */ + movd %eax, %xmm0 + pshufd $0, %xmm0, %xmm0 + testl $0xf, %edx + jz L(aligned_16) +/* ECX > 32 and EDX is not 16 byte aligned. */ +L(not_aligned_16): + movdqu %xmm0, (%edx) + movl %edx, %eax + and $-16, %edx + add $16, %edx + sub %edx, %eax + add %eax, %ecx + movd %xmm0, %eax + + ALIGN(4) +L(aligned_16): + cmp $128, %ecx + jae L(128bytesormore) + +L(aligned_16_less128bytes): + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + ALIGN(4) +L(128bytesormore): + PUSH(%ebx) + mov $SHARED_CACHE_SIZE, %ebx + cmp %ebx, %ecx + jae L(128bytesormore_nt_start) + + + POP(%ebx) +# define RESTORE_EBX_STATE CFI_PUSH(%ebx) + cmp $DATA_CACHE_SIZE, %ecx + + jae L(128bytes_L2_normal) + subl $128, %ecx +L(128bytesormore_normal): + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jb L(128bytesless_normal) + + + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jae L(128bytesormore_normal) + +L(128bytesless_normal): + add $128, %ecx + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + ALIGN(4) +L(128bytes_L2_normal): + prefetcht0 0x380(%edx) + prefetcht0 0x3c0(%edx) + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + add $128, %edx + cmp $128, %ecx + jae L(128bytes_L2_normal) + +L(128bytesless_L2_normal): + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + RESTORE_EBX_STATE +L(128bytesormore_nt_start): + sub %ebx, %ecx + mov %ebx, %eax + and $0x7f, %eax + add %eax, %ecx + movd %xmm0, %eax + ALIGN(4) +L(128bytesormore_shared_cache_loop): + prefetcht0 0x3c0(%edx) + prefetcht0 0x380(%edx) + sub $0x80, %ebx + movdqa %xmm0, (%edx) + movdqa %xmm0, 0x10(%edx) + movdqa %xmm0, 0x20(%edx) + movdqa %xmm0, 0x30(%edx) + movdqa %xmm0, 0x40(%edx) + movdqa %xmm0, 0x50(%edx) + movdqa %xmm0, 0x60(%edx) + movdqa %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ebx + jae L(128bytesormore_shared_cache_loop) + cmp $0x80, %ecx + jb L(shared_cache_loop_end) + ALIGN(4) +L(128bytesormore_nt): + sub $0x80, %ecx + movntdq %xmm0, (%edx) + movntdq %xmm0, 0x10(%edx) + movntdq %xmm0, 0x20(%edx) + movntdq %xmm0, 0x30(%edx) + movntdq %xmm0, 0x40(%edx) + movntdq %xmm0, 0x50(%edx) + movntdq %xmm0, 0x60(%edx) + movntdq %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ecx + jae L(128bytesormore_nt) + sfence +L(shared_cache_loop_end): + POP(%ebx) + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + + .pushsection .rodata.sse2,"a",@progbits + ALIGN(2) +L(table_16_128bytes): + .int JMPTBL(L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_1bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_2bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_3bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_5bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_6bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_7bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_9bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_10bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_11bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_13bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_14bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_15bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_17bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_18bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_19bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_21bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_22bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_23bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_25bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_26bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_27bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_29bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_30bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_31bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_33bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_34bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_35bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_37bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_38bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_39bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_41bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_42bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_43bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_45bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_46bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_47bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_49bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_50bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_51bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_53bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_54bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_55bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_57bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_58bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_59bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_61bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_62bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_63bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_65bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_66bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_67bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_69bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_70bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_71bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_73bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_74bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_75bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_77bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_78bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_79bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_81bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_82bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_83bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_85bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_86bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_87bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_89bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_90bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_91bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_93bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_94bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_95bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_97bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_98bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_99bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_101bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_102bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_103bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_105bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_106bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_107bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_109bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_110bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_111bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_113bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_114bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_115bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_117bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_118bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_119bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_121bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_122bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_123bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_124bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_125bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_126bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_127bytes), L(table_16_128bytes)) + .popsection + + ALIGN(4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%edx) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%edx) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%edx) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%edx) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%edx) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%edx) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%edx) +L(aligned_16_0bytes): + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_113bytes): + movdqa %xmm0, -113(%edx) +L(aligned_16_97bytes): + movdqa %xmm0, -97(%edx) +L(aligned_16_81bytes): + movdqa %xmm0, -81(%edx) +L(aligned_16_65bytes): + movdqa %xmm0, -65(%edx) +L(aligned_16_49bytes): + movdqa %xmm0, -49(%edx) +L(aligned_16_33bytes): + movdqa %xmm0, -33(%edx) +L(aligned_16_17bytes): + movdqa %xmm0, -17(%edx) +L(aligned_16_1bytes): + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_114bytes): + movdqa %xmm0, -114(%edx) +L(aligned_16_98bytes): + movdqa %xmm0, -98(%edx) +L(aligned_16_82bytes): + movdqa %xmm0, -82(%edx) +L(aligned_16_66bytes): + movdqa %xmm0, -66(%edx) +L(aligned_16_50bytes): + movdqa %xmm0, -50(%edx) +L(aligned_16_34bytes): + movdqa %xmm0, -34(%edx) +L(aligned_16_18bytes): + movdqa %xmm0, -18(%edx) +L(aligned_16_2bytes): + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_115bytes): + movdqa %xmm0, -115(%edx) +L(aligned_16_99bytes): + movdqa %xmm0, -99(%edx) +L(aligned_16_83bytes): + movdqa %xmm0, -83(%edx) +L(aligned_16_67bytes): + movdqa %xmm0, -67(%edx) +L(aligned_16_51bytes): + movdqa %xmm0, -51(%edx) +L(aligned_16_35bytes): + movdqa %xmm0, -35(%edx) +L(aligned_16_19bytes): + movdqa %xmm0, -19(%edx) +L(aligned_16_3bytes): + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%edx) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%edx) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%edx) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%edx) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%edx) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%edx) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%edx) +L(aligned_16_4bytes): + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_117bytes): + movdqa %xmm0, -117(%edx) +L(aligned_16_101bytes): + movdqa %xmm0, -101(%edx) +L(aligned_16_85bytes): + movdqa %xmm0, -85(%edx) +L(aligned_16_69bytes): + movdqa %xmm0, -69(%edx) +L(aligned_16_53bytes): + movdqa %xmm0, -53(%edx) +L(aligned_16_37bytes): + movdqa %xmm0, -37(%edx) +L(aligned_16_21bytes): + movdqa %xmm0, -21(%edx) +L(aligned_16_5bytes): + movl %eax, -5(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_118bytes): + movdqa %xmm0, -118(%edx) +L(aligned_16_102bytes): + movdqa %xmm0, -102(%edx) +L(aligned_16_86bytes): + movdqa %xmm0, -86(%edx) +L(aligned_16_70bytes): + movdqa %xmm0, -70(%edx) +L(aligned_16_54bytes): + movdqa %xmm0, -54(%edx) +L(aligned_16_38bytes): + movdqa %xmm0, -38(%edx) +L(aligned_16_22bytes): + movdqa %xmm0, -22(%edx) +L(aligned_16_6bytes): + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_119bytes): + movdqa %xmm0, -119(%edx) +L(aligned_16_103bytes): + movdqa %xmm0, -103(%edx) +L(aligned_16_87bytes): + movdqa %xmm0, -87(%edx) +L(aligned_16_71bytes): + movdqa %xmm0, -71(%edx) +L(aligned_16_55bytes): + movdqa %xmm0, -55(%edx) +L(aligned_16_39bytes): + movdqa %xmm0, -39(%edx) +L(aligned_16_23bytes): + movdqa %xmm0, -23(%edx) +L(aligned_16_7bytes): + movl %eax, -7(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%edx) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%edx) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%edx) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%edx) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%edx) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%edx) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%edx) +L(aligned_16_8bytes): + movq %xmm0, -8(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_121bytes): + movdqa %xmm0, -121(%edx) +L(aligned_16_105bytes): + movdqa %xmm0, -105(%edx) +L(aligned_16_89bytes): + movdqa %xmm0, -89(%edx) +L(aligned_16_73bytes): + movdqa %xmm0, -73(%edx) +L(aligned_16_57bytes): + movdqa %xmm0, -57(%edx) +L(aligned_16_41bytes): + movdqa %xmm0, -41(%edx) +L(aligned_16_25bytes): + movdqa %xmm0, -25(%edx) +L(aligned_16_9bytes): + movq %xmm0, -9(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_122bytes): + movdqa %xmm0, -122(%edx) +L(aligned_16_106bytes): + movdqa %xmm0, -106(%edx) +L(aligned_16_90bytes): + movdqa %xmm0, -90(%edx) +L(aligned_16_74bytes): + movdqa %xmm0, -74(%edx) +L(aligned_16_58bytes): + movdqa %xmm0, -58(%edx) +L(aligned_16_42bytes): + movdqa %xmm0, -42(%edx) +L(aligned_16_26bytes): + movdqa %xmm0, -26(%edx) +L(aligned_16_10bytes): + movq %xmm0, -10(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_123bytes): + movdqa %xmm0, -123(%edx) +L(aligned_16_107bytes): + movdqa %xmm0, -107(%edx) +L(aligned_16_91bytes): + movdqa %xmm0, -91(%edx) +L(aligned_16_75bytes): + movdqa %xmm0, -75(%edx) +L(aligned_16_59bytes): + movdqa %xmm0, -59(%edx) +L(aligned_16_43bytes): + movdqa %xmm0, -43(%edx) +L(aligned_16_27bytes): + movdqa %xmm0, -27(%edx) +L(aligned_16_11bytes): + movq %xmm0, -11(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%edx) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%edx) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%edx) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%edx) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%edx) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%edx) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%edx) +L(aligned_16_12bytes): + movq %xmm0, -12(%edx) + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_125bytes): + movdqa %xmm0, -125(%edx) +L(aligned_16_109bytes): + movdqa %xmm0, -109(%edx) +L(aligned_16_93bytes): + movdqa %xmm0, -93(%edx) +L(aligned_16_77bytes): + movdqa %xmm0, -77(%edx) +L(aligned_16_61bytes): + movdqa %xmm0, -61(%edx) +L(aligned_16_45bytes): + movdqa %xmm0, -45(%edx) +L(aligned_16_29bytes): + movdqa %xmm0, -29(%edx) +L(aligned_16_13bytes): + movq %xmm0, -13(%edx) + movl %eax, -5(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_126bytes): + movdqa %xmm0, -126(%edx) +L(aligned_16_110bytes): + movdqa %xmm0, -110(%edx) +L(aligned_16_94bytes): + movdqa %xmm0, -94(%edx) +L(aligned_16_78bytes): + movdqa %xmm0, -78(%edx) +L(aligned_16_62bytes): + movdqa %xmm0, -62(%edx) +L(aligned_16_46bytes): + movdqa %xmm0, -46(%edx) +L(aligned_16_30bytes): + movdqa %xmm0, -30(%edx) +L(aligned_16_14bytes): + movq %xmm0, -14(%edx) + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_127bytes): + movdqa %xmm0, -127(%edx) +L(aligned_16_111bytes): + movdqa %xmm0, -111(%edx) +L(aligned_16_95bytes): + movdqa %xmm0, -95(%edx) +L(aligned_16_79bytes): + movdqa %xmm0, -79(%edx) +L(aligned_16_63bytes): + movdqa %xmm0, -63(%edx) +L(aligned_16_47bytes): + movdqa %xmm0, -47(%edx) +L(aligned_16_31bytes): + movdqa %xmm0, -31(%edx) +L(aligned_16_15bytes): + movq %xmm0, -15(%edx) + movl %eax, -7(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN_END + +END(memset_atom) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-strchr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-strchr-atom.S new file mode 100644 index 000000000..e325181f4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-strchr-atom.S @@ -0,0 +1,391 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 8 +#define ENTRANCE PUSH(%edi) +#define RETURN POP (%edi); ret; CFI_PUSH (%edi); + + +#define STR1 PARMS +#define STR2 STR1+4 + + .text +ENTRY (strchr) + + ENTRANCE + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + + pxor %xmm2, %xmm2 + mov %ecx, %edi + punpcklbw %xmm1, %xmm1 + punpcklbw %xmm1, %xmm1 + /* ECX has OFFSET. */ + and $15, %ecx + pshufd $0, %xmm1, %xmm1 + je L(loop) + +/* Handle unaligned string. */ + and $-16, %edi + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + /* Find where NULL is. */ + pmovmskb %xmm2, %edx + /* Check if there is a match. */ + pmovmskb %xmm0, %eax + /* Remove the leading bytes. */ + sarl %cl, %edx + sarl %cl, %eax + test %eax, %eax + jz L(unaligned_no_match) + add %ecx, %edi + test %edx, %edx + jz L(match_case1) + jmp L(match_case2) + + .p2align 4 +L(unaligned_no_match): + test %edx, %edx + jne L(return_null) + + pxor %xmm2, %xmm2 + add $16, %edi + + .p2align 4 +/* Loop start on aligned string. */ +L(loop): + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches) + test %edx, %edx + jnz L(return_null) + add $16, %edi + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches) + test %edx, %edx + jnz L(return_null) + add $16, %edi + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches) + test %edx, %edx + jnz L(return_null) + add $16, %edi + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(matches) + test %edx, %edx + jnz L(return_null) + add $16, %edi + jmp L(loop) + +L(matches): + /* There is a match. First find where NULL is. */ + test %edx, %edx + jz L(match_case1) + + .p2align 4 +L(match_case2): + test %al, %al + jz L(match_higth_case2) + + mov %al, %cl + and $15, %cl + jnz L(match_case2_4) + + mov %dl, %ch + and $15, %ch + jnz L(return_null) + + test $0x10, %al + jnz L(Exit5) + test $0x10, %dl + jnz L(return_null) + test $0x20, %al + jnz L(Exit6) + test $0x20, %dl + jnz L(return_null) + test $0x40, %al + jnz L(Exit7) + test $0x40, %dl + jnz L(return_null) + lea 7(%edi), %eax + RETURN + + .p2align 4 +L(match_case2_4): + test $0x01, %al + jnz L(Exit1) + test $0x01, %dl + jnz L(return_null) + test $0x02, %al + jnz L(Exit2) + test $0x02, %dl + jnz L(return_null) + test $0x04, %al + jnz L(Exit3) + test $0x04, %dl + jnz L(return_null) + lea 3(%edi), %eax + RETURN + + .p2align 4 +L(match_higth_case2): + test %dl, %dl + jnz L(return_null) + + mov %ah, %cl + and $15, %cl + jnz L(match_case2_12) + + mov %dh, %ch + and $15, %ch + jnz L(return_null) + + test $0x10, %ah + jnz L(Exit13) + test $0x10, %dh + jnz L(return_null) + test $0x20, %ah + jnz L(Exit14) + test $0x20, %dh + jnz L(return_null) + test $0x40, %ah + jnz L(Exit15) + test $0x40, %dh + jnz L(return_null) + lea 15(%edi), %eax + RETURN + + .p2align 4 +L(match_case2_12): + test $0x01, %ah + jnz L(Exit9) + test $0x01, %dh + jnz L(return_null) + test $0x02, %ah + jnz L(Exit10) + test $0x02, %dh + jnz L(return_null) + test $0x04, %ah + jnz L(Exit11) + test $0x04, %dh + jnz L(return_null) + lea 11(%edi), %eax + RETURN + + .p2align 4 +L(match_case1): + test %al, %al + jz L(match_higth_case1) + + test $0x01, %al + jnz L(Exit1) + test $0x02, %al + jnz L(Exit2) + test $0x04, %al + jnz L(Exit3) + test $0x08, %al + jnz L(Exit4) + test $0x10, %al + jnz L(Exit5) + test $0x20, %al + jnz L(Exit6) + test $0x40, %al + jnz L(Exit7) + lea 7(%edi), %eax + RETURN + + .p2align 4 +L(match_higth_case1): + test $0x01, %ah + jnz L(Exit9) + test $0x02, %ah + jnz L(Exit10) + test $0x04, %ah + jnz L(Exit11) + test $0x08, %ah + jnz L(Exit12) + test $0x10, %ah + jnz L(Exit13) + test $0x20, %ah + jnz L(Exit14) + test $0x40, %ah + jnz L(Exit15) + lea 15(%edi), %eax + RETURN + + .p2align 4 +L(Exit1): + lea (%edi), %eax + RETURN + + .p2align 4 +L(Exit2): + lea 1(%edi), %eax + RETURN + + .p2align 4 +L(Exit3): + lea 2(%edi), %eax + RETURN + + .p2align 4 +L(Exit4): + lea 3(%edi), %eax + RETURN + + .p2align 4 +L(Exit5): + lea 4(%edi), %eax + RETURN + + .p2align 4 +L(Exit6): + lea 5(%edi), %eax + RETURN + + .p2align 4 +L(Exit7): + lea 6(%edi), %eax + RETURN + + .p2align 4 +L(Exit9): + lea 8(%edi), %eax + RETURN + + .p2align 4 +L(Exit10): + lea 9(%edi), %eax + RETURN + + .p2align 4 +L(Exit11): + lea 10(%edi), %eax + RETURN + + .p2align 4 +L(Exit12): + lea 11(%edi), %eax + RETURN + + .p2align 4 +L(Exit13): + lea 12(%edi), %eax + RETURN + + .p2align 4 +L(Exit14): + lea 13(%edi), %eax + RETURN + + .p2align 4 +L(Exit15): + lea 14(%edi), %eax + RETURN + + .p2align 4 +L(return_null): + xor %eax, %eax + RETURN + +END (strchr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-strlen-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-strlen-atom.S new file mode 100644 index 000000000..6a1acfbd7 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-strlen-atom.S @@ -0,0 +1,749 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_STRCAT + +# ifndef STRLEN +# define STRLEN strlen_atom +# endif + +# ifndef L +# define L(label) .L##label +# endif + +# ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +# endif + +# ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +# endif + +/* calee safe register only for strnlen is required */ + +# ifdef USE_AS_STRNLEN +# ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# endif + +# ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +# endif + +# ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# endif +# endif + +# ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +# endif + +# ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +# endif + +# define PARMS 4 +# define STR PARMS +# define RETURN ret + +# ifdef USE_AS_STRNLEN +# define LEN PARMS + 8 +# define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +# define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +# define PUSH(REG) pushl REG; CFI_PUSH (REG) +# define POP(REG) popl REG; CFI_POP (REG) +# undef RETURN +# define RETURN POP (%edi); ret; CFI_PUSH(%edi); +# endif + + .text +ENTRY (STRLEN) + mov STR(%esp), %edx +# ifdef USE_AS_STRNLEN + PUSH (%edi) + movl LEN(%esp), %edi + sub $4, %edi + jbe L(len_less4_prolog) +# endif +#endif + xor %eax, %eax + cmpb $0, (%edx) + jz L(exit_tail0) + cmpb $0, 1(%edx) + jz L(exit_tail1) + cmpb $0, 2(%edx) + jz L(exit_tail2) + cmpb $0, 3(%edx) + jz L(exit_tail3) + +#ifdef USE_AS_STRNLEN + sub $4, %edi + jbe L(len_less8_prolog) +#endif + + cmpb $0, 4(%edx) + jz L(exit_tail4) + cmpb $0, 5(%edx) + jz L(exit_tail5) + cmpb $0, 6(%edx) + jz L(exit_tail6) + cmpb $0, 7(%edx) + jz L(exit_tail7) + +#ifdef USE_AS_STRNLEN + sub $4, %edi + jbe L(len_less12_prolog) +#endif + + cmpb $0, 8(%edx) + jz L(exit_tail8) + cmpb $0, 9(%edx) + jz L(exit_tail9) + cmpb $0, 10(%edx) + jz L(exit_tail10) + cmpb $0, 11(%edx) + jz L(exit_tail11) + +#ifdef USE_AS_STRNLEN + sub $4, %edi + jbe L(len_less16_prolog) +#endif + + cmpb $0, 12(%edx) + jz L(exit_tail12) + cmpb $0, 13(%edx) + jz L(exit_tail13) + cmpb $0, 14(%edx) + jz L(exit_tail14) + cmpb $0, 15(%edx) + jz L(exit_tail15) + + pxor %xmm0, %xmm0 + lea 16(%edx), %eax + mov %eax, %ecx + and $-16, %eax + +#ifdef USE_AS_STRNLEN + and $15, %edx + add %edx, %edi + sub $64, %edi + jbe L(len_less64) +#endif + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + pxor %xmm2, %xmm2 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + pxor %xmm3, %xmm3 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + +#ifdef USE_AS_STRNLEN + sub $64, %edi + jbe L(len_less64) +#endif + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + +#ifdef USE_AS_STRNLEN + sub $64, %edi + jbe L(len_less64) +#endif + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + +#ifdef USE_AS_STRNLEN + sub $64, %edi + jbe L(len_less64) +#endif + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + +#ifdef USE_AS_STRNLEN + mov %eax, %edx + and $63, %edx + add %edx, %edi +#endif + + and $-0x40, %eax + + .p2align 4 +L(aligned_64_loop): +#ifdef USE_AS_STRNLEN + sub $64, %edi + jbe L(len_less64) +#endif + movaps (%eax), %xmm0 + movaps 16(%eax), %xmm1 + movaps 32(%eax), %xmm2 + movaps 48(%eax), %xmm6 + pminub %xmm1, %xmm0 + pminub %xmm6, %xmm2 + pminub %xmm0, %xmm2 + pcmpeqb %xmm3, %xmm2 + pmovmskb %xmm2, %edx + lea 64(%eax), %eax + test %edx, %edx + jz L(aligned_64_loop) + + pcmpeqb -64(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 48(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb -32(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm6, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx +L(exit): + sub %ecx, %eax + test %dl, %dl + jz L(exit_high) + + mov %dl, %cl + and $15, %cl + jz L(exit_8) + test $0x01, %dl + jnz L(exit_tail0) + test $0x02, %dl + jnz L(exit_tail1) + test $0x04, %dl + jnz L(exit_tail2) + add $3, %eax + RETURN + + .p2align 4 +L(exit_8): + test $0x10, %dl + jnz L(exit_tail4) + test $0x20, %dl + jnz L(exit_tail5) + test $0x40, %dl + jnz L(exit_tail6) + add $7, %eax + RETURN + + .p2align 4 +L(exit_high): + mov %dh, %ch + and $15, %ch + jz L(exit_high_8) + test $0x01, %dh + jnz L(exit_tail8) + test $0x02, %dh + jnz L(exit_tail9) + test $0x04, %dh + jnz L(exit_tail10) + add $11, %eax + RETURN + + .p2align 4 +L(exit_high_8): + test $0x10, %dh + jnz L(exit_tail12) + test $0x20, %dh + jnz L(exit_tail13) + test $0x40, %dh + jnz L(exit_tail14) + add $15, %eax +L(exit_tail0): + RETURN + +#ifdef USE_AS_STRNLEN + + .p2align 4 +L(len_less64): + pxor %xmm0, %xmm0 + add $64, %edi + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 + lea 16(%eax), %eax + test %edx, %edx + jnz L(strnlen_exit) + + sub $16, %edi + jbe L(return_start_len) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(strnlen_exit) + + sub $16, %edi + jbe L(return_start_len) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(strnlen_exit) + + sub $16, %edi + jbe L(return_start_len) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(strnlen_exit) + +#ifndef USE_AS_STRLCAT + movl LEN(%esp), %eax + RETURN +#else + jmp L(return_start_len) +#endif + + .p2align 4 +L(strnlen_exit): + sub %ecx, %eax + + test %dl, %dl + jz L(strnlen_exit_high) + mov %dl, %cl + and $15, %cl + jz L(strnlen_exit_8) + test $0x01, %dl + jnz L(exit_tail0) + test $0x02, %dl + jnz L(strnlen_exit_tail1) + test $0x04, %dl + jnz L(strnlen_exit_tail2) + sub $4, %edi + jb L(return_start_len) + lea 3(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_8): + test $0x10, %dl + jnz L(strnlen_exit_tail4) + test $0x20, %dl + jnz L(strnlen_exit_tail5) + test $0x40, %dl + jnz L(strnlen_exit_tail6) + sub $8, %edi + jb L(return_start_len) + lea 7(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_high): + mov %dh, %ch + and $15, %ch + jz L(strnlen_exit_high_8) + test $0x01, %dh + jnz L(strnlen_exit_tail8) + test $0x02, %dh + jnz L(strnlen_exit_tail9) + test $0x04, %dh + jnz L(strnlen_exit_tail10) + sub $12, %edi + jb L(return_start_len) + lea 11(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_high_8): + test $0x10, %dh + jnz L(strnlen_exit_tail12) + test $0x20, %dh + jnz L(strnlen_exit_tail13) + test $0x40, %dh + jnz L(strnlen_exit_tail14) + sub $16, %edi + jb L(return_start_len) + lea 15(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail1): + sub $2, %edi + jb L(return_start_len) + lea 1(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail2): + sub $3, %edi + jb L(return_start_len) + lea 2(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail4): + sub $5, %edi + jb L(return_start_len) + lea 4(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail5): + sub $6, %edi + jb L(return_start_len) + lea 5(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail6): + sub $7, %edi + jb L(return_start_len) + lea 6(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail8): + sub $9, %edi + jb L(return_start_len) + lea 8(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail9): + sub $10, %edi + jb L(return_start_len) + lea 9(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail10): + sub $11, %edi + jb L(return_start_len) + lea 10(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail12): + sub $13, %edi + jb L(return_start_len) + lea 12(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail13): + sub $14, %edi + jb L(return_start_len) + lea 13(%eax), %eax + RETURN + + .p2align 4 +L(strnlen_exit_tail14): + sub $15, %edi + jb L(return_start_len) + lea 14(%eax), %eax + RETURN + +#ifndef USE_AS_STRLCAT + .p2align 4 +L(return_start_len): + movl LEN(%esp), %eax + RETURN +#endif + +/* for prolog only */ + + .p2align 4 +L(len_less4_prolog): + xor %eax, %eax + + add $4, %edi + jz L(exit_tail0) + + cmpb $0, (%edx) + jz L(exit_tail0) + cmp $1, %edi + je L(exit_tail1) + + cmpb $0, 1(%edx) + jz L(exit_tail1) + cmp $2, %edi + je L(exit_tail2) + + cmpb $0, 2(%edx) + jz L(exit_tail2) + cmp $3, %edi + je L(exit_tail3) + + cmpb $0, 3(%edx) + jz L(exit_tail3) + mov %edi, %eax + RETURN + + .p2align 4 +L(len_less8_prolog): + add $4, %edi + + cmpb $0, 4(%edx) + jz L(exit_tail4) + cmp $1, %edi + je L(exit_tail5) + + cmpb $0, 5(%edx) + jz L(exit_tail5) + cmp $2, %edi + je L(exit_tail6) + + cmpb $0, 6(%edx) + jz L(exit_tail6) + cmp $3, %edi + je L(exit_tail7) + + cmpb $0, 7(%edx) + jz L(exit_tail7) + mov $8, %eax + RETURN + + + .p2align 4 +L(len_less12_prolog): + add $4, %edi + + cmpb $0, 8(%edx) + jz L(exit_tail8) + cmp $1, %edi + je L(exit_tail9) + + cmpb $0, 9(%edx) + jz L(exit_tail9) + cmp $2, %edi + je L(exit_tail10) + + cmpb $0, 10(%edx) + jz L(exit_tail10) + cmp $3, %edi + je L(exit_tail11) + + cmpb $0, 11(%edx) + jz L(exit_tail11) + mov $12, %eax + RETURN + + .p2align 4 +L(len_less16_prolog): + add $4, %edi + + cmpb $0, 12(%edx) + jz L(exit_tail12) + cmp $1, %edi + je L(exit_tail13) + + cmpb $0, 13(%edx) + jz L(exit_tail13) + cmp $2, %edi + je L(exit_tail14) + + cmpb $0, 14(%edx) + jz L(exit_tail14) + cmp $3, %edi + je L(exit_tail15) + + cmpb $0, 15(%edx) + jz L(exit_tail15) + mov $16, %eax + RETURN +#endif + + .p2align 4 +L(exit_tail1): + add $1, %eax + RETURN + +L(exit_tail2): + add $2, %eax + RETURN + +L(exit_tail3): + add $3, %eax + RETURN + +L(exit_tail4): + add $4, %eax + RETURN + +L(exit_tail5): + add $5, %eax + RETURN + +L(exit_tail6): + add $6, %eax + RETURN + +L(exit_tail7): + add $7, %eax + RETURN + +L(exit_tail8): + add $8, %eax + RETURN + +L(exit_tail9): + add $9, %eax + RETURN + +L(exit_tail10): + add $10, %eax + RETURN + +L(exit_tail11): + add $11, %eax + RETURN + +L(exit_tail12): + add $12, %eax + RETURN + +L(exit_tail13): + add $13, %eax + RETURN + +L(exit_tail14): + add $14, %eax + RETURN + +L(exit_tail15): + add $15, %eax +#ifndef USE_AS_STRCAT + RETURN +END (STRLEN) +#endif diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-strnlen-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-strnlen-atom.S new file mode 100644 index 000000000..1f89b4ec9 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-strnlen-atom.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNLEN 1 +#define STRLEN strnlen +#include "sse2-strlen-atom.S" diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-strrchr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-strrchr-atom.S new file mode 100644 index 000000000..e916bc1e5 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-strrchr-atom.S @@ -0,0 +1,753 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 8 +#define ENTRANCE PUSH(%edi); +#define RETURN POP (%edi); ret; CFI_PUSH (%edi); + +#define STR1 PARMS +#define STR2 STR1+4 + + .text +ENTRY (strrchr) + + ENTRANCE + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + + pxor %xmm2, %xmm2 + mov %ecx, %edi + punpcklbw %xmm1, %xmm1 + punpcklbw %xmm1, %xmm1 + /* ECX has OFFSET. */ + and $63, %ecx + pshufd $0, %xmm1, %xmm1 + cmp $48, %ecx + ja L(crosscache) + +/* unaligned string. */ + movdqu (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + pcmpeqb %xmm1, %xmm0 + /* Find where NULL is. */ + pmovmskb %xmm2, %ecx + /* Check if there is a match. */ + pmovmskb %xmm0, %eax + add $16, %edi + + test %eax, %eax + jnz L(unaligned_match1) + + test %ecx, %ecx + jnz L(return_null) + + and $-16, %edi + + PUSH (%esi) + PUSH (%ebx) + + xor %ebx, %ebx + jmp L(loop) + + CFI_POP (%esi) + CFI_POP (%ebx) + + .p2align 4 +L(unaligned_match1): + test %ecx, %ecx + jnz L(prolog_find_zero_1) + + PUSH (%esi) + PUSH (%ebx) + + mov %eax, %ebx + mov %edi, %esi + and $-16, %edi + jmp L(loop) + + CFI_POP (%esi) + CFI_POP (%ebx) + + .p2align 4 +L(crosscache): +/* Hancle unaligned string. */ + and $15, %ecx + and $-16, %edi + pxor %xmm3, %xmm3 + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm3 + pcmpeqb %xmm1, %xmm0 + /* Find where NULL is. */ + pmovmskb %xmm3, %edx + /* Check if there is a match. */ + pmovmskb %xmm0, %eax + /* Remove the leading bytes. */ + shr %cl, %edx + shr %cl, %eax + add $16, %edi + + test %eax, %eax + jnz L(unaligned_match) + + test %edx, %edx + jnz L(return_null) + + PUSH (%esi) + PUSH (%ebx) + + xor %ebx, %ebx + jmp L(loop) + + CFI_POP (%esi) + CFI_POP (%ebx) + + .p2align 4 +L(unaligned_match): + test %edx, %edx + jnz L(prolog_find_zero) + + PUSH (%esi) + PUSH (%ebx) + + mov %eax, %ebx + lea (%edi, %ecx), %esi + +/* Loop start on aligned string. */ + .p2align 4 +L(loop): + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + add $16, %edi + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %ecx + pmovmskb %xmm0, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + add $16, %edi + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %ecx + pmovmskb %xmm0, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + add $16, %edi + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %ecx + pmovmskb %xmm0, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm0 + pcmpeqb %xmm0, %xmm2 + add $16, %edi + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm2, %ecx + pmovmskb %xmm0, %eax + or %eax, %ecx + jz L(loop) + +L(matches): + test %eax, %eax + jnz L(match) +L(return_value): + test %ebx, %ebx + jz L(return_null_1) + mov %ebx, %eax + mov %esi, %edi + + POP (%ebx) + POP (%esi) + + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(return_null_1): + POP (%ebx) + POP (%esi) + + xor %eax, %eax + RETURN + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(match): + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(find_zero) + mov %eax, %ebx + mov %edi, %esi + jmp L(loop) + + .p2align 4 +L(find_zero): + test %cl, %cl + jz L(find_zero_high) + mov %cl, %dl + and $15, %dl + jz L(find_zero_8) + test $0x01, %cl + jnz L(FindZeroExit1) + test $0x02, %cl + jnz L(FindZeroExit2) + test $0x04, %cl + jnz L(FindZeroExit3) + and $(1 << 4) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_8): + test $0x10, %cl + jnz L(FindZeroExit5) + test $0x20, %cl + jnz L(FindZeroExit6) + test $0x40, %cl + jnz L(FindZeroExit7) + and $(1 << 8) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_high): + mov %ch, %dh + and $15, %dh + jz L(find_zero_high_8) + test $0x01, %ch + jnz L(FindZeroExit9) + test $0x02, %ch + jnz L(FindZeroExit10) + test $0x04, %ch + jnz L(FindZeroExit11) + and $(1 << 12) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_high_8): + test $0x10, %ch + jnz L(FindZeroExit13) + test $0x20, %ch + jnz L(FindZeroExit14) + test $0x40, %ch + jnz L(FindZeroExit15) + and $(1 << 16) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit1): + and $1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit2): + and $(1 << 2) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit3): + and $(1 << 3) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit5): + and $(1 << 5) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit6): + and $(1 << 6) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit7): + and $(1 << 7) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit9): + and $(1 << 9) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit10): + and $(1 << 10) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit11): + and $(1 << 11) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit13): + and $(1 << 13) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit14): + and $(1 << 14) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + jmp L(match_case1) + + CFI_PUSH (%ebx) + CFI_PUSH (%esi) + + .p2align 4 +L(FindZeroExit15): + and $(1 << 15) - 1, %eax + jz L(return_value) + + POP (%ebx) + POP (%esi) + + .p2align 4 +L(match_case1): + test %ah, %ah + jnz L(match_case1_high) + mov %al, %dl + and $15 << 4, %dl + jnz L(match_case1_8) + test $0x08, %al + jnz L(Exit4) + test $0x04, %al + jnz L(Exit3) + test $0x02, %al + jnz L(Exit2) + lea -16(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_8): + test $0x80, %al + jnz L(Exit8) + test $0x40, %al + jnz L(Exit7) + test $0x20, %al + jnz L(Exit6) + lea -12(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_high): + mov %ah, %dh + and $15 << 4, %dh + jnz L(match_case1_high_8) + test $0x08, %ah + jnz L(Exit12) + test $0x04, %ah + jnz L(Exit11) + test $0x02, %ah + jnz L(Exit10) + lea -8(%edi), %eax + RETURN + + .p2align 4 +L(match_case1_high_8): + test $0x80, %ah + jnz L(Exit16) + test $0x40, %ah + jnz L(Exit15) + test $0x20, %ah + jnz L(Exit14) + lea -4(%edi), %eax + RETURN + + .p2align 4 +L(Exit2): + lea -15(%edi), %eax + RETURN + + .p2align 4 +L(Exit3): + lea -14(%edi), %eax + RETURN + + .p2align 4 +L(Exit4): + lea -13(%edi), %eax + RETURN + + .p2align 4 +L(Exit6): + lea -11(%edi), %eax + RETURN + + .p2align 4 +L(Exit7): + lea -10(%edi), %eax + RETURN + + .p2align 4 +L(Exit8): + lea -9(%edi), %eax + RETURN + + .p2align 4 +L(Exit10): + lea -7(%edi), %eax + RETURN + + .p2align 4 +L(Exit11): + lea -6(%edi), %eax + RETURN + + .p2align 4 +L(Exit12): + lea -5(%edi), %eax + RETURN + + .p2align 4 +L(Exit14): + lea -3(%edi), %eax + RETURN + + .p2align 4 +L(Exit15): + lea -2(%edi), %eax + RETURN + + .p2align 4 +L(Exit16): + lea -1(%edi), %eax + RETURN + +/* Return NULL. */ + .p2align 4 +L(return_null): + xor %eax, %eax + RETURN + + .p2align 4 +L(prolog_find_zero): + add %ecx, %edi + mov %edx, %ecx +L(prolog_find_zero_1): + test %cl, %cl + jz L(prolog_find_zero_high) + mov %cl, %dl + and $15, %dl + jz L(prolog_find_zero_8) + test $0x01, %cl + jnz L(PrologFindZeroExit1) + test $0x02, %cl + jnz L(PrologFindZeroExit2) + test $0x04, %cl + jnz L(PrologFindZeroExit3) + and $(1 << 4) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(prolog_find_zero_8): + test $0x10, %cl + jnz L(PrologFindZeroExit5) + test $0x20, %cl + jnz L(PrologFindZeroExit6) + test $0x40, %cl + jnz L(PrologFindZeroExit7) + and $(1 << 8) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(prolog_find_zero_high): + mov %ch, %dh + and $15, %dh + jz L(prolog_find_zero_high_8) + test $0x01, %ch + jnz L(PrologFindZeroExit9) + test $0x02, %ch + jnz L(PrologFindZeroExit10) + test $0x04, %ch + jnz L(PrologFindZeroExit11) + and $(1 << 12) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(prolog_find_zero_high_8): + test $0x10, %ch + jnz L(PrologFindZeroExit13) + test $0x20, %ch + jnz L(PrologFindZeroExit14) + test $0x40, %ch + jnz L(PrologFindZeroExit15) + and $(1 << 16) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit1): + and $1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit2): + and $(1 << 2) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit3): + and $(1 << 3) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit5): + and $(1 << 5) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit6): + and $(1 << 6) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit7): + and $(1 << 7) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit9): + and $(1 << 9) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit10): + and $(1 << 10) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit11): + and $(1 << 11) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit13): + and $(1 << 13) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit14): + and $(1 << 14) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + + .p2align 4 +L(PrologFindZeroExit15): + and $(1 << 15) - 1, %eax + jnz L(match_case1) + xor %eax, %eax + RETURN + +END (strrchr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-wcschr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcschr-atom.S new file mode 100644 index 000000000..729302bcd --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcschr-atom.S @@ -0,0 +1,267 @@ +/* +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 4 + + +#define STR1 PARMS +#define STR2 STR1+4 + + .text +ENTRY (wcschr) + + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + + mov %ecx, %eax + punpckldq %xmm1, %xmm1 + pxor %xmm2, %xmm2 + punpckldq %xmm1, %xmm1 + + and $63, %eax + cmp $48, %eax + ja L(cross_cache) + + movdqu (%ecx), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + or %eax, %edx + jnz L(matches) + and $-16, %ecx + jmp L(loop) + + .p2align 4 +L(cross_cache): + PUSH (%edi) + mov %ecx, %edi + mov %eax, %ecx + and $-16, %edi + and $15, %ecx + movdqa (%edi), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + + sarl %cl, %edx + sarl %cl, %eax + test %eax, %eax + jz L(unaligned_no_match) + + add %edi, %ecx + POP (%edi) + + test %edx, %edx + jz L(match_case1) + test %al, %al + jz L(match_higth_case2) + test $15, %al + jnz L(match_case2_4) + test $15, %dl + jnz L(return_null) + lea 4(%ecx), %eax + ret + + CFI_PUSH (%edi) + + .p2align 4 +L(unaligned_no_match): + mov %edi, %ecx + POP (%edi) + + test %edx, %edx + jnz L(return_null) + + pxor %xmm2, %xmm2 + +/* Loop start on aligned string. */ + .p2align 4 +L(loop): + add $16, %ecx + movdqa (%ecx), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + or %eax, %edx + jnz L(matches) + add $16, %ecx + + movdqa (%ecx), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + or %eax, %edx + jnz L(matches) + add $16, %ecx + + movdqa (%ecx), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + or %eax, %edx + jnz L(matches) + add $16, %ecx + + movdqa (%ecx), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %edx + pmovmskb %xmm0, %eax + or %eax, %edx + jz L(loop) + + .p2align 4 +L(matches): + pmovmskb %xmm2, %edx + test %eax, %eax + jz L(return_null) + test %edx, %edx + jz L(match_case1) + + .p2align 4 +L(match_case2): + test %al, %al + jz L(match_higth_case2) + test $15, %al + jnz L(match_case2_4) + test $15, %dl + jnz L(return_null) + lea 4(%ecx), %eax + ret + + .p2align 4 +L(match_case2_4): + mov %ecx, %eax + ret + + .p2align 4 +L(match_higth_case2): + test %dl, %dl + jnz L(return_null) + test $15, %ah + jnz L(match_case2_12) + test $15, %dh + jnz L(return_null) + lea 12(%ecx), %eax + ret + + .p2align 4 +L(match_case2_12): + lea 8(%ecx), %eax + ret + + .p2align 4 +L(match_case1): + test %al, %al + jz L(match_higth_case1) + + test $0x01, %al + jnz L(exit0) + lea 4(%ecx), %eax + ret + + .p2align 4 +L(match_higth_case1): + test $0x01, %ah + jnz L(exit3) + lea 12(%ecx), %eax + ret + + .p2align 4 +L(exit0): + mov %ecx, %eax + ret + + .p2align 4 +L(exit3): + lea 8(%ecx), %eax + ret + + .p2align 4 +L(return_null): + xor %eax, %eax + ret + +END (wcschr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-wcscmp-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcscmp-atom.S new file mode 100644 index 000000000..8867d28ae --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcscmp-atom.S @@ -0,0 +1,1062 @@ +/* +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define ENTRANCE PUSH(%esi); PUSH(%edi) +#define RETURN POP(%edi); POP(%esi); ret; CFI_PUSH(%esi); CFI_PUSH(%edi); +#define PARMS 4 +#define STR1 PARMS +#define STR2 STR1+4 + + .text +ENTRY (wcscmp) +/* + * This implementation uses SSE to compare up to 16 bytes at a time. +*/ + mov STR1(%esp), %edx + mov STR2(%esp), %eax + + mov (%eax), %ecx + cmp %ecx, (%edx) + jne L(neq) + test %ecx, %ecx + jz L(eq) + + mov 4(%eax), %ecx + cmp %ecx, 4(%edx) + jne L(neq) + test %ecx, %ecx + jz L(eq) + + mov 8(%eax), %ecx + cmp %ecx, 8(%edx) + jne L(neq) + test %ecx, %ecx + jz L(eq) + + mov 12(%eax), %ecx + cmp %ecx, 12(%edx) + jne L(neq) + test %ecx, %ecx + jz L(eq) + + ENTRANCE + add $16, %eax + add $16, %edx + + mov %eax, %esi + mov %edx, %edi + pxor %xmm0, %xmm0 /* clear %xmm0 for null char checks */ + mov %al, %ch + mov %dl, %cl + and $63, %eax /* esi alignment in cache line */ + and $63, %edx /* edi alignment in cache line */ + and $15, %cl + jz L(continue_00) + cmp $16, %edx + jb L(continue_0) + cmp $32, %edx + jb L(continue_16) + cmp $48, %edx + jb L(continue_32) + +L(continue_48): + and $15, %ch + jz L(continue_48_00) + cmp $16, %eax + jb L(continue_0_48) + cmp $32, %eax + jb L(continue_16_48) + cmp $48, %eax + jb L(continue_32_48) + + .p2align 4 +L(continue_48_48): + mov (%esi), %ecx + cmp %ecx, (%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + movdqu 16(%edi), %xmm1 + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%edi), %xmm1 + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + movdqu 48(%edi), %xmm1 + movdqu 48(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_48_48) + +L(continue_0): + and $15, %ch + jz L(continue_0_00) + cmp $16, %eax + jb L(continue_0_0) + cmp $32, %eax + jb L(continue_0_16) + cmp $48, %eax + jb L(continue_0_32) + + .p2align 4 +L(continue_0_48): + mov (%esi), %ecx + cmp %ecx, (%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + movdqu 16(%edi), %xmm1 + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%edi), %xmm1 + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + mov 48(%esi), %ecx + cmp %ecx, 48(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 52(%esi), %ecx + cmp %ecx, 52(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 56(%esi), %ecx + cmp %ecx, 56(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 60(%esi), %ecx + cmp %ecx, 60(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + add $64, %esi + add $64, %edi + jmp L(continue_0_48) + + .p2align 4 +L(continue_00): + and $15, %ch + jz L(continue_00_00) + cmp $16, %eax + jb L(continue_00_0) + cmp $32, %eax + jb L(continue_00_16) + cmp $48, %eax + jb L(continue_00_32) + + .p2align 4 +L(continue_00_48): + pcmpeqd (%edi), %xmm0 + mov (%edi), %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(less4_double_words1) + + cmp (%esi), %eax + jne L(nequal) + + mov 4(%edi), %eax + cmp 4(%esi), %eax + jne L(nequal) + + mov 8(%edi), %eax + cmp 8(%esi), %eax + jne L(nequal) + + mov 12(%edi), %eax + cmp 12(%esi), %eax + jne L(nequal) + + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 32(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + movdqu 48(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 48(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_00_48) + + .p2align 4 +L(continue_32): + and $15, %ch + jz L(continue_32_00) + cmp $16, %eax + jb L(continue_0_32) + cmp $32, %eax + jb L(continue_16_32) + cmp $48, %eax + jb L(continue_32_32) + + .p2align 4 +L(continue_32_48): + mov (%esi), %ecx + cmp %ecx, (%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 16(%esi), %ecx + cmp %ecx, 16(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 20(%esi), %ecx + cmp %ecx, 20(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 24(%esi), %ecx + cmp %ecx, 24(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 28(%esi), %ecx + cmp %ecx, 28(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + movdqu 32(%edi), %xmm1 + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + movdqu 48(%edi), %xmm1 + movdqu 48(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_32_48) + + .p2align 4 +L(continue_16): + and $15, %ch + jz L(continue_16_00) + cmp $16, %eax + jb L(continue_0_16) + cmp $32, %eax + jb L(continue_16_16) + cmp $48, %eax + jb L(continue_16_32) + + .p2align 4 +L(continue_16_48): + mov (%esi), %ecx + cmp %ecx, (%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + movdqu 16(%edi), %xmm1 + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + mov 32(%esi), %ecx + cmp %ecx, 32(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 36(%esi), %ecx + cmp %ecx, 36(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 40(%esi), %ecx + cmp %ecx, 40(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 44(%esi), %ecx + cmp %ecx, 44(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + movdqu 48(%edi), %xmm1 + movdqu 48(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_16_48) + + .p2align 4 +L(continue_00_00): + movdqa (%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd (%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqa 16(%edi), %xmm3 + pcmpeqd %xmm3, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%esi), %xmm3 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm3 /* packed sub of comparison results*/ + pmovmskb %xmm3, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqa 32(%edi), %xmm5 + pcmpeqd %xmm5, %xmm0 /* Any null double_word? */ + pcmpeqd 32(%esi), %xmm5 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm5 /* packed sub of comparison results*/ + pmovmskb %xmm5, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + movdqa 48(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 48(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_00_00) + + .p2align 4 +L(continue_00_32): + movdqu (%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd (%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + add $16, %esi + add $16, %edi + jmp L(continue_00_48) + + .p2align 4 +L(continue_00_16): + movdqu (%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd (%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + add $32, %esi + add $32, %edi + jmp L(continue_00_48) + + .p2align 4 +L(continue_00_0): + movdqu (%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd (%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm2, %xmm0 /* Any null double_word? */ + pcmpeqd 32(%edi), %xmm2 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + add $48, %esi + add $48, %edi + jmp L(continue_00_48) + + .p2align 4 +L(continue_48_00): + pcmpeqd (%esi), %xmm0 + mov (%edi), %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(less4_double_words1) + + cmp (%esi), %eax + jne L(nequal) + + mov 4(%edi), %eax + cmp 4(%esi), %eax + jne L(nequal) + + mov 8(%edi), %eax + cmp 8(%esi), %eax + jne L(nequal) + + mov 12(%edi), %eax + cmp 12(%esi), %eax + jne L(nequal) + + movdqu 16(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 32(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + movdqu 48(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 48(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_48) + + add $64, %esi + add $64, %edi + jmp L(continue_48_00) + + .p2align 4 +L(continue_32_00): + movdqu (%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd (%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + add $16, %esi + add $16, %edi + jmp L(continue_48_00) + + .p2align 4 +L(continue_16_00): + movdqu (%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd (%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + add $32, %esi + add $32, %edi + jmp L(continue_48_00) + + .p2align 4 +L(continue_0_00): + movdqu (%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd (%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 16(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%edi), %xmm1 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd 32(%esi), %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + add $48, %esi + add $48, %edi + jmp L(continue_48_00) + + .p2align 4 +L(continue_32_32): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + add $16, %esi + add $16, %edi + jmp L(continue_48_48) + + .p2align 4 +L(continue_16_16): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%edi), %xmm3 + movdqu 16(%esi), %xmm4 + pcmpeqd %xmm3, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm4, %xmm3 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm3 /* packed sub of comparison results*/ + pmovmskb %xmm3, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + add $32, %esi + add $32, %edi + jmp L(continue_48_48) + + .p2align 4 +L(continue_0_0): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%edi), %xmm3 + movdqu 16(%esi), %xmm4 + pcmpeqd %xmm3, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm4, %xmm3 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm3 /* packed sub of comparison results*/ + pmovmskb %xmm3, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + movdqu 32(%edi), %xmm1 + movdqu 32(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_32) + + add $48, %esi + add $48, %edi + jmp L(continue_48_48) + + .p2align 4 +L(continue_0_16): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + movdqu 16(%edi), %xmm1 + movdqu 16(%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words_16) + + add $32, %esi + add $32, %edi + jmp L(continue_32_48) + + .p2align 4 +L(continue_0_32): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + add $16, %esi + add $16, %edi + jmp L(continue_16_48) + + .p2align 4 +L(continue_16_32): + movdqu (%edi), %xmm1 + movdqu (%esi), %xmm2 + pcmpeqd %xmm1, %xmm0 /* Any null double_word? */ + pcmpeqd %xmm2, %xmm1 /* compare first 4 double_words for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 4 double_words are same, edx == 0xffff */ + jnz L(less4_double_words) + + add $16, %esi + add $16, %edi + jmp L(continue_32_48) + + .p2align 4 +L(less4_double_words1): + cmp (%esi), %eax + jne L(nequal) + test %eax, %eax + jz L(equal) + + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + test %ecx, %ecx + jz L(equal) + + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + xor %eax, %eax + RETURN + + .p2align 4 +L(less4_double_words): + xor %eax, %eax + test %dl, %dl + jz L(next_two_double_words) + and $15, %dl + jz L(second_double_word) + mov (%esi), %ecx + cmp %ecx, (%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(second_double_word): + mov 4(%esi), %ecx + cmp %ecx, 4(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(next_two_double_words): + and $15, %dh + jz L(fourth_double_word) + mov 8(%esi), %ecx + cmp %ecx, 8(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(fourth_double_word): + mov 12(%esi), %ecx + cmp %ecx, 12(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(less4_double_words_16): + xor %eax, %eax + test %dl, %dl + jz L(next_two_double_words_16) + and $15, %dl + jz L(second_double_word_16) + mov 16(%esi), %ecx + cmp %ecx, 16(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(second_double_word_16): + mov 20(%esi), %ecx + cmp %ecx, 20(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(next_two_double_words_16): + and $15, %dh + jz L(fourth_double_word_16) + mov 24(%esi), %ecx + cmp %ecx, 24(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(fourth_double_word_16): + mov 28(%esi), %ecx + cmp %ecx, 28(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(less4_double_words_32): + xor %eax, %eax + test %dl, %dl + jz L(next_two_double_words_32) + and $15, %dl + jz L(second_double_word_32) + mov 32(%esi), %ecx + cmp %ecx, 32(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(second_double_word_32): + mov 36(%esi), %ecx + cmp %ecx, 36(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(next_two_double_words_32): + and $15, %dh + jz L(fourth_double_word_32) + mov 40(%esi), %ecx + cmp %ecx, 40(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(fourth_double_word_32): + mov 44(%esi), %ecx + cmp %ecx, 44(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(less4_double_words_48): + xor %eax, %eax + test %dl, %dl + jz L(next_two_double_words_48) + and $15, %dl + jz L(second_double_word_48) + mov 48(%esi), %ecx + cmp %ecx, 48(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(second_double_word_48): + mov 52(%esi), %ecx + cmp %ecx, 52(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(next_two_double_words_48): + and $15, %dh + jz L(fourth_double_word_48) + mov 56(%esi), %ecx + cmp %ecx, 56(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(fourth_double_word_48): + mov 60(%esi), %ecx + cmp %ecx, 60(%edi) + jne L(nequal) + RETURN + + .p2align 4 +L(nequal): + mov $1, %eax + jg L(return) + neg %eax + RETURN + + .p2align 4 +L(return): + RETURN + + .p2align 4 +L(equal): + xorl %eax, %eax + RETURN + + CFI_POP (%edi) + CFI_POP (%esi) + + .p2align 4 +L(neq): + mov $1, %eax + jg L(neq_bigger) + neg %eax + +L(neq_bigger): + ret + + .p2align 4 +L(eq): + xorl %eax, %eax + ret + +END (wcscmp) + diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-wcslen-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcslen-atom.S new file mode 100644 index 000000000..2f10db450 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcslen-atom.S @@ -0,0 +1,306 @@ +/* +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_WCSCAT + +# ifndef L +# define L(label) .L##label +# endif + +# ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +# endif + +# ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +# endif + +# ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +# endif + +# ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +# endif + +# define PARMS 4 +# define STR PARMS +# define RETURN ret + + .text +ENTRY (wcslen) + mov STR(%esp), %edx +#endif + cmpl $0, (%edx) + jz L(exit_tail0) + cmpl $0, 4(%edx) + jz L(exit_tail1) + cmpl $0, 8(%edx) + jz L(exit_tail2) + cmpl $0, 12(%edx) + jz L(exit_tail3) + cmpl $0, 16(%edx) + jz L(exit_tail4) + cmpl $0, 20(%edx) + jz L(exit_tail5) + cmpl $0, 24(%edx) + jz L(exit_tail6) + cmpl $0, 28(%edx) + jz L(exit_tail7) + + pxor %xmm0, %xmm0 + + lea 32(%edx), %eax + lea -16(%eax), %ecx + and $-16, %eax + + pcmpeqd (%eax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm1 + pmovmskb %xmm1, %edx + pxor %xmm2, %xmm2 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm2 + pmovmskb %xmm2, %edx + pxor %xmm3, %xmm3 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqd (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + and $-0x40, %eax + + .p2align 4 +L(aligned_64_loop): + movaps (%eax), %xmm0 + movaps 16(%eax), %xmm1 + movaps 32(%eax), %xmm2 + movaps 48(%eax), %xmm6 + + pminub %xmm1, %xmm0 + pminub %xmm6, %xmm2 + pminub %xmm0, %xmm2 + pcmpeqd %xmm3, %xmm2 + pmovmskb %xmm2, %edx + lea 64(%eax), %eax + test %edx, %edx + jz L(aligned_64_loop) + + pcmpeqd -64(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 48(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqd %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqd -32(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqd %xmm6, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + jmp L(aligned_64_loop) + + .p2align 4 +L(exit): + sub %ecx, %eax + shr $2, %eax + test %dl, %dl + jz L(exit_high) + + mov %dl, %cl + and $15, %cl + jz L(exit_1) + RETURN + + .p2align 4 +L(exit_high): + mov %dh, %ch + and $15, %ch + jz L(exit_3) + add $2, %eax + RETURN + + .p2align 4 +L(exit_1): + add $1, %eax + RETURN + + .p2align 4 +L(exit_3): + add $3, %eax + RETURN + + .p2align 4 +L(exit_tail0): + xor %eax, %eax + RETURN + + .p2align 4 +L(exit_tail1): + mov $1, %eax + RETURN + + .p2align 4 +L(exit_tail2): + mov $2, %eax + RETURN + + .p2align 4 +L(exit_tail3): + mov $3, %eax + RETURN + + .p2align 4 +L(exit_tail4): + mov $4, %eax + RETURN + + .p2align 4 +L(exit_tail5): + mov $5, %eax + RETURN + + .p2align 4 +L(exit_tail6): + mov $6, %eax + RETURN + + .p2align 4 +L(exit_tail7): + mov $7, %eax +#ifndef USE_AS_WCSCAT + RETURN + +END (wcslen) +#endif diff --git a/aosp/bionic/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S new file mode 100644 index 000000000..1a55df24a --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S @@ -0,0 +1,402 @@ +/* +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 8 +#define ENTRANCE PUSH(%edi); +#define RETURN POP(%edi); ret; CFI_PUSH(%edi); + +#define STR1 PARMS +#define STR2 STR1+4 + + .text +ENTRY (wcsrchr) + + ENTRANCE + mov STR1(%esp), %ecx + movd STR2(%esp), %xmm1 + + mov %ecx, %edi + punpckldq %xmm1, %xmm1 + pxor %xmm2, %xmm2 + punpckldq %xmm1, %xmm1 + +/* ECX has OFFSET. */ + and $63, %ecx + cmp $48, %ecx + ja L(crosscache) + +/* unaligned string. */ + movdqu (%edi), %xmm0 + pcmpeqd %xmm0, %xmm2 + pcmpeqd %xmm1, %xmm0 +/* Find where NULL is. */ + pmovmskb %xmm2, %ecx +/* Check if there is a match. */ + pmovmskb %xmm0, %eax + add $16, %edi + + test %eax, %eax + jnz L(unaligned_match1) + + test %ecx, %ecx + jnz L(return_null) + + and $-16, %edi + + PUSH (%esi) + + xor %edx, %edx + jmp L(loop) + + CFI_POP (%esi) + + .p2align 4 +L(unaligned_match1): + test %ecx, %ecx + jnz L(prolog_find_zero_1) + + PUSH (%esi) + +/* Save current match */ + mov %eax, %edx + mov %edi, %esi + and $-16, %edi + jmp L(loop) + + CFI_POP (%esi) + + .p2align 4 +L(crosscache): +/* Hancle unaligned string. */ + and $15, %ecx + and $-16, %edi + pxor %xmm3, %xmm3 + movdqa (%edi), %xmm0 + pcmpeqd %xmm0, %xmm3 + pcmpeqd %xmm1, %xmm0 +/* Find where NULL is. */ + pmovmskb %xmm3, %edx +/* Check if there is a match. */ + pmovmskb %xmm0, %eax +/* Remove the leading bytes. */ + shr %cl, %edx + shr %cl, %eax + add $16, %edi + + test %eax, %eax + jnz L(unaligned_match) + + test %edx, %edx + jnz L(return_null) + + PUSH (%esi) + + xor %edx, %edx + jmp L(loop) + + CFI_POP (%esi) + + .p2align 4 +L(unaligned_match): + test %edx, %edx + jnz L(prolog_find_zero) + + PUSH (%esi) + + mov %eax, %edx + lea (%edi, %ecx), %esi + +/* Loop start on aligned string. */ + .p2align 4 +L(loop): + movdqa (%edi), %xmm0 + pcmpeqd %xmm0, %xmm2 + add $16, %edi + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm2, %ecx + pmovmskb %xmm0, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm3 + pcmpeqd %xmm3, %xmm2 + add $16, %edi + pcmpeqd %xmm1, %xmm3 + pmovmskb %xmm2, %ecx + pmovmskb %xmm3, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm4 + pcmpeqd %xmm4, %xmm2 + add $16, %edi + pcmpeqd %xmm1, %xmm4 + pmovmskb %xmm2, %ecx + pmovmskb %xmm4, %eax + or %eax, %ecx + jnz L(matches) + + movdqa (%edi), %xmm5 + pcmpeqd %xmm5, %xmm2 + add $16, %edi + pcmpeqd %xmm1, %xmm5 + pmovmskb %xmm2, %ecx + pmovmskb %xmm5, %eax + or %eax, %ecx + jz L(loop) + + .p2align 4 +L(matches): + test %eax, %eax + jnz L(match) +L(return_value): + test %edx, %edx + jz L(return_null_1) + mov %edx, %eax + mov %esi, %edi + + POP (%esi) + + test %ah, %ah + jnz L(match_third_or_fourth_wchar) + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(return_null_1): + POP (%esi) + + xor %eax, %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(match): + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(find_zero) +/* save match info */ + mov %eax, %edx + mov %edi, %esi + jmp L(loop) + + .p2align 4 +L(find_zero): + test %cl, %cl + jz L(find_zero_in_third_or_fourth_wchar) + test $15, %cl + jz L(find_zero_in_second_wchar) + and $1, %eax + jz L(return_value) + + POP (%esi) + + lea -16(%edi), %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_in_second_wchar): + and $(1 << 5) - 1, %eax + jz L(return_value) + + POP (%esi) + + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_in_third_or_fourth_wchar): + test $15, %ch + jz L(find_zero_in_fourth_wchar) + and $(1 << 9) - 1, %eax + jz L(return_value) + + POP (%esi) + + test %ah, %ah + jnz L(match_third_wchar) + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(find_zero_in_fourth_wchar): + + POP (%esi) + + test %ah, %ah + jnz L(match_third_or_fourth_wchar) + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(match_second_wchar): + lea -12(%edi), %eax + RETURN + + .p2align 4 +L(match_third_or_fourth_wchar): + test $15 << 4, %ah + jnz L(match_fourth_wchar) + lea -8(%edi), %eax + RETURN + + .p2align 4 +L(match_third_wchar): + lea -8(%edi), %eax + RETURN + + .p2align 4 +L(match_fourth_wchar): + lea -4(%edi), %eax + RETURN + + .p2align 4 +L(return_null): + xor %eax, %eax + RETURN + + .p2align 4 +L(prolog_find_zero): + add %ecx, %edi + mov %edx, %ecx +L(prolog_find_zero_1): + test %cl, %cl + jz L(prolog_find_zero_in_third_or_fourth_wchar) + test $15, %cl + jz L(prolog_find_zero_in_second_wchar) + and $1, %eax + jz L(return_null) + + lea -16(%edi), %eax + RETURN + + .p2align 4 +L(prolog_find_zero_in_second_wchar): + and $(1 << 5) - 1, %eax + jz L(return_null) + + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + .p2align 4 +L(prolog_find_zero_in_third_or_fourth_wchar): + test $15, %ch + jz L(prolog_find_zero_in_fourth_wchar) + and $(1 << 9) - 1, %eax + jz L(return_null) + + test %ah, %ah + jnz L(match_third_wchar) + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + + .p2align 4 +L(prolog_find_zero_in_fourth_wchar): + test %ah, %ah + jnz L(match_third_or_fourth_wchar) + test $15 << 4, %al + jnz L(match_second_wchar) + lea -16(%edi), %eax + RETURN + +END (wcsrchr) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcmp-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcmp-atom.S new file mode 100644 index 000000000..be2c4f6f5 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcmp-atom.S @@ -0,0 +1,2496 @@ +/* +Copyright (c) 2010, 2011, 2012, 2013 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef cfi_remember_state +# define cfi_remember_state .cfi_remember_state +#endif + +#ifndef cfi_restore_state +# define cfi_restore_state .cfi_restore_state +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#ifndef MEMCMP +# define MEMCMP memcmp_atom +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 4 +#define BLK1 PARMS +#define BLK2 BLK1+4 +#define LEN BLK2+4 +#define RETURN_END POP (%edi); POP (%esi); POP (%ebx); ret +#define RETURN RETURN_END; cfi_restore_state; cfi_remember_state + +/* Warning! + wmemcmp has to use SIGNED comparison for elements. + memcmp has to use UNSIGNED comparison for elemnts. +*/ + + .text +ENTRY (MEMCMP) + movl LEN(%esp), %ecx + +#ifdef USE_WCHAR + shl $2, %ecx + jz L(zero) +#elif defined USE_UTF16 + shl $1, %ecx + jz L(zero) +#endif + + movl BLK1(%esp), %eax + cmp $48, %ecx + movl BLK2(%esp), %edx + jae L(48bytesormore) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $1, %ecx + jbe L(less1bytes) +#endif + + PUSH (%ebx) + add %ecx, %edx + add %ecx, %eax + jmp L(less48bytes) + + CFI_POP (%ebx) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + .p2align 4 +L(less1bytes): + jb L(zero) + movb (%eax), %cl + cmp (%edx), %cl + je L(zero) + mov $1, %eax + ja L(1bytesend) + neg %eax +L(1bytesend): + ret +#endif + + .p2align 4 +L(zero): + xor %eax, %eax + ret + + .p2align 4 +L(48bytesormore): + PUSH (%ebx) + PUSH (%esi) + PUSH (%edi) + cfi_remember_state + movdqu (%eax), %xmm3 + movdqu (%edx), %xmm0 + movl %eax, %edi + movl %edx, %esi + pcmpeqb %xmm0, %xmm3 + pmovmskb %xmm3, %edx + lea 16(%edi), %edi + + sub $0xffff, %edx + lea 16(%esi), %esi + jnz L(less16bytes) + mov %edi, %edx + and $0xf, %edx + xor %edx, %edi + sub %edx, %esi + add %edx, %ecx + mov %esi, %edx + and $0xf, %edx + jz L(shr_0) + xor %edx, %esi + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $8, %edx + jae L(next_unaligned_table) + cmp $0, %edx + je L(shr_0) + cmp $1, %edx + je L(shr_1) + cmp $2, %edx + je L(shr_2) + cmp $3, %edx + je L(shr_3) + cmp $4, %edx + je L(shr_4) + cmp $5, %edx + je L(shr_5) + cmp $6, %edx + je L(shr_6) + jmp L(shr_7) + + .p2align 2 +L(next_unaligned_table): + cmp $8, %edx + je L(shr_8) + cmp $9, %edx + je L(shr_9) + cmp $10, %edx + je L(shr_10) + cmp $11, %edx + je L(shr_11) + cmp $12, %edx + je L(shr_12) + cmp $13, %edx + je L(shr_13) + cmp $14, %edx + je L(shr_14) + jmp L(shr_15) +#elif defined(USE_WCHAR) + cmp $0, %edx + je L(shr_0) + cmp $4, %edx + je L(shr_4) + cmp $8, %edx + je L(shr_8) + jmp L(shr_12) +#elif defined(USE_UTF16) + cmp $0, %edx + je L(shr_0) + cmp $2, %edx + je L(shr_2) + cmp $4, %edx + je L(shr_4) + cmp $6, %edx + je L(shr_6) + cmp $8, %edx + je L(shr_8) + cmp $10, %edx + je L(shr_10) + cmp $12, %edx + je L(shr_12) + jmp L(shr_14) +#endif + + .p2align 4 +L(shr_0): + cmp $80, %ecx + jae L(shr_0_gobble) + lea -48(%ecx), %ecx + xor %eax, %eax + movaps (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + movaps 16(%esi), %xmm2 + pcmpeqb 16(%edi), %xmm2 + pand %xmm1, %xmm2 + pmovmskb %xmm2, %edx + add $32, %edi + add $32, %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea (%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_0_gobble): + lea -48(%ecx), %ecx + movdqa (%esi), %xmm0 + xor %eax, %eax + pcmpeqb (%edi), %xmm0 + sub $32, %ecx + movdqa 16(%esi), %xmm2 + pcmpeqb 16(%edi), %xmm2 +L(shr_0_gobble_loop): + pand %xmm0, %xmm2 + sub $32, %ecx + pmovmskb %xmm2, %edx + movdqa %xmm0, %xmm1 + movdqa 32(%esi), %xmm0 + movdqa 48(%esi), %xmm2 + sbb $0xffff, %edx + pcmpeqb 32(%edi), %xmm0 + pcmpeqb 48(%edi), %xmm2 + lea 32(%edi), %edi + lea 32(%esi), %esi + jz L(shr_0_gobble_loop) + + pand %xmm0, %xmm2 + cmp $0, %ecx + jge L(shr_0_gobble_loop_next) + inc %edx + add $32, %ecx +L(shr_0_gobble_loop_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm2, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea (%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_1): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_1_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $1,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $1,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 1(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_1_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $1,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $1,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_1_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $1,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $1,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_1_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_1_gobble_next) + inc %edx + add $32, %ecx +L(shr_1_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 1(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + + +#if !defined(USE_WCHAR) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_2): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_2_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $2,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $2,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 2(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_2_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $2,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $2,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_2_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $2,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $2,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_2_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_2_gobble_next) + inc %edx + add $32, %ecx +L(shr_2_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 2(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_3): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_3_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $3,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $3,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 3(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_3_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $3,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $3,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_3_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $3,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $3,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_3_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_3_gobble_next) + inc %edx + add $32, %ecx +L(shr_3_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 3(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_4): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_4_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $4,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $4,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 4(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_4_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $4,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $4,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_4_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $4,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $4,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_4_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_4_gobble_next) + inc %edx + add $32, %ecx +L(shr_4_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 4(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_5): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_5_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $5,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $5,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 5(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_5_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $5,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $5,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_5_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $5,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $5,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_5_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_5_gobble_next) + inc %edx + add $32, %ecx +L(shr_5_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 5(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_6): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_6_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $6,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $6,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 6(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_6_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $6,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $6,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_6_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $6,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $6,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_6_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_6_gobble_next) + inc %edx + add $32, %ecx +L(shr_6_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 6(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_7): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_7_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $7,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $7,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 7(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_7_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $7,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $7,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_7_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $7,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $7,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_7_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_7_gobble_next) + inc %edx + add $32, %ecx +L(shr_7_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 7(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_8): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_8_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $8,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $8,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 8(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_8_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $8,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $8,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_8_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $8,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $8,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_8_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_8_gobble_next) + inc %edx + add $32, %ecx +L(shr_8_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 8(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_9): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_9_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $9,(%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $9,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 9(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_9_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $9,(%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $9,16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_9_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $9,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $9,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_9_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_9_gobble_next) + inc %edx + add $32, %ecx +L(shr_9_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 9(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_10): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_10_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $10, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $10,%xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 10(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_10_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $10, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $10, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_10_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $10,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $10,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_10_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_10_gobble_next) + inc %edx + add $32, %ecx +L(shr_10_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 10(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_11): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_11_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $11, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $11, %xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 11(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_11_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $11, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $11, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_11_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $11,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $11,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_11_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_11_gobble_next) + inc %edx + add $32, %ecx +L(shr_11_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 11(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_12): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_12_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $12, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $12, %xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 12(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_12_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $12, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $12, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_12_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $12,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $12,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_12_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_12_gobble_next) + inc %edx + add $32, %ecx +L(shr_12_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 12(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_13): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_13_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $13, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $13, %xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 13(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_13_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $13, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $13, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_13_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $13,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $13,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_13_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_13_gobble_next) + inc %edx + add $32, %ecx +L(shr_13_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 13(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_14): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_14_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $14, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $14, %xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 14(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_14_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $14, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $14, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_14_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $14,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $14,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_14_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_14_gobble_next) + inc %edx + add $32, %ecx +L(shr_14_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 14(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_15): + cmp $80, %ecx + lea -48(%ecx), %ecx + mov %edx, %eax + jae L(shr_15_gobble) + + movdqa 16(%esi), %xmm1 + movdqa %xmm1, %xmm2 + palignr $15, (%esi), %xmm1 + pcmpeqb (%edi), %xmm1 + + movdqa 32(%esi), %xmm3 + palignr $15, %xmm2, %xmm3 + pcmpeqb 16(%edi), %xmm3 + + pand %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + lea (%ecx, %edi,1), %eax + lea 15(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(shr_15_gobble): + sub $32, %ecx + movdqa 16(%esi), %xmm0 + palignr $15, (%esi), %xmm0 + pcmpeqb (%edi), %xmm0 + + movdqa 32(%esi), %xmm3 + palignr $15, 16(%esi), %xmm3 + pcmpeqb 16(%edi), %xmm3 + +L(shr_15_gobble_loop): + pand %xmm0, %xmm3 + sub $32, %ecx + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + + movdqa 64(%esi), %xmm3 + palignr $15,48(%esi), %xmm3 + sbb $0xffff, %edx + movdqa 48(%esi), %xmm0 + palignr $15,32(%esi), %xmm0 + pcmpeqb 32(%edi), %xmm0 + lea 32(%esi), %esi + pcmpeqb 48(%edi), %xmm3 + + lea 32(%edi), %edi + jz L(shr_15_gobble_loop) + pand %xmm0, %xmm3 + + cmp $0, %ecx + jge L(shr_15_gobble_next) + inc %edx + add $32, %ecx +L(shr_15_gobble_next): + test %edx, %edx + jnz L(exit) + + pmovmskb %xmm3, %edx + movdqa %xmm0, %xmm1 + lea 32(%edi), %edi + lea 32(%esi), %esi + sub $0xffff, %edx + jnz L(exit) + + lea (%ecx, %edi,1), %eax + lea 15(%ecx, %esi,1), %edx + POP (%edi) + POP (%esi) + jmp L(less48bytes) +#endif + + cfi_restore_state + cfi_remember_state + .p2align 4 +L(exit): + pmovmskb %xmm1, %ebx + sub $0xffff, %ebx + jz L(first16bytes) + lea -16(%esi), %esi + lea -16(%edi), %edi + mov %ebx, %edx + +L(first16bytes): + add %eax, %esi +L(less16bytes): + +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + test %dl, %dl + jz L(next_24_bytes) + + test $0x01, %dl + jnz L(Byte16) + + test $0x02, %dl + jnz L(Byte17) + + test $0x04, %dl + jnz L(Byte18) + + test $0x08, %dl + jnz L(Byte19) + + test $0x10, %dl + jnz L(Byte20) + + test $0x20, %dl + jnz L(Byte21) + + test $0x40, %dl + jnz L(Byte22) +L(Byte23): + movzbl -9(%edi), %eax + movzbl -9(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte16): + movzbl -16(%edi), %eax + movzbl -16(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte17): + movzbl -15(%edi), %eax + movzbl -15(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte18): + movzbl -14(%edi), %eax + movzbl -14(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte19): + movzbl -13(%edi), %eax + movzbl -13(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte20): + movzbl -12(%edi), %eax + movzbl -12(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte21): + movzbl -11(%edi), %eax + movzbl -11(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(Byte22): + movzbl -10(%edi), %eax + movzbl -10(%esi), %edx + sub %edx, %eax + RETURN + + .p2align 4 +L(next_24_bytes): + lea 8(%edi), %edi + lea 8(%esi), %esi + test $0x01, %dh + jnz L(Byte16) + + test $0x02, %dh + jnz L(Byte17) + + test $0x04, %dh + jnz L(Byte18) + + test $0x08, %dh + jnz L(Byte19) + + test $0x10, %dh + jnz L(Byte20) + + test $0x20, %dh + jnz L(Byte21) + + test $0x40, %dh + jnz L(Byte22) + + .p2align 4 +L(Byte31): + movzbl -9(%edi), %eax + movzbl -9(%esi), %edx + sub %edx, %eax + RETURN_END +#elif defined(USE_AS_WMEMCMP) + +/* special for wmemcmp */ + test %dl, %dl + jz L(next_two_double_words) + and $15, %dl + jz L(second_double_word) + mov -16(%edi), %ecx + cmp -16(%esi), %ecx + mov $1, %eax + jg L(nequal_bigger) + neg %eax + RETURN + + .p2align 4 +L(second_double_word): + mov -12(%edi), %ecx + cmp -12(%esi), %ecx + mov $1, %eax + jg L(nequal_bigger) + neg %eax + RETURN + + .p2align 4 +L(next_two_double_words): + and $15, %dh + jz L(fourth_double_word) + mov -8(%edi), %ecx + cmp -8(%esi), %ecx + mov $1, %eax + jg L(nequal_bigger) + neg %eax + RETURN + + .p2align 4 +L(fourth_double_word): + mov -4(%edi), %ecx + cmp -4(%esi), %ecx + mov $1, %eax + jg L(nequal_bigger) + neg %eax + RETURN + + .p2align 4 +L(nequal_bigger): + RETURN_END + +#elif defined(USE_AS_MEMCMP16) + +/* special for __memcmp16 */ + test %dl, %dl + jz L(next_four_words) + test $15, %dl + jz L(second_two_words) + test $3, %dl + jz L(second_word) + movzwl -16(%edi), %eax + movzwl -16(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(second_word): + movzwl -14(%edi), %eax + movzwl -14(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(second_two_words): + test $63, %dl + jz L(fourth_word) + movzwl -12(%edi), %eax + movzwl -12(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(fourth_word): + movzwl -10(%edi), %eax + movzwl -10(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(next_four_words): + test $15, %dh + jz L(fourth_two_words) + test $3, %dh + jz L(sixth_word) + movzwl -8(%edi), %eax + movzwl -8(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(sixth_word): + movzwl -6(%edi), %eax + movzwl -6(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(fourth_two_words): + test $63, %dh + jz L(eighth_word) + movzwl -4(%edi), %eax + movzwl -4(%esi), %ebx + subl %ebx, %eax + RETURN + + .p2align 4 +L(eighth_word): + movzwl -2(%edi), %eax + movzwl -2(%esi), %ebx + subl %ebx, %eax + RETURN +#else +# error Unreachable preprocessor case +#endif + + CFI_PUSH (%ebx) + + .p2align 4 +L(more8bytes): + cmp $16, %ecx + jae L(more16bytes) + cmp $8, %ecx + je L(8bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $9, %ecx + je L(9bytes) + cmp $10, %ecx + je L(10bytes) + cmp $11, %ecx + je L(11bytes) + cmp $12, %ecx + je L(12bytes) + cmp $13, %ecx + je L(13bytes) + cmp $14, %ecx + je L(14bytes) + jmp L(15bytes) +#elif defined(USE_WCHAR) && !defined(USE_UTF16) + jmp L(12bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $10, %ecx + je L(10bytes) + cmp $12, %ecx + je L(12bytes) + jmp L(14bytes) +#else +# error Unreachable preprocessor case +#endif + + .p2align 4 +L(more16bytes): + cmp $24, %ecx + jae L(more24bytes) + cmp $16, %ecx + je L(16bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $17, %ecx + je L(17bytes) + cmp $18, %ecx + je L(18bytes) + cmp $19, %ecx + je L(19bytes) + cmp $20, %ecx + je L(20bytes) + cmp $21, %ecx + je L(21bytes) + cmp $22, %ecx + je L(22bytes) + jmp L(23bytes) +#elif defined(USE_WCHAR) && !defined(USE_UTF16) + jmp L(20bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $18, %ecx + je L(18bytes) + cmp $20, %ecx + je L(20bytes) + jmp L(22bytes) +#else +# error Unreachable preprocessor case +#endif + + .p2align 4 +L(more24bytes): + cmp $32, %ecx + jae L(more32bytes) + cmp $24, %ecx + je L(24bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $25, %ecx + je L(25bytes) + cmp $26, %ecx + je L(26bytes) + cmp $27, %ecx + je L(27bytes) + cmp $28, %ecx + je L(28bytes) + cmp $29, %ecx + je L(29bytes) + cmp $30, %ecx + je L(30bytes) + jmp L(31bytes) +#elif defined(USE_WCHAR) && !defined(USE_UTF16) + jmp L(28bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $26, %ecx + je L(26bytes) + cmp $28, %ecx + je L(28bytes) + jmp L(30bytes) +#else +# error Unreachable preprocessor case +#endif + + .p2align 4 +L(more32bytes): + cmp $40, %ecx + jae L(more40bytes) + cmp $32, %ecx + je L(32bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $33, %ecx + je L(33bytes) + cmp $34, %ecx + je L(34bytes) + cmp $35, %ecx + je L(35bytes) + cmp $36, %ecx + je L(36bytes) + cmp $37, %ecx + je L(37bytes) + cmp $38, %ecx + je L(38bytes) + jmp L(39bytes) +#elif defined(USE_WCHAR) && !defined(USE_UTF16) + jmp L(36bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $34, %ecx + je L(34bytes) + cmp $36, %ecx + je L(36bytes) + jmp L(38bytes) +#else +# error Unreachable preprocessor case +#endif + + .p2align 4 +L(less48bytes): + cmp $8, %ecx + jae L(more8bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $2, %ecx + je L(2bytes) + cmp $3, %ecx + je L(3bytes) + cmp $4, %ecx + je L(4bytes) + cmp $5, %ecx + je L(5bytes) + cmp $6, %ecx + je L(6bytes) + jmp L(7bytes) +#elif defined(USE_WCHAR) && !defined(USE_UTF16) + jmp L(4bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $2, %ecx + je L(2bytes) + cmp $4, %ecx + je L(4bytes) + jmp L(6bytes) +#else +# error Unreachable preprocessor case +#endif + + .p2align 4 +L(more40bytes): + cmp $40, %ecx + je L(40bytes) +#if !defined(USE_WCHAR) && !defined(USE_UTF16) + cmp $41, %ecx + je L(41bytes) + cmp $42, %ecx + je L(42bytes) + cmp $43, %ecx + je L(43bytes) + cmp $44, %ecx + je L(44bytes) + cmp $45, %ecx + je L(45bytes) + cmp $46, %ecx + je L(46bytes) + jmp L(47bytes) +#elif defined(USE_UTF16) && !defined(USE_WCHAR) + cmp $42, %ecx + je L(42bytes) + cmp $44, %ecx + je L(44bytes) + jmp L(46bytes) +#endif + +#if !defined(USE_AS_WMEMCMP) && !defined(USE_AS_MEMCMP16) + .p2align 4 +L(44bytes): + mov -44(%eax), %ecx + mov -44(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(40bytes): + mov -40(%eax), %ecx + mov -40(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(36bytes): + mov -36(%eax), %ecx + mov -36(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(32bytes): + mov -32(%eax), %ecx + mov -32(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(28bytes): + mov -28(%eax), %ecx + mov -28(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(24bytes): + mov -24(%eax), %ecx + mov -24(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(20bytes): + mov -20(%eax), %ecx + mov -20(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(16bytes): + mov -16(%eax), %ecx + mov -16(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(12bytes): + mov -12(%eax), %ecx + mov -12(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(8bytes): + mov -8(%eax), %ecx + mov -8(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(4bytes): + mov -4(%eax), %ecx + mov -4(%edx), %ebx + cmp %ebx, %ecx + mov $0, %eax + jne L(find_diff) + POP (%ebx) + ret + CFI_PUSH (%ebx) +#elif defined(USE_AS_WMEMCMP) + + .p2align 4 +L(44bytes): + mov -44(%eax), %ecx + cmp -44(%edx), %ecx + jne L(find_diff) +L(40bytes): + mov -40(%eax), %ecx + cmp -40(%edx), %ecx + jne L(find_diff) +L(36bytes): + mov -36(%eax), %ecx + cmp -36(%edx), %ecx + jne L(find_diff) +L(32bytes): + mov -32(%eax), %ecx + cmp -32(%edx), %ecx + jne L(find_diff) +L(28bytes): + mov -28(%eax), %ecx + cmp -28(%edx), %ecx + jne L(find_diff) +L(24bytes): + mov -24(%eax), %ecx + cmp -24(%edx), %ecx + jne L(find_diff) +L(20bytes): + mov -20(%eax), %ecx + cmp -20(%edx), %ecx + jne L(find_diff) +L(16bytes): + mov -16(%eax), %ecx + cmp -16(%edx), %ecx + jne L(find_diff) +L(12bytes): + mov -12(%eax), %ecx + cmp -12(%edx), %ecx + jne L(find_diff) +L(8bytes): + mov -8(%eax), %ecx + cmp -8(%edx), %ecx + jne L(find_diff) +L(4bytes): + mov -4(%eax), %ecx + xor %eax, %eax + cmp -4(%edx), %ecx + jne L(find_diff) + POP (%ebx) + ret + CFI_PUSH (%ebx) +#elif defined USE_AS_MEMCMP16 + + .p2align 4 +L(46bytes): + movzwl -46(%eax), %ecx + movzwl -46(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(44bytes): + movzwl -44(%eax), %ecx + movzwl -44(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(42bytes): + movzwl -42(%eax), %ecx + movzwl -42(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(40bytes): + movzwl -40(%eax), %ecx + movzwl -40(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(38bytes): + movzwl -38(%eax), %ecx + movzwl -38(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(36bytes): + movzwl -36(%eax), %ecx + movzwl -36(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(34bytes): + movzwl -34(%eax), %ecx + movzwl -34(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(32bytes): + movzwl -32(%eax), %ecx + movzwl -32(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(30bytes): + movzwl -30(%eax), %ecx + movzwl -30(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(28bytes): + movzwl -28(%eax), %ecx + movzwl -28(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(26bytes): + movzwl -26(%eax), %ecx + movzwl -26(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(24bytes): + movzwl -24(%eax), %ecx + movzwl -24(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(22bytes): + movzwl -22(%eax), %ecx + movzwl -22(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(20bytes): + movzwl -20(%eax), %ecx + movzwl -20(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(18bytes): + movzwl -18(%eax), %ecx + movzwl -18(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(16bytes): + movzwl -16(%eax), %ecx + movzwl -16(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(14bytes): + movzwl -14(%eax), %ecx + movzwl -14(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(12bytes): + movzwl -12(%eax), %ecx + movzwl -12(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(10bytes): + movzwl -10(%eax), %ecx + movzwl -10(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(8bytes): + movzwl -8(%eax), %ecx + movzwl -8(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(6bytes): + movzwl -6(%eax), %ecx + movzwl -6(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(4bytes): + movzwl -4(%eax), %ecx + movzwl -4(%edx), %ebx + subl %ebx, %ecx + jne L(memcmp16_exit) +L(2bytes): + movzwl -2(%eax), %eax + movzwl -2(%edx), %ebx + subl %ebx, %eax + POP (%ebx) + ret + CFI_PUSH (%ebx) +#else +# error Unreachable preprocessor case +#endif + +#if !defined(USE_AS_WMEMCMP) && !defined(USE_AS_MEMCMP16) + + .p2align 4 +L(45bytes): + mov -45(%eax), %ecx + mov -45(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(41bytes): + mov -41(%eax), %ecx + mov -41(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(37bytes): + mov -37(%eax), %ecx + mov -37(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(33bytes): + mov -33(%eax), %ecx + mov -33(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(29bytes): + mov -29(%eax), %ecx + mov -29(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(25bytes): + mov -25(%eax), %ecx + mov -25(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(21bytes): + mov -21(%eax), %ecx + mov -21(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(17bytes): + mov -17(%eax), %ecx + mov -17(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(13bytes): + mov -13(%eax), %ecx + mov -13(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(9bytes): + mov -9(%eax), %ecx + mov -9(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(5bytes): + mov -5(%eax), %ecx + mov -5(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzbl -1(%eax), %ecx + cmp -1(%edx), %cl + mov $0, %eax + jne L(end) + POP (%ebx) + ret + CFI_PUSH (%ebx) + + .p2align 4 +L(46bytes): + mov -46(%eax), %ecx + mov -46(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(42bytes): + mov -42(%eax), %ecx + mov -42(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(38bytes): + mov -38(%eax), %ecx + mov -38(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(34bytes): + mov -34(%eax), %ecx + mov -34(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(30bytes): + mov -30(%eax), %ecx + mov -30(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(26bytes): + mov -26(%eax), %ecx + mov -26(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(22bytes): + mov -22(%eax), %ecx + mov -22(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(18bytes): + mov -18(%eax), %ecx + mov -18(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(14bytes): + mov -14(%eax), %ecx + mov -14(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(10bytes): + mov -10(%eax), %ecx + mov -10(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(6bytes): + mov -6(%eax), %ecx + mov -6(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(2bytes): + movzwl -2(%eax), %ecx + movzwl -2(%edx), %ebx + cmp %bl, %cl + jne L(end) + cmp %bh, %ch + mov $0, %eax + jne L(end) + POP (%ebx) + ret + CFI_PUSH (%ebx) + + .p2align 4 +L(47bytes): + movl -47(%eax), %ecx + movl -47(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(43bytes): + movl -43(%eax), %ecx + movl -43(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(39bytes): + movl -39(%eax), %ecx + movl -39(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(35bytes): + movl -35(%eax), %ecx + movl -35(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(31bytes): + movl -31(%eax), %ecx + movl -31(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(27bytes): + movl -27(%eax), %ecx + movl -27(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(23bytes): + movl -23(%eax), %ecx + movl -23(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(19bytes): + movl -19(%eax), %ecx + movl -19(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(15bytes): + movl -15(%eax), %ecx + movl -15(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(11bytes): + movl -11(%eax), %ecx + movl -11(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(7bytes): + movl -7(%eax), %ecx + movl -7(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(3bytes): + movzwl -3(%eax), %ecx + movzwl -3(%edx), %ebx + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + movzbl -1(%eax), %eax + cmpb -1(%edx), %al + mov $0, %eax + jne L(end) + POP (%ebx) + ret + CFI_PUSH (%ebx) + + .p2align 4 +L(find_diff): + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + shr $16,%ecx + shr $16,%ebx + cmp %bl, %cl + jne L(end) + cmp %bx, %cx + + .p2align 4 +L(end): + POP (%ebx) + mov $1, %eax + ja L(bigger) + neg %eax +L(bigger): + ret +#elif defined(USE_AS_WMEMCMP) + + .p2align 4 +L(find_diff): + POP (%ebx) + mov $1, %eax + jg L(find_diff_bigger) + neg %eax + ret + + .p2align 4 +L(find_diff_bigger): + ret + +#elif defined(USE_AS_MEMCMP16) + + .p2align 4 +L(memcmp16_exit): + POP (%ebx) + mov %ecx, %eax + ret +#else +# error Unreachable preprocessor case +#endif +END (MEMCMP) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcpy-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcpy-atom.S new file mode 100644 index 000000000..5532e2ef4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memcpy-atom.S @@ -0,0 +1,3124 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 "cache.h" + +#ifndef MEMCPY +# define MEMCPY memcpy_atom +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define DEST PARMS +#define SRC DEST+4 +#define LEN SRC+4 + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#if (defined SHARED || defined __PIC__) +# define PARMS 8 /* Preserve EBX. */ +# define ENTRANCE PUSH (%ebx); +# define RETURN_END POP (%ebx); ret +# define RETURN RETURN_END; CFI_PUSH (%ebx) +# define JMPTBL(I, B) I - B + +# define SETUP_PIC_REG(x) call __x86.get_pc_thunk.x + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. INDEX is a register contains the + index into the jump table. SCALE is the scale of INDEX. */ + +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + /* We first load PC into EBX. */ \ + SETUP_PIC_REG(bx); \ + /* Get the address of the jump table. */ \ + addl $(TABLE - .), %ebx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + addl (%ebx, INDEX, SCALE), %ebx; \ + /* We loaded the jump table. Go. */ \ + jmp *%ebx +#else + +# define PARMS 4 +# define ENTRANCE +# define RETURN_END ret +# define RETURN RETURN_END +# define JMPTBL(I, B) I + +/* Branch to an entry in a jump table. TABLE is a jump table with + absolute offsets. INDEX is a register contains the index into the + jump table. SCALE is the scale of INDEX. */ + +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + jmp *TABLE(, INDEX, SCALE) +#endif + + .section .text.ssse3,"ax",@progbits +ENTRY (MEMCPY) + ENTRANCE + movl LEN(%esp), %ecx + movl SRC(%esp), %eax + movl DEST(%esp), %edx + +#ifdef USE_AS_MEMMOVE + cmp %eax, %edx + jb L(copy_forward) + je L(fwd_write_0bytes) + cmp $32, %ecx + jae L(memmove_bwd) + jmp L(bk_write_less32bytes_2) + + .p2align 4 +L(memmove_bwd): + add %ecx, %eax + cmp %eax, %edx + movl SRC(%esp), %eax + jb L(copy_backward) + +L(copy_forward): +#endif + cmp $48, %ecx + jae L(48bytesormore) + +L(fwd_write_less32bytes): +#ifndef USE_AS_MEMMOVE + cmp %dl, %al + jb L(bk_write) +#endif + add %ecx, %edx + add %ecx, %eax + BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd), %ecx, 4) +#ifndef USE_AS_MEMMOVE + .p2align 4 +L(bk_write): + BRANCH_TO_JMPTBL_ENTRY (L(table_48_bytes_bwd), %ecx, 4) +#endif + + .p2align 4 +L(48bytesormore): +#ifndef USE_AS_MEMMOVE + movlpd (%eax), %xmm0 + movlpd 8(%eax), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) +#else + movdqu (%eax), %xmm0 +#endif + PUSH (%edi) + movl %edx, %edi + and $-16, %edx + add $16, %edx + sub %edx, %edi + add %edi, %ecx + sub %edi, %eax + +#ifdef SHARED_CACHE_SIZE_HALF + cmp $SHARED_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_shared_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_shared_cache_size_half, %ecx +# endif +#endif + + mov %eax, %edi + jae L(large_page) + and $0xf, %edi + jz L(shl_0) + BRANCH_TO_JMPTBL_ENTRY (L(shl_table), %edi, 4) + + .p2align 4 +L(shl_0): +#ifdef USE_AS_MEMMOVE + movl DEST+4(%esp), %edi + movdqu %xmm0, (%edi) +#endif + xor %edi, %edi + cmp $127, %ecx + ja L(shl_0_gobble) + lea -32(%ecx), %ecx + + .p2align 4 +L(shl_0_loop): + movdqa (%eax, %edi), %xmm0 + movdqa 16(%eax, %edi), %xmm1 + sub $32, %ecx + movdqa %xmm0, (%edx, %edi) + movdqa %xmm1, 16(%edx, %edi) + lea 32(%edi), %edi + jb L(shl_0_end) + + movdqa (%eax, %edi), %xmm0 + movdqa 16(%eax, %edi), %xmm1 + sub $32, %ecx + movdqa %xmm0, (%edx, %edi) + movdqa %xmm1, 16(%edx, %edi) + lea 32(%edi), %edi + jb L(shl_0_end) + + movdqa (%eax, %edi), %xmm0 + movdqa 16(%eax, %edi), %xmm1 + sub $32, %ecx + movdqa %xmm0, (%edx, %edi) + movdqa %xmm1, 16(%edx, %edi) + lea 32(%edi), %edi + jb L(shl_0_end) + + movdqa (%eax, %edi), %xmm0 + movdqa 16(%eax, %edi), %xmm1 + sub $32, %ecx + movdqa %xmm0, (%edx, %edi) + movdqa %xmm1, 16(%edx, %edi) + lea 32(%edi), %edi + +L(shl_0_end): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + add %edi, %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd_align), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_0_gobble): +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + POP (%edi) + lea -128(%ecx), %ecx + jae L(shl_0_gobble_mem_loop) + + .p2align 4 +L(shl_0_gobble_cache_loop): + movdqa (%eax), %xmm0 + movdqa 0x10(%eax), %xmm1 + movdqa 0x20(%eax), %xmm2 + movdqa 0x30(%eax), %xmm3 + movdqa 0x40(%eax), %xmm4 + movdqa 0x50(%eax), %xmm5 + movdqa 0x60(%eax), %xmm6 + movdqa 0x70(%eax), %xmm7 + lea 0x80(%eax), %eax + sub $128, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + movdqa %xmm2, 0x20(%edx) + movdqa %xmm3, 0x30(%edx) + movdqa %xmm4, 0x40(%edx) + movdqa %xmm5, 0x50(%edx) + movdqa %xmm6, 0x60(%edx) + movdqa %xmm7, 0x70(%edx) + lea 0x80(%edx), %edx + + jae L(shl_0_gobble_cache_loop) + cmp $-0x40, %ecx + lea 0x80(%ecx), %ecx + jl L(shl_0_cache_less_64bytes) + + movdqa (%eax), %xmm0 + sub $0x40, %ecx + movdqa 0x10(%eax), %xmm1 + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + movdqa 0x20(%eax), %xmm0 + movdqa 0x30(%eax), %xmm1 + add $0x40, %eax + movdqa %xmm0, 0x20(%edx) + movdqa %xmm1, 0x30(%edx) + add $0x40, %edx + +L(shl_0_cache_less_64bytes): + cmp $0x20, %ecx + jb L(shl_0_cache_less_32bytes) + movdqa (%eax), %xmm0 + sub $0x20, %ecx + movdqa 0x10(%eax), %xmm1 + add $0x20, %eax + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + add $0x20, %edx + +L(shl_0_cache_less_32bytes): + cmp $0x10, %ecx + jb L(shl_0_cache_less_16bytes) + sub $0x10, %ecx + movdqa (%eax), %xmm0 + add $0x10, %eax + movdqa %xmm0, (%edx) + add $0x10, %edx + +L(shl_0_cache_less_16bytes): + add %ecx, %edx + add %ecx, %eax + BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd), %ecx, 4) + + .p2align 4 +L(shl_0_gobble_mem_loop): + prefetcht0 0x1c0(%eax) + prefetcht0 0x280(%eax) + prefetcht0 0x1c0(%edx) + + movdqa (%eax), %xmm0 + movdqa 0x10(%eax), %xmm1 + movdqa 0x20(%eax), %xmm2 + movdqa 0x30(%eax), %xmm3 + movdqa 0x40(%eax), %xmm4 + movdqa 0x50(%eax), %xmm5 + movdqa 0x60(%eax), %xmm6 + movdqa 0x70(%eax), %xmm7 + lea 0x80(%eax), %eax + sub $0x80, %ecx + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + movdqa %xmm2, 0x20(%edx) + movdqa %xmm3, 0x30(%edx) + movdqa %xmm4, 0x40(%edx) + movdqa %xmm5, 0x50(%edx) + movdqa %xmm6, 0x60(%edx) + movdqa %xmm7, 0x70(%edx) + lea 0x80(%edx), %edx + + jae L(shl_0_gobble_mem_loop) + cmp $-0x40, %ecx + lea 0x80(%ecx), %ecx + jl L(shl_0_mem_less_64bytes) + + movdqa (%eax), %xmm0 + sub $0x40, %ecx + movdqa 0x10(%eax), %xmm1 + + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + + movdqa 0x20(%eax), %xmm0 + movdqa 0x30(%eax), %xmm1 + add $0x40, %eax + + movdqa %xmm0, 0x20(%edx) + movdqa %xmm1, 0x30(%edx) + add $0x40, %edx + +L(shl_0_mem_less_64bytes): + cmp $0x20, %ecx + jb L(shl_0_mem_less_32bytes) + movdqa (%eax), %xmm0 + sub $0x20, %ecx + movdqa 0x10(%eax), %xmm1 + add $0x20, %eax + movdqa %xmm0, (%edx) + movdqa %xmm1, 0x10(%edx) + add $0x20, %edx + +L(shl_0_mem_less_32bytes): + cmp $0x10, %ecx + jb L(shl_0_mem_less_16bytes) + sub $0x10, %ecx + movdqa (%eax), %xmm0 + add $0x10, %eax + movdqa %xmm0, (%edx) + add $0x10, %edx + +L(shl_0_mem_less_16bytes): + add %ecx, %edx + add %ecx, %eax + BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd_align), %ecx, 4) + + .p2align 4 +L(shl_1): +#ifndef USE_AS_MEMMOVE + movaps -1(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -1(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_1_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl1LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 15(%eax), %xmm2 + movaps 31(%eax), %xmm3 + movaps 47(%eax), %xmm4 + movaps 63(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $1, %xmm4, %xmm5 + palignr $1, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $1, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $1, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl1LoopStart) + +L(Shl1LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 15(%eax), %xmm2 + movaps 31(%eax), %xmm3 + palignr $1, %xmm2, %xmm3 + palignr $1, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_1_no_prefetch): + lea -32(%ecx), %ecx + lea -1(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_1_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $1, %xmm2, %xmm3 + palignr $1, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_1_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $1, %xmm2, %xmm3 + palignr $1, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_1_no_prefetch_loop) + +L(sh_1_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 1(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_2): +#ifndef USE_AS_MEMMOVE + movaps -2(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -2(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_2_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl2LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 14(%eax), %xmm2 + movaps 30(%eax), %xmm3 + movaps 46(%eax), %xmm4 + movaps 62(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $2, %xmm4, %xmm5 + palignr $2, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $2, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $2, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl2LoopStart) + +L(Shl2LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 14(%eax), %xmm2 + movaps 30(%eax), %xmm3 + palignr $2, %xmm2, %xmm3 + palignr $2, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_2_no_prefetch): + lea -32(%ecx), %ecx + lea -2(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_2_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $2, %xmm2, %xmm3 + palignr $2, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_2_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $2, %xmm2, %xmm3 + palignr $2, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_2_no_prefetch_loop) + +L(sh_2_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 2(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_3): +#ifndef USE_AS_MEMMOVE + movaps -3(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -3(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_3_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl3LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 13(%eax), %xmm2 + movaps 29(%eax), %xmm3 + movaps 45(%eax), %xmm4 + movaps 61(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $3, %xmm4, %xmm5 + palignr $3, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $3, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $3, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl3LoopStart) + +L(Shl3LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 13(%eax), %xmm2 + movaps 29(%eax), %xmm3 + palignr $3, %xmm2, %xmm3 + palignr $3, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_3_no_prefetch): + lea -32(%ecx), %ecx + lea -3(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_3_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $3, %xmm2, %xmm3 + palignr $3, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jb L(sh_3_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $3, %xmm2, %xmm3 + palignr $3, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jae L(sh_3_no_prefetch_loop) + +L(sh_3_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 3(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_4): +#ifndef USE_AS_MEMMOVE + movaps -4(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -4(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_4_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl4LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 12(%eax), %xmm2 + movaps 28(%eax), %xmm3 + movaps 44(%eax), %xmm4 + movaps 60(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $4, %xmm4, %xmm5 + palignr $4, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $4, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $4, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl4LoopStart) + +L(Shl4LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 12(%eax), %xmm2 + movaps 28(%eax), %xmm3 + palignr $4, %xmm2, %xmm3 + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_4_no_prefetch): + lea -32(%ecx), %ecx + lea -4(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_4_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $4, %xmm2, %xmm3 + palignr $4, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jb L(sh_4_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $4, %xmm2, %xmm3 + palignr $4, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jae L(sh_4_no_prefetch_loop) + +L(sh_4_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 4(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_5): +#ifndef USE_AS_MEMMOVE + movaps -5(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -5(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_5_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl5LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 11(%eax), %xmm2 + movaps 27(%eax), %xmm3 + movaps 43(%eax), %xmm4 + movaps 59(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $5, %xmm4, %xmm5 + palignr $5, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $5, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $5, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl5LoopStart) + +L(Shl5LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 11(%eax), %xmm2 + movaps 27(%eax), %xmm3 + palignr $5, %xmm2, %xmm3 + palignr $5, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_5_no_prefetch): + lea -32(%ecx), %ecx + lea -5(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_5_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $5, %xmm2, %xmm3 + palignr $5, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jb L(sh_5_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $5, %xmm2, %xmm3 + palignr $5, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jae L(sh_5_no_prefetch_loop) + +L(sh_5_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 5(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_6): +#ifndef USE_AS_MEMMOVE + movaps -6(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -6(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_6_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl6LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 10(%eax), %xmm2 + movaps 26(%eax), %xmm3 + movaps 42(%eax), %xmm4 + movaps 58(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $6, %xmm4, %xmm5 + palignr $6, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $6, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $6, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl6LoopStart) + +L(Shl6LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 10(%eax), %xmm2 + movaps 26(%eax), %xmm3 + palignr $6, %xmm2, %xmm3 + palignr $6, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_6_no_prefetch): + lea -32(%ecx), %ecx + lea -6(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_6_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $6, %xmm2, %xmm3 + palignr $6, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jb L(sh_6_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $6, %xmm2, %xmm3 + palignr $6, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + + jae L(sh_6_no_prefetch_loop) + +L(sh_6_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 6(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_7): +#ifndef USE_AS_MEMMOVE + movaps -7(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -7(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_7_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl7LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 9(%eax), %xmm2 + movaps 25(%eax), %xmm3 + movaps 41(%eax), %xmm4 + movaps 57(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $7, %xmm4, %xmm5 + palignr $7, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $7, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $7, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl7LoopStart) + +L(Shl7LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 9(%eax), %xmm2 + movaps 25(%eax), %xmm3 + palignr $7, %xmm2, %xmm3 + palignr $7, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_7_no_prefetch): + lea -32(%ecx), %ecx + lea -7(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_7_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $7, %xmm2, %xmm3 + palignr $7, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_7_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $7, %xmm2, %xmm3 + palignr $7, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_7_no_prefetch_loop) + +L(sh_7_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 7(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_8): +#ifndef USE_AS_MEMMOVE + movaps -8(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -8(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_8_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl8LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 8(%eax), %xmm2 + movaps 24(%eax), %xmm3 + movaps 40(%eax), %xmm4 + movaps 56(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $8, %xmm4, %xmm5 + palignr $8, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $8, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $8, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl8LoopStart) + +L(LoopLeave8): + add $32, %ecx + jle L(shl_end_0) + + movaps 8(%eax), %xmm2 + movaps 24(%eax), %xmm3 + palignr $8, %xmm2, %xmm3 + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_8_no_prefetch): + lea -32(%ecx), %ecx + lea -8(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_8_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $8, %xmm2, %xmm3 + palignr $8, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_8_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $8, %xmm2, %xmm3 + palignr $8, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_8_no_prefetch_loop) + +L(sh_8_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 8(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_9): +#ifndef USE_AS_MEMMOVE + movaps -9(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -9(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_9_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl9LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 7(%eax), %xmm2 + movaps 23(%eax), %xmm3 + movaps 39(%eax), %xmm4 + movaps 55(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $9, %xmm4, %xmm5 + palignr $9, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $9, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $9, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl9LoopStart) + +L(Shl9LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 7(%eax), %xmm2 + movaps 23(%eax), %xmm3 + palignr $9, %xmm2, %xmm3 + palignr $9, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_9_no_prefetch): + lea -32(%ecx), %ecx + lea -9(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_9_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $9, %xmm2, %xmm3 + palignr $9, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_9_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $9, %xmm2, %xmm3 + palignr $9, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_9_no_prefetch_loop) + +L(sh_9_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 9(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_10): +#ifndef USE_AS_MEMMOVE + movaps -10(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -10(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_10_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl10LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 6(%eax), %xmm2 + movaps 22(%eax), %xmm3 + movaps 38(%eax), %xmm4 + movaps 54(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $10, %xmm4, %xmm5 + palignr $10, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $10, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $10, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl10LoopStart) + +L(Shl10LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 6(%eax), %xmm2 + movaps 22(%eax), %xmm3 + palignr $10, %xmm2, %xmm3 + palignr $10, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_10_no_prefetch): + lea -32(%ecx), %ecx + lea -10(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_10_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $10, %xmm2, %xmm3 + palignr $10, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_10_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $10, %xmm2, %xmm3 + palignr $10, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_10_no_prefetch_loop) + +L(sh_10_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 10(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_11): +#ifndef USE_AS_MEMMOVE + movaps -11(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -11(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_11_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl11LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 5(%eax), %xmm2 + movaps 21(%eax), %xmm3 + movaps 37(%eax), %xmm4 + movaps 53(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $11, %xmm4, %xmm5 + palignr $11, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $11, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $11, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl11LoopStart) + +L(Shl11LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 5(%eax), %xmm2 + movaps 21(%eax), %xmm3 + palignr $11, %xmm2, %xmm3 + palignr $11, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_11_no_prefetch): + lea -32(%ecx), %ecx + lea -11(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_11_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $11, %xmm2, %xmm3 + palignr $11, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_11_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $11, %xmm2, %xmm3 + palignr $11, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_11_no_prefetch_loop) + +L(sh_11_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 11(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_12): +#ifndef USE_AS_MEMMOVE + movaps -12(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -12(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_12_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl12LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 4(%eax), %xmm2 + movaps 20(%eax), %xmm3 + movaps 36(%eax), %xmm4 + movaps 52(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $12, %xmm4, %xmm5 + palignr $12, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $12, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $12, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl12LoopStart) + +L(Shl12LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 4(%eax), %xmm2 + movaps 20(%eax), %xmm3 + palignr $12, %xmm2, %xmm3 + palignr $12, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_12_no_prefetch): + lea -32(%ecx), %ecx + lea -12(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_12_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $12, %xmm2, %xmm3 + palignr $12, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_12_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $12, %xmm2, %xmm3 + palignr $12, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_12_no_prefetch_loop) + +L(sh_12_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 12(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_13): +#ifndef USE_AS_MEMMOVE + movaps -13(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -13(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_13_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl13LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 3(%eax), %xmm2 + movaps 19(%eax), %xmm3 + movaps 35(%eax), %xmm4 + movaps 51(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $13, %xmm4, %xmm5 + palignr $13, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $13, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $13, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl13LoopStart) + +L(Shl13LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 3(%eax), %xmm2 + movaps 19(%eax), %xmm3 + palignr $13, %xmm2, %xmm3 + palignr $13, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_13_no_prefetch): + lea -32(%ecx), %ecx + lea -13(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_13_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $13, %xmm2, %xmm3 + palignr $13, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_13_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $13, %xmm2, %xmm3 + palignr $13, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_13_no_prefetch_loop) + +L(sh_13_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 13(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_14): +#ifndef USE_AS_MEMMOVE + movaps -14(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -14(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_14_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl14LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 2(%eax), %xmm2 + movaps 18(%eax), %xmm3 + movaps 34(%eax), %xmm4 + movaps 50(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $14, %xmm4, %xmm5 + palignr $14, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $14, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $14, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl14LoopStart) + +L(Shl14LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 2(%eax), %xmm2 + movaps 18(%eax), %xmm3 + palignr $14, %xmm2, %xmm3 + palignr $14, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_14_no_prefetch): + lea -32(%ecx), %ecx + lea -14(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_14_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $14, %xmm2, %xmm3 + palignr $14, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_14_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $14, %xmm2, %xmm3 + palignr $14, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_14_no_prefetch_loop) + +L(sh_14_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 14(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_15): +#ifndef USE_AS_MEMMOVE + movaps -15(%eax), %xmm1 +#else + movl DEST+4(%esp), %edi + movaps -15(%eax), %xmm1 + movdqu %xmm0, (%edi) +#endif +#ifdef DATA_CACHE_SIZE_HALF + cmp $DATA_CACHE_SIZE_HALF, %ecx +#else +# if (defined SHARED || defined __PIC__) + SETUP_PIC_REG(bx) + add $_GLOBAL_OFFSET_TABLE_, %ebx + cmp __x86_data_cache_size_half@GOTOFF(%ebx), %ecx +# else + cmp __x86_data_cache_size_half, %ecx +# endif +#endif + jb L(sh_15_no_prefetch) + + lea -64(%ecx), %ecx + + .p2align 4 +L(Shl15LoopStart): + prefetcht0 0x1c0(%eax) + prefetcht0 0x1c0(%edx) + movaps 1(%eax), %xmm2 + movaps 17(%eax), %xmm3 + movaps 33(%eax), %xmm4 + movaps 49(%eax), %xmm5 + movaps %xmm5, %xmm7 + palignr $15, %xmm4, %xmm5 + palignr $15, %xmm3, %xmm4 + movaps %xmm5, 48(%edx) + palignr $15, %xmm2, %xmm3 + lea 64(%eax), %eax + palignr $15, %xmm1, %xmm2 + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm7, %xmm1 + movaps %xmm2, (%edx) + lea 64(%edx), %edx + sub $64, %ecx + ja L(Shl15LoopStart) + +L(Shl15LoopLeave): + add $32, %ecx + jle L(shl_end_0) + + movaps 1(%eax), %xmm2 + movaps 17(%eax), %xmm3 + palignr $15, %xmm2, %xmm3 + palignr $15, %xmm1, %xmm2 + + movaps %xmm2, (%edx) + movaps %xmm3, 16(%edx) + lea 32(%edx, %ecx), %edx + lea 32(%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(sh_15_no_prefetch): + lea -32(%ecx), %ecx + lea -15(%eax), %eax + xor %edi, %edi + + .p2align 4 +L(sh_15_no_prefetch_loop): + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm4 + palignr $15, %xmm2, %xmm3 + palignr $15, %xmm1, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jb L(sh_15_end_no_prefetch_loop) + + movdqa 16(%eax, %edi), %xmm2 + sub $32, %ecx + movdqa 32(%eax, %edi), %xmm3 + movdqa %xmm3, %xmm1 + palignr $15, %xmm2, %xmm3 + palignr $15, %xmm4, %xmm2 + lea 32(%edi), %edi + movdqa %xmm2, -32(%edx, %edi) + movdqa %xmm3, -16(%edx, %edi) + jae L(sh_15_no_prefetch_loop) + +L(sh_15_end_no_prefetch_loop): + lea 32(%ecx), %ecx + add %ecx, %edi + add %edi, %edx + lea 15(%edi, %eax), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(shl_end_0): + lea 32(%ecx), %ecx + lea (%edx, %ecx), %edx + lea (%eax, %ecx), %eax + POP (%edi) + BRANCH_TO_JMPTBL_ENTRY(L(table_48bytes_fwd), %ecx, 4) + + .p2align 4 +L(fwd_write_44bytes): + movq -44(%eax), %xmm0 + movq %xmm0, -44(%edx) +L(fwd_write_36bytes): + movq -36(%eax), %xmm0 + movq %xmm0, -36(%edx) +L(fwd_write_28bytes): + movq -28(%eax), %xmm0 + movq %xmm0, -28(%edx) +L(fwd_write_20bytes): + movq -20(%eax), %xmm0 + movq %xmm0, -20(%edx) +L(fwd_write_12bytes): + movq -12(%eax), %xmm0 + movq %xmm0, -12(%edx) +L(fwd_write_4bytes): + movl -4(%eax), %ecx + movl %ecx, -4(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_40bytes): + movq -40(%eax), %xmm0 + movq %xmm0, -40(%edx) +L(fwd_write_32bytes): + movq -32(%eax), %xmm0 + movq %xmm0, -32(%edx) +L(fwd_write_24bytes): + movq -24(%eax), %xmm0 + movq %xmm0, -24(%edx) +L(fwd_write_16bytes): + movq -16(%eax), %xmm0 + movq %xmm0, -16(%edx) +L(fwd_write_8bytes): + movq -8(%eax), %xmm0 + movq %xmm0, -8(%edx) +L(fwd_write_0bytes): +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_5bytes): + movl -5(%eax), %ecx + movl -4(%eax), %eax + movl %ecx, -5(%edx) + movl %eax, -4(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_45bytes): + movq -45(%eax), %xmm0 + movq %xmm0, -45(%edx) +L(fwd_write_37bytes): + movq -37(%eax), %xmm0 + movq %xmm0, -37(%edx) +L(fwd_write_29bytes): + movq -29(%eax), %xmm0 + movq %xmm0, -29(%edx) +L(fwd_write_21bytes): + movq -21(%eax), %xmm0 + movq %xmm0, -21(%edx) +L(fwd_write_13bytes): + movq -13(%eax), %xmm0 + movq %xmm0, -13(%edx) + movl -5(%eax), %ecx + movl %ecx, -5(%edx) + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_41bytes): + movq -41(%eax), %xmm0 + movq %xmm0, -41(%edx) +L(fwd_write_33bytes): + movq -33(%eax), %xmm0 + movq %xmm0, -33(%edx) +L(fwd_write_25bytes): + movq -25(%eax), %xmm0 + movq %xmm0, -25(%edx) +L(fwd_write_17bytes): + movq -17(%eax), %xmm0 + movq %xmm0, -17(%edx) +L(fwd_write_9bytes): + movq -9(%eax), %xmm0 + movq %xmm0, -9(%edx) +L(fwd_write_1bytes): + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_46bytes): + movq -46(%eax), %xmm0 + movq %xmm0, -46(%edx) +L(fwd_write_38bytes): + movq -38(%eax), %xmm0 + movq %xmm0, -38(%edx) +L(fwd_write_30bytes): + movq -30(%eax), %xmm0 + movq %xmm0, -30(%edx) +L(fwd_write_22bytes): + movq -22(%eax), %xmm0 + movq %xmm0, -22(%edx) +L(fwd_write_14bytes): + movq -14(%eax), %xmm0 + movq %xmm0, -14(%edx) +L(fwd_write_6bytes): + movl -6(%eax), %ecx + movl %ecx, -6(%edx) + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_42bytes): + movq -42(%eax), %xmm0 + movq %xmm0, -42(%edx) +L(fwd_write_34bytes): + movq -34(%eax), %xmm0 + movq %xmm0, -34(%edx) +L(fwd_write_26bytes): + movq -26(%eax), %xmm0 + movq %xmm0, -26(%edx) +L(fwd_write_18bytes): + movq -18(%eax), %xmm0 + movq %xmm0, -18(%edx) +L(fwd_write_10bytes): + movq -10(%eax), %xmm0 + movq %xmm0, -10(%edx) +L(fwd_write_2bytes): + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_47bytes): + movq -47(%eax), %xmm0 + movq %xmm0, -47(%edx) +L(fwd_write_39bytes): + movq -39(%eax), %xmm0 + movq %xmm0, -39(%edx) +L(fwd_write_31bytes): + movq -31(%eax), %xmm0 + movq %xmm0, -31(%edx) +L(fwd_write_23bytes): + movq -23(%eax), %xmm0 + movq %xmm0, -23(%edx) +L(fwd_write_15bytes): + movq -15(%eax), %xmm0 + movq %xmm0, -15(%edx) +L(fwd_write_7bytes): + movl -7(%eax), %ecx + movl %ecx, -7(%edx) + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_43bytes): + movq -43(%eax), %xmm0 + movq %xmm0, -43(%edx) +L(fwd_write_35bytes): + movq -35(%eax), %xmm0 + movq %xmm0, -35(%edx) +L(fwd_write_27bytes): + movq -27(%eax), %xmm0 + movq %xmm0, -27(%edx) +L(fwd_write_19bytes): + movq -19(%eax), %xmm0 + movq %xmm0, -19(%edx) +L(fwd_write_11bytes): + movq -11(%eax), %xmm0 + movq %xmm0, -11(%edx) +L(fwd_write_3bytes): + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_40bytes_align): + movdqa -40(%eax), %xmm0 + movdqa %xmm0, -40(%edx) +L(fwd_write_24bytes_align): + movdqa -24(%eax), %xmm0 + movdqa %xmm0, -24(%edx) +L(fwd_write_8bytes_align): + movq -8(%eax), %xmm0 + movq %xmm0, -8(%edx) +L(fwd_write_0bytes_align): +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_32bytes_align): + movdqa -32(%eax), %xmm0 + movdqa %xmm0, -32(%edx) +L(fwd_write_16bytes_align): + movdqa -16(%eax), %xmm0 + movdqa %xmm0, -16(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_5bytes_align): + movl -5(%eax), %ecx + movl -4(%eax), %eax + movl %ecx, -5(%edx) + movl %eax, -4(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_45bytes_align): + movdqa -45(%eax), %xmm0 + movdqa %xmm0, -45(%edx) +L(fwd_write_29bytes_align): + movdqa -29(%eax), %xmm0 + movdqa %xmm0, -29(%edx) +L(fwd_write_13bytes_align): + movq -13(%eax), %xmm0 + movq %xmm0, -13(%edx) + movl -5(%eax), %ecx + movl %ecx, -5(%edx) + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_37bytes_align): + movdqa -37(%eax), %xmm0 + movdqa %xmm0, -37(%edx) +L(fwd_write_21bytes_align): + movdqa -21(%eax), %xmm0 + movdqa %xmm0, -21(%edx) + movl -5(%eax), %ecx + movl %ecx, -5(%edx) + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_41bytes_align): + movdqa -41(%eax), %xmm0 + movdqa %xmm0, -41(%edx) +L(fwd_write_25bytes_align): + movdqa -25(%eax), %xmm0 + movdqa %xmm0, -25(%edx) +L(fwd_write_9bytes_align): + movq -9(%eax), %xmm0 + movq %xmm0, -9(%edx) +L(fwd_write_1bytes_align): + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_33bytes_align): + movdqa -33(%eax), %xmm0 + movdqa %xmm0, -33(%edx) +L(fwd_write_17bytes_align): + movdqa -17(%eax), %xmm0 + movdqa %xmm0, -17(%edx) + movzbl -1(%eax), %ecx + movb %cl, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_46bytes_align): + movdqa -46(%eax), %xmm0 + movdqa %xmm0, -46(%edx) +L(fwd_write_30bytes_align): + movdqa -30(%eax), %xmm0 + movdqa %xmm0, -30(%edx) +L(fwd_write_14bytes_align): + movq -14(%eax), %xmm0 + movq %xmm0, -14(%edx) +L(fwd_write_6bytes_align): + movl -6(%eax), %ecx + movl %ecx, -6(%edx) + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_38bytes_align): + movdqa -38(%eax), %xmm0 + movdqa %xmm0, -38(%edx) +L(fwd_write_22bytes_align): + movdqa -22(%eax), %xmm0 + movdqa %xmm0, -22(%edx) + movl -6(%eax), %ecx + movl %ecx, -6(%edx) + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_42bytes_align): + movdqa -42(%eax), %xmm0 + movdqa %xmm0, -42(%edx) +L(fwd_write_26bytes_align): + movdqa -26(%eax), %xmm0 + movdqa %xmm0, -26(%edx) +L(fwd_write_10bytes_align): + movq -10(%eax), %xmm0 + movq %xmm0, -10(%edx) +L(fwd_write_2bytes_align): + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_34bytes_align): + movdqa -34(%eax), %xmm0 + movdqa %xmm0, -34(%edx) +L(fwd_write_18bytes_align): + movdqa -18(%eax), %xmm0 + movdqa %xmm0, -18(%edx) + movzwl -2(%eax), %ecx + movw %cx, -2(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_47bytes_align): + movdqa -47(%eax), %xmm0 + movdqa %xmm0, -47(%edx) +L(fwd_write_31bytes_align): + movdqa -31(%eax), %xmm0 + movdqa %xmm0, -31(%edx) +L(fwd_write_15bytes_align): + movq -15(%eax), %xmm0 + movq %xmm0, -15(%edx) +L(fwd_write_7bytes_align): + movl -7(%eax), %ecx + movl %ecx, -7(%edx) + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_39bytes_align): + movdqa -39(%eax), %xmm0 + movdqa %xmm0, -39(%edx) +L(fwd_write_23bytes_align): + movdqa -23(%eax), %xmm0 + movdqa %xmm0, -23(%edx) + movl -7(%eax), %ecx + movl %ecx, -7(%edx) + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_43bytes_align): + movdqa -43(%eax), %xmm0 + movdqa %xmm0, -43(%edx) +L(fwd_write_27bytes_align): + movdqa -27(%eax), %xmm0 + movdqa %xmm0, -27(%edx) +L(fwd_write_11bytes_align): + movq -11(%eax), %xmm0 + movq %xmm0, -11(%edx) +L(fwd_write_3bytes_align): + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_35bytes_align): + movdqa -35(%eax), %xmm0 + movdqa %xmm0, -35(%edx) +L(fwd_write_19bytes_align): + movdqa -19(%eax), %xmm0 + movdqa %xmm0, -19(%edx) + movzwl -3(%eax), %ecx + movzbl -1(%eax), %eax + movw %cx, -3(%edx) + movb %al, -1(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_44bytes_align): + movdqa -44(%eax), %xmm0 + movdqa %xmm0, -44(%edx) +L(fwd_write_28bytes_align): + movdqa -28(%eax), %xmm0 + movdqa %xmm0, -28(%edx) +L(fwd_write_12bytes_align): + movq -12(%eax), %xmm0 + movq %xmm0, -12(%edx) +L(fwd_write_4bytes_align): + movl -4(%eax), %ecx + movl %ecx, -4(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN + + .p2align 4 +L(fwd_write_36bytes_align): + movdqa -36(%eax), %xmm0 + movdqa %xmm0, -36(%edx) +L(fwd_write_20bytes_align): + movdqa -20(%eax), %xmm0 + movdqa %xmm0, -20(%edx) + movl -4(%eax), %ecx + movl %ecx, -4(%edx) +#ifdef USE_AS_MEMPCPY + movl %edx, %eax +#else + movl DEST(%esp), %eax +#endif + RETURN_END + + CFI_PUSH (%edi) + + .p2align 4 +L(large_page): + movdqu (%eax), %xmm1 +#ifdef USE_AS_MEMMOVE + movl DEST+4(%esp), %edi + movdqu %xmm0, (%edi) +#endif + lea 16(%eax), %eax + movntdq %xmm1, (%edx) + lea 16(%edx), %edx + lea -0x90(%ecx), %ecx + POP (%edi) + + .p2align 4 +L(large_page_loop): + movdqu (%eax), %xmm0 + movdqu 0x10(%eax), %xmm1 + movdqu 0x20(%eax), %xmm2 + movdqu 0x30(%eax), %xmm3 + movdqu 0x40(%eax), %xmm4 + movdqu 0x50(%eax), %xmm5 + movdqu 0x60(%eax), %xmm6 + movdqu 0x70(%eax), %xmm7 + lea 0x80(%eax), %eax + + sub $0x80, %ecx + movntdq %xmm0, (%edx) + movntdq %xmm1, 0x10(%edx) + movntdq %xmm2, 0x20(%edx) + movntdq %xmm3, 0x30(%edx) + movntdq %xmm4, 0x40(%edx) + movntdq %xmm5, 0x50(%edx) + movntdq %xmm6, 0x60(%edx) + movntdq %xmm7, 0x70(%edx) + lea 0x80(%edx), %edx + jae L(large_page_loop) + cmp $-0x40, %ecx + lea 0x80(%ecx), %ecx + jl L(large_page_less_64bytes) + + movdqu (%eax), %xmm0 + movdqu 0x10(%eax), %xmm1 + movdqu 0x20(%eax), %xmm2 + movdqu 0x30(%eax), %xmm3 + lea 0x40(%eax), %eax + + movntdq %xmm0, (%edx) + movntdq %xmm1, 0x10(%edx) + movntdq %xmm2, 0x20(%edx) + movntdq %xmm3, 0x30(%edx) + lea 0x40(%edx), %edx + sub $0x40, %ecx +L(large_page_less_64bytes): + cmp $32, %ecx + jb L(large_page_less_32bytes) + movdqu (%eax), %xmm0 + movdqu 0x10(%eax), %xmm1 + lea 0x20(%eax), %eax + movntdq %xmm0, (%edx) + movntdq %xmm1, 0x10(%edx) + lea 0x20(%edx), %edx + sub $0x20, %ecx +L(large_page_less_32bytes): + add %ecx, %edx + add %ecx, %eax + sfence + BRANCH_TO_JMPTBL_ENTRY (L(table_48bytes_fwd), %ecx, 4) + + .p2align 4 +L(bk_write_44bytes): + movq 36(%eax), %xmm0 + movq %xmm0, 36(%edx) +L(bk_write_36bytes): + movq 28(%eax), %xmm0 + movq %xmm0, 28(%edx) +L(bk_write_28bytes): + movq 20(%eax), %xmm0 + movq %xmm0, 20(%edx) +L(bk_write_20bytes): + movq 12(%eax), %xmm0 + movq %xmm0, 12(%edx) +L(bk_write_12bytes): + movq 4(%eax), %xmm0 + movq %xmm0, 4(%edx) +L(bk_write_4bytes): + movl (%eax), %ecx + movl %ecx, (%edx) +L(bk_write_0bytes): + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_40bytes): + movq 32(%eax), %xmm0 + movq %xmm0, 32(%edx) +L(bk_write_32bytes): + movq 24(%eax), %xmm0 + movq %xmm0, 24(%edx) +L(bk_write_24bytes): + movq 16(%eax), %xmm0 + movq %xmm0, 16(%edx) +L(bk_write_16bytes): + movq 8(%eax), %xmm0 + movq %xmm0, 8(%edx) +L(bk_write_8bytes): + movq (%eax), %xmm0 + movq %xmm0, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_45bytes): + movq 37(%eax), %xmm0 + movq %xmm0, 37(%edx) +L(bk_write_37bytes): + movq 29(%eax), %xmm0 + movq %xmm0, 29(%edx) +L(bk_write_29bytes): + movq 21(%eax), %xmm0 + movq %xmm0, 21(%edx) +L(bk_write_21bytes): + movq 13(%eax), %xmm0 + movq %xmm0, 13(%edx) +L(bk_write_13bytes): + movq 5(%eax), %xmm0 + movq %xmm0, 5(%edx) +L(bk_write_5bytes): + movl 1(%eax), %ecx + movl %ecx, 1(%edx) +L(bk_write_1bytes): + movzbl (%eax), %ecx + movb %cl, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_41bytes): + movq 33(%eax), %xmm0 + movq %xmm0, 33(%edx) +L(bk_write_33bytes): + movq 25(%eax), %xmm0 + movq %xmm0, 25(%edx) +L(bk_write_25bytes): + movq 17(%eax), %xmm0 + movq %xmm0, 17(%edx) +L(bk_write_17bytes): + movq 9(%eax), %xmm0 + movq %xmm0, 9(%edx) +L(bk_write_9bytes): + movq 1(%eax), %xmm0 + movq %xmm0, 1(%edx) + movzbl (%eax), %ecx + movb %cl, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_46bytes): + movq 38(%eax), %xmm0 + movq %xmm0, 38(%edx) +L(bk_write_38bytes): + movq 30(%eax), %xmm0 + movq %xmm0, 30(%edx) +L(bk_write_30bytes): + movq 22(%eax), %xmm0 + movq %xmm0, 22(%edx) +L(bk_write_22bytes): + movq 14(%eax), %xmm0 + movq %xmm0, 14(%edx) +L(bk_write_14bytes): + movq 6(%eax), %xmm0 + movq %xmm0, 6(%edx) +L(bk_write_6bytes): + movl 2(%eax), %ecx + movl %ecx, 2(%edx) + movzwl (%eax), %ecx + movw %cx, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_42bytes): + movq 34(%eax), %xmm0 + movq %xmm0, 34(%edx) +L(bk_write_34bytes): + movq 26(%eax), %xmm0 + movq %xmm0, 26(%edx) +L(bk_write_26bytes): + movq 18(%eax), %xmm0 + movq %xmm0, 18(%edx) +L(bk_write_18bytes): + movq 10(%eax), %xmm0 + movq %xmm0, 10(%edx) +L(bk_write_10bytes): + movq 2(%eax), %xmm0 + movq %xmm0, 2(%edx) +L(bk_write_2bytes): + movzwl (%eax), %ecx + movw %cx, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_47bytes): + movq 39(%eax), %xmm0 + movq %xmm0, 39(%edx) +L(bk_write_39bytes): + movq 31(%eax), %xmm0 + movq %xmm0, 31(%edx) +L(bk_write_31bytes): + movq 23(%eax), %xmm0 + movq %xmm0, 23(%edx) +L(bk_write_23bytes): + movq 15(%eax), %xmm0 + movq %xmm0, 15(%edx) +L(bk_write_15bytes): + movq 7(%eax), %xmm0 + movq %xmm0, 7(%edx) +L(bk_write_7bytes): + movl 3(%eax), %ecx + movl %ecx, 3(%edx) + movzwl 1(%eax), %ecx + movw %cx, 1(%edx) + movzbl (%eax), %eax + movb %al, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN + + .p2align 4 +L(bk_write_43bytes): + movq 35(%eax), %xmm0 + movq %xmm0, 35(%edx) +L(bk_write_35bytes): + movq 27(%eax), %xmm0 + movq %xmm0, 27(%edx) +L(bk_write_27bytes): + movq 19(%eax), %xmm0 + movq %xmm0, 19(%edx) +L(bk_write_19bytes): + movq 11(%eax), %xmm0 + movq %xmm0, 11(%edx) +L(bk_write_11bytes): + movq 3(%eax), %xmm0 + movq %xmm0, 3(%edx) +L(bk_write_3bytes): + movzwl 1(%eax), %ecx + movw %cx, 1(%edx) + movzbl (%eax), %eax + movb %al, (%edx) + movl DEST(%esp), %eax +#ifdef USE_AS_MEMPCPY + movl LEN(%esp), %ecx + add %ecx, %eax +#endif + RETURN_END + + + .pushsection .rodata.ssse3,"a",@progbits + .p2align 2 +L(table_48bytes_fwd): + .int JMPTBL (L(fwd_write_0bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_1bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_2bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_3bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_4bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_5bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_6bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_7bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_8bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_9bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_10bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_11bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_12bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_13bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_14bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_15bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_16bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_17bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_18bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_19bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_20bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_21bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_22bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_23bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_24bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_25bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_26bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_27bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_28bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_29bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_30bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_31bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_32bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_33bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_34bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_35bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_36bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_37bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_38bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_39bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_40bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_41bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_42bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_43bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_44bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_45bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_46bytes), L(table_48bytes_fwd)) + .int JMPTBL (L(fwd_write_47bytes), L(table_48bytes_fwd)) + + .p2align 2 +L(table_48bytes_fwd_align): + .int JMPTBL (L(fwd_write_0bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_1bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_2bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_3bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_4bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_5bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_6bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_7bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_8bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_9bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_10bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_11bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_12bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_13bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_14bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_15bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_16bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_17bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_18bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_19bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_20bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_21bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_22bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_23bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_24bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_25bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_26bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_27bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_28bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_29bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_30bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_31bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_32bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_33bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_34bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_35bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_36bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_37bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_38bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_39bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_40bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_41bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_42bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_43bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_44bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_45bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_46bytes_align), L(table_48bytes_fwd_align)) + .int JMPTBL (L(fwd_write_47bytes_align), L(table_48bytes_fwd_align)) + + .p2align 2 +L(shl_table): + .int JMPTBL (L(shl_0), L(shl_table)) + .int JMPTBL (L(shl_1), L(shl_table)) + .int JMPTBL (L(shl_2), L(shl_table)) + .int JMPTBL (L(shl_3), L(shl_table)) + .int JMPTBL (L(shl_4), L(shl_table)) + .int JMPTBL (L(shl_5), L(shl_table)) + .int JMPTBL (L(shl_6), L(shl_table)) + .int JMPTBL (L(shl_7), L(shl_table)) + .int JMPTBL (L(shl_8), L(shl_table)) + .int JMPTBL (L(shl_9), L(shl_table)) + .int JMPTBL (L(shl_10), L(shl_table)) + .int JMPTBL (L(shl_11), L(shl_table)) + .int JMPTBL (L(shl_12), L(shl_table)) + .int JMPTBL (L(shl_13), L(shl_table)) + .int JMPTBL (L(shl_14), L(shl_table)) + .int JMPTBL (L(shl_15), L(shl_table)) + + .p2align 2 +L(table_48_bytes_bwd): + .int JMPTBL (L(bk_write_0bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_1bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_2bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_3bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_4bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_5bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_6bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_7bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_8bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_9bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_10bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_11bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_12bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_13bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_14bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_15bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_16bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_17bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_18bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_19bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_20bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_21bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_22bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_23bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_24bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_25bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_26bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_27bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_28bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_29bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_30bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_31bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_32bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_33bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_34bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_35bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_36bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_37bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_38bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_39bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_40bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_41bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_42bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_43bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_44bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_45bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_46bytes), L(table_48_bytes_bwd)) + .int JMPTBL (L(bk_write_47bytes), L(table_48_bytes_bwd)) + + .popsection + +#ifdef USE_AS_MEMMOVE + .p2align 4 +L(copy_backward): + PUSH (%edi) + movl %eax, %edi + lea (%ecx,%edx,1),%edx + lea (%ecx,%edi,1),%edi + testl $0x3, %edx + jnz L(bk_align) + +L(bk_aligned_4): + cmp $64, %ecx + jae L(bk_write_more64bytes) + +L(bk_write_64bytesless): + cmp $32, %ecx + jb L(bk_write_less32bytes) + +L(bk_write_more32bytes): + /* Copy 32 bytes at a time. */ + sub $32, %ecx + movq -8(%edi), %xmm0 + movq %xmm0, -8(%edx) + movq -16(%edi), %xmm0 + movq %xmm0, -16(%edx) + movq -24(%edi), %xmm0 + movq %xmm0, -24(%edx) + movq -32(%edi), %xmm0 + movq %xmm0, -32(%edx) + sub $32, %edx + sub $32, %edi + +L(bk_write_less32bytes): + movl %edi, %eax + sub %ecx, %edx + sub %ecx, %eax + POP (%edi) +L(bk_write_less32bytes_2): + BRANCH_TO_JMPTBL_ENTRY (L(table_48_bytes_bwd), %ecx, 4) + + CFI_PUSH (%edi) + + .p2align 4 +L(bk_align): + cmp $8, %ecx + jbe L(bk_write_less32bytes) + testl $1, %edx + /* We get here only if (EDX & 3 ) != 0 so if (EDX & 1) ==0, + then (EDX & 2) must be != 0. */ + jz L(bk_got2) + sub $1, %edi + sub $1, %ecx + sub $1, %edx + movzbl (%edi), %eax + movb %al, (%edx) + + testl $2, %edx + jz L(bk_aligned_4) + +L(bk_got2): + sub $2, %edi + sub $2, %ecx + sub $2, %edx + movzwl (%edi), %eax + movw %ax, (%edx) + jmp L(bk_aligned_4) + + .p2align 4 +L(bk_write_more64bytes): + /* Check alignment of last byte. */ + testl $15, %edx + jz L(bk_ssse3_cpy_pre) + +/* EDX is aligned 4 bytes, but not 16 bytes. */ +L(bk_ssse3_align): + sub $4, %edi + sub $4, %ecx + sub $4, %edx + movl (%edi), %eax + movl %eax, (%edx) + + testl $15, %edx + jz L(bk_ssse3_cpy_pre) + + sub $4, %edi + sub $4, %ecx + sub $4, %edx + movl (%edi), %eax + movl %eax, (%edx) + + testl $15, %edx + jz L(bk_ssse3_cpy_pre) + + sub $4, %edi + sub $4, %ecx + sub $4, %edx + movl (%edi), %eax + movl %eax, (%edx) + +L(bk_ssse3_cpy_pre): + cmp $64, %ecx + jb L(bk_write_more32bytes) + + .p2align 4 +L(bk_ssse3_cpy): + sub $64, %edi + sub $64, %ecx + sub $64, %edx + movdqu 0x30(%edi), %xmm3 + movdqa %xmm3, 0x30(%edx) + movdqu 0x20(%edi), %xmm2 + movdqa %xmm2, 0x20(%edx) + movdqu 0x10(%edi), %xmm1 + movdqa %xmm1, 0x10(%edx) + movdqu (%edi), %xmm0 + movdqa %xmm0, (%edx) + cmp $64, %ecx + jae L(bk_ssse3_cpy) + jmp L(bk_write_64bytesless) + +#endif + +END (MEMCPY) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-memmove-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memmove-atom.S new file mode 100644 index 000000000..3572eac9c --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-memmove-atom.S @@ -0,0 +1,34 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + + +#define MEMCPY memmove_atom +#define USE_AS_MEMMOVE +#include "ssse3-memcpy-atom.S" diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcat-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcat-atom.S new file mode 100644 index 000000000..8d8e89d55 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcat-atom.S @@ -0,0 +1,620 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef cfi_remember_state +# define cfi_remember_state .cfi_remember_state +#endif + +#ifndef cfi_restore_state +# define cfi_restore_state .cfi_restore_state +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#ifndef STRCAT +# define STRCAT strcat_ssse3 +#endif + +#define PARMS 4 +#define STR1 PARMS+4 +#define STR2 STR1+4 + +#ifdef USE_AS_STRNCAT +# define LEN STR2+8 +#endif + +#define USE_AS_STRCAT + + .section .text.ssse3,"ax",@progbits +ENTRY (STRCAT) + PUSH (%edi) + mov STR1(%esp), %edi + mov %edi, %edx + +#define RETURN jmp L(StrcpyAtom) +#include "sse2-strlen-atom.S" + +L(StrcpyAtom): + mov STR2(%esp), %ecx + lea (%edi, %eax), %edx +#ifdef USE_AS_STRNCAT + PUSH (%ebx) + mov LEN(%esp), %ebx + test %ebx, %ebx + jz L(StrncatExit0) + cmp $8, %ebx + jbe L(StrncpyExit8Bytes) +#endif + cmpb $0, (%ecx) + jz L(Exit1) + cmpb $0, 1(%ecx) + jz L(Exit2) + cmpb $0, 2(%ecx) + jz L(Exit3) + cmpb $0, 3(%ecx) + jz L(Exit4) + cmpb $0, 4(%ecx) + jz L(Exit5) + cmpb $0, 5(%ecx) + jz L(Exit6) + cmpb $0, 6(%ecx) + jz L(Exit7) + cmpb $0, 7(%ecx) + jz L(Exit8) + cmpb $0, 8(%ecx) + jz L(Exit9) +#ifdef USE_AS_STRNCAT + cmp $16, %ebx + jb L(StrncpyExit15Bytes) +#endif + cmpb $0, 9(%ecx) + jz L(Exit10) + cmpb $0, 10(%ecx) + jz L(Exit11) + cmpb $0, 11(%ecx) + jz L(Exit12) + cmpb $0, 12(%ecx) + jz L(Exit13) + cmpb $0, 13(%ecx) + jz L(Exit14) + cmpb $0, 14(%ecx) + jz L(Exit15) + cmpb $0, 15(%ecx) + jz L(Exit16) +#ifdef USE_AS_STRNCAT + cmp $16, %ebx + je L(StrncatExit16) + +# define RETURN1 POP (%ebx); POP (%edi); ret; \ + CFI_PUSH (%ebx); CFI_PUSH (%edi) +# define USE_AS_STRNCPY +#else +# define RETURN1 POP(%edi); ret; CFI_PUSH(%edi) +#endif +#include "ssse3-strcpy-atom.S" + + .p2align 4 +L(CopyFrom1To16Bytes): + add %esi, %edx + add %esi, %ecx + + POP (%esi) + test %al, %al + jz L(ExitHigh) + test $0x01, %al + jnz L(Exit1) + test $0x02, %al + jnz L(Exit2) + test $0x04, %al + jnz L(Exit3) + test $0x08, %al + jnz L(Exit4) + test $0x10, %al + jnz L(Exit5) + test $0x20, %al + jnz L(Exit6) + test $0x40, %al + jnz L(Exit7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh): + test $0x01, %ah + jnz L(Exit9) + test $0x02, %ah + jnz L(Exit10) + test $0x04, %ah + jnz L(Exit11) + test $0x08, %ah + jnz L(Exit12) + test $0x10, %ah + jnz L(Exit13) + test $0x20, %ah + jnz L(Exit14) + test $0x40, %ah + jnz L(Exit15) + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit1): + movb %bh, 1(%edx) +L(Exit1): + movb (%ecx), %al + movb %al, (%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit2): + movb %bh, 2(%edx) +L(Exit2): + movw (%ecx), %ax + movw %ax, (%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit3): + movb %bh, 3(%edx) +L(Exit3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit4): + movb %bh, 4(%edx) +L(Exit4): + movl (%ecx), %eax + movl %eax, (%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit5): + movb %bh, 5(%edx) +L(Exit5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit6): + movb %bh, 6(%edx) +L(Exit6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit7): + movb %bh, 7(%edx) +L(Exit7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit8): + movb %bh, 8(%edx) +L(Exit8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit9): + movb %bh, 9(%edx) +L(Exit9): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit10): + movb %bh, 10(%edx) +L(Exit10): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit11): + movb %bh, 11(%edx) +L(Exit11): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit12): + movb %bh, 12(%edx) +L(Exit12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit13): + movb %bh, 13(%edx) +L(Exit13): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit14): + movb %bh, 14(%edx) +L(Exit14): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit15): + movb %bh, 15(%edx) +L(Exit15): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit16): + movb %bh, 16(%edx) +L(Exit16): + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + movl %edi, %eax + RETURN1 + +#ifdef USE_AS_STRNCPY + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %ebx + add %esi, %ecx + lea (%esi, %edx), %esi + lea -9(%ebx), %edx + and $1<<7, %dh + or %al, %dh + lea (%esi), %edx + POP (%esi) + jz L(ExitHighCase2) + + test $0x01, %al + jnz L(Exit1) + cmp $1, %ebx + je L(StrncatExit1) + test $0x02, %al + jnz L(Exit2) + cmp $2, %ebx + je L(StrncatExit2) + test $0x04, %al + jnz L(Exit3) + cmp $3, %ebx + je L(StrncatExit3) + test $0x08, %al + jnz L(Exit4) + cmp $4, %ebx + je L(StrncatExit4) + test $0x10, %al + jnz L(Exit5) + cmp $5, %ebx + je L(StrncatExit5) + test $0x20, %al + jnz L(Exit6) + cmp $6, %ebx + je L(StrncatExit6) + test $0x40, %al + jnz L(Exit7) + cmp $7, %ebx + je L(StrncatExit7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + lea 7(%edx), %eax + cmpb $1, (%eax) + sbb $-1, %eax + xor %cl, %cl + movb %cl, (%eax) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHighCase2): + test $0x01, %ah + jnz L(Exit9) + cmp $9, %ebx + je L(StrncatExit9) + test $0x02, %ah + jnz L(Exit10) + cmp $10, %ebx + je L(StrncatExit10) + test $0x04, %ah + jnz L(Exit11) + cmp $11, %ebx + je L(StrncatExit11) + test $0x8, %ah + jnz L(Exit12) + cmp $12, %ebx + je L(StrncatExit12) + test $0x10, %ah + jnz L(Exit13) + cmp $13, %ebx + je L(StrncatExit13) + test $0x20, %ah + jnz L(Exit14) + cmp $14, %ebx + je L(StrncatExit14) + test $0x40, %ah + jnz L(Exit15) + cmp $15, %ebx + je L(StrncatExit15) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 8(%ecx), %xmm1 + movlpd %xmm1, 8(%edx) + movl %edi, %eax + RETURN1 + + CFI_PUSH(%esi) + +L(CopyFrom1To16BytesCase2OrCase3): + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + + .p2align 4 +L(CopyFrom1To16BytesCase3): + add $16, %ebx + add %esi, %edx + add %esi, %ecx + + POP (%esi) + + cmp $8, %ebx + ja L(ExitHighCase3) + cmp $1, %ebx + je L(StrncatExit1) + cmp $2, %ebx + je L(StrncatExit2) + cmp $3, %ebx + je L(StrncatExit3) + cmp $4, %ebx + je L(StrncatExit4) + cmp $5, %ebx + je L(StrncatExit5) + cmp $6, %ebx + je L(StrncatExit6) + cmp $7, %ebx + je L(StrncatExit7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb %bh, 8(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHighCase3): + cmp $9, %ebx + je L(StrncatExit9) + cmp $10, %ebx + je L(StrncatExit10) + cmp $11, %ebx + je L(StrncatExit11) + cmp $12, %ebx + je L(StrncatExit12) + cmp $13, %ebx + je L(StrncatExit13) + cmp $14, %ebx + je L(StrncatExit14) + cmp $15, %ebx + je L(StrncatExit15) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 8(%ecx), %xmm1 + movlpd %xmm1, 8(%edx) + movb %bh, 16(%edx) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncatExit0): + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncpyExit15Bytes): + cmp $9, %ebx + je L(StrncatExit9) + cmpb $0, 9(%ecx) + jz L(Exit10) + cmp $10, %ebx + je L(StrncatExit10) + cmpb $0, 10(%ecx) + jz L(Exit11) + cmp $11, %ebx + je L(StrncatExit11) + cmpb $0, 11(%ecx) + jz L(Exit12) + cmp $12, %ebx + je L(StrncatExit12) + cmpb $0, 12(%ecx) + jz L(Exit13) + cmp $13, %ebx + je L(StrncatExit13) + cmpb $0, 13(%ecx) + jz L(Exit14) + cmp $14, %ebx + je L(StrncatExit14) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + lea 14(%edx), %eax + cmpb $1, (%eax) + sbb $-1, %eax + movb %bh, (%eax) + movl %edi, %eax + RETURN1 + + .p2align 4 +L(StrncpyExit8Bytes): + cmpb $0, (%ecx) + jz L(Exit1) + cmp $1, %ebx + je L(StrncatExit1) + cmpb $0, 1(%ecx) + jz L(Exit2) + cmp $2, %ebx + je L(StrncatExit2) + cmpb $0, 2(%ecx) + jz L(Exit3) + cmp $3, %ebx + je L(StrncatExit3) + cmpb $0, 3(%ecx) + jz L(Exit4) + cmp $4, %ebx + je L(StrncatExit4) + cmpb $0, 4(%ecx) + jz L(Exit5) + cmp $5, %ebx + je L(StrncatExit5) + cmpb $0, 5(%ecx) + jz L(Exit6) + cmp $6, %ebx + je L(StrncatExit6) + cmpb $0, 6(%ecx) + jz L(Exit7) + cmp $7, %ebx + je L(StrncatExit7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + lea 7(%edx), %eax + cmpb $1, (%eax) + sbb $-1, %eax + movb %bh, (%eax) + movl %edi, %eax + RETURN1 + +#endif +END (STRCAT_ssse3) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcmp-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcmp-atom.S new file mode 100644 index 000000000..08f6d4ad0 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcmp-atom.S @@ -0,0 +1,2275 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef cfi_remember_state +# define cfi_remember_state .cfi_remember_state +#endif + +#ifndef cfi_restore_state +# define cfi_restore_state .cfi_restore_state +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#ifndef USE_AS_STRNCMP +# define STR1 4 +# define STR2 STR1+4 +# define RETURN ret + +# define UPDATE_STRNCMP_COUNTER +#else +# define STR1 8 +# define STR2 STR1+4 +# define CNT STR2+4 +# define RETURN POP (%ebp); ret; CFI_PUSH (%ebp) + +# define UPDATE_STRNCMP_COUNTER \ + /* calculate left number to compare */ \ + mov $16, %esi; \ + sub %ecx, %esi; \ + cmpl %esi, %ebp; \ + jbe L(more8byteseq); \ + sub %esi, %ebp +#endif + +#ifndef STRCMP +# define STRCMP strcmp_ssse3 +#endif + + .section .text.ssse3,"ax",@progbits +ENTRY (STRCMP) +#ifdef USE_AS_STRNCMP + PUSH (%ebp) + cfi_remember_state +#endif + movl STR1(%esp), %edx + movl STR2(%esp), %eax +#ifdef USE_AS_STRNCMP + movl CNT(%esp), %ebp + cmpl $16, %ebp + jb L(less16bytes_sncmp) + jmp L(more16bytes) +#endif + + movzbl (%eax), %ecx + cmpb %cl, (%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 1(%eax), %ecx + cmpb %cl, 1(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 2(%eax), %ecx + cmpb %cl, 2(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 3(%eax), %ecx + cmpb %cl, 3(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 4(%eax), %ecx + cmpb %cl, 4(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 5(%eax), %ecx + cmpb %cl, 5(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 6(%eax), %ecx + cmpb %cl, 6(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + movzbl 7(%eax), %ecx + cmpb %cl, 7(%edx) + jne L(neq) + cmpl $0, %ecx + je L(eq) + + add $8, %edx + add $8, %eax +#ifdef USE_AS_STRNCMP + cmpl $8, %ebp + lea -8(%ebp), %ebp + je L(eq) +L(more16bytes): +#endif + movl %edx, %ecx + and $0xfff, %ecx + cmpl $0xff0, %ecx + ja L(crosspage) + mov %eax, %ecx + and $0xfff, %ecx + cmpl $0xff0, %ecx + ja L(crosspage) + pxor %xmm0, %xmm0 + movlpd (%eax), %xmm1 + movlpd (%edx), %xmm2 + movhpd 8(%eax), %xmm1 + movhpd 8(%edx), %xmm2 + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %ecx + sub $0xffff, %ecx + jnz L(less16bytes) +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(eq) +#endif + add $16, %eax + add $16, %edx + +L(crosspage): + + PUSH (%ebx) + PUSH (%edi) + PUSH (%esi) + + movl %edx, %edi + movl %eax, %ecx + and $0xf, %ecx + and $0xf, %edi + xor %ecx, %eax + xor %edi, %edx + xor %ebx, %ebx + cmpl %edi, %ecx + je L(ashr_0) + ja L(bigger) + or $0x20, %ebx + xchg %edx, %eax + xchg %ecx, %edi +L(bigger): + lea 15(%edi), %edi + sub %ecx, %edi + cmpl $8, %edi + jle L(ashr_less_8) + cmpl $14, %edi + je L(ashr_15) + cmpl $13, %edi + je L(ashr_14) + cmpl $12, %edi + je L(ashr_13) + cmpl $11, %edi + je L(ashr_12) + cmpl $10, %edi + je L(ashr_11) + cmpl $9, %edi + je L(ashr_10) +L(ashr_less_8): + je L(ashr_9) + cmpl $7, %edi + je L(ashr_8) + cmpl $6, %edi + je L(ashr_7) + cmpl $5, %edi + je L(ashr_6) + cmpl $4, %edi + je L(ashr_5) + cmpl $3, %edi + je L(ashr_4) + cmpl $2, %edi + je L(ashr_3) + cmpl $1, %edi + je L(ashr_2) + cmpl $0, %edi + je L(ashr_1) + +/* + * The following cases will be handled by ashr_0 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(0~15) n(0~15) 15(15+ n-n) ashr_0 + */ + .p2align 4 +L(ashr_0): + mov $0xffff, %esi + movdqa (%eax), %xmm1 + pxor %xmm0, %xmm0 + pcmpeqb %xmm1, %xmm0 + pcmpeqb (%edx), %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + mov %ecx, %edi + jne L(less32bytes) + UPDATE_STRNCMP_COUNTER + mov $0x10, %ebx + mov $0x10, %ecx + pxor %xmm0, %xmm0 + .p2align 4 +L(loop_ashr_0): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + jmp L(loop_ashr_0) + +/* + * The following cases will be handled by ashr_1 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(15) n -15 0(15 +(n-15) - n) ashr_1 + */ + .p2align 4 +L(ashr_1): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $15, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -15(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $1, %ebx + lea 1(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_1): + add $16, %edi + jg L(nibble_ashr_1) + +L(gobble_ashr_1): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $1, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_1) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $1, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_1) + + .p2align 4 +L(nibble_ashr_1): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfffe, %esi + jnz L(ashr_1_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $15, %ebp + jbe L(ashr_1_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_1) + + .p2align 4 +L(ashr_1_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $1, %xmm0 + psrldq $1, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_2 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(14~15) n -14 1(15 +(n-14) - n) ashr_2 + */ + .p2align 4 +L(ashr_2): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $14, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -14(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $2, %ebx + lea 2(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_2): + add $16, %edi + jg L(nibble_ashr_2) + +L(gobble_ashr_2): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $2, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_2) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $2, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_2) + + .p2align 4 +L(nibble_ashr_2): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfffc, %esi + jnz L(ashr_2_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $14, %ebp + jbe L(ashr_2_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_2) + + .p2align 4 +L(ashr_2_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $2, %xmm0 + psrldq $2, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_3 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(13~15) n -13 2(15 +(n-13) - n) ashr_3 + */ + .p2align 4 +L(ashr_3): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $13, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -13(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $3, %ebx + lea 3(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_3): + add $16, %edi + jg L(nibble_ashr_3) + +L(gobble_ashr_3): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $3, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_3) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $3, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_3) + + .p2align 4 +L(nibble_ashr_3): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfff8, %esi + jnz L(ashr_3_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $13, %ebp + jbe L(ashr_3_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_3) + + .p2align 4 +L(ashr_3_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $3, %xmm0 + psrldq $3, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_4 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(12~15) n -12 3(15 +(n-12) - n) ashr_4 + */ + .p2align 4 +L(ashr_4): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $12, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -12(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $4, %ebx + lea 4(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_4): + add $16, %edi + jg L(nibble_ashr_4) + +L(gobble_ashr_4): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $4, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_4) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $4, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_4) + + .p2align 4 +L(nibble_ashr_4): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfff0, %esi + jnz L(ashr_4_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $12, %ebp + jbe L(ashr_4_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_4) + + .p2align 4 +L(ashr_4_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $4, %xmm0 + psrldq $4, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_5 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(11~15) n -11 4(15 +(n-11) - n) ashr_5 + */ + .p2align 4 +L(ashr_5): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $11, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -11(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $5, %ebx + lea 5(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_5): + add $16, %edi + jg L(nibble_ashr_5) + +L(gobble_ashr_5): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $5, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_5) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $5, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_5) + + .p2align 4 +L(nibble_ashr_5): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xffe0, %esi + jnz L(ashr_5_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $11, %ebp + jbe L(ashr_5_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_5) + + .p2align 4 +L(ashr_5_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $5, %xmm0 + psrldq $5, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_6 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(10~15) n -10 5(15 +(n-10) - n) ashr_6 + */ + + .p2align 4 +L(ashr_6): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $10, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -10(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $6, %ebx + lea 6(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_6): + add $16, %edi + jg L(nibble_ashr_6) + +L(gobble_ashr_6): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $6, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_6) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $6, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_6) + + .p2align 4 +L(nibble_ashr_6): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xffc0, %esi + jnz L(ashr_6_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $10, %ebp + jbe L(ashr_6_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_6) + + .p2align 4 +L(ashr_6_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $6, %xmm0 + psrldq $6, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_7 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(9~15) n - 9 6(15 +(n-9) - n) ashr_7 + */ + + .p2align 4 +L(ashr_7): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $9, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -9(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $7, %ebx + lea 8(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_7): + add $16, %edi + jg L(nibble_ashr_7) + +L(gobble_ashr_7): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $7, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_7) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $7, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_7) + + .p2align 4 +L(nibble_ashr_7): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xff80, %esi + jnz L(ashr_7_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $9, %ebp + jbe L(ashr_7_exittail) +#endif + pxor %xmm0, %xmm0 + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_7) + + .p2align 4 +L(ashr_7_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $7, %xmm0 + psrldq $7, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_8 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(8~15) n - 8 7(15 +(n-8) - n) ashr_8 + */ + .p2align 4 +L(ashr_8): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $8, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -8(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $8, %ebx + lea 8(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_8): + add $16, %edi + jg L(nibble_ashr_8) + +L(gobble_ashr_8): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $8, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_8) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $8, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_8) + + .p2align 4 +L(nibble_ashr_8): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xff00, %esi + jnz L(ashr_8_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $8, %ebp + jbe L(ashr_8_exittail) +#endif + pxor %xmm0, %xmm0 + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_8) + + .p2align 4 +L(ashr_8_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $8, %xmm0 + psrldq $8, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_9 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(7~15) n - 7 8(15 +(n-7) - n) ashr_9 + */ + .p2align 4 +L(ashr_9): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $7, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -7(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $9, %ebx + lea 9(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_9): + add $16, %edi + jg L(nibble_ashr_9) + +L(gobble_ashr_9): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $9, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_9) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $9, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_9) + + .p2align 4 +L(nibble_ashr_9): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfe00, %esi + jnz L(ashr_9_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $7, %ebp + jbe L(ashr_9_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_9) + + .p2align 4 +L(ashr_9_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $9, %xmm0 + psrldq $9, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_10 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(6~15) n - 6 9(15 +(n-6) - n) ashr_10 + */ + .p2align 4 +L(ashr_10): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $6, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -6(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $10, %ebx + lea 10(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_10): + add $16, %edi + jg L(nibble_ashr_10) + +L(gobble_ashr_10): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $10, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_10) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $10, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_10) + + .p2align 4 +L(nibble_ashr_10): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xfc00, %esi + jnz L(ashr_10_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $6, %ebp + jbe L(ashr_10_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_10) + + .p2align 4 +L(ashr_10_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $10, %xmm0 + psrldq $10, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_11 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(5~15) n - 5 10(15 +(n-5) - n) ashr_11 + */ + .p2align 4 +L(ashr_11): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $5, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -5(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $11, %ebx + lea 11(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_11): + add $16, %edi + jg L(nibble_ashr_11) + +L(gobble_ashr_11): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $11, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_11) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $11, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_11) + + .p2align 4 +L(nibble_ashr_11): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xf800, %esi + jnz L(ashr_11_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $5, %ebp + jbe L(ashr_11_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_11) + + .p2align 4 +L(ashr_11_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $11, %xmm0 + psrldq $11, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_12 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(4~15) n - 4 11(15 +(n-4) - n) ashr_12 + */ + .p2align 4 +L(ashr_12): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $4, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -4(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $12, %ebx + lea 12(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_12): + add $16, %edi + jg L(nibble_ashr_12) + +L(gobble_ashr_12): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $12, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_12) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $12, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_12) + + .p2align 4 +L(nibble_ashr_12): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xf000, %esi + jnz L(ashr_12_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $4, %ebp + jbe L(ashr_12_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_12) + + .p2align 4 +L(ashr_12_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $12, %xmm0 + psrldq $12, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_13 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(3~15) n - 3 12(15 +(n-3) - n) ashr_13 + */ + .p2align 4 +L(ashr_13): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $3, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -3(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $13, %ebx + lea 13(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_13): + add $16, %edi + jg L(nibble_ashr_13) + +L(gobble_ashr_13): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $13, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_13) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $13, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_13) + + .p2align 4 +L(nibble_ashr_13): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xe000, %esi + jnz L(ashr_13_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $3, %ebp + jbe L(ashr_13_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_13) + + .p2align 4 +L(ashr_13_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $13, %xmm0 + psrldq $13, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_14 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(2~15) n - 2 13(15 +(n-2) - n) ashr_14 + */ + .p2align 4 +L(ashr_14): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $2, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -2(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $14, %ebx + lea 14(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_14): + add $16, %edi + jg L(nibble_ashr_14) + +L(gobble_ashr_14): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $14, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_14) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $14, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_14) + + .p2align 4 +L(nibble_ashr_14): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0xc000, %esi + jnz L(ashr_14_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $2, %ebp + jbe L(ashr_14_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_14) + + .p2align 4 +L(ashr_14_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $14, %xmm0 + psrldq $14, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_14 + * ecx(offset of esi) eax(offset of edi) relative offset corresponding case + * n(1~15) n - 1 14(15 +(n-1) - n) ashr_15 + */ + + .p2align 4 +L(ashr_15): + mov $0xffff, %esi + pxor %xmm0, %xmm0 + movdqa (%edx), %xmm2 + movdqa (%eax), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $1, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %edi + shr %cl, %esi + shr %cl, %edi + sub %edi, %esi + lea -1(%ecx), %edi + jnz L(less32bytes) + + UPDATE_STRNCMP_COUNTER + + movdqa (%edx), %xmm3 + pxor %xmm0, %xmm0 + mov $16, %ecx + or $15, %ebx + lea 15(%edx), %edi + and $0xfff, %edi + sub $0x1000, %edi + + .p2align 4 +L(loop_ashr_15): + add $16, %edi + jg L(nibble_ashr_15) + +L(gobble_ashr_15): + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $15, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + + add $16, %edi + jg L(nibble_ashr_15) + + movdqa (%eax, %ecx), %xmm1 + movdqa (%edx, %ecx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $15, %xmm3, %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + sub $0xffff, %esi + jnz L(exit) + +#ifdef USE_AS_STRNCMP + cmpl $16, %ebp + lea -16(%ebp), %ebp + jbe L(more8byteseq) +#endif + add $16, %ecx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_15) + + .p2align 4 +L(nibble_ashr_15): + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %esi + test $0x8000, %esi + jnz L(ashr_15_exittail) + +#ifdef USE_AS_STRNCMP + cmpl $1, %ebp + jbe L(ashr_15_exittail) +#endif + pxor %xmm0, %xmm0 + sub $0x1000, %edi + jmp L(gobble_ashr_15) + + .p2align 4 +L(ashr_15_exittail): + movdqa (%eax, %ecx), %xmm1 + psrldq $15, %xmm0 + psrldq $15, %xmm3 + jmp L(aftertail) + + .p2align 4 +L(aftertail): + pcmpeqb %xmm3, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %esi + not %esi +L(exit): + mov %ebx, %edi + and $0x1f, %edi + lea -16(%edi, %ecx), %edi +L(less32bytes): + add %edi, %edx + add %ecx, %eax + test $0x20, %ebx + jz L(ret2) + xchg %eax, %edx + + .p2align 4 +L(ret2): + mov %esi, %ecx + POP (%esi) + POP (%edi) + POP (%ebx) +L(less16bytes): + test %cl, %cl + jz L(2next_8_bytes) + + test $0x01, %cl + jnz L(Byte0) + + test $0x02, %cl + jnz L(Byte1) + + test $0x04, %cl + jnz L(Byte2) + + test $0x08, %cl + jnz L(Byte3) + + test $0x10, %cl + jnz L(Byte4) + + test $0x20, %cl + jnz L(Byte5) + + test $0x40, %cl + jnz L(Byte6) +#ifdef USE_AS_STRNCMP + cmpl $7, %ebp + jbe L(eq) +#endif + + movzbl 7(%eax), %ecx + movzbl 7(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte0): +#ifdef USE_AS_STRNCMP + cmpl $0, %ebp + jbe L(eq) +#endif + movzbl (%eax), %ecx + movzbl (%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte1): +#ifdef USE_AS_STRNCMP + cmpl $1, %ebp + jbe L(eq) +#endif + movzbl 1(%eax), %ecx + movzbl 1(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte2): +#ifdef USE_AS_STRNCMP + cmpl $2, %ebp + jbe L(eq) +#endif + movzbl 2(%eax), %ecx + movzbl 2(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte3): +#ifdef USE_AS_STRNCMP + cmpl $3, %ebp + jbe L(eq) +#endif + movzbl 3(%eax), %ecx + movzbl 3(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte4): +#ifdef USE_AS_STRNCMP + cmpl $4, %ebp + jbe L(eq) +#endif + movzbl 4(%eax), %ecx + movzbl 4(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte5): +#ifdef USE_AS_STRNCMP + cmpl $5, %ebp + jbe L(eq) +#endif + movzbl 5(%eax), %ecx + movzbl 5(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(Byte6): +#ifdef USE_AS_STRNCMP + cmpl $6, %ebp + jbe L(eq) +#endif + movzbl 6(%eax), %ecx + movzbl 6(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(2next_8_bytes): + add $8, %eax + add $8, %edx +#ifdef USE_AS_STRNCMP + cmpl $8, %ebp + lea -8(%ebp), %ebp + jbe L(eq) +#endif + + test $0x01, %ch + jnz L(Byte0) + + test $0x02, %ch + jnz L(Byte1) + + test $0x04, %ch + jnz L(Byte2) + + test $0x08, %ch + jnz L(Byte3) + + test $0x10, %ch + jnz L(Byte4) + + test $0x20, %ch + jnz L(Byte5) + + test $0x40, %ch + jnz L(Byte6) + +#ifdef USE_AS_STRNCMP + cmpl $7, %ebp + jbe L(eq) +#endif + movzbl 7(%eax), %ecx + movzbl 7(%edx), %eax + + sub %ecx, %eax + RETURN + + .p2align 4 +L(neq): + mov $1, %eax + ja L(neq_bigger) + neg %eax +L(neq_bigger): + RETURN + +#ifdef USE_AS_STRNCMP + .p2align 4 +L(more8byteseq): + POP (%esi) + POP (%edi) + POP (%ebx) +#endif + +L(eq): + +#ifdef USE_AS_STRNCMP + POP (%ebp) +#endif + xorl %eax, %eax + ret + +#ifdef USE_AS_STRNCMP + cfi_restore_state + + .p2align 4 +L(less16bytes_sncmp): + test %ebp, %ebp + jz L(eq) + + movzbl (%eax), %ecx + cmpb %cl, (%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $1, %ebp + je L(eq) + + movzbl 1(%eax), %ecx + cmpb %cl, 1(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $2, %ebp + je L(eq) + + movzbl 2(%eax), %ecx + cmpb %cl, 2(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $3, %ebp + je L(eq) + + movzbl 3(%eax), %ecx + cmpb %cl, 3(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $4, %ebp + je L(eq) + + movzbl 4(%eax), %ecx + cmpb %cl, 4(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $5, %ebp + je L(eq) + + movzbl 5(%eax), %ecx + cmpb %cl, 5(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $6, %ebp + je L(eq) + + movzbl 6(%eax), %ecx + cmpb %cl, 6(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $7, %ebp + je L(eq) + + movzbl 7(%eax), %ecx + cmpb %cl, 7(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + + cmpl $8, %ebp + je L(eq) + + movzbl 8(%eax), %ecx + cmpb %cl, 8(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $9, %ebp + je L(eq) + + movzbl 9(%eax), %ecx + cmpb %cl, 9(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $10, %ebp + je L(eq) + + movzbl 10(%eax), %ecx + cmpb %cl, 10(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $11, %ebp + je L(eq) + + movzbl 11(%eax), %ecx + cmpb %cl, 11(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + + cmpl $12, %ebp + je L(eq) + + movzbl 12(%eax), %ecx + cmpb %cl, 12(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $13, %ebp + je L(eq) + + movzbl 13(%eax), %ecx + cmpb %cl, 13(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $14, %ebp + je L(eq) + + movzbl 14(%eax), %ecx + cmpb %cl, 14(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + cmpl $15, %ebp + je L(eq) + + movzbl 15(%eax), %ecx + cmpb %cl, 15(%edx) + jne L(neq) + test %cl, %cl + je L(eq) + + POP (%ebp) + xor %eax, %eax + ret +#endif + +END (STRCMP) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcpy-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcpy-atom.S new file mode 100644 index 000000000..45b0c0256 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strcpy-atom.S @@ -0,0 +1,3955 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_STRCAT + +# ifndef L +# define L(label) .L##label +# endif + +# ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +# endif + +# ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +# endif + +# ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# endif + +# ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +# endif + +# ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# endif + +# ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +# endif + +# ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +# endif + +# define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +# define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +# define PUSH(REG) pushl REG; CFI_PUSH (REG) +# define POP(REG) popl REG; CFI_POP (REG) + +# ifndef STRCPY +# define STRCPY strcpy_atom +# endif + +# ifdef USE_AS_STRNCPY +# define PARMS 8 +# define ENTRANCE PUSH (%ebx) +# define RETURN POP (%ebx); ret; CFI_PUSH (%ebx); +# define RETURN1 POP (%edi); POP (%ebx); ret; CFI_PUSH (%ebx); CFI_PUSH (%edi) +# else +# define PARMS 4 +# define ENTRANCE +# define RETURN ret +# define RETURN1 POP (%edi); ret; CFI_PUSH (%edi) +# endif + +# ifdef USE_AS_STPCPY +# define SAVE_RESULT(n) lea n(%edx), %eax +# define SAVE_RESULT_TAIL(n) lea n(%edx), %eax +# else +# define SAVE_RESULT(n) movl %edi, %eax +# define SAVE_RESULT_TAIL(n) movl %edx, %eax +# endif + +# define STR1 PARMS +# define STR2 STR1+4 +# define LEN STR2+4 + +/* In this code following instructions are used for copying: + movb - 1 byte + movw - 2 byte + movl - 4 byte + movlpd - 8 byte + movaps - 16 byte - requires 16 byte alignment + of sourse and destination adresses. +*/ + +.text +ENTRY (STRCPY) + ENTRANCE + mov STR1(%esp), %edx + mov STR2(%esp), %ecx +# ifdef USE_AS_STRNCPY + movl LEN(%esp), %ebx + cmp $8, %ebx + jbe L(StrncpyExit8Bytes) +# endif + cmpb $0, (%ecx) + jz L(ExitTail1) + cmpb $0, 1(%ecx) + jz L(ExitTail2) + cmpb $0, 2(%ecx) + jz L(ExitTail3) + cmpb $0, 3(%ecx) + jz L(ExitTail4) + cmpb $0, 4(%ecx) + jz L(ExitTail5) + cmpb $0, 5(%ecx) + jz L(ExitTail6) + cmpb $0, 6(%ecx) + jz L(ExitTail7) + cmpb $0, 7(%ecx) + jz L(ExitTail8) +# ifdef USE_AS_STRNCPY + cmp $16, %ebx + jb L(StrncpyExit15Bytes) +# endif + cmpb $0, 8(%ecx) + jz L(ExitTail9) + cmpb $0, 9(%ecx) + jz L(ExitTail10) + cmpb $0, 10(%ecx) + jz L(ExitTail11) + cmpb $0, 11(%ecx) + jz L(ExitTail12) + cmpb $0, 12(%ecx) + jz L(ExitTail13) + cmpb $0, 13(%ecx) + jz L(ExitTail14) + cmpb $0, 14(%ecx) + jz L(ExitTail15) +# if defined USE_AS_STRNCPY && !defined USE_AS_STRLCPY + cmp $16, %ebx + je L(ExitTail16) +# endif + cmpb $0, 15(%ecx) + jz L(ExitTail16) + +# if defined USE_AS_STRNCPY && defined USE_AS_STRLCPY + cmp $16, %ebx + je L(StrlcpyExitTail16) +# endif + + PUSH (%edi) +# ifndef USE_AS_STRLCPY + mov %edx, %edi +# else + mov %ecx, %edi +# endif +#endif + PUSH (%esi) +#ifdef USE_AS_STRNCPY + mov %ecx, %esi + sub $16, %ebx + and $0xf, %esi + +/* add 16 bytes ecx_offset to ebx */ + + add %esi, %ebx +#endif + lea 16(%ecx), %esi + and $-16, %esi + pxor %xmm0, %xmm0 + movlpd (%ecx), %xmm1 + movlpd %xmm1, (%edx) + + pcmpeqb (%esi), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm1, 8(%edx) + + pmovmskb %xmm0, %eax + sub %ecx, %esi + +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + mov %edx, %eax + lea 16(%edx), %edx + and $-16, %edx + sub %edx, %eax + +#ifdef USE_AS_STRNCPY + add %eax, %esi + lea -1(%esi), %esi + and $1<<31, %esi + test %esi, %esi + jnz L(ContinueCopy) + lea 16(%ebx), %ebx + +L(ContinueCopy): +#endif + sub %eax, %ecx + mov %ecx, %eax + and $0xf, %eax + mov $0, %esi + +/* case: ecx_offset == edx_offset */ + + jz L(Align16Both) + + cmp $8, %eax + jae L(ShlHigh8) + cmp $1, %eax + je L(Shl1) + cmp $2, %eax + je L(Shl2) + cmp $3, %eax + je L(Shl3) + cmp $4, %eax + je L(Shl4) + cmp $5, %eax + je L(Shl5) + cmp $6, %eax + je L(Shl6) + jmp L(Shl7) + +L(ShlHigh8): + je L(Shl8) + cmp $9, %eax + je L(Shl9) + cmp $10, %eax + je L(Shl10) + cmp $11, %eax + je L(Shl11) + cmp $12, %eax + je L(Shl12) + cmp $13, %eax + je L(Shl13) + cmp $14, %eax + je L(Shl14) + jmp L(Shl15) + +L(Align16Both): + movaps (%ecx), %xmm1 + movaps 16(%ecx), %xmm2 + movaps %xmm1, (%edx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm3 + movaps %xmm2, (%edx, %esi) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm4 + movaps %xmm3, (%edx, %esi) + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm1 + movaps %xmm4, (%edx, %esi) + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm2 + movaps %xmm1, (%edx, %esi) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm3 + movaps %xmm2, (%edx, %esi) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps %xmm3, (%edx, %esi) + mov %ecx, %eax + lea 16(%ecx, %esi), %ecx + and $-0x40, %ecx + sub %ecx, %eax + sub %eax, %edx +#ifdef USE_AS_STRNCPY + lea 112(%ebx, %eax), %ebx +#endif + mov $-0x40, %esi + +L(Aligned64Loop): + movaps (%ecx), %xmm2 + movaps 32(%ecx), %xmm3 + movaps %xmm2, %xmm4 + movaps 16(%ecx), %xmm5 + movaps %xmm3, %xmm6 + movaps 48(%ecx), %xmm7 + pminub %xmm5, %xmm2 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + lea 64(%edx), %edx + pcmpeqb %xmm0, %xmm3 + lea 64(%ecx), %ecx + pmovmskb %xmm3, %eax +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeaveCase2OrCase3) +#endif + test %eax, %eax + jnz L(Aligned64Leave) + movaps %xmm4, -64(%edx) + movaps %xmm5, -48(%edx) + movaps %xmm6, -32(%edx) + movaps %xmm7, -16(%edx) + jmp L(Aligned64Loop) + +L(Aligned64Leave): +#ifdef USE_AS_STRNCPY + lea 48(%ebx), %ebx +#endif + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqb %xmm5, %xmm0 +#ifdef USE_AS_STRNCPY + lea -16(%ebx), %ebx +#endif + pmovmskb %xmm0, %eax + movaps %xmm4, -64(%edx) + lea 16(%esi), %esi + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqb %xmm6, %xmm0 +#ifdef USE_AS_STRNCPY + lea -16(%ebx), %ebx +#endif + pmovmskb %xmm0, %eax + movaps %xmm5, -48(%edx) + lea 16(%esi), %esi + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps %xmm6, -32(%edx) + pcmpeqb %xmm7, %xmm0 +#ifdef USE_AS_STRNCPY + lea -16(%ebx), %ebx +#endif + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl1): + movaps -1(%ecx), %xmm1 + movaps 15(%ecx), %xmm2 +L(Shl1Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit1Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl1LoopExit) + + palignr $1, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 31(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit1Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl1LoopExit) + + palignr $1, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 31(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit1Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl1LoopExit) + + palignr $1, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 31(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit1Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl1LoopExit) + + palignr $1, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 31(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -15(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -1(%ecx), %xmm1 + +L(Shl1LoopStart): + movaps 15(%ecx), %xmm2 + movaps 31(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 47(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 63(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $1, %xmm4, %xmm5 + palignr $1, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl1Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave1) +#endif + palignr $1, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $1, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl1LoopStart) + +L(Shl1LoopExit): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + mov $15, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl2): + movaps -2(%ecx), %xmm1 + movaps 14(%ecx), %xmm2 +L(Shl2Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit2Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl2LoopExit) + + palignr $2, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 30(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit2Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl2LoopExit) + + palignr $2, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 30(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit2Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl2LoopExit) + + palignr $2, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 30(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit2Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl2LoopExit) + + palignr $2, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 30(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -14(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -2(%ecx), %xmm1 + +L(Shl2LoopStart): + movaps 14(%ecx), %xmm2 + movaps 30(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 46(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 62(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $2, %xmm4, %xmm5 + palignr $2, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl2Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave2) +#endif + palignr $2, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $2, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl2LoopStart) + +L(Shl2LoopExit): + movlpd (%ecx), %xmm0 + movlpd 6(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 6(%edx) + mov $14, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl3): + movaps -3(%ecx), %xmm1 + movaps 13(%ecx), %xmm2 +L(Shl3Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit3Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl3LoopExit) + + palignr $3, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 29(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit3Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl3LoopExit) + + palignr $3, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 29(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit3Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl3LoopExit) + + palignr $3, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 29(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit3Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl3LoopExit) + + palignr $3, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 29(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -13(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -3(%ecx), %xmm1 + +L(Shl3LoopStart): + movaps 13(%ecx), %xmm2 + movaps 29(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 45(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 61(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $3, %xmm4, %xmm5 + palignr $3, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl3Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave3) +#endif + palignr $3, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $3, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl3LoopStart) + +L(Shl3LoopExit): + movlpd (%ecx), %xmm0 + movlpd 5(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 5(%edx) + mov $13, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl4): + movaps -4(%ecx), %xmm1 + movaps 12(%ecx), %xmm2 +L(Shl4Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit4Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit4Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit4Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit4Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 28(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -12(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -4(%ecx), %xmm1 + +L(Shl4LoopStart): + movaps 12(%ecx), %xmm2 + movaps 28(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 44(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 60(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $4, %xmm4, %xmm5 + palignr $4, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl4Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave4) +#endif + palignr $4, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $4, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl4LoopStart) + +L(Shl4LoopExit): + movlpd (%ecx), %xmm0 + movl 8(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 8(%edx) + mov $12, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl5): + movaps -5(%ecx), %xmm1 + movaps 11(%ecx), %xmm2 +L(Shl5Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit5Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl5LoopExit) + + palignr $5, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 27(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit5Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl5LoopExit) + + palignr $5, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 27(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit5Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl5LoopExit) + + palignr $5, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 27(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit5Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl5LoopExit) + + palignr $5, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 27(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -11(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -5(%ecx), %xmm1 + +L(Shl5LoopStart): + movaps 11(%ecx), %xmm2 + movaps 27(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 43(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 59(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $5, %xmm4, %xmm5 + palignr $5, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl5Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave5) +#endif + palignr $5, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $5, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl5LoopStart) + +L(Shl5LoopExit): + movlpd (%ecx), %xmm0 + movl 7(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 7(%edx) + mov $11, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl6): + movaps -6(%ecx), %xmm1 + movaps 10(%ecx), %xmm2 +L(Shl6Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit6Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl6LoopExit) + + palignr $6, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 26(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit6Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl6LoopExit) + + palignr $6, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 26(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit6Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl6LoopExit) + + palignr $6, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 26(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit6Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl6LoopExit) + + palignr $6, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 26(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -10(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -6(%ecx), %xmm1 + +L(Shl6LoopStart): + movaps 10(%ecx), %xmm2 + movaps 26(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 42(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 58(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $6, %xmm4, %xmm5 + palignr $6, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl6Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave6) +#endif + palignr $6, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $6, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl6LoopStart) + +L(Shl6LoopExit): + movlpd (%ecx), %xmm0 + movl 6(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 6(%edx) + mov $10, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl7): + movaps -7(%ecx), %xmm1 + movaps 9(%ecx), %xmm2 +L(Shl7Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit7Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl7LoopExit) + + palignr $7, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 25(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit7Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl7LoopExit) + + palignr $7, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 25(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit7Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl7LoopExit) + + palignr $7, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 25(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit7Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl7LoopExit) + + palignr $7, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 25(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -9(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -7(%ecx), %xmm1 + +L(Shl7LoopStart): + movaps 9(%ecx), %xmm2 + movaps 25(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 41(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 57(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $7, %xmm4, %xmm5 + palignr $7, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl7Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave7) +#endif + palignr $7, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $7, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl7LoopStart) + +L(Shl7LoopExit): + movlpd (%ecx), %xmm0 + movl 5(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 5(%edx) + mov $9, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl8): + movaps -8(%ecx), %xmm1 + movaps 8(%ecx), %xmm2 +L(Shl8Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit8Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit8Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit8Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit8Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 24(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -8(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -8(%ecx), %xmm1 + +L(Shl8LoopStart): + movaps 8(%ecx), %xmm2 + movaps 24(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 40(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 56(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $8, %xmm4, %xmm5 + palignr $8, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl8Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave8) +#endif + palignr $8, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $8, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl8LoopStart) + +L(Shl8LoopExit): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + mov $8, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl9): + movaps -9(%ecx), %xmm1 + movaps 7(%ecx), %xmm2 +L(Shl9Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit9Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl9LoopExit) + + palignr $9, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 23(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit9Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl9LoopExit) + + palignr $9, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 23(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit9Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl9LoopExit) + + palignr $9, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 23(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit9Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl9LoopExit) + + palignr $9, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 23(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -7(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -9(%ecx), %xmm1 + +L(Shl9LoopStart): + movaps 7(%ecx), %xmm2 + movaps 23(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 39(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 55(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $9, %xmm4, %xmm5 + palignr $9, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl9Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave9) +#endif + palignr $9, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $9, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl9LoopStart) + +L(Shl9LoopExit): + movlpd -1(%ecx), %xmm0 + movlpd %xmm0, -1(%edx) + mov $7, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl10): + movaps -10(%ecx), %xmm1 + movaps 6(%ecx), %xmm2 +L(Shl10Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit10Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl10LoopExit) + + palignr $10, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 22(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit10Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl10LoopExit) + + palignr $10, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 22(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit10Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl10LoopExit) + + palignr $10, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 22(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit10Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl10LoopExit) + + palignr $10, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 22(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -6(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -10(%ecx), %xmm1 + +L(Shl10LoopStart): + movaps 6(%ecx), %xmm2 + movaps 22(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 38(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 54(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $10, %xmm4, %xmm5 + palignr $10, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl10Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave10) +#endif + palignr $10, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $10, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl10LoopStart) + +L(Shl10LoopExit): + movlpd -2(%ecx), %xmm0 + movlpd %xmm0, -2(%edx) + mov $6, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl11): + movaps -11(%ecx), %xmm1 + movaps 5(%ecx), %xmm2 +L(Shl11Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit11Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl11LoopExit) + + palignr $11, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 21(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit11Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl11LoopExit) + + palignr $11, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 21(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit11Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl11LoopExit) + + palignr $11, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 21(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit11Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl11LoopExit) + + palignr $11, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 21(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -5(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -11(%ecx), %xmm1 + +L(Shl11LoopStart): + movaps 5(%ecx), %xmm2 + movaps 21(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 37(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 53(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $11, %xmm4, %xmm5 + palignr $11, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl11Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave11) +#endif + palignr $11, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $11, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl11LoopStart) + +L(Shl11LoopExit): + movlpd -3(%ecx), %xmm0 + movlpd %xmm0, -3(%edx) + mov $5, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl12): + movaps -12(%ecx), %xmm1 + movaps 4(%ecx), %xmm2 +L(Shl12Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit12Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit12Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit12Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit12Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 20(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -4(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -12(%ecx), %xmm1 + +L(Shl12LoopStart): + movaps 4(%ecx), %xmm2 + movaps 20(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 36(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 52(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $12, %xmm4, %xmm5 + palignr $12, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl12Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave12) +#endif + palignr $12, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $12, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl12LoopStart) + +L(Shl12LoopExit): + movl (%ecx), %esi + movl %esi, (%edx) + mov $4, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl13): + movaps -13(%ecx), %xmm1 + movaps 3(%ecx), %xmm2 +L(Shl13Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit13Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl13LoopExit) + + palignr $13, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 19(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit13Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl13LoopExit) + + palignr $13, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 19(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit13Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl13LoopExit) + + palignr $13, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 19(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit13Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl13LoopExit) + + palignr $13, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 19(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -3(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -13(%ecx), %xmm1 + +L(Shl13LoopStart): + movaps 3(%ecx), %xmm2 + movaps 19(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 35(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 51(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $13, %xmm4, %xmm5 + palignr $13, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl13Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave13) +#endif + palignr $13, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $13, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl13LoopStart) + +L(Shl13LoopExit): + movl -1(%ecx), %esi + movl %esi, -1(%edx) + mov $3, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl14): + movaps -14(%ecx), %xmm1 + movaps 2(%ecx), %xmm2 +L(Shl14Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit14Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl14LoopExit) + + palignr $14, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 18(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit14Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl14LoopExit) + + palignr $14, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 18(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit14Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl14LoopExit) + + palignr $14, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 18(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit14Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl14LoopExit) + + palignr $14, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 18(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -2(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -14(%ecx), %xmm1 + +L(Shl14LoopStart): + movaps 2(%ecx), %xmm2 + movaps 18(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 34(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 50(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $14, %xmm4, %xmm5 + palignr $14, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl14Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave14) +#endif + palignr $14, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $14, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl14LoopStart) + +L(Shl14LoopExit): + movl -2(%ecx), %esi + movl %esi, -2(%edx) + mov $2, %esi + jmp L(CopyFrom1To16Bytes) + + .p2align 4 +L(Shl15): + movaps -15(%ecx), %xmm1 + movaps 1(%ecx), %xmm2 +L(Shl15Start): + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit15Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl15LoopExit) + + palignr $15, %xmm1, %xmm2 + movaps %xmm3, %xmm1 + movaps %xmm2, (%edx) + movaps 17(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit15Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl15LoopExit) + + palignr $15, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 17(%ecx), %xmm2 + movaps %xmm3, %xmm1 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit15Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl15LoopExit) + + palignr $15, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 17(%ecx), %xmm2 + + pcmpeqb %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(StrncpyExit15Case2OrCase3) +#endif + test %eax, %eax + jnz L(Shl15LoopExit) + + palignr $15, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 17(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -1(%ecx), %ecx + sub %eax, %edx +#ifdef USE_AS_STRNCPY + add %eax, %ebx +#endif + movaps -15(%ecx), %xmm1 + +L(Shl15LoopStart): + movaps 1(%ecx), %xmm2 + movaps 17(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 33(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 49(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqb %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $15, %xmm4, %xmm5 + palignr $15, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl15Start) +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(StrncpyLeave15) +#endif + palignr $15, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $15, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl15LoopStart) + +L(Shl15LoopExit): + movl -3(%ecx), %esi + movl %esi, -3(%edx) + mov $1, %esi +#if defined USE_AS_STRCAT || defined USE_AS_STRLCPY + jmp L(CopyFrom1To16Bytes) +#endif + + +#if !defined USE_AS_STRCAT && !defined USE_AS_STRLCPY + + .p2align 4 +L(CopyFrom1To16Bytes): +# ifdef USE_AS_STRNCPY + add $16, %ebx +# endif + add %esi, %edx + add %esi, %ecx + + POP (%esi) + test %al, %al + jz L(ExitHigh8) + +L(CopyFrom1To16BytesLess8): + mov %al, %ah + and $15, %ah + jz L(ExitHigh4) + + test $0x01, %al + jnz L(Exit1) + test $0x02, %al + jnz L(Exit2) + test $0x04, %al + jnz L(Exit3) + + .p2align 4 +L(Exit4): + movl (%ecx), %eax + movl %eax, (%edx) + SAVE_RESULT (3) +# ifdef USE_AS_STRNCPY + sub $4, %ebx + lea 4(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(ExitHigh4): + test $0x10, %al + jnz L(Exit5) + test $0x20, %al + jnz L(Exit6) + test $0x40, %al + jnz L(Exit7) + + .p2align 4 +L(Exit8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + SAVE_RESULT (7) +# ifdef USE_AS_STRNCPY + sub $8, %ebx + lea 8(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(ExitHigh8): + mov %ah, %al + and $15, %al + jz L(ExitHigh12) + + test $0x01, %ah + jnz L(Exit9) + test $0x02, %ah + jnz L(Exit10) + test $0x04, %ah + jnz L(Exit11) + + .p2align 4 +L(Exit12): + movlpd (%ecx), %xmm0 + movl 8(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 8(%edx) + SAVE_RESULT (11) +# ifdef USE_AS_STRNCPY + sub $12, %ebx + lea 12(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(ExitHigh12): + test $0x10, %ah + jnz L(Exit13) + test $0x20, %ah + jnz L(Exit14) + test $0x40, %ah + jnz L(Exit15) + + .p2align 4 +L(Exit16): + movdqu (%ecx), %xmm0 + movdqu %xmm0, (%edx) + SAVE_RESULT (15) +# ifdef USE_AS_STRNCPY + sub $16, %ebx + lea 16(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + +# ifdef USE_AS_STRNCPY + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %ebx + add %esi, %ecx + add %esi, %edx + + POP (%esi) + + test %al, %al + jz L(ExitHighCase2) + + cmp $8, %ebx + ja L(CopyFrom1To16BytesLess8) + + test $0x01, %al + jnz L(Exit1) + cmp $1, %ebx + je L(Exit1) + test $0x02, %al + jnz L(Exit2) + cmp $2, %ebx + je L(Exit2) + test $0x04, %al + jnz L(Exit3) + cmp $3, %ebx + je L(Exit3) + test $0x08, %al + jnz L(Exit4) + cmp $4, %ebx + je L(Exit4) + test $0x10, %al + jnz L(Exit5) + cmp $5, %ebx + je L(Exit5) + test $0x20, %al + jnz L(Exit6) + cmp $6, %ebx + je L(Exit6) + test $0x40, %al + jnz L(Exit7) + cmp $7, %ebx + je L(Exit7) + jmp L(Exit8) + + .p2align 4 +L(ExitHighCase2): + cmp $8, %ebx + jbe L(CopyFrom1To16BytesLess8Case3) + + test $0x01, %ah + jnz L(Exit9) + cmp $9, %ebx + je L(Exit9) + test $0x02, %ah + jnz L(Exit10) + cmp $10, %ebx + je L(Exit10) + test $0x04, %ah + jnz L(Exit11) + cmp $11, %ebx + je L(Exit11) + test $0x8, %ah + jnz L(Exit12) + cmp $12, %ebx + je L(Exit12) + test $0x10, %ah + jnz L(Exit13) + cmp $13, %ebx + je L(Exit13) + test $0x20, %ah + jnz L(Exit14) + cmp $14, %ebx + je L(Exit14) + test $0x40, %ah + jnz L(Exit15) + cmp $15, %ebx + je L(Exit15) + jmp L(Exit16) + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2OrCase3): + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + + .p2align 4 +L(CopyFrom1To16BytesCase3): + add $16, %ebx + add %esi, %edx + add %esi, %ecx + + POP (%esi) + + cmp $8, %ebx + ja L(ExitHigh8Case3) + +L(CopyFrom1To16BytesLess8Case3): + cmp $4, %ebx + ja L(ExitHigh4Case3) + + cmp $1, %ebx + je L(Exit1) + cmp $2, %ebx + je L(Exit2) + cmp $3, %ebx + je L(Exit3) + movl (%ecx), %eax + movl %eax, (%edx) + SAVE_RESULT (4) + RETURN1 + + .p2align 4 +L(ExitHigh4Case3): + cmp $5, %ebx + je L(Exit5) + cmp $6, %ebx + je L(Exit6) + cmp $7, %ebx + je L(Exit7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + SAVE_RESULT (8) + RETURN1 + + .p2align 4 +L(ExitHigh8Case3): + cmp $12, %ebx + ja L(ExitHigh12Case3) + + cmp $9, %ebx + je L(Exit9) + cmp $10, %ebx + je L(Exit10) + cmp $11, %ebx + je L(Exit11) + movlpd (%ecx), %xmm0 + movl 8(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 8(%edx) + SAVE_RESULT (12) + RETURN1 + + .p2align 4 +L(ExitHigh12Case3): + cmp $13, %ebx + je L(Exit13) + cmp $14, %ebx + je L(Exit14) + cmp $15, %ebx + je L(Exit15) + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + SAVE_RESULT (16) + RETURN1 + +# endif + + .p2align 4 +L(Exit1): + movb (%ecx), %al + movb %al, (%edx) + SAVE_RESULT (0) +# ifdef USE_AS_STRNCPY + sub $1, %ebx + lea 1(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit2): + movw (%ecx), %ax + movw %ax, (%edx) + SAVE_RESULT (1) +# ifdef USE_AS_STRNCPY + sub $2, %ebx + lea 2(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + SAVE_RESULT (2) +# ifdef USE_AS_STRNCPY + sub $3, %ebx + lea 3(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + SAVE_RESULT (4) +# ifdef USE_AS_STRNCPY + sub $5, %ebx + lea 5(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + SAVE_RESULT (5) +# ifdef USE_AS_STRNCPY + sub $6, %ebx + lea 6(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + SAVE_RESULT (6) +# ifdef USE_AS_STRNCPY + sub $7, %ebx + lea 7(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit9): + movlpd (%ecx), %xmm0 + movb 8(%ecx), %al + movlpd %xmm0, (%edx) + movb %al, 8(%edx) + SAVE_RESULT (8) +# ifdef USE_AS_STRNCPY + sub $9, %ebx + lea 9(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit10): + movlpd (%ecx), %xmm0 + movw 8(%ecx), %ax + movlpd %xmm0, (%edx) + movw %ax, 8(%edx) + SAVE_RESULT (9) +# ifdef USE_AS_STRNCPY + sub $10, %ebx + lea 10(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit11): + movlpd (%ecx), %xmm0 + movl 7(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 7(%edx) + SAVE_RESULT (10) +# ifdef USE_AS_STRNCPY + sub $11, %ebx + lea 11(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit13): + movlpd (%ecx), %xmm0 + movlpd 5(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 5(%edx) + SAVE_RESULT (12) +# ifdef USE_AS_STRNCPY + sub $13, %ebx + lea 13(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit14): + movlpd (%ecx), %xmm0 + movlpd 6(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 6(%edx) + SAVE_RESULT (13) +# ifdef USE_AS_STRNCPY + sub $14, %ebx + lea 14(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + + .p2align 4 +L(Exit15): + movlpd (%ecx), %xmm0 + movlpd 7(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 7(%edx) + SAVE_RESULT (14) +# ifdef USE_AS_STRNCPY + sub $15, %ebx + lea 15(%edx), %ecx + jnz L(StrncpyFillTailWithZero1) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN1 + +CFI_POP (%edi) + +# ifdef USE_AS_STRNCPY + .p2align 4 +L(Fill0): + RETURN + + .p2align 4 +L(Fill1): + movb %dl, (%ecx) + RETURN + + .p2align 4 +L(Fill2): + movw %dx, (%ecx) + RETURN + + .p2align 4 +L(Fill3): + movw %dx, (%ecx) + movb %dl, 2(%ecx) + RETURN + + .p2align 4 +L(Fill4): + movl %edx, (%ecx) + RETURN + + .p2align 4 +L(Fill5): + movl %edx, (%ecx) + movb %dl, 4(%ecx) + RETURN + + .p2align 4 +L(Fill6): + movl %edx, (%ecx) + movw %dx, 4(%ecx) + RETURN + + .p2align 4 +L(Fill7): + movl %edx, (%ecx) + movl %edx, 3(%ecx) + RETURN + + .p2align 4 +L(Fill8): + movlpd %xmm0, (%ecx) + RETURN + + .p2align 4 +L(Fill9): + movlpd %xmm0, (%ecx) + movb %dl, 8(%ecx) + RETURN + + .p2align 4 +L(Fill10): + movlpd %xmm0, (%ecx) + movw %dx, 8(%ecx) + RETURN + + .p2align 4 +L(Fill11): + movlpd %xmm0, (%ecx) + movl %edx, 7(%ecx) + RETURN + + .p2align 4 +L(Fill12): + movlpd %xmm0, (%ecx) + movl %edx, 8(%ecx) + RETURN + + .p2align 4 +L(Fill13): + movlpd %xmm0, (%ecx) + movlpd %xmm0, 5(%ecx) + RETURN + + .p2align 4 +L(Fill14): + movlpd %xmm0, (%ecx) + movlpd %xmm0, 6(%ecx) + RETURN + + .p2align 4 +L(Fill15): + movlpd %xmm0, (%ecx) + movlpd %xmm0, 7(%ecx) + RETURN + + .p2align 4 +L(Fill16): + movlpd %xmm0, (%ecx) + movlpd %xmm0, 8(%ecx) + RETURN + + .p2align 4 +L(StrncpyFillExit1): + lea 16(%ebx), %ebx +L(FillFrom1To16Bytes): + test %ebx, %ebx + jz L(Fill0) + cmp $16, %ebx + je L(Fill16) + cmp $8, %ebx + je L(Fill8) + jg L(FillMore8) + cmp $4, %ebx + je L(Fill4) + jg L(FillMore4) + cmp $2, %ebx + jl L(Fill1) + je L(Fill2) + jg L(Fill3) +L(FillMore8): /* but less than 16 */ + cmp $12, %ebx + je L(Fill12) + jl L(FillLess12) + cmp $14, %ebx + jl L(Fill13) + je L(Fill14) + jg L(Fill15) +L(FillMore4): /* but less than 8 */ + cmp $6, %ebx + jl L(Fill5) + je L(Fill6) + jg L(Fill7) +L(FillLess12): /* but more than 8 */ + cmp $10, %ebx + jl L(Fill9) + je L(Fill10) + jmp L(Fill11) + + CFI_PUSH(%edi) + + .p2align 4 +L(StrncpyFillTailWithZero1): + POP (%edi) +L(StrncpyFillTailWithZero): + pxor %xmm0, %xmm0 + xor %edx, %edx + sub $16, %ebx + jbe L(StrncpyFillExit1) + + movlpd %xmm0, (%ecx) + movlpd %xmm0, 8(%ecx) + + lea 16(%ecx), %ecx + + mov %ecx, %edx + and $0xf, %edx + sub %edx, %ecx + add %edx, %ebx + xor %edx, %edx + sub $64, %ebx + jb L(StrncpyFillLess64) + +L(StrncpyFillLoopMovdqa): + movdqa %xmm0, (%ecx) + movdqa %xmm0, 16(%ecx) + movdqa %xmm0, 32(%ecx) + movdqa %xmm0, 48(%ecx) + lea 64(%ecx), %ecx + sub $64, %ebx + jae L(StrncpyFillLoopMovdqa) + +L(StrncpyFillLess64): + add $32, %ebx + jl L(StrncpyFillLess32) + movdqa %xmm0, (%ecx) + movdqa %xmm0, 16(%ecx) + lea 32(%ecx), %ecx + sub $16, %ebx + jl L(StrncpyFillExit1) + movdqa %xmm0, (%ecx) + lea 16(%ecx), %ecx + jmp L(FillFrom1To16Bytes) + +L(StrncpyFillLess32): + add $16, %ebx + jl L(StrncpyFillExit1) + movdqa %xmm0, (%ecx) + lea 16(%ecx), %ecx + jmp L(FillFrom1To16Bytes) +# endif + + .p2align 4 +L(ExitTail1): + movb (%ecx), %al + movb %al, (%edx) + SAVE_RESULT_TAIL (0) +# ifdef USE_AS_STRNCPY + sub $1, %ebx + lea 1(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail2): + movw (%ecx), %ax + movw %ax, (%edx) + SAVE_RESULT_TAIL (1) +# ifdef USE_AS_STRNCPY + sub $2, %ebx + lea 2(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + SAVE_RESULT_TAIL (2) +# ifdef USE_AS_STRNCPY + sub $3, %ebx + lea 3(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail4): + movl (%ecx), %eax + movl %eax, (%edx) + SAVE_RESULT_TAIL (3) +# ifdef USE_AS_STRNCPY + sub $4, %ebx + lea 4(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + SAVE_RESULT_TAIL (4) +# ifdef USE_AS_STRNCPY + sub $5, %ebx + lea 5(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + SAVE_RESULT_TAIL (5) +# ifdef USE_AS_STRNCPY + sub $6, %ebx + lea 6(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + SAVE_RESULT_TAIL (6) +# ifdef USE_AS_STRNCPY + sub $7, %ebx + lea 7(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + SAVE_RESULT_TAIL (7) +# ifdef USE_AS_STRNCPY + sub $8, %ebx + lea 8(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# endif + RETURN + + .p2align 4 +L(ExitTail9): + movlpd (%ecx), %xmm0 + movb 8(%ecx), %al + movlpd %xmm0, (%edx) + movb %al, 8(%edx) + SAVE_RESULT_TAIL (8) +# ifdef USE_AS_STRNCPY + sub $9, %ebx + lea 9(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail10): + movlpd (%ecx), %xmm0 + movw 8(%ecx), %ax + movlpd %xmm0, (%edx) + movw %ax, 8(%edx) + SAVE_RESULT_TAIL (9) +# ifdef USE_AS_STRNCPY + sub $10, %ebx + lea 10(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail11): + movlpd (%ecx), %xmm0 + movl 7(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 7(%edx) + SAVE_RESULT_TAIL (10) +# ifdef USE_AS_STRNCPY + sub $11, %ebx + lea 11(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail12): + movlpd (%ecx), %xmm0 + movl 8(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 8(%edx) + SAVE_RESULT_TAIL (11) +# ifdef USE_AS_STRNCPY + sub $12, %ebx + lea 12(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail13): + movlpd (%ecx), %xmm0 + movlpd 5(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 5(%edx) + SAVE_RESULT_TAIL (12) +# ifdef USE_AS_STRNCPY + sub $13, %ebx + lea 13(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail14): + movlpd (%ecx), %xmm0 + movlpd 6(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 6(%edx) + SAVE_RESULT_TAIL (13) +# ifdef USE_AS_STRNCPY + sub $14, %ebx + lea 14(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN + + .p2align 4 +L(ExitTail15): + movlpd (%ecx), %xmm0 + movlpd 7(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 7(%edx) + SAVE_RESULT_TAIL (14) +# ifdef USE_AS_STRNCPY + sub $15, %ebx + lea 15(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# endif + RETURN + + .p2align 4 +L(ExitTail16): + movdqu (%ecx), %xmm0 + movdqu %xmm0, (%edx) + SAVE_RESULT_TAIL (15) +# ifdef USE_AS_STRNCPY + sub $16, %ebx + lea 16(%edx), %ecx + jnz L(StrncpyFillTailWithZero) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif +# endif + RETURN +#endif + +#ifdef USE_AS_STRNCPY +# if !defined(USE_AS_STRCAT) && !defined(USE_AS_STRLCPY) + CFI_PUSH (%esi) + CFI_PUSH (%edi) +# endif + .p2align 4 +L(StrncpyLeaveCase2OrCase3): + test %eax, %eax + jnz L(Aligned64LeaveCase2) + +L(Aligned64LeaveCase3): + add $48, %ebx + jle L(CopyFrom1To16BytesCase3) + movaps %xmm4, -64(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase3) + movaps %xmm5, -48(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase3) + movaps %xmm6, -32(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx + jmp L(CopyFrom1To16BytesCase3) + +L(Aligned64LeaveCase2): + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %eax + add $48, %ebx + jle L(CopyFrom1To16BytesCase2OrCase3) + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqb %xmm5, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm4, -64(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqb %xmm6, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm5, -48(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqb %xmm7, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm6, -32(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx + jmp L(CopyFrom1To16BytesCase2) + +/*--------------------------------------------------*/ + .p2align 4 +L(StrncpyExit1Case2OrCase3): + movlpd (%ecx), %xmm0 + movlpd 7(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 7(%edx) + mov $15, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit2Case2OrCase3): + movlpd (%ecx), %xmm0 + movlpd 6(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 6(%edx) + mov $14, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit3Case2OrCase3): + movlpd (%ecx), %xmm0 + movlpd 5(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 5(%edx) + mov $13, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit4Case2OrCase3): + movlpd (%ecx), %xmm0 + movl 8(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 8(%edx) + mov $12, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit5Case2OrCase3): + movlpd (%ecx), %xmm0 + movl 7(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 7(%edx) + mov $11, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit6Case2OrCase3): + movlpd (%ecx), %xmm0 + movl 6(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 6(%edx) + mov $10, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit7Case2OrCase3): + movlpd (%ecx), %xmm0 + movl 5(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 5(%edx) + mov $9, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit8Case2OrCase3): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + mov $8, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit9Case2OrCase3): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + mov $7, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit10Case2OrCase3): + movlpd -1(%ecx), %xmm0 + movlpd %xmm0, -1(%edx) + mov $6, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit11Case2OrCase3): + movlpd -2(%ecx), %xmm0 + movlpd %xmm0, -2(%edx) + mov $5, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit12Case2OrCase3): + movl (%ecx), %esi + movl %esi, (%edx) + mov $4, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit13Case2OrCase3): + movl -1(%ecx), %esi + movl %esi, -1(%edx) + mov $3, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit14Case2OrCase3): + movl -2(%ecx), %esi + movl %esi, -2(%edx) + mov $2, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + + .p2align 4 +L(StrncpyExit15Case2OrCase3): + movl -3(%ecx), %esi + movl %esi, -3(%edx) + mov $1, %esi + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave1): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit1) + palignr $1, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 31(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit1) + palignr $1, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit1) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit1) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit1): + lea 15(%edx, %esi), %edx + lea 15(%ecx, %esi), %ecx + movdqu -16(%ecx), %xmm0 + xor %esi, %esi + movdqu %xmm0, -16(%edx) + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave2): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit2) + palignr $2, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 30(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit2) + palignr $2, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit2) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit2) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit2): + lea 14(%edx, %esi), %edx + lea 14(%ecx, %esi), %ecx + movdqu -16(%ecx), %xmm0 + xor %esi, %esi + movdqu %xmm0, -16(%edx) + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave3): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit3) + palignr $3, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 29(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit3) + palignr $3, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit3) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit3) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit3): + lea 13(%edx, %esi), %edx + lea 13(%ecx, %esi), %ecx + movdqu -16(%ecx), %xmm0 + xor %esi, %esi + movdqu %xmm0, -16(%edx) + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave4): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit4) + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit4) + palignr $4, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit4) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit4) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit4): + lea 12(%edx, %esi), %edx + lea 12(%ecx, %esi), %ecx + movlpd -12(%ecx), %xmm0 + movl -4(%ecx), %eax + movlpd %xmm0, -12(%edx) + movl %eax, -4(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave5): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit5) + palignr $5, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 27(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit5) + palignr $5, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit5) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit5) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit5): + lea 11(%edx, %esi), %edx + lea 11(%ecx, %esi), %ecx + movlpd -11(%ecx), %xmm0 + movl -4(%ecx), %eax + movlpd %xmm0, -11(%edx) + movl %eax, -4(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave6): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit6) + palignr $6, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 26(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit6) + palignr $6, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit6) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit6) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit6): + lea 10(%edx, %esi), %edx + lea 10(%ecx, %esi), %ecx + + movlpd -10(%ecx), %xmm0 + movw -2(%ecx), %ax + movlpd %xmm0, -10(%edx) + movw %ax, -2(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave7): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit7) + palignr $7, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 25(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit7) + palignr $7, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit7) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit7) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit7): + lea 9(%edx, %esi), %edx + lea 9(%ecx, %esi), %ecx + + movlpd -9(%ecx), %xmm0 + movb -1(%ecx), %ah + movlpd %xmm0, -9(%edx) + movb %ah, -1(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave8): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit8) + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit8) + palignr $8, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit8) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit8) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit8): + lea 8(%edx, %esi), %edx + lea 8(%ecx, %esi), %ecx + movlpd -8(%ecx), %xmm0 + movlpd %xmm0, -8(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave9): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit9) + palignr $9, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 23(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit9) + palignr $9, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit9) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit9) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit9): + lea 7(%edx, %esi), %edx + lea 7(%ecx, %esi), %ecx + + movlpd -8(%ecx), %xmm0 + movlpd %xmm0, -8(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave10): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit10) + palignr $10, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 22(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit10) + palignr $10, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit10) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit10) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit10): + lea 6(%edx, %esi), %edx + lea 6(%ecx, %esi), %ecx + + movlpd -8(%ecx), %xmm0 + movlpd %xmm0, -8(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave11): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit11) + palignr $11, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 21(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit11) + palignr $11, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit11) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit11) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit11): + lea 5(%edx, %esi), %edx + lea 5(%ecx, %esi), %ecx + movl -5(%ecx), %esi + movb -1(%ecx), %ah + movl %esi, -5(%edx) + movb %ah, -1(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave12): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit12) + palignr $12, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit12) + palignr $12, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit12) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit12) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit12): + lea 4(%edx, %esi), %edx + lea 4(%ecx, %esi), %ecx + movl -4(%ecx), %eax + movl %eax, -4(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave13): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit13) + palignr $13, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 19(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit13) + palignr $13, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit13) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit13) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit13): + lea 3(%edx, %esi), %edx + lea 3(%ecx, %esi), %ecx + + movl -4(%ecx), %eax + movl %eax, -4(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave14): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit14) + palignr $14, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 18(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit14) + palignr $14, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit14) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit14) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit14): + lea 2(%edx, %esi), %edx + lea 2(%ecx, %esi), %ecx + movw -2(%ecx), %ax + movw %ax, -2(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) + +L(StrncpyLeave15): + movaps %xmm2, %xmm3 + add $48, %ebx + jle L(StrncpyExit15) + palignr $15, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 17(%ecx), %xmm2 + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit15) + palignr $15, %xmm3, %xmm2 + movaps %xmm2, 16(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit15) + movaps %xmm4, 32(%edx) + lea 16(%esi), %esi + sub $16, %ebx + jbe L(StrncpyExit15) + movaps %xmm5, 48(%edx) + lea 16(%esi), %esi + lea -16(%ebx), %ebx +L(StrncpyExit15): + lea 1(%edx, %esi), %edx + lea 1(%ecx, %esi), %ecx + movb -1(%ecx), %ah + movb %ah, -1(%edx) + xor %esi, %esi + jmp L(CopyFrom1To16BytesCase3) +#endif + +#if !defined USE_AS_STRCAT && ! defined USE_AS_STRLCPY +# ifdef USE_AS_STRNCPY + CFI_POP (%esi) + CFI_POP (%edi) + + .p2align 4 +L(ExitTail0): + movl %edx, %eax + RETURN + + .p2align 4 +L(StrncpyExit15Bytes): + cmp $12, %ebx + jbe L(StrncpyExit12Bytes) + cmpb $0, 8(%ecx) + jz L(ExitTail9) + cmpb $0, 9(%ecx) + jz L(ExitTail10) + cmpb $0, 10(%ecx) + jz L(ExitTail11) + cmpb $0, 11(%ecx) + jz L(ExitTail12) + cmp $13, %ebx + je L(ExitTail13) + cmpb $0, 12(%ecx) + jz L(ExitTail13) + cmp $14, %ebx + je L(ExitTail14) + cmpb $0, 13(%ecx) + jz L(ExitTail14) + movlpd (%ecx), %xmm0 + movlpd 7(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 7(%edx) +# ifdef USE_AS_STPCPY + lea 14(%edx), %eax + cmpb $1, (%eax) + sbb $-1, %eax +# else + movl %edx, %eax +# endif + RETURN + + .p2align 4 +L(StrncpyExit12Bytes): + cmp $9, %ebx + je L(ExitTail9) + cmpb $0, 8(%ecx) + jz L(ExitTail9) + cmp $10, %ebx + je L(ExitTail10) + cmpb $0, 9(%ecx) + jz L(ExitTail10) + cmp $11, %ebx + je L(ExitTail11) + cmpb $0, 10(%ecx) + jz L(ExitTail11) + movlpd (%ecx), %xmm0 + movl 8(%ecx), %eax + movlpd %xmm0, (%edx) + movl %eax, 8(%edx) + SAVE_RESULT_TAIL (11) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif + RETURN + + .p2align 4 +L(StrncpyExit8Bytes): + cmp $4, %ebx + jbe L(StrncpyExit4Bytes) + cmpb $0, (%ecx) + jz L(ExitTail1) + cmpb $0, 1(%ecx) + jz L(ExitTail2) + cmpb $0, 2(%ecx) + jz L(ExitTail3) + cmpb $0, 3(%ecx) + jz L(ExitTail4) + + cmp $5, %ebx + je L(ExitTail5) + cmpb $0, 4(%ecx) + jz L(ExitTail5) + cmp $6, %ebx + je L(ExitTail6) + cmpb $0, 5(%ecx) + jz L(ExitTail6) + cmp $7, %ebx + je L(ExitTail7) + cmpb $0, 6(%ecx) + jz L(ExitTail7) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) +# ifdef USE_AS_STPCPY + lea 7(%edx), %eax + cmpb $1, (%eax) + sbb $-1, %eax +# else + movl %edx, %eax +# endif + RETURN + + .p2align 4 +L(StrncpyExit4Bytes): + test %ebx, %ebx + jz L(ExitTail0) + cmp $1, %ebx + je L(ExitTail1) + cmpb $0, (%ecx) + jz L(ExitTail1) + cmp $2, %ebx + je L(ExitTail2) + cmpb $0, 1(%ecx) + jz L(ExitTail2) + cmp $3, %ebx + je L(ExitTail3) + cmpb $0, 2(%ecx) + jz L(ExitTail3) + movl (%ecx), %eax + movl %eax, (%edx) + SAVE_RESULT_TAIL (3) +# ifdef USE_AS_STPCPY + cmpb $1, (%eax) + sbb $-1, %eax +# endif + RETURN +# endif + +END (STRCPY) +#endif diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcat-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcat-atom.S new file mode 100644 index 000000000..055b48909 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcat-atom.S @@ -0,0 +1,1225 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +/* Optimized strlcat with SSSE3 */ + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) +#define L(label) .L##Prolog_##label + +#define DST 4 +#define SRC DST+8 +#define LEN SRC+4 + + .text +ENTRY (strlcat_ssse3) + mov DST(%esp), %edx + PUSH (%ebx) + mov LEN(%esp), %ebx + sub $4, %ebx + jbe L(len_less4_prolog) + +#define RETURN jmp L(StrcpyStep) +#define edi ebx + +#define USE_AS_STRNLEN +#define USE_AS_STRCAT +#define USE_AS_STRLCAT + +#include "sse2-strlen-atom.S" + + .p2align 4 +L(StrcpyStep): + +#undef edi +#undef L +#define L(label) .L##label +#undef RETURN +#define RETURN POP (%ebx); ret; CFI_PUSH (%ebx); +#define RETURN1 POP (%edi); POP (%ebx); ret; CFI_PUSH (%ebx); CFI_PUSH (%edi) + + movl SRC(%esp), %ecx + movl LEN(%esp), %ebx + + cmp %eax, %ebx + je L(CalculateLengthOfSrcProlog) + sub %eax, %ebx + + test %ebx, %ebx + jz L(CalculateLengthOfSrcProlog) + + mov DST + 4(%esp), %edx + + PUSH (%edi) + add %eax, %edx + mov %ecx, %edi + sub %eax, %edi + + cmp $8, %ebx + jbe L(StrncpyExit8Bytes) + + cmpb $0, (%ecx) + jz L(Exit1) + cmpb $0, 1(%ecx) + jz L(Exit2) + cmpb $0, 2(%ecx) + jz L(Exit3) + cmpb $0, 3(%ecx) + jz L(Exit4) + cmpb $0, 4(%ecx) + jz L(Exit5) + cmpb $0, 5(%ecx) + jz L(Exit6) + cmpb $0, 6(%ecx) + jz L(Exit7) + cmpb $0, 7(%ecx) + jz L(Exit8) + cmp $16, %ebx + jb L(StrncpyExit15Bytes) + cmpb $0, 8(%ecx) + jz L(Exit9) + cmpb $0, 9(%ecx) + jz L(Exit10) + cmpb $0, 10(%ecx) + jz L(Exit11) + cmpb $0, 11(%ecx) + jz L(Exit12) + cmpb $0, 12(%ecx) + jz L(Exit13) + cmpb $0, 13(%ecx) + jz L(Exit14) + cmpb $0, 14(%ecx) + jz L(Exit15) + cmpb $0, 15(%ecx) + jz L(Exit16) + cmp $16, %ebx + je L(StrlcpyExit16) + +#define USE_AS_STRNCPY +#include "ssse3-strcpy-atom.S" + + .p2align 4 +L(CopyFrom1To16Bytes): + add %esi, %edx + add %esi, %ecx + + POP (%esi) + test %al, %al + jz L(ExitHigh8) + +L(CopyFrom1To16BytesLess8): + mov %al, %ah + and $15, %ah + jz L(ExitHigh4) + + test $0x01, %al + jnz L(Exit1) + test $0x02, %al + jnz L(Exit2) + test $0x04, %al + jnz L(Exit3) +L(Exit4): + movl (%ecx), %eax + movl %eax, (%edx) + + lea 3(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh4): + test $0x10, %al + jnz L(Exit5) + test $0x20, %al + jnz L(Exit6) + test $0x40, %al + jnz L(Exit7) +L(Exit8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + lea 7(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh8): + mov %ah, %al + and $15, %al + jz L(ExitHigh12) + + test $0x01, %ah + jnz L(Exit9) + test $0x02, %ah + jnz L(Exit10) + test $0x04, %ah + jnz L(Exit11) +L(Exit12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + lea 11(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh12): + test $0x10, %ah + jnz L(Exit13) + test $0x20, %ah + jnz L(Exit14) + test $0x40, %ah + jnz L(Exit15) +L(Exit16): + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + + lea 15(%ecx), %eax + sub %edi, %eax + RETURN1 + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %ebx + add %esi, %ecx + add %esi, %edx + + POP (%esi) + + test %al, %al + jz L(ExitHighCase2) + + cmp $8, %ebx + ja L(CopyFrom1To16BytesLess8) + + test $0x01, %al + jnz L(Exit1) + cmp $1, %ebx + je L(StrlcpyExit1) + test $0x02, %al + jnz L(Exit2) + cmp $2, %ebx + je L(StrlcpyExit2) + test $0x04, %al + jnz L(Exit3) + cmp $3, %ebx + je L(StrlcpyExit3) + test $0x08, %al + jnz L(Exit4) + cmp $4, %ebx + je L(StrlcpyExit4) + test $0x10, %al + jnz L(Exit5) + cmp $5, %ebx + je L(StrlcpyExit5) + test $0x20, %al + jnz L(Exit6) + cmp $6, %ebx + je L(StrlcpyExit6) + test $0x40, %al + jnz L(Exit7) + cmp $7, %ebx + je L(StrlcpyExit7) + test $0x80, %al + jnz L(Exit8) + jmp L(StrlcpyExit8) + + .p2align 4 +L(ExitHighCase2): + cmp $8, %ebx + jbe L(CopyFrom1To16BytesLess8Case3) + + test $0x01, %ah + jnz L(Exit9) + cmp $9, %ebx + je L(StrlcpyExit9) + test $0x02, %ah + jnz L(Exit10) + cmp $10, %ebx + je L(StrlcpyExit10) + test $0x04, %ah + jnz L(Exit11) + cmp $11, %ebx + je L(StrlcpyExit11) + test $0x8, %ah + jnz L(Exit12) + cmp $12, %ebx + je L(StrlcpyExit12) + test $0x10, %ah + jnz L(Exit13) + cmp $13, %ebx + je L(StrlcpyExit13) + test $0x20, %ah + jnz L(Exit14) + cmp $14, %ebx + je L(StrlcpyExit14) + test $0x40, %ah + jnz L(Exit15) + cmp $15, %ebx + je L(StrlcpyExit15) + test $0x80, %ah + jnz L(Exit16) + jmp L(StrlcpyExit16) + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2OrCase3): + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + + .p2align 4 +L(CopyFrom1To16BytesCase3): + add $16, %ebx + add %esi, %edx + add %esi, %ecx + + POP (%esi) + + cmp $8, %ebx + ja L(ExitHigh8Case3) + +L(CopyFrom1To16BytesLess8Case3): + cmp $4, %ebx + ja L(ExitHigh4Case3) + + cmp $1, %ebx + je L(StrlcpyExit1) + cmp $2, %ebx + je L(StrlcpyExit2) + cmp $3, %ebx + je L(StrlcpyExit3) +L(StrlcpyExit4): + movb %bh, 3(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + lea 4(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh4Case3): + cmp $5, %ebx + je L(StrlcpyExit5) + cmp $6, %ebx + je L(StrlcpyExit6) + cmp $7, %ebx + je L(StrlcpyExit7) +L(StrlcpyExit8): + movb %bh, 7(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + lea 8(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh8Case3): + cmp $12, %ebx + ja L(ExitHigh12Case3) + + cmp $9, %ebx + je L(StrlcpyExit9) + cmp $10, %ebx + je L(StrlcpyExit10) + cmp $11, %ebx + je L(StrlcpyExit11) +L(StrlcpyExit12): + movb %bh, 11(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + lea 12(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh12Case3): + cmp $13, %ebx + je L(StrlcpyExit13) + cmp $14, %ebx + je L(StrlcpyExit14) + cmp $15, %ebx + je L(StrlcpyExit15) +L(StrlcpyExit16): + movb %bh, 15(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + lea 16(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(StrlcpyExit1): + movb %bh, (%edx) + + lea 1(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit1): + movb (%ecx), %al + movb %al, (%edx) + + mov %ecx, %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit2): + movb %bh, 1(%edx) + movb (%ecx), %al + movb %al, (%edx) + + lea 2(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit2): + movw (%ecx), %ax + movw %ax, (%edx) + movl %edi, %eax + + lea 1(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit3): + movb %bh, 2(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + + lea 3(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + lea 2(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit5): + movb %bh, 4(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl %edi, %eax + + lea 5(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + lea 4(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit6): + movb %bh, 5(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + lea 6(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + lea 5(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit7): + movb %bh, 6(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + lea 7(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + lea 6(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit9): + movb %bh, 8(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + lea 9(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit9): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + lea 8(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit10): + movb %bh, 9(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + lea 10(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit10): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + lea 9(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit11): + movb %bh, 10(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + lea 11(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit11): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + lea 10(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit13): + movb %bh, 12(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + lea 13(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit13): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + lea 12(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit14): + movb %bh, 13(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + lea 14(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit14): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + lea 13(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit15): + movb %bh, 14(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + lea 15(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit15): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + lea 14(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrncpyExit15Bytes): + cmp $12, %ebx + ja L(StrncpyExit15Bytes1) + + cmpb $0, 8(%ecx) + jz L(Exit9) + cmp $9, %ebx + je L(StrlcpyExit9) + + cmpb $0, 9(%ecx) + jz L(Exit10) + cmp $10, %ebx + je L(StrlcpyExit10) + + cmpb $0, 10(%ecx) + jz L(Exit11) + cmp $11, %ebx + je L(StrlcpyExit11) + + cmpb $0, 11(%ecx) + jz L(Exit12) + jmp L(StrlcpyExit12) + + .p2align 4 +L(StrncpyExit15Bytes1): + cmpb $0, 8(%ecx) + jz L(Exit9) + cmpb $0, 9(%ecx) + jz L(Exit10) + cmpb $0, 10(%ecx) + jz L(Exit11) + cmpb $0, 11(%ecx) + jz L(Exit12) + + cmpb $0, 12(%ecx) + jz L(Exit13) + cmp $13, %ebx + je L(StrlcpyExit13) + + cmpb $0, 13(%ecx) + jz L(Exit14) + cmp $14, %ebx + je L(StrlcpyExit14) + + cmpb $0, 14(%ecx) + jz L(Exit15) + jmp L(StrlcpyExit15) + + .p2align 4 +L(StrncpyExit8Bytes): + cmp $4, %ebx + ja L(StrncpyExit8Bytes1) + + cmpb $0, (%ecx) + jz L(Exit1) + cmp $1, %ebx + je L(StrlcpyExit1) + + cmpb $0, 1(%ecx) + jz L(Exit2) + cmp $2, %ebx + je L(StrlcpyExit2) + + cmpb $0, 2(%ecx) + jz L(Exit3) + cmp $3, %ebx + je L(StrlcpyExit3) + + cmpb $0, 3(%ecx) + jz L(Exit4) + jmp L(StrlcpyExit4) + + .p2align 4 +L(StrncpyExit8Bytes1): + cmpb $0, (%ecx) + jz L(Exit1) + cmpb $0, 1(%ecx) + jz L(Exit2) + cmpb $0, 2(%ecx) + jz L(Exit3) + cmpb $0, 3(%ecx) + jz L(Exit4) + + cmpb $0, 4(%ecx) + jz L(Exit5) + cmp $5, %ebx + je L(StrlcpyExit5) + + cmpb $0, 5(%ecx) + jz L(Exit6) + cmp $6, %ebx + je L(StrlcpyExit6) + + cmpb $0, 6(%ecx) + jz L(Exit7) + cmp $7, %ebx + je L(StrlcpyExit7) + + cmpb $0, 7(%ecx) + jz L(Exit8) + jmp L(StrlcpyExit8) + + CFI_POP (%edi) + + + .p2align 4 +L(Prolog_return_start_len): + movl LEN(%esp), %ebx + movl SRC(%esp), %ecx +L(CalculateLengthOfSrcProlog): + mov %ecx, %edx + sub %ebx, %ecx + + .p2align 4 +L(CalculateLengthOfSrc): + cmpb $0, (%edx) + jz L(exit_tail0) + cmpb $0, 1(%edx) + jz L(exit_tail1) + cmpb $0, 2(%edx) + jz L(exit_tail2) + cmpb $0, 3(%edx) + jz L(exit_tail3) + + cmpb $0, 4(%edx) + jz L(exit_tail4) + cmpb $0, 5(%edx) + jz L(exit_tail5) + cmpb $0, 6(%edx) + jz L(exit_tail6) + cmpb $0, 7(%edx) + jz L(exit_tail7) + + cmpb $0, 8(%edx) + jz L(exit_tail8) + cmpb $0, 9(%edx) + jz L(exit_tail9) + cmpb $0, 10(%edx) + jz L(exit_tail10) + cmpb $0, 11(%edx) + jz L(exit_tail11) + + cmpb $0, 12(%edx) + jz L(exit_tail12) + cmpb $0, 13(%edx) + jz L(exit_tail13) + cmpb $0, 14(%edx) + jz L(exit_tail14) + cmpb $0, 15(%edx) + jz L(exit_tail15) + + pxor %xmm0, %xmm0 + lea 16(%edx), %eax + add $16, %ecx + and $-16, %eax + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + pxor %xmm2, %xmm2 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + pxor %xmm3, %xmm3 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + and $-0x40, %eax + + .p2align 4 +L(aligned_64_loop): + movaps (%eax), %xmm0 + movaps 16(%eax), %xmm1 + movaps 32(%eax), %xmm2 + movaps 48(%eax), %xmm6 + pminub %xmm1, %xmm0 + pminub %xmm6, %xmm2 + pminub %xmm0, %xmm2 + pcmpeqb %xmm3, %xmm2 + pmovmskb %xmm2, %edx + lea 64(%eax), %eax + test %edx, %edx + jz L(aligned_64_loop) + + pcmpeqb -64(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 48(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb -32(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm6, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + + .p2align 4 +L(exit): + sub %ecx, %eax + test %dl, %dl + jz L(exit_more_8) + + mov %dl, %cl + and $15, %cl + jz L(exit_more_4) + test $0x01, %dl + jnz L(exit_0) + test $0x02, %dl + jnz L(exit_1) + test $0x04, %dl + jnz L(exit_2) + add $3, %eax + RETURN + + .p2align 4 +L(exit_more_4): + test $0x10, %dl + jnz L(exit_4) + test $0x20, %dl + jnz L(exit_5) + test $0x40, %dl + jnz L(exit_6) + add $7, %eax + RETURN + + .p2align 4 +L(exit_more_8): + mov %dh, %ch + and $15, %ch + jz L(exit_more_12) + test $0x01, %dh + jnz L(exit_8) + test $0x02, %dh + jnz L(exit_9) + test $0x04, %dh + jnz L(exit_10) + add $11, %eax + RETURN + + .p2align 4 +L(exit_more_12): + test $0x10, %dh + jnz L(exit_12) + test $0x20, %dh + jnz L(exit_13) + test $0x40, %dh + jnz L(exit_14) + add $15, %eax +L(exit_0): + RETURN + + .p2align 4 +L(exit_1): + add $1, %eax + RETURN + +L(exit_2): + add $2, %eax + RETURN + +L(exit_3): + add $3, %eax + RETURN + +L(exit_4): + add $4, %eax + RETURN + +L(exit_5): + add $5, %eax + RETURN + +L(exit_6): + add $6, %eax + RETURN + +L(exit_7): + add $7, %eax + RETURN + +L(exit_8): + add $8, %eax + RETURN + +L(exit_9): + add $9, %eax + RETURN + +L(exit_10): + add $10, %eax + RETURN + +L(exit_11): + add $11, %eax + RETURN + +L(exit_12): + add $12, %eax + RETURN + +L(exit_13): + add $13, %eax + RETURN + +L(exit_14): + add $14, %eax + RETURN + +L(exit_15): + add $15, %eax + RETURN + +L(exit_tail0): + mov %edx, %eax + sub %ecx, %eax + RETURN + + .p2align 4 +L(exit_tail1): + lea 1(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail2): + lea 2(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail3): + lea 3(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail4): + lea 4(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail5): + lea 5(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail6): + lea 6(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail7): + lea 7(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail8): + lea 8(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail9): + lea 9(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail10): + lea 10(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail11): + lea 11(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail12): + lea 12(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail13): + lea 13(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail14): + lea 14(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail15): + lea 15(%edx), %eax + sub %ecx, %eax + RETURN + +END (strlcat) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S new file mode 100644 index 000000000..1671da6b6 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strlcpy-atom.S @@ -0,0 +1,1403 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define STRCPY strlcpy_ssse3 +#define STRLEN strlcpy_ssse3 +#define USE_AS_STRLCPY +#include "ssse3-strcpy-atom.S" + + .p2align 4 +L(CopyFrom1To16Bytes): + add %esi, %edx + add %esi, %ecx + + POP (%esi) + test %al, %al + jz L(ExitHigh8) + +L(CopyFrom1To16BytesLess8): + mov %al, %ah + and $15, %ah + jz L(ExitHigh4) + + test $0x01, %al + jnz L(Exit1) + test $0x02, %al + jnz L(Exit2) + test $0x04, %al + jnz L(Exit3) +L(Exit4): + movl (%ecx), %eax + movl %eax, (%edx) + + lea 3(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh4): + test $0x10, %al + jnz L(Exit5) + test $0x20, %al + jnz L(Exit6) + test $0x40, %al + jnz L(Exit7) +L(Exit8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + lea 7(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh8): + mov %ah, %al + and $15, %al + jz L(ExitHigh12) + + test $0x01, %ah + jnz L(Exit9) + test $0x02, %ah + jnz L(Exit10) + test $0x04, %ah + jnz L(Exit11) +L(Exit12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + lea 11(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(ExitHigh12): + test $0x10, %ah + jnz L(Exit13) + test $0x20, %ah + jnz L(Exit14) + test $0x40, %ah + jnz L(Exit15) +L(Exit16): + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + + lea 15(%ecx), %eax + sub %edi, %eax + RETURN1 + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %ebx + add %esi, %ecx + add %esi, %edx + + POP (%esi) + + test %al, %al + jz L(ExitHighCase2) + + cmp $8, %ebx + ja L(CopyFrom1To16BytesLess8) + + test $0x01, %al + jnz L(Exit1) + cmp $1, %ebx + je L(StrlcpyExit1) + test $0x02, %al + jnz L(Exit2) + cmp $2, %ebx + je L(StrlcpyExit2) + test $0x04, %al + jnz L(Exit3) + cmp $3, %ebx + je L(StrlcpyExit3) + test $0x08, %al + jnz L(Exit4) + cmp $4, %ebx + je L(StrlcpyExit4) + test $0x10, %al + jnz L(Exit5) + cmp $5, %ebx + je L(StrlcpyExit5) + test $0x20, %al + jnz L(Exit6) + cmp $6, %ebx + je L(StrlcpyExit6) + test $0x40, %al + jnz L(Exit7) + cmp $7, %ebx + je L(StrlcpyExit7) + test $0x80, %al + jnz L(Exit8) + jmp L(StrlcpyExit8) + + .p2align 4 +L(ExitHighCase2): + cmp $8, %ebx + jbe L(CopyFrom1To16BytesLess8Case3) + + test $0x01, %ah + jnz L(Exit9) + cmp $9, %ebx + je L(StrlcpyExit9) + test $0x02, %ah + jnz L(Exit10) + cmp $10, %ebx + je L(StrlcpyExit10) + test $0x04, %ah + jnz L(Exit11) + cmp $11, %ebx + je L(StrlcpyExit11) + test $0x8, %ah + jnz L(Exit12) + cmp $12, %ebx + je L(StrlcpyExit12) + test $0x10, %ah + jnz L(Exit13) + cmp $13, %ebx + je L(StrlcpyExit13) + test $0x20, %ah + jnz L(Exit14) + cmp $14, %ebx + je L(StrlcpyExit14) + test $0x40, %ah + jnz L(Exit15) + cmp $15, %ebx + je L(StrlcpyExit15) + test $0x80, %ah + jnz L(Exit16) + jmp L(StrlcpyExit16) + + CFI_PUSH(%esi) + + .p2align 4 +L(CopyFrom1To16BytesCase2OrCase3): + test %eax, %eax + jnz L(CopyFrom1To16BytesCase2) + + .p2align 4 +L(CopyFrom1To16BytesCase3): + add $16, %ebx + add %esi, %edx + add %esi, %ecx + + POP (%esi) + + cmp $8, %ebx + ja L(ExitHigh8Case3) + +L(CopyFrom1To16BytesLess8Case3): + cmp $4, %ebx + ja L(ExitHigh4Case3) + + cmp $1, %ebx + je L(StrlcpyExit1) + cmp $2, %ebx + je L(StrlcpyExit2) + cmp $3, %ebx + je L(StrlcpyExit3) +L(StrlcpyExit4): + movb %bh, 3(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + lea 4(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh4Case3): + cmp $5, %ebx + je L(StrlcpyExit5) + cmp $6, %ebx + je L(StrlcpyExit6) + cmp $7, %ebx + je L(StrlcpyExit7) +L(StrlcpyExit8): + movb %bh, 7(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + lea 8(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh8Case3): + cmp $12, %ebx + ja L(ExitHigh12Case3) + + cmp $9, %ebx + je L(StrlcpyExit9) + cmp $10, %ebx + je L(StrlcpyExit10) + cmp $11, %ebx + je L(StrlcpyExit11) +L(StrlcpyExit12): + movb %bh, 11(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + lea 12(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(ExitHigh12Case3): + cmp $13, %ebx + je L(StrlcpyExit13) + cmp $14, %ebx + je L(StrlcpyExit14) + cmp $15, %ebx + je L(StrlcpyExit15) +L(StrlcpyExit16): + movb %bh, 15(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + lea 16(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(StrlcpyExit1): + movb %bh, (%edx) + + lea 1(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit1): + movb (%ecx), %al + movb %al, (%edx) + + mov %ecx, %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit2): + movb %bh, 1(%edx) + movb (%ecx), %al + movb %al, (%edx) + + lea 2(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit2): + movw (%ecx), %ax + movw %ax, (%edx) + movl %edi, %eax + + lea 1(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit3): + movb %bh, 2(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + + lea 3(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + lea 2(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit5): + movb %bh, 4(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl %edi, %eax + + lea 5(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + lea 4(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit6): + movb %bh, 5(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + lea 6(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + lea 5(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit7): + movb %bh, 6(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + lea 7(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + lea 6(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit9): + movb %bh, 8(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + lea 9(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit9): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + lea 8(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit10): + movb %bh, 9(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + lea 10(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit10): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + lea 9(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit11): + movb %bh, 10(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + lea 11(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit11): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + lea 10(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit13): + movb %bh, 12(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + lea 13(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit13): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + lea 12(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit14): + movb %bh, 13(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + lea 14(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit14): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + lea 13(%ecx), %eax + sub %edi, %eax + RETURN1 + + .p2align 4 +L(StrlcpyExit15): + movb %bh, 14(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + lea 15(%ecx), %edx + mov %edi, %ecx + POP (%edi) + jmp L(CalculateLengthOfSrc) + CFI_PUSH (%edi) + + .p2align 4 +L(Exit15): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + lea 14(%ecx), %eax + sub %edi, %eax + RETURN1 + + CFI_POP (%edi) + + .p2align 4 +L(StrlcpyExit0): + movl $0, %eax + RETURN + + .p2align 4 +L(StrncpyExit15Bytes): + cmp $12, %ebx + ja L(StrncpyExit15Bytes1) + + cmpb $0, 8(%ecx) + jz L(ExitTail9) + cmp $9, %ebx + je L(StrlcpyExitTail9) + + cmpb $0, 9(%ecx) + jz L(ExitTail10) + cmp $10, %ebx + je L(StrlcpyExitTail10) + + cmpb $0, 10(%ecx) + jz L(ExitTail11) + cmp $11, %ebx + je L(StrlcpyExitTail11) + + cmpb $0, 11(%ecx) + jz L(ExitTail12) + + movb %bh, 11(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + lea 12(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(StrncpyExit15Bytes1): + cmpb $0, 8(%ecx) + jz L(ExitTail9) + cmpb $0, 9(%ecx) + jz L(ExitTail10) + cmpb $0, 10(%ecx) + jz L(ExitTail11) + cmpb $0, 11(%ecx) + jz L(ExitTail12) + + cmpb $0, 12(%ecx) + jz L(ExitTail13) + cmp $13, %ebx + je L(StrlcpyExitTail13) + + cmpb $0, 13(%ecx) + jz L(ExitTail14) + cmp $14, %ebx + je L(StrlcpyExitTail14) + + cmpb $0, 14(%ecx) + jz L(ExitTail15) + + movb %bh, 14(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + lea 15(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(StrncpyExit8Bytes): + cmp $4, %ebx + ja L(StrncpyExit8Bytes1) + + test %ebx, %ebx + jz L(StrlcpyExitTail0) + + cmpb $0, (%ecx) + jz L(ExitTail1) + cmp $1, %ebx + je L(StrlcpyExitTail1) + + cmpb $0, 1(%ecx) + jz L(ExitTail2) + cmp $2, %ebx + je L(StrlcpyExitTail2) + + cmpb $0, 2(%ecx) + jz L(ExitTail3) + cmp $3, %ebx + je L(StrlcpyExitTail3) + + cmpb $0, 3(%ecx) + jz L(ExitTail4) + + movb %bh, 3(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + lea 4(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(StrncpyExit8Bytes1): + cmpb $0, (%ecx) + jz L(ExitTail1) + cmpb $0, 1(%ecx) + jz L(ExitTail2) + cmpb $0, 2(%ecx) + jz L(ExitTail3) + cmpb $0, 3(%ecx) + jz L(ExitTail4) + + cmpb $0, 4(%ecx) + jz L(ExitTail5) + cmp $5, %ebx + je L(StrlcpyExitTail5) + + cmpb $0, 5(%ecx) + jz L(ExitTail6) + cmp $6, %ebx + je L(StrlcpyExitTail6) + + cmpb $0, 6(%ecx) + jz L(ExitTail7) + cmp $7, %ebx + je L(StrlcpyExitTail7) + + cmpb $0, 7(%ecx) + jz L(ExitTail8) + + movb %bh, 7(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + lea 8(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(StrlcpyExitTail0): + mov %ecx, %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(StrlcpyExitTail1): + movb %bh, (%edx) + + lea 1(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail1): + movb (%ecx), %al + movb %al, (%edx) + + mov $0, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail2): + movb %bh, 1(%edx) + movb (%ecx), %al + movb %al, (%edx) + + lea 2(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail2): + movw (%ecx), %ax + movw %ax, (%edx) + movl %edx, %eax + + mov $1, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail3): + movb %bh, 2(%edx) + movw (%ecx), %ax + movw %ax, (%edx) + + lea 3(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail3): + movw (%ecx), %ax + movw %ax, (%edx) + movb 2(%ecx), %al + movb %al, 2(%edx) + + mov $2, %eax + RETURN + + .p2align 4 +L(ExitTail4): + movl (%ecx), %eax + movl %eax, (%edx) + + mov $3, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail5): + movb %bh, 4(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movl %edx, %eax + + lea 5(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail5): + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + mov $4, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail6): + movb %bh, 5(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movb 4(%ecx), %al + movb %al, 4(%edx) + + lea 6(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail6): + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + mov $5, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail7): + movb %bh, 6(%edx) + movl (%ecx), %eax + movl %eax, (%edx) + movw 4(%ecx), %ax + movw %ax, 4(%edx) + + lea 7(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail7): + movl (%ecx), %eax + movl %eax, (%edx) + movl 3(%ecx), %eax + movl %eax, 3(%edx) + + mov $6, %eax + RETURN + + .p2align 4 +L(ExitTail8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + mov $7, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail9): + movb %bh, 8(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + + lea 9(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail9): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + mov $8, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail10): + movb %bh, 9(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movb 8(%ecx), %al + movb %al, 8(%edx) + + lea 10(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail10): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + mov $9, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail11): + movb %bh, 10(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movw 8(%ecx), %ax + movw %ax, 8(%edx) + + lea 11(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail11): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 7(%ecx), %eax + movl %eax, 7(%edx) + + mov $10, %eax + RETURN + + .p2align 4 +L(ExitTail12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + mov $11, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail13): + movb %bh, 12(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + + lea 13(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail13): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + mov $12, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail14): + movb %bh, 13(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 5(%ecx), %xmm0 + movlpd %xmm0, 5(%edx) + + lea 14(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail14): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 6(%ecx), %xmm0 + movlpd %xmm0, 6(%edx) + + mov $13, %eax + RETURN + + .p2align 4 +L(ExitTail15): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + mov $14, %eax + RETURN + + .p2align 4 +L(StrlcpyExitTail16): + movb %bh, 15(%edx) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movlpd 7(%ecx), %xmm0 + movlpd %xmm0, 7(%edx) + + lea 16(%ecx), %edx + jmp L(CalculateLengthOfSrc) + + .p2align 4 +L(ExitTail16): + movlpd (%ecx), %xmm0 + movlpd 8(%ecx), %xmm1 + movlpd %xmm0, (%edx) + movlpd %xmm1, 8(%edx) + + mov $15, %eax + RETURN + + .p2align 4 +L(CalculateLengthOfSrc): + xor %eax, %eax + cmpb $0, (%edx) + jz L(exit_tail0) + cmpb $0, 1(%edx) + jz L(exit_tail1) + cmpb $0, 2(%edx) + jz L(exit_tail2) + cmpb $0, 3(%edx) + jz L(exit_tail3) + + cmpb $0, 4(%edx) + jz L(exit_tail4) + cmpb $0, 5(%edx) + jz L(exit_tail5) + cmpb $0, 6(%edx) + jz L(exit_tail6) + cmpb $0, 7(%edx) + jz L(exit_tail7) + + cmpb $0, 8(%edx) + jz L(exit_tail8) + cmpb $0, 9(%edx) + jz L(exit_tail9) + cmpb $0, 10(%edx) + jz L(exit_tail10) + cmpb $0, 11(%edx) + jz L(exit_tail11) + + cmpb $0, 12(%edx) + jz L(exit_tail12) + cmpb $0, 13(%edx) + jz L(exit_tail13) + cmpb $0, 14(%edx) + jz L(exit_tail14) + cmpb $0, 15(%edx) + jz L(exit_tail15) + + pxor %xmm0, %xmm0 + lea 16(%edx), %eax + add $16, %ecx + and $-16, %eax + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + pxor %xmm1, %xmm1 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + pxor %xmm2, %xmm2 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + pxor %xmm3, %xmm3 + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm0 + pmovmskb %xmm0, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm1 + pmovmskb %xmm1, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm2 + pmovmskb %xmm2, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + pcmpeqb (%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 16(%eax), %eax + test %edx, %edx + jnz L(exit) + + and $-0x40, %eax + + .p2align 4 +L(aligned_64_loop): + movaps (%eax), %xmm0 + movaps 16(%eax), %xmm1 + movaps 32(%eax), %xmm2 + movaps 48(%eax), %xmm6 + pminub %xmm1, %xmm0 + pminub %xmm6, %xmm2 + pminub %xmm0, %xmm2 + pcmpeqb %xmm3, %xmm2 + pmovmskb %xmm2, %edx + lea 64(%eax), %eax + test %edx, %edx + jz L(aligned_64_loop) + + pcmpeqb -64(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea 48(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm1, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb -32(%eax), %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + test %edx, %edx + jnz L(exit) + + pcmpeqb %xmm6, %xmm3 + pmovmskb %xmm3, %edx + lea -16(%ecx), %ecx + + .p2align 4 +L(exit): + sub %ecx, %eax + test %dl, %dl + jz L(exit_more_8) + + mov %dl, %cl + and $15, %cl + jz L(exit_more_4) + test $0x01, %dl + jnz L(exit_0) + test $0x02, %dl + jnz L(exit_1) + test $0x04, %dl + jnz L(exit_2) + add $3, %eax + RETURN + + .p2align 4 +L(exit_more_4): + test $0x10, %dl + jnz L(exit_4) + test $0x20, %dl + jnz L(exit_5) + test $0x40, %dl + jnz L(exit_6) + add $7, %eax + RETURN + + .p2align 4 +L(exit_more_8): + mov %dh, %ch + and $15, %ch + jz L(exit_more_12) + test $0x01, %dh + jnz L(exit_8) + test $0x02, %dh + jnz L(exit_9) + test $0x04, %dh + jnz L(exit_10) + add $11, %eax + RETURN + + .p2align 4 +L(exit_more_12): + test $0x10, %dh + jnz L(exit_12) + test $0x20, %dh + jnz L(exit_13) + test $0x40, %dh + jnz L(exit_14) + add $15, %eax +L(exit_0): + RETURN + + .p2align 4 +L(exit_1): + add $1, %eax + RETURN + +L(exit_2): + add $2, %eax + RETURN + +L(exit_3): + add $3, %eax + RETURN + +L(exit_4): + add $4, %eax + RETURN + +L(exit_5): + add $5, %eax + RETURN + +L(exit_6): + add $6, %eax + RETURN + +L(exit_7): + add $7, %eax + RETURN + +L(exit_8): + add $8, %eax + RETURN + +L(exit_9): + add $9, %eax + RETURN + +L(exit_10): + add $10, %eax + RETURN + +L(exit_11): + add $11, %eax + RETURN + +L(exit_12): + add $12, %eax + RETURN + +L(exit_13): + add $13, %eax + RETURN + +L(exit_14): + add $14, %eax + RETURN + +L(exit_15): + add $15, %eax + RETURN + +L(exit_tail0): + mov %edx, %eax + sub %ecx, %eax + RETURN + + .p2align 4 +L(exit_tail1): + lea 1(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail2): + lea 2(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail3): + lea 3(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail4): + lea 4(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail5): + lea 5(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail6): + lea 6(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail7): + lea 7(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail8): + lea 8(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail9): + lea 9(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail10): + lea 10(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail11): + lea 11(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail12): + lea 12(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail13): + lea 13(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail14): + lea 14(%edx), %eax + sub %ecx, %eax + RETURN + +L(exit_tail15): + lea 15(%edx), %eax + sub %ecx, %eax + RETURN + +END (STRCPY) + diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncat-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncat-atom.S new file mode 100644 index 000000000..ccb08a7e6 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncat-atom.S @@ -0,0 +1,34 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define STRCAT strncat_ssse3 +#define USE_AS_STRNCAT + +#include "ssse3-strcat-atom.S" diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncmp-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncmp-atom.S new file mode 100644 index 000000000..2bf5002cb --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncmp-atom.S @@ -0,0 +1,35 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + + +#define USE_AS_STRNCMP +#define STRCMP strncmp_ssse3 +#include "ssse3-strcmp-atom.S" + diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncpy-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncpy-atom.S new file mode 100644 index 000000000..0c27ffebc --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-strncpy-atom.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define STRCPY strncpy_atom +#include "ssse3-strcpy-atom.S" diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscat-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscat-atom.S new file mode 100644 index 000000000..a307983b0 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscat-atom.S @@ -0,0 +1,114 @@ +/* +Copyright (c) 2011 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 4 +#define STR1 PARMS+4 +#define STR2 STR1+4 + +#define USE_AS_WCSCAT + +.text +ENTRY (wcscat_ssse3) + PUSH (%edi) + mov STR1(%esp), %edi + mov %edi, %edx + +#define RETURN jmp L(WcscpyAtom) +#include "sse2-wcslen-atom.S" + +L(WcscpyAtom): + shl $2, %eax + mov STR2(%esp), %ecx + lea (%edi, %eax), %edx + + cmpl $0, (%ecx) + jz L(Exit4) + cmpl $0, 4(%ecx) + jz L(Exit8) + cmpl $0, 8(%ecx) + jz L(Exit12) + cmpl $0, 12(%ecx) + jz L(Exit16) + +#undef RETURN +#define RETURN POP(%edi); ret; CFI_PUSH(%edi) +#include "ssse3-wcscpy-atom.S" + +END (wcscat_ssse3) diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S new file mode 100644 index 000000000..80aa15faf --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wcscpy-atom.S @@ -0,0 +1,652 @@ +/* +Copyright (c) 2011, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_WCSCAT + +# ifndef L +# define L(label) .L##label +# endif + +# ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +# endif + +# ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +# endif + +# ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# endif + +# ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +# endif + +# ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# endif + +# ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +# endif + +# ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +# endif + +# define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +# define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +# define PUSH(REG) pushl REG; CFI_PUSH (REG) +# define POP(REG) popl REG; CFI_POP (REG) + +# define PARMS 4 +# define RETURN POP (%edi); ret; CFI_PUSH (%edi) + +# define STR1 PARMS +# define STR2 STR1+4 +# define LEN STR2+4 + +.text +ENTRY (wcscpy_ssse3) + mov STR1(%esp), %edx + mov STR2(%esp), %ecx + + cmpl $0, (%ecx) + jz L(ExitTail4) + cmpl $0, 4(%ecx) + jz L(ExitTail8) + cmpl $0, 8(%ecx) + jz L(ExitTail12) + cmpl $0, 12(%ecx) + jz L(ExitTail16) + + PUSH (%edi) + mov %edx, %edi +#endif + PUSH (%esi) + lea 16(%ecx), %esi + + and $-16, %esi + + pxor %xmm0, %xmm0 + pcmpeqd (%esi), %xmm0 + movdqu (%ecx), %xmm1 + movdqu %xmm1, (%edx) + + pmovmskb %xmm0, %eax + sub %ecx, %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + mov %edx, %eax + lea 16(%edx), %edx + and $-16, %edx + sub %edx, %eax + + sub %eax, %ecx + mov %ecx, %eax + and $0xf, %eax + mov $0, %esi + + jz L(Align16Both) + cmp $4, %eax + je L(Shl4) + cmp $8, %eax + je L(Shl8) + jmp L(Shl12) + +L(Align16Both): + movaps (%ecx), %xmm1 + movaps 16(%ecx), %xmm2 + movaps %xmm1, (%edx) + pcmpeqd %xmm2, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm3 + movaps %xmm2, (%edx, %esi) + pcmpeqd %xmm3, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm4 + movaps %xmm3, (%edx, %esi) + pcmpeqd %xmm4, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm1 + movaps %xmm4, (%edx, %esi) + pcmpeqd %xmm1, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm2 + movaps %xmm1, (%edx, %esi) + pcmpeqd %xmm2, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps 16(%ecx, %esi), %xmm3 + movaps %xmm2, (%edx, %esi) + pcmpeqd %xmm3, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps %xmm3, (%edx, %esi) + mov %ecx, %eax + lea 16(%ecx, %esi), %ecx + and $-0x40, %ecx + sub %ecx, %eax + sub %eax, %edx + + mov $-0x40, %esi + +L(Aligned64Loop): + movaps (%ecx), %xmm2 + movaps 32(%ecx), %xmm3 + movaps %xmm2, %xmm4 + movaps 16(%ecx), %xmm5 + movaps %xmm3, %xmm6 + movaps 48(%ecx), %xmm7 + pminub %xmm5, %xmm2 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + lea 64(%edx), %edx + pcmpeqd %xmm0, %xmm3 + lea 64(%ecx), %ecx + pmovmskb %xmm3, %eax + + test %eax, %eax + jnz L(Aligned64Leave) + movaps %xmm4, -64(%edx) + movaps %xmm5, -48(%edx) + movaps %xmm6, -32(%edx) + movaps %xmm7, -16(%edx) + jmp L(Aligned64Loop) + +L(Aligned64Leave): + pcmpeqd %xmm4, %xmm0 + pmovmskb %xmm0, %eax + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqd %xmm5, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm4, -64(%edx) + lea 16(%esi), %esi + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + pcmpeqd %xmm6, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm5, -48(%edx) + lea 16(%esi), %esi + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + movaps %xmm6, -32(%edx) + pcmpeqd %xmm7, %xmm0 + pmovmskb %xmm0, %eax + lea 16(%esi), %esi + test %eax, %eax + jnz L(CopyFrom1To16Bytes) + + mov $-0x40, %esi + movaps %xmm7, -16(%edx) + jmp L(Aligned64Loop) + + .p2align 4 +L(Shl4): + movaps -4(%ecx), %xmm1 + movaps 12(%ecx), %xmm2 +L(Shl4Start): + pcmpeqd %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm1 + + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm3, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 28(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + + test %eax, %eax + jnz L(Shl4LoopExit) + + palignr $4, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 28(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -12(%ecx), %ecx + sub %eax, %edx + + movaps -4(%ecx), %xmm1 + +L(Shl4LoopStart): + movaps 12(%ecx), %xmm2 + movaps 28(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 44(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 60(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqd %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $4, %xmm4, %xmm5 + palignr $4, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl4Start) + + palignr $4, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $4, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl4LoopStart) + +L(Shl4LoopExit): + movlpd (%ecx), %xmm0 + movl 8(%ecx), %esi + movlpd %xmm0, (%edx) + movl %esi, 8(%edx) + POP (%esi) + add $12, %edx + add $12, %ecx + test %al, %al + jz L(ExitHigh) + test $0x01, %al + jnz L(Exit4) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edi, %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(Shl8): + movaps -8(%ecx), %xmm1 + movaps 8(%ecx), %xmm2 +L(Shl8Start): + pcmpeqd %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm1 + + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm3, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 24(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + + test %eax, %eax + jnz L(Shl8LoopExit) + + palignr $8, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 24(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -8(%ecx), %ecx + sub %eax, %edx + + movaps -8(%ecx), %xmm1 + +L(Shl8LoopStart): + movaps 8(%ecx), %xmm2 + movaps 24(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 40(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 56(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqd %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $8, %xmm4, %xmm5 + palignr $8, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl8Start) + + palignr $8, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $8, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl8LoopStart) + +L(Shl8LoopExit): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + POP (%esi) + add $8, %edx + add $8, %ecx + test %al, %al + jz L(ExitHigh) + test $0x01, %al + jnz L(Exit4) + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edi, %eax + RETURN + + CFI_PUSH (%esi) + + .p2align 4 +L(Shl12): + movaps -12(%ecx), %xmm1 + movaps 4(%ecx), %xmm2 +L(Shl12Start): + pcmpeqd %xmm2, %xmm0 + pmovmskb %xmm0, %eax + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm1 + + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm3, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + movaps %xmm2, %xmm3 + + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm1, %xmm2 + movaps %xmm2, (%edx) + movaps 20(%ecx), %xmm2 + + pcmpeqd %xmm2, %xmm0 + lea 16(%edx), %edx + pmovmskb %xmm0, %eax + lea 16(%ecx), %ecx + + test %eax, %eax + jnz L(Shl12LoopExit) + + palignr $12, %xmm3, %xmm2 + movaps %xmm2, (%edx) + lea 20(%ecx), %ecx + lea 16(%edx), %edx + + mov %ecx, %eax + and $-0x40, %ecx + sub %ecx, %eax + lea -4(%ecx), %ecx + sub %eax, %edx + + movaps -12(%ecx), %xmm1 + +L(Shl12LoopStart): + movaps 4(%ecx), %xmm2 + movaps 20(%ecx), %xmm3 + movaps %xmm3, %xmm6 + movaps 36(%ecx), %xmm4 + movaps %xmm4, %xmm7 + movaps 52(%ecx), %xmm5 + pminub %xmm2, %xmm6 + pminub %xmm5, %xmm7 + pminub %xmm6, %xmm7 + pcmpeqd %xmm0, %xmm7 + pmovmskb %xmm7, %eax + movaps %xmm5, %xmm7 + palignr $12, %xmm4, %xmm5 + palignr $12, %xmm3, %xmm4 + test %eax, %eax + jnz L(Shl12Start) + + palignr $12, %xmm2, %xmm3 + lea 64(%ecx), %ecx + palignr $12, %xmm1, %xmm2 + movaps %xmm7, %xmm1 + movaps %xmm5, 48(%edx) + movaps %xmm4, 32(%edx) + movaps %xmm3, 16(%edx) + movaps %xmm2, (%edx) + lea 64(%edx), %edx + jmp L(Shl12LoopStart) + +L(Shl12LoopExit): + movl (%ecx), %esi + movl %esi, (%edx) + mov $4, %esi + + .p2align 4 +L(CopyFrom1To16Bytes): + add %esi, %edx + add %esi, %ecx + + POP (%esi) + test %al, %al + jz L(ExitHigh) + test $0x01, %al + jnz L(Exit4) +L(Exit8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edi, %eax + RETURN + + .p2align 4 +L(ExitHigh): + test $0x01, %ah + jnz L(Exit12) +L(Exit16): + movdqu (%ecx), %xmm0 + movdqu %xmm0, (%edx) + movl %edi, %eax + RETURN + + .p2align 4 +L(Exit4): + movl (%ecx), %eax + movl %eax, (%edx) + movl %edi, %eax + RETURN + + .p2align 4 +L(Exit12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + movl %edi, %eax + RETURN + +CFI_POP (%edi) + + .p2align 4 +L(ExitTail4): + movl (%ecx), %eax + movl %eax, (%edx) + movl %edx, %eax + ret + + .p2align 4 +L(ExitTail8): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl %edx, %eax + ret + + .p2align 4 +L(ExitTail12): + movlpd (%ecx), %xmm0 + movlpd %xmm0, (%edx) + movl 8(%ecx), %eax + movl %eax, 8(%edx) + movl %edx, %eax + ret + + .p2align 4 +L(ExitTail16): + movdqu (%ecx), %xmm0 + movdqu %xmm0, (%edx) + movl %edx, %eax + ret + +#ifndef USE_AS_WCSCAT +END (wcscpy_ssse3) +#endif diff --git a/aosp/bionic/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S new file mode 100644 index 000000000..a81b78bca --- /dev/null +++ b/aosp/bionic/libc/arch-x86/atom/string/ssse3-wmemcmp-atom.S @@ -0,0 +1,35 @@ +/* +Copyright (c) 2011, 2012, 2013 Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define MEMCMP wmemcmp_atom + +#define USE_WCHAR +#define USE_AS_WMEMCMP 1 +#include "ssse3-memcmp-atom.S" diff --git a/aosp/bionic/libc/arch-x86/bionic/__bionic_clone.S b/aosp/bionic/libc/arch-x86/bionic/__bionic_clone.S new file mode 100644 index 000000000..b682b4863 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/__bionic_clone.S @@ -0,0 +1,64 @@ +#include + +// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg); +ENTRY_PRIVATE(__bionic_clone) + pushl %ebx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebx, 0 + pushl %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + pushl %edi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edi, 0 + + # Load system call arguments into registers. + movl 16(%esp), %ebx # flags + movl 20(%esp), %ecx # child_stack + movl 24(%esp), %edx # parent_tid + movl 28(%esp), %esi # tls + movl 32(%esp), %edi # child_tid + + # Copy 'fn' and 'arg' onto the child stack + movl 36(%esp), %eax # Read 'fn'. + movl %eax, -16(%ecx) # Write 'fn'. + movl 40(%esp), %eax # Read 'arg'. + movl %eax, -12(%ecx) # Write 'arg'. + subl $16, %ecx + + # Make the system call. + movl $__NR_clone, %eax + int $0x80 + + # Check result. + testl %eax, %eax + jz .L_bc_child + jg .L_bc_parent + + # An error occurred, so set errno and return -1. + negl %eax + pushl %eax + call __set_errno_internal + addl $4, %esp + jmp .L_bc_return + +.L_bc_child: + # We don't want anyone to unwind past this point. + .cfi_undefined %eip + call __start_thread + hlt + +.L_bc_parent: + # We're the parent; nothing to do. +.L_bc_return: + popl %edi + .cfi_adjust_cfa_offset -4 + .cfi_restore edi + popl %esi + .cfi_adjust_cfa_offset -4 + .cfi_restore esi + popl %ebx + .cfi_adjust_cfa_offset -4 + .cfi_restore ebx + ret +END(__bionic_clone) diff --git a/aosp/bionic/libc/arch-x86/bionic/__libc_init_sysinfo.cpp b/aosp/bionic/libc/arch-x86/bionic/__libc_init_sysinfo.cpp new file mode 100644 index 000000000..5c44b4ea4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/__libc_init_sysinfo.cpp @@ -0,0 +1,47 @@ +/* + * 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_auxv.h" +#include "private/bionic_globals.h" + +// This file is compiled without stack protection, because it runs before TLS +// has been set up. + +__LIBC_HIDDEN__ __attribute__((__naked__)) void __libc_int0x80() { + __asm__ volatile("int $0x80; ret"); +} + +__LIBC_HIDDEN__ void __libc_init_sysinfo() { + bool dummy; + __libc_sysinfo = reinterpret_cast(__bionic_getauxval(AT_SYSINFO, dummy)); +} + +// TODO: lose this function and just access __libc_sysinfo directly. +__LIBC_HIDDEN__ extern "C" void* __kernel_syscall() { + return __libc_sysinfo; +} diff --git a/aosp/bionic/libc/arch-x86/bionic/__restore.S b/aosp/bionic/libc/arch-x86/bionic/__restore.S new file mode 100644 index 000000000..cb18fd027 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/__restore.S @@ -0,0 +1,135 @@ +/* + * 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 + +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_deref 0x06 + +// Offsets into struct sigcontext. +#define OFFSET_EDI 16 +#define OFFSET_ESI 20 +#define OFFSET_EBP 24 +#define OFFSET_ESP 28 +#define OFFSET_EBX 32 +#define OFFSET_EDX 36 +#define OFFSET_ECX 40 +#define OFFSET_EAX 44 +#define OFFSET_EIP 56 + +// Non-standard DWARF constants for the x86 registers. +#define DW_x86_REG_EAX 0 +#define DW_x86_REG_ECX 1 +#define DW_x86_REG_EDX 2 +#define DW_x86_REG_EBX 3 +#define DW_x86_REG_EBP 5 +#define DW_x86_REG_ESI 6 +#define DW_x86_REG_EDI 7 +#define DW_x86_REG_EIP 8 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -4; /* Data alignment factor. */ \ + .uleb128 DW_x86_REG_EIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel|DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore) +.L__restore_START: + popl %eax + movl $__NR_sigreturn, %eax + int $0x80 +.L__restore_END: +END(__restore) +cfi_signal_frame_start(__restore) + cfi_def_cfa(OFFSET_ESP + 4) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 4) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 4) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 4) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 4) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 4) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 4) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 4) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 4) +cfi_signal_frame_end(__restore) + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: + movl $__NR_rt_sigreturn, %eax + int $0x80 +.L__restore_rt_END: +END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_ESP + 160) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 160) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 160) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 160) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 160) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 160) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 160) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 160) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 160) +cfi_signal_frame_end(__restore_rt) diff --git a/aosp/bionic/libc/arch-x86/bionic/__set_tls.cpp b/aosp/bionic/libc/arch-x86/bionic/__set_tls.cpp new file mode 100644 index 000000000..3f58bc5e1 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/__set_tls.cpp @@ -0,0 +1,73 @@ +/* + * 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 +#include + +#include + +extern "C" int __set_thread_area(user_desc*); + +__LIBC_HIDDEN__ void __init_user_desc(user_desc* result, bool allocate, void* base_addr) { + if (allocate) { + // Let the kernel choose. + result->entry_number = -1; + } else { + // Get the existing entry number from %gs. + uint32_t gs; + __asm__ __volatile__("movw %%gs, %w0" : "=q"(gs) /*output*/); + result->entry_number = (gs & 0xffff) >> 3; + } + + result->base_addr = reinterpret_cast(base_addr); + + result->limit = 0xfffff; + + result->seg_32bit = 1; + result->contents = MODIFY_LDT_CONTENTS_DATA; + result->read_exec_only = 0; + result->limit_in_pages = 1; + result->seg_not_present = 0; + result->useable = 1; +} + +extern "C" __LIBC_HIDDEN__ int __set_tls(void* ptr) { + user_desc tls_descriptor = {}; + __init_user_desc(&tls_descriptor, true, ptr); + + int rc = __set_thread_area(&tls_descriptor); + if (rc != -1) { + // Change %gs to be new GDT entry. + uint16_t table_indicator = 0; // GDT + uint16_t rpl = 3; // Requested privilege level + uint16_t selector = (tls_descriptor.entry_number << 3) | table_indicator | rpl; + __asm__ __volatile__("movw %w0, %%gs" : /*output*/ : "q"(selector) /*input*/ : /*clobber*/); + } + + return rc; +} diff --git a/aosp/bionic/libc/arch-x86/bionic/__stack_chk_fail_local.h b/aosp/bionic/libc/arch-x86/bionic/__stack_chk_fail_local.h new file mode 100644 index 000000000..0b0fd7f8b --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/__stack_chk_fail_local.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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 + +/* + __stack_chk_fail routine is runtime part of stack protector compiler + feature. It's implemented in libc and represents die routine when stack + corruption is detected. + + Calls are generated by compiler and injected into user functions when + -fstack-protector* options are used. + + __stack_chk_fail_local is wrapper for __stack_chk_fail. Compiler generates + wrapper calls instead for PIC code only and only on IA32 for optimization + purpose (see gcc/config/i386/i386.c). Wrapper body is always included into + executable or library. This is the idea of optimization. + + Glibc is doing this via libc_nonshared.a which is linked automatically + everytime with libc.so. In bionic we have to bring it within crtfiles + because libc.so is real library and not a link script like libc.so at glibc. + + For x86_64 or non-PIC code compiler always generates __stack_chk_fail calls. +*/ + +#ifdef __i386__ +extern void __stack_chk_fail(); + +__LIBC_HIDDEN__ void __stack_chk_fail_local() { + __stack_chk_fail(); +} +#endif diff --git a/aosp/bionic/libc/arch-x86/bionic/_exit_with_stack_teardown.S b/aosp/bionic/libc/arch-x86/bionic/_exit_with_stack_teardown.S new file mode 100644 index 000000000..ce8c2ea0b --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/_exit_with_stack_teardown.S @@ -0,0 +1,16 @@ +#include + +// void _exit_with_stack_teardown(void* stackBase, size_t stackSize) +ENTRY_PRIVATE(_exit_with_stack_teardown) + // We can trash registers because this function never returns. + mov 4(%esp), %ebx // stackBase + mov 8(%esp), %ecx // stackSize + mov $__NR_munmap, %eax + int $0x80 + // If munmap failed, we ignore the failure and exit anyway. + + mov $0, %ebx // status + movl $__NR_exit, %eax + int $0x80 + // The exit syscall does not return. +END(_exit_with_stack_teardown) diff --git a/aosp/bionic/libc/arch-x86/bionic/atexit.h b/aosp/bionic/libc/arch-x86/bionic/atexit.h new file mode 100644 index 000000000..bc776a8b4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/atexit.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 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. + */ + +extern void *__dso_handle; + +__attribute__ ((visibility ("hidden"))) +int atexit(void (*func)(void)) +{ + return (__cxa_atexit((void (*)(void *))func, (void *)0, &__dso_handle)); +} diff --git a/aosp/bionic/libc/arch-x86/bionic/libcrt_compat.c b/aosp/bionic/libc/arch-x86/bionic/libcrt_compat.c new file mode 100644 index 000000000..cfa41f261 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/libcrt_compat.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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. + */ + +extern char __divdi3; +extern char __moddi3; +extern char __popcountsi2; +extern char __udivdi3; +extern char __umoddi3; + +void* __bionic_libcrt_compat_symbols[] = { + &__divdi3, + &__moddi3, + &__popcountsi2, + &__udivdi3, + &__umoddi3, +}; diff --git a/aosp/bionic/libc/arch-x86/bionic/setjmp.S b/aosp/bionic/libc/arch-x86/bionic/setjmp.S new file mode 100644 index 000000000..1e1ce58c3 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/setjmp.S @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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 + +// The internal structure of a jmp_buf is totally private. +// Current layout (changes from release to release): +// +// word name description +// 0 edx registers +// 1 ebx +// 2 esp +// 3 ebp +// 4 esi +// 5 edi +// 6 sigmask 64-bit signal mask (not used with _setjmp / _longjmp) +// 7 " " +// 8 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit +// 9 checksum checksum of the core registers, to give better error messages. + +#define _JB_EDX 0 +#define _JB_EBX 1 +#define _JB_ESP 2 +#define _JB_EBP 3 +#define _JB_ESI 4 +#define _JB_EDI 5 +#define _JB_SIGMASK 6 +#define _JB_SIGFLAG 8 +#define _JB_CHECKSUM 9 + +.macro m_mangle_registers reg + xorl \reg,%edx + xorl \reg,%ebx + xorl \reg,%esp + xorl \reg,%ebp + xorl \reg,%esi + xorl \reg,%edi +.endm + +.macro m_unmangle_registers reg + m_mangle_registers \reg +.endm + +.macro m_calculate_checksum dst, src + movl $0, \dst + .irp i,0,1,2,3,4,5 + xorl (\i*4)(\src), \dst + .endr +.endm + +ENTRY(setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(setjmp) + movl 4(%esp),%ecx + mov $1,%eax + jmp .L_sigsetjmp +END(setjmp) + +ENTRY(_setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_setjmp) + movl 4(%esp),%ecx + movl $0,%eax + jmp .L_sigsetjmp +END(_setjmp) + +ENTRY(sigsetjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp) + movl 4(%esp),%ecx + movl 8(%esp),%eax + +.L_sigsetjmp: + PIC_PROLOGUE + pushl %eax + call PIC_PLT(__bionic_setjmp_cookie_get) + addl $4,%esp + PIC_EPILOGUE + + // Record the setjmp cookie and whether or not we're saving the signal mask. + movl %eax,(_JB_SIGFLAG * 4)(%ecx) + + // Do we need to save the signal mask? + testl $1,%eax + jz 1f + + // Save the current signal mask. + pushl %ecx + PIC_PROLOGUE + leal (_JB_SIGMASK * 4)(%ecx),%eax + pushl %eax + pushl $0 // NULL + pushl $2 // SIG_SETMASK + call PIC_PLT(sigprocmask64) + addl $12,%esp + PIC_EPILOGUE + popl %ecx + +1: + // Fetch the setjmp cookie and clear the signal flag bit. + movl (_JB_SIGFLAG * 4)(%ecx),%eax + andl $-2,%eax + + // Save the callee-save registers. + movl 0(%esp),%edx + m_mangle_registers %eax + movl %edx,(_JB_EDX * 4)(%ecx) + movl %ebx,(_JB_EBX * 4)(%ecx) + movl %esp,(_JB_ESP * 4)(%ecx) + movl %ebp,(_JB_EBP * 4)(%ecx) + movl %esi,(_JB_ESI * 4)(%ecx) + movl %edi,(_JB_EDI * 4)(%ecx) + m_unmangle_registers %eax + + m_calculate_checksum %eax, %ecx + movl %eax, (_JB_CHECKSUM * 4)(%ecx) + + xorl %eax,%eax + ret +END(sigsetjmp) + +ENTRY(siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(siglongjmp) + movl 4(%esp),%edx + + // Check the checksum before doing anything. + m_calculate_checksum %eax, %edx + xorl (_JB_CHECKSUM * 4)(%edx), %eax + jnz 3f + + // Do we have a signal mask to restore? + movl (_JB_SIGFLAG * 4)(%edx), %eax + testl $1,%eax + jz 1f + + // Restore the signal mask. + leal (_JB_SIGMASK * 4)(%edx),%eax + PIC_PROLOGUE + pushl $0 // NULL + pushl %eax + pushl $2 // SIG_SETMASK + call PIC_PLT(sigprocmask64) + addl $12,%esp + PIC_EPILOGUE + +1: + // Restore the callee-save registers. + movl 4(%esp),%edx + movl 8(%esp),%eax + + movl (_JB_SIGFLAG * 4)(%edx),%ecx + andl $-2,%ecx + + movl %ecx,%ebx + movl %ecx,%esp + movl %ecx,%ebp + movl %ecx,%esi + movl %ecx,%edi + xorl (_JB_EDX * 4)(%edx),%ecx + xorl (_JB_EBX * 4)(%edx),%ebx + xorl (_JB_ESP * 4)(%edx),%esp + xorl (_JB_EBP * 4)(%edx),%ebp + xorl (_JB_ESI * 4)(%edx),%esi + xorl (_JB_EDI * 4)(%edx),%edi + + PIC_PROLOGUE + pushl %eax + pushl %ecx + pushl (_JB_SIGFLAG * 4)(%edx) + call PIC_PLT(__bionic_setjmp_cookie_check) + addl $4,%esp + popl %ecx + popl %eax + PIC_EPILOGUE + + testl %eax,%eax + jnz 2f + incl %eax +2: + movl %ecx,0(%esp) + ret + +3: + PIC_PROLOGUE + pushl (_JB_SIGMASK * 4)(%edx) + call PIC_PLT(__bionic_setjmp_checksum_mismatch) +END(siglongjmp) + +ALIAS_SYMBOL(longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp) +ALIAS_SYMBOL(_longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp) diff --git a/aosp/bionic/libc/arch-x86/bionic/syscall.S b/aosp/bionic/libc/arch-x86/bionic/syscall.S new file mode 100644 index 000000000..12402aca4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/syscall.S @@ -0,0 +1,73 @@ +/* + * Generic syscall call. + * Upon entry: + * %eax: system call number - caller save + * %ebx: arg0 to system call - callee save + * %ecx: arg1 - caller save + * %edx: arg2 - caller save + * %esi: arg3 - callee save + * %edi: arg4 - callee save + * %ebp: arg5 - callee save + */ + +#include + +ENTRY(syscall) + # Push the callee save registers. + push %ebx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebx, 0 + push %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + push %edi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edi, 0 + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebp, 0 + + # Get and save the system call entry address. + call __kernel_syscall + push %eax + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset eax, 0 + + # Load all the arguments from the calling frame. + # (Not all will be valid, depending on the syscall.) + mov 24(%esp),%eax + mov 28(%esp),%ebx + mov 32(%esp),%ecx + mov 36(%esp),%edx + mov 40(%esp),%esi + mov 44(%esp),%edi + mov 48(%esp),%ebp + + # Make the system call. + call *(%esp) + addl $4, %esp + + # Error? + cmpl $-MAX_ERRNO, %eax + jb 1f + # Yes, so set errno. + negl %eax + pushl %eax + call __set_errno_internal + addl $4, %esp +1: + # Restore the callee save registers. + pop %ebp + .cfi_adjust_cfa_offset -4 + .cfi_restore ebp + pop %edi + .cfi_adjust_cfa_offset -4 + .cfi_restore edi + pop %esi + .cfi_adjust_cfa_offset -4 + .cfi_restore esi + pop %ebx + .cfi_adjust_cfa_offset -4 + .cfi_restore ebx + ret +END(syscall) diff --git a/aosp/bionic/libc/arch-x86/bionic/vfork.S b/aosp/bionic/libc/arch-x86/bionic/vfork.S new file mode 100644 index 000000000..231a36ec7 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/bionic/vfork.S @@ -0,0 +1,66 @@ +/* + * 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 +#include + +// This custom code preserves the return address across the system call. + +ENTRY(vfork) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork) + popl %ecx // Grab the return address. + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ecx, 0 + + // Set cached_pid_ to 0, vforked_ to 1, and stash the previous value. + movl %gs:0, %eax + movl (TLS_SLOT_THREAD_ID * 4)(%eax), %eax + movl 12(%eax), %edx + movl $0x80000000, 12(%eax) + + movl $__NR_vfork, %eax + int $0x80 + + test %eax, %eax + jz 1f + + // rc != 0: restore the previous cached_pid_/vforked_ values. + pushl %ecx + movl %gs:0, %ecx + movl (TLS_SLOT_THREAD_ID * 4)(%ecx), %ecx + movl %edx, 12(%ecx) + popl %ecx + + cmpl $-MAX_ERRNO, %eax + jb 1f + negl %eax + pushl %eax + call __set_errno_internal +1: + jmp *%ecx // Jump to the stored return address. +END(vfork) diff --git a/aosp/bionic/libc/arch-x86/dynamic_function_dispatch.cpp b/aosp/bionic/libc/arch-x86/dynamic_function_dispatch.cpp new file mode 100644 index 000000000..e94fa1f72 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/dynamic_function_dispatch.cpp @@ -0,0 +1,161 @@ +/* + * 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 + +#include + +extern "C" { + +typedef int memcmp_func(const void* __lhs, const void* __rhs, size_t __n); +DEFINE_IFUNC_FOR(memcmp) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(memcmp_func, memcmp_atom); + if (__builtin_cpu_supports("sse4.1")) RETURN_FUNC(memcmp_func, memcmp_sse4); + RETURN_FUNC(memcmp_func, memcmp_generic); +} + +typedef void* memset_func(void* __dst, int __ch, size_t __n); +DEFINE_IFUNC_FOR(memset) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(memset_func, memset_atom); + RETURN_FUNC(memset_func, memset_generic); +} + +typedef void* __memset_chk_func(void *s, int c, size_t n, size_t n2); +DEFINE_IFUNC_FOR(__memset_chk) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(__memset_chk_func, __memset_chk_atom); + RETURN_FUNC(__memset_chk_func, __memset_chk_generic); +} + +typedef void* memmove_func(void* __dst, const void* __src, size_t __n); +DEFINE_IFUNC_FOR(memmove) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(memmove_func, memmove_atom); + RETURN_FUNC(memmove_func, memmove_generic); +} + +typedef void* memcpy_func(void*, const void*, size_t); +DEFINE_IFUNC_FOR(memcpy) { + return memmove_resolver(); +} + +typedef char* strcpy_func(char* __dst, const char* __src); +DEFINE_IFUNC_FOR(strcpy) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(strcpy_func, strcpy_atom); + RETURN_FUNC(strcpy_func, strcpy_generic); +} + +typedef char* strncpy_func(char* __dst, const char* __src, size_t __n); +DEFINE_IFUNC_FOR(strncpy) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(strncpy_func, strncpy_atom); + RETURN_FUNC(strncpy_func, strncpy_generic); +} + +typedef size_t strlen_func(const char* __s); +DEFINE_IFUNC_FOR(strlen) { + __builtin_cpu_init(); + if (__builtin_cpu_is("atom")) RETURN_FUNC(strlen_func, strlen_atom); + RETURN_FUNC(strlen_func, strlen_generic); +} + +typedef int wmemcmp_func(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); +DEFINE_IFUNC_FOR(wmemcmp) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("sse4.1")) RETURN_FUNC(wmemcmp_func, wmemcmp_sse4); + if (__builtin_cpu_is("atom")) RETURN_FUNC(wmemcmp_func, wmemcmp_atom); + RETURN_FUNC(wmemcmp_func, wmemcmp_freebsd); +} + +typedef int wmemset_func(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); +DEFINE_IFUNC_FOR(wmemset) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("avx2")) RETURN_FUNC(wmemset_func, wmemset_avx2); + RETURN_FUNC(wmemset_func, wmemset_freebsd); +} + +typedef int strcmp_func(const char* __lhs, const char* __rhs); +DEFINE_IFUNC_FOR(strcmp) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strcmp_func, strcmp_ssse3); + RETURN_FUNC(strcmp_func, strcmp_generic); +} + +typedef int strncmp_func(const char* __lhs, const char* __rhs, size_t __n); +DEFINE_IFUNC_FOR(strncmp) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strncmp_func, strncmp_ssse3); + RETURN_FUNC(strncmp_func, strncmp_generic); +} + +typedef char* strcat_func(char* __dst, const char* __src); +DEFINE_IFUNC_FOR(strcat) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strcat_func, strcat_ssse3); + RETURN_FUNC(strcat_func, strcat_generic); +} + +typedef char* strncat_func(char* __dst, const char* __src, size_t __n); +DEFINE_IFUNC_FOR(strncat) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strncat_func, strncat_ssse3); + RETURN_FUNC(strncat_func, strncat_openbsd); +} + +typedef size_t strlcat_func(char *dst, const char *src, size_t dsize); +DEFINE_IFUNC_FOR(strlcat) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strlcat_func, strlcat_ssse3); + RETURN_FUNC(strlcat_func, strlcat_openbsd); +} + +typedef size_t strlcpy_func(char *dst, const char *src, size_t dsize); +DEFINE_IFUNC_FOR(strlcpy) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(strlcpy_func, strlcpy_ssse3); + RETURN_FUNC(strlcpy_func, strlcpy_openbsd); +} + +typedef wchar_t* wcscat_func(wchar_t *s1, const wchar_t *s2); +DEFINE_IFUNC_FOR(wcscat) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(wcscat_func, wcscat_ssse3); + RETURN_FUNC(wcscat_func, wcscat_freebsd); +} + +typedef wchar_t* wcscpy_func(wchar_t *s1, const wchar_t *s2); +DEFINE_IFUNC_FOR(wcscpy) { + __builtin_cpu_init(); + if (__builtin_cpu_supports("ssse3")) RETURN_FUNC(wcscpy_func, wcscpy_ssse3); + RETURN_FUNC(wcscpy_func, wcscpy_freebsd); +} + +} // extern "C" diff --git a/aosp/bionic/libc/arch-x86/generic/string/memcmp.S b/aosp/bionic/libc/arch-x86/generic/string/memcmp.S new file mode 100644 index 000000000..1d327c76f --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/memcmp.S @@ -0,0 +1,44 @@ +/* $OpenBSD: memcmp.S,v 1.4 2005/08/07 11:30:38 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +ENTRY(memcmp_generic) + pushl %edi + pushl %esi + movl 12(%esp),%edi + movl 16(%esp),%esi + cld /* set compare direction forward */ + + movl 20(%esp),%ecx /* compare by words */ + shrl $2,%ecx + repe + cmpsl + jne L5 /* do we match so far? */ + + movl 20(%esp),%ecx /* compare remainder by bytes */ + andl $3,%ecx + repe + cmpsb + jne L6 /* do we match? */ + + xorl %eax,%eax /* we match, return zero */ + popl %esi + popl %edi + ret + +L5: movl $4,%ecx /* We know that one of the next */ + subl %ecx,%edi /* four pairs of bytes do not */ + subl %ecx,%esi /* match. */ + repe + cmpsb +L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */ + movzbl -1(%esi),%edx + subl %edx,%eax + popl %esi + popl %edi + ret +END(memcmp_generic) diff --git a/aosp/bionic/libc/arch-x86/generic/string/strcat.S b/aosp/bionic/libc/arch-x86/generic/string/strcat.S new file mode 100644 index 000000000..e2e962388 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strcat.S @@ -0,0 +1,74 @@ +/* $OpenBSD: strcat.S,v 1.8 2005/08/07 11:30:38 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +#if defined(APIWARN) +#APP + .section .gnu.warning.strcat + .ascii "warning: strcat() is almost always misused, please use strlcat()" +#NO_APP +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcat_generic) + pushl %edi /* save edi */ + movl 8(%esp),%edi /* dst address */ + movl 12(%esp),%edx /* src address */ + pushl %edi /* push destination address */ + + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movl $-1,%ecx /* set search for lots of characters */ + repne /* search! */ + scasb + + leal -1(%edi),%ecx /* correct dst address */ + + .align 2,0x90 +L1: movb (%edx),%al /* unroll loop, but not too much */ + movb %al,(%ecx) + testb %al,%al + jz L2 + movb 1(%edx),%al + movb %al,1(%ecx) + testb %al,%al + jz L2 + movb 2(%edx),%al + movb %al,2(%ecx) + testb %al,%al + jz L2 + movb 3(%edx),%al + movb %al,3(%ecx) + testb %al,%al + jz L2 + movb 4(%edx),%al + movb %al,4(%ecx) + testb %al,%al + jz L2 + movb 5(%edx),%al + movb %al,5(%ecx) + testb %al,%al + jz L2 + movb 6(%edx),%al + movb %al,6(%ecx) + testb %al,%al + jz L2 + movb 7(%edx),%al + movb %al,7(%ecx) + addl $8,%edx + addl $8,%ecx + testb %al,%al + jnz L1 +L2: popl %eax /* pop destination address */ + popl %edi /* restore edi */ + ret +END(strcat_generic) diff --git a/aosp/bionic/libc/arch-x86/generic/string/strcmp.S b/aosp/bionic/libc/arch-x86/generic/string/strcmp.S new file mode 100644 index 000000000..7b003e87b --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strcmp.S @@ -0,0 +1,82 @@ +/* $OpenBSD: strcmp.S,v 1.3 2005/08/07 11:30:38 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcmp_generic) + movl 0x04(%esp),%eax + movl 0x08(%esp),%edx + jmp L2 /* Jump into the loop! */ + + .align 2,0x90 +L1: incl %eax + incl %edx +L2: movb (%eax),%cl + testb %cl,%cl /* null terminator??? */ + jz L3 + cmpb %cl,(%edx) /* chars match??? */ + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + je L1 + .align 2, 0x90 +L3: movzbl (%eax),%eax /* unsigned comparison */ + movzbl (%edx),%edx + subl %edx,%eax + ret +END(strcmp_generic) diff --git a/aosp/bionic/libc/arch-x86/generic/string/strlcat.c b/aosp/bionic/libc/arch-x86/generic/string/strlcat.c new file mode 100644 index 000000000..95c34a394 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strlcat.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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 + +#define strlcat strlcat_openbsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/strlcpy.c b/aosp/bionic/libc/arch-x86/generic/string/strlcpy.c new file mode 100644 index 000000000..8d4047c97 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strlcpy.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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 + +#define strlcpy strlcpy_openbsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/strncat.c b/aosp/bionic/libc/arch-x86/generic/string/strncat.c new file mode 100644 index 000000000..687e56041 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strncat.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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 + +#define strncat strncat_openbsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/strncmp.S b/aosp/bionic/libc/arch-x86/generic/string/strncmp.S new file mode 100644 index 000000000..6d9f23ceb --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/strncmp.S @@ -0,0 +1,114 @@ +/* $OpenBSD: strncmp.S,v 1.3 2005/08/07 11:30:38 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strncmp_generic) + pushl %ebx + movl 8(%esp),%eax + movl 12(%esp),%ecx + movl 16(%esp),%edx + testl %edx,%edx + jmp L2 /* Jump into the loop! */ + + .align 2,0x90 +L1: incl %eax + incl %ecx + decl %edx +L2: jz L4 /* strings are equal */ + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + je L1 + + .align 2,0x90 +L3: movzbl (%eax),%eax /* unsigned comparision */ + movzbl (%ecx),%ecx + subl %ecx,%eax + popl %ebx + ret + .align 2,0x90 +L4: xorl %eax,%eax + popl %ebx + ret +END(strncmp_generic) diff --git a/aosp/bionic/libc/arch-x86/generic/string/wcscat.c b/aosp/bionic/libc/arch-x86/generic/string/wcscat.c new file mode 100644 index 000000000..a1025517c --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/wcscat.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define wcscat wcscat_freebsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/wcscpy.c b/aosp/bionic/libc/arch-x86/generic/string/wcscpy.c new file mode 100644 index 000000000..10fb66d5e --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/wcscpy.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define wcscpy wcscpy_freebsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/wmemcmp.c b/aosp/bionic/libc/arch-x86/generic/string/wmemcmp.c new file mode 100644 index 000000000..9d5e929e3 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/wmemcmp.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define wmemcmp wmemcmp_freebsd +#include diff --git a/aosp/bionic/libc/arch-x86/generic/string/wmemset.c b/aosp/bionic/libc/arch-x86/generic/string/wmemset.c new file mode 100644 index 000000000..35d489f44 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/generic/string/wmemset.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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. +*/ + +#define wmemset wmemset_freebsd + +#include diff --git a/aosp/bionic/libc/arch-x86/kabylake/string/avx2-wmemset-kbl.S b/aosp/bionic/libc/arch-x86/kabylake/string/avx2-wmemset-kbl.S new file mode 100644 index 000000000..69b66c795 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/kabylake/string/avx2-wmemset-kbl.S @@ -0,0 +1,148 @@ +/* +Copyright (C) 2019 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 + +#ifndef WMEMSET + #define WMEMSET wmemset_avx2 +#endif + +ENTRY(WMEMSET) +# BB#0: + pushl %ebp + pushl %ebx + pushl %edi + pushl %esi + pushl %eax + movl 32(%esp), %ecx + movl 24(%esp), %eax + testl %ecx, %ecx + je .LBB0_12 +# BB#1: + movl 28(%esp), %edx + xorl %edi, %edi + movl %eax, %esi + cmpl $32, %ecx + jb .LBB0_10 +# BB#2: + movl %ecx, %eax + andl $-32, %eax + vmovd %edx, %xmm0 + vpbroadcastd %xmm0, %ymm0 + movl %eax, (%esp) # 4-byte Spill + leal -32(%eax), %esi + movl %esi, %eax + shrl $5, %eax + leal 1(%eax), %edi + andl $7, %edi + xorl %ebx, %ebx + cmpl $224, %esi + jb .LBB0_5 +# BB#3: + movl 24(%esp), %esi + leal 992(%esi), %ebp + leal -1(%edi), %esi + subl %eax, %esi + xorl %ebx, %ebx + .p2align 4, 0x90 +.LBB0_4: # =>This Inner Loop Header: Depth=1 + vmovdqu %ymm0, -992(%ebp,%ebx,4) + vmovdqu %ymm0, -960(%ebp,%ebx,4) + vmovdqu %ymm0, -928(%ebp,%ebx,4) + vmovdqu %ymm0, -896(%ebp,%ebx,4) + vmovdqu %ymm0, -864(%ebp,%ebx,4) + vmovdqu %ymm0, -832(%ebp,%ebx,4) + vmovdqu %ymm0, -800(%ebp,%ebx,4) + vmovdqu %ymm0, -768(%ebp,%ebx,4) + vmovdqu %ymm0, -736(%ebp,%ebx,4) + vmovdqu %ymm0, -704(%ebp,%ebx,4) + vmovdqu %ymm0, -672(%ebp,%ebx,4) + vmovdqu %ymm0, -640(%ebp,%ebx,4) + vmovdqu %ymm0, -608(%ebp,%ebx,4) + vmovdqu %ymm0, -576(%ebp,%ebx,4) + vmovdqu %ymm0, -544(%ebp,%ebx,4) + vmovdqu %ymm0, -512(%ebp,%ebx,4) + vmovdqu %ymm0, -480(%ebp,%ebx,4) + vmovdqu %ymm0, -448(%ebp,%ebx,4) + vmovdqu %ymm0, -416(%ebp,%ebx,4) + vmovdqu %ymm0, -384(%ebp,%ebx,4) + vmovdqu %ymm0, -352(%ebp,%ebx,4) + vmovdqu %ymm0, -320(%ebp,%ebx,4) + vmovdqu %ymm0, -288(%ebp,%ebx,4) + vmovdqu %ymm0, -256(%ebp,%ebx,4) + vmovdqu %ymm0, -224(%ebp,%ebx,4) + vmovdqu %ymm0, -192(%ebp,%ebx,4) + vmovdqu %ymm0, -160(%ebp,%ebx,4) + vmovdqu %ymm0, -128(%ebp,%ebx,4) + vmovdqu %ymm0, -96(%ebp,%ebx,4) + vmovdqu %ymm0, -64(%ebp,%ebx,4) + vmovdqu %ymm0, -32(%ebp,%ebx,4) + vmovdqu %ymm0, (%ebp,%ebx,4) + addl $256, %ebx # imm = 0x100 + addl $8, %esi + jne .LBB0_4 +.LBB0_5: + testl %edi, %edi + movl 24(%esp), %eax + je .LBB0_8 +# BB#6: + leal (%eax,%ebx,4), %esi + addl $96, %esi + negl %edi + .p2align 4, 0x90 +.LBB0_7: # =>This Inner Loop Header: Depth=1 + vmovdqu %ymm0, -96(%esi) + vmovdqu %ymm0, -64(%esi) + vmovdqu %ymm0, -32(%esi) + vmovdqu %ymm0, (%esi) + subl $-128, %esi + addl $1, %edi + jne .LBB0_7 +.LBB0_8: + movl (%esp), %edi # 4-byte Reload + cmpl %ecx, %edi + je .LBB0_12 +# BB#9: + leal (%eax,%edi,4), %esi +.LBB0_10: + subl %edi, %ecx + .p2align 4, 0x90 +.LBB0_11: # =>This Inner Loop Header: Depth=1 + movl %edx, (%esi) + addl $4, %esi + addl $-1, %ecx + jne .LBB0_11 +.LBB0_12: + addl $4, %esp + popl %esi + popl %edi + popl %ebx + popl %ebp + vzeroupper + retl +END(WMEMSET) diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/cache.h b/aosp/bionic/libc/arch-x86/silvermont/string/cache.h new file mode 100644 index 000000000..c342b1c33 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/cache.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2010, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +/* Values are optimized for Silvermont */ +#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ + +#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) +#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memmove-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memmove-slm.S new file mode 100644 index 000000000..da6456ccc --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memmove-slm.S @@ -0,0 +1,539 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 "cache.h" + +#ifndef MEMMOVE +# define MEMMOVE memmove_generic +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define DEST PARMS +#define SRC DEST+4 +#define LEN SRC+4 + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 8 /* Preserve EBX. */ +#define ENTRANCE PUSH (%ebx); +#define RETURN_END POP (%ebx); ret +#define RETURN RETURN_END; CFI_PUSH (%ebx) + + .section .text.sse2,"ax",@progbits +ENTRY (MEMMOVE) + ENTRANCE + movl LEN(%esp), %ecx + movl SRC(%esp), %eax + movl DEST(%esp), %edx + +/* Check whether we should copy backward or forward. */ + cmp %eax, %edx + je L(mm_return) + jg L(mm_len_0_or_more_backward) + +/* Now do checks for lengths. We do [0..16], [0..32], [0..64], [0..128] + separately. */ + cmp $16, %ecx + jbe L(mm_len_0_16_bytes_forward) + + cmpl $32, %ecx + ja L(mm_len_32_or_more_forward) + +/* Copy [0..32] and return. */ + movdqu (%eax), %xmm0 + movdqu -16(%eax, %ecx), %xmm1 + movdqu %xmm0, (%edx) + movdqu %xmm1, -16(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_32_or_more_forward): + cmpl $64, %ecx + ja L(mm_len_64_or_more_forward) + +/* Copy [0..64] and return. */ + movdqu (%eax), %xmm0 + movdqu 16(%eax), %xmm1 + movdqu -16(%eax, %ecx), %xmm2 + movdqu -32(%eax, %ecx), %xmm3 + movdqu %xmm0, (%edx) + movdqu %xmm1, 16(%edx) + movdqu %xmm2, -16(%edx, %ecx) + movdqu %xmm3, -32(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_64_or_more_forward): + cmpl $128, %ecx + ja L(mm_len_128_or_more_forward) + +/* Copy [0..128] and return. */ + movdqu (%eax), %xmm0 + movdqu 16(%eax), %xmm1 + movdqu 32(%eax), %xmm2 + movdqu 48(%eax), %xmm3 + movdqu -64(%eax, %ecx), %xmm4 + movdqu -48(%eax, %ecx), %xmm5 + movdqu -32(%eax, %ecx), %xmm6 + movdqu -16(%eax, %ecx), %xmm7 + movdqu %xmm0, (%edx) + movdqu %xmm1, 16(%edx) + movdqu %xmm2, 32(%edx) + movdqu %xmm3, 48(%edx) + movdqu %xmm4, -64(%edx, %ecx) + movdqu %xmm5, -48(%edx, %ecx) + movdqu %xmm6, -32(%edx, %ecx) + movdqu %xmm7, -16(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_128_or_more_forward): + PUSH (%esi) + PUSH (%edi) + +/* Aligning the address of destination. */ + movdqu (%eax), %xmm0 + movdqu 16(%eax), %xmm1 + movdqu 32(%eax), %xmm2 + movdqu 48(%eax), %xmm3 + + leal 64(%edx), %edi + andl $-64, %edi + subl %edx, %eax + + movdqu (%eax, %edi), %xmm4 + movdqu 16(%eax, %edi), %xmm5 + movdqu 32(%eax, %edi), %xmm6 + movdqu 48(%eax, %edi), %xmm7 + + movdqu %xmm0, (%edx) + movdqu %xmm1, 16(%edx) + movdqu %xmm2, 32(%edx) + movdqu %xmm3, 48(%edx) + movdqa %xmm4, (%edi) + movaps %xmm5, 16(%edi) + movaps %xmm6, 32(%edi) + movaps %xmm7, 48(%edi) + addl $64, %edi + + leal (%edx, %ecx), %ebx + andl $-64, %ebx + cmp %edi, %ebx + jbe L(mm_copy_remaining_forward) + + cmp $SHARED_CACHE_SIZE_HALF, %ecx + jae L(mm_large_page_loop_forward) + + .p2align 4 +L(mm_main_loop_forward): + + prefetcht0 128(%eax, %edi) + + movdqu (%eax, %edi), %xmm0 + movdqu 16(%eax, %edi), %xmm1 + movdqu 32(%eax, %edi), %xmm2 + movdqu 48(%eax, %edi), %xmm3 + movdqa %xmm0, (%edi) + movaps %xmm1, 16(%edi) + movaps %xmm2, 32(%edi) + movaps %xmm3, 48(%edi) + leal 64(%edi), %edi + cmp %edi, %ebx + ja L(mm_main_loop_forward) + +L(mm_copy_remaining_forward): + addl %edx, %ecx + subl %edi, %ecx +/* We copied all up till %edi position in the dst. + In %ecx now is how many bytes are left to copy. + Now we need to advance %esi. */ + leal (%edi, %eax), %esi + +L(mm_remaining_0_64_bytes_forward): + cmp $32, %ecx + ja L(mm_remaining_33_64_bytes_forward) + cmp $16, %ecx + ja L(mm_remaining_17_32_bytes_forward) + testl %ecx, %ecx + .p2align 4,,2 + je L(mm_return_pop_all) + + cmpb $8, %cl + ja L(mm_remaining_9_16_bytes_forward) + cmpb $4, %cl + .p2align 4,,5 + ja L(mm_remaining_5_8_bytes_forward) + cmpb $2, %cl + .p2align 4,,1 + ja L(mm_remaining_3_4_bytes_forward) + movzbl -1(%esi,%ecx), %eax + movzbl (%esi), %ebx + movb %al, -1(%edi,%ecx) + movb %bl, (%edi) + jmp L(mm_return_pop_all) + +L(mm_remaining_33_64_bytes_forward): + movdqu (%esi), %xmm0 + movdqu 16(%esi), %xmm1 + movdqu -32(%esi, %ecx), %xmm2 + movdqu -16(%esi, %ecx), %xmm3 + movdqu %xmm0, (%edi) + movdqu %xmm1, 16(%edi) + movdqu %xmm2, -32(%edi, %ecx) + movdqu %xmm3, -16(%edi, %ecx) + jmp L(mm_return_pop_all) + +L(mm_remaining_17_32_bytes_forward): + movdqu (%esi), %xmm0 + movdqu -16(%esi, %ecx), %xmm1 + movdqu %xmm0, (%edi) + movdqu %xmm1, -16(%edi, %ecx) + jmp L(mm_return_pop_all) + +L(mm_remaining_9_16_bytes_forward): + movq (%esi), %xmm0 + movq -8(%esi, %ecx), %xmm1 + movq %xmm0, (%edi) + movq %xmm1, -8(%edi, %ecx) + jmp L(mm_return_pop_all) + +L(mm_remaining_5_8_bytes_forward): + movl (%esi), %eax + movl -4(%esi,%ecx), %ebx + movl %eax, (%edi) + movl %ebx, -4(%edi,%ecx) + jmp L(mm_return_pop_all) + +L(mm_remaining_3_4_bytes_forward): + movzwl -2(%esi,%ecx), %eax + movzwl (%esi), %ebx + movw %ax, -2(%edi,%ecx) + movw %bx, (%edi) + jmp L(mm_return_pop_all) + +L(mm_len_0_16_bytes_forward): + testb $24, %cl + jne L(mm_len_9_16_bytes_forward) + testb $4, %cl + .p2align 4,,5 + jne L(mm_len_5_8_bytes_forward) + testl %ecx, %ecx + .p2align 4,,2 + je L(mm_return) + testb $2, %cl + .p2align 4,,1 + jne L(mm_len_2_4_bytes_forward) + movzbl -1(%eax,%ecx), %ebx + movzbl (%eax), %eax + movb %bl, -1(%edx,%ecx) + movb %al, (%edx) + jmp L(mm_return) + +L(mm_len_2_4_bytes_forward): + movzwl -2(%eax,%ecx), %ebx + movzwl (%eax), %eax + movw %bx, -2(%edx,%ecx) + movw %ax, (%edx) + jmp L(mm_return) + +L(mm_len_5_8_bytes_forward): + movl (%eax), %ebx + movl -4(%eax,%ecx), %eax + movl %ebx, (%edx) + movl %eax, -4(%edx,%ecx) + jmp L(mm_return) + +L(mm_len_9_16_bytes_forward): + movq (%eax), %xmm0 + movq -8(%eax, %ecx), %xmm1 + movq %xmm0, (%edx) + movq %xmm1, -8(%edx, %ecx) + jmp L(mm_return) + + CFI_POP (%edi) + CFI_POP (%esi) + +L(mm_recalc_len): +/* Compute in %ecx how many bytes are left to copy after + the main loop stops. */ + movl %ebx, %ecx + subl %edx, %ecx +/* The code for copying backwards. */ +L(mm_len_0_or_more_backward): + +/* Now do checks for lengths. We do [0..16], [16..32], [32..64], [64..128] + separately. */ + cmp $16, %ecx + jbe L(mm_len_0_16_bytes_backward) + + cmpl $32, %ecx + jg L(mm_len_32_or_more_backward) + +/* Copy [0..32] and return. */ + movdqu (%eax), %xmm0 + movdqu -16(%eax, %ecx), %xmm1 + movdqu %xmm0, (%edx) + movdqu %xmm1, -16(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_32_or_more_backward): + cmpl $64, %ecx + jg L(mm_len_64_or_more_backward) + +/* Copy [0..64] and return. */ + movdqu (%eax), %xmm0 + movdqu 16(%eax), %xmm1 + movdqu -16(%eax, %ecx), %xmm2 + movdqu -32(%eax, %ecx), %xmm3 + movdqu %xmm0, (%edx) + movdqu %xmm1, 16(%edx) + movdqu %xmm2, -16(%edx, %ecx) + movdqu %xmm3, -32(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_64_or_more_backward): + cmpl $128, %ecx + jg L(mm_len_128_or_more_backward) + +/* Copy [0..128] and return. */ + movdqu (%eax), %xmm0 + movdqu 16(%eax), %xmm1 + movdqu 32(%eax), %xmm2 + movdqu 48(%eax), %xmm3 + movdqu -64(%eax, %ecx), %xmm4 + movdqu -48(%eax, %ecx), %xmm5 + movdqu -32(%eax, %ecx), %xmm6 + movdqu -16(%eax, %ecx), %xmm7 + movdqu %xmm0, (%edx) + movdqu %xmm1, 16(%edx) + movdqu %xmm2, 32(%edx) + movdqu %xmm3, 48(%edx) + movdqu %xmm4, -64(%edx, %ecx) + movdqu %xmm5, -48(%edx, %ecx) + movdqu %xmm6, -32(%edx, %ecx) + movdqu %xmm7, -16(%edx, %ecx) + jmp L(mm_return) + +L(mm_len_128_or_more_backward): + PUSH (%esi) + PUSH (%edi) + +/* Aligning the address of destination. We need to save + 16 bits from the source in order not to overwrite them. */ + movdqu -16(%eax, %ecx), %xmm0 + movdqu -32(%eax, %ecx), %xmm1 + movdqu -48(%eax, %ecx), %xmm2 + movdqu -64(%eax, %ecx), %xmm3 + + leal (%edx, %ecx), %edi + andl $-64, %edi + + movl %eax, %esi + subl %edx, %esi + + movdqu -16(%edi, %esi), %xmm4 + movdqu -32(%edi, %esi), %xmm5 + movdqu -48(%edi, %esi), %xmm6 + movdqu -64(%edi, %esi), %xmm7 + + movdqu %xmm0, -16(%edx, %ecx) + movdqu %xmm1, -32(%edx, %ecx) + movdqu %xmm2, -48(%edx, %ecx) + movdqu %xmm3, -64(%edx, %ecx) + movdqa %xmm4, -16(%edi) + movdqa %xmm5, -32(%edi) + movdqa %xmm6, -48(%edi) + movdqa %xmm7, -64(%edi) + leal -64(%edi), %edi + + leal 64(%edx), %ebx + andl $-64, %ebx + + cmp %edi, %ebx + jae L(mm_main_loop_backward_end) + + cmp $SHARED_CACHE_SIZE_HALF, %ecx + jae L(mm_large_page_loop_backward) + + .p2align 4 +L(mm_main_loop_backward): + + prefetcht0 -128(%edi, %esi) + + movdqu -64(%edi, %esi), %xmm0 + movdqu -48(%edi, %esi), %xmm1 + movdqu -32(%edi, %esi), %xmm2 + movdqu -16(%edi, %esi), %xmm3 + movdqa %xmm0, -64(%edi) + movdqa %xmm1, -48(%edi) + movdqa %xmm2, -32(%edi) + movdqa %xmm3, -16(%edi) + leal -64(%edi), %edi + cmp %edi, %ebx + jb L(mm_main_loop_backward) +L(mm_main_loop_backward_end): + POP (%edi) + POP (%esi) + jmp L(mm_recalc_len) + +/* Copy [0..16] and return. */ +L(mm_len_0_16_bytes_backward): + testb $24, %cl + jnz L(mm_len_9_16_bytes_backward) + testb $4, %cl + .p2align 4,,5 + jnz L(mm_len_5_8_bytes_backward) + testl %ecx, %ecx + .p2align 4,,2 + je L(mm_return) + testb $2, %cl + .p2align 4,,1 + jne L(mm_len_3_4_bytes_backward) + movzbl -1(%eax,%ecx), %ebx + movzbl (%eax), %eax + movb %bl, -1(%edx,%ecx) + movb %al, (%edx) + jmp L(mm_return) + +L(mm_len_3_4_bytes_backward): + movzwl -2(%eax,%ecx), %ebx + movzwl (%eax), %eax + movw %bx, -2(%edx,%ecx) + movw %ax, (%edx) + jmp L(mm_return) + +L(mm_len_9_16_bytes_backward): + PUSH (%esi) + movl -4(%eax,%ecx), %ebx + movl -8(%eax,%ecx), %esi + movl %ebx, -4(%edx,%ecx) + movl %esi, -8(%edx,%ecx) + subl $8, %ecx + POP (%esi) + jmp L(mm_len_0_16_bytes_backward) + +L(mm_len_5_8_bytes_backward): + movl (%eax), %ebx + movl -4(%eax,%ecx), %eax + movl %ebx, (%edx) + movl %eax, -4(%edx,%ecx) + +L(mm_return): + movl %edx, %eax + RETURN + +L(mm_return_pop_all): + movl %edx, %eax + POP (%edi) + POP (%esi) + RETURN + +/* Big length copy forward part. */ + + .p2align 4 +L(mm_large_page_loop_forward): + movdqu (%eax, %edi), %xmm0 + movdqu 16(%eax, %edi), %xmm1 + movdqu 32(%eax, %edi), %xmm2 + movdqu 48(%eax, %edi), %xmm3 + movntdq %xmm0, (%edi) + movntdq %xmm1, 16(%edi) + movntdq %xmm2, 32(%edi) + movntdq %xmm3, 48(%edi) + leal 64(%edi), %edi + cmp %edi, %ebx + ja L(mm_large_page_loop_forward) + sfence + jmp L(mm_copy_remaining_forward) + +/* Big length copy backward part. */ + .p2align 4 +L(mm_large_page_loop_backward): + movdqu -64(%edi, %esi), %xmm0 + movdqu -48(%edi, %esi), %xmm1 + movdqu -32(%edi, %esi), %xmm2 + movdqu -16(%edi, %esi), %xmm3 + movntdq %xmm0, -64(%edi) + movntdq %xmm1, -48(%edi) + movntdq %xmm2, -32(%edi) + movntdq %xmm3, -16(%edi) + leal -64(%edi), %edi + cmp %edi, %ebx + jb L(mm_large_page_loop_backward) + sfence + POP (%edi) + POP (%esi) + jmp L(mm_recalc_len) + +END (MEMMOVE) diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memset-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memset-slm.S new file mode 100644 index 000000000..adaccae10 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-memset-slm.S @@ -0,0 +1,761 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 + +#include "cache.h" + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#define CFI_PUSH(REG) \ + .cfi_adjust_cfa_offset 4; \ + .cfi_rel_offset REG, 0 + +#define CFI_POP(REG) \ + .cfi_adjust_cfa_offset -4; \ + .cfi_restore REG + +#define PUSH(REG) pushl REG; CFI_PUSH(REG) +#define POP(REG) popl REG; CFI_POP(REG) + +#define PARMS 8 /* Preserve EBX. */ +#define DST PARMS +#define CHR (DST+4) +#define LEN (CHR+4) +#define CHK_DST_LEN (LEN+4) +#define SETRTNVAL movl DST(%esp), %eax + +# define ENTRANCE PUSH(%ebx); +# define RETURN_END POP(%ebx); ret +# define RETURN RETURN_END; CFI_PUSH(%ebx) +# define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \ + /* We first load PC into EBX. */ \ + call __x86.get_pc_thunk.bx; \ + /* Get the address of the jump table. */ \ + add $(TABLE - .), %ebx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + add (%ebx,%ecx,4), %ebx; \ + add %ecx, %edx; \ + /* We loaded the jump table and adjusted EDX. Go. */ \ + jmp *%ebx + + .section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + ALIGN(4) + .type __x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret + +ENTRY(__memset_chk_generic) + ENTRANCE + + movl LEN(%esp), %ecx + cmpl CHK_DST_LEN(%esp), %ecx + jna L(memset_length_loaded) + + POP(%ebx) // Undo ENTRANCE without returning. + jmp __memset_chk_fail +END(__memset_chk_generic) + + .section .text.sse2,"ax",@progbits + ALIGN(4) +ENTRY(memset_generic) + ENTRANCE + + movl LEN(%esp), %ecx +L(memset_length_loaded): + cmp $0, %ecx + ja L(1byteormore) + SETRTNVAL + RETURN + +L(1byteormore): + movzbl CHR(%esp), %eax + movb %al, %ah + /* Fill the whole EAX with pattern. */ + movl %eax, %edx + shl $16, %eax + or %edx, %eax + movl DST(%esp), %edx + cmp $1, %ecx + je L(1byte) + cmp $16, %ecx + jae L(16bytesormore) + + cmp $4, %ecx + jb L(4bytesless) + movl %eax, (%edx) + movl %eax, -4(%edx, %ecx) + cmp $8, %ecx + jb L(8bytesless) + movl %eax, 4(%edx) + movl %eax, -8(%edx, %ecx) +L(8bytesless): + SETRTNVAL + RETURN + +L(4bytesless): + movw %ax, (%edx) + movw %ax, -2(%edx, %ecx) + SETRTNVAL + RETURN + +L(1byte): + movb %al, (%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(16bytesormore): + movd %eax, %xmm0 + pshufd $0, %xmm0, %xmm0 + + cmp $64, %ecx + ja L(64bytesmore) + movdqu %xmm0, (%edx) + movdqu %xmm0, -16(%edx, %ecx) + cmp $32, %ecx + jbe L(32bytesless) + movdqu %xmm0, 16(%edx) + movdqu %xmm0, -32(%edx, %ecx) +L(32bytesless): + SETRTNVAL + RETURN + +L(64bytesmore): + testl $0xf, %edx + jz L(aligned_16) +L(not_aligned_16): + movdqu %xmm0, (%edx) + movl %edx, %eax + and $-16, %edx + add $16, %edx + sub %edx, %eax + add %eax, %ecx + movd %xmm0, %eax + + ALIGN(4) +L(aligned_16): + cmp $128, %ecx + jae L(128bytesormore) + +L(aligned_16_less128bytes): + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + ALIGN(4) +L(128bytesormore): + PUSH(%ebx) + mov $SHARED_CACHE_SIZE, %ebx + cmp %ebx, %ecx + jae L(128bytesormore_nt_start) + + POP(%ebx) + + PUSH(%ebx) + mov $DATA_CACHE_SIZE, %ebx + + cmp %ebx, %ecx + jae L(128bytes_L2_normal) + subl $128, %ecx +L(128bytesormore_normal): + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jb L(128bytesless_normal) + + + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + lea 128(%edx), %edx + jae L(128bytesormore_normal) + +L(128bytesless_normal): + lea 128(%ecx), %ecx + POP(%ebx) + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + ALIGN(4) +L(128bytes_L2_normal): + prefetchnta 0x380(%edx) + prefetchnta 0x3c0(%edx) + sub $128, %ecx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + add $128, %edx + cmp $128, %ecx + jae L(128bytes_L2_normal) + +L(128bytesless_L2_normal): + POP(%ebx) + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + +L(128bytesormore_nt_start): + sub %ebx, %ecx + ALIGN(4) +L(128bytesormore_shared_cache_loop): + prefetchnta 0x3c0(%edx) + prefetchnta 0x380(%edx) + sub $0x80, %ebx + movdqa %xmm0, (%edx) + movaps %xmm0, 0x10(%edx) + movaps %xmm0, 0x20(%edx) + movaps %xmm0, 0x30(%edx) + movaps %xmm0, 0x40(%edx) + movaps %xmm0, 0x50(%edx) + movaps %xmm0, 0x60(%edx) + movaps %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ebx + jae L(128bytesormore_shared_cache_loop) + cmp $0x80, %ecx + jb L(shared_cache_loop_end) + ALIGN(4) +L(128bytesormore_nt): + sub $0x80, %ecx + movntdq %xmm0, (%edx) + movntdq %xmm0, 0x10(%edx) + movntdq %xmm0, 0x20(%edx) + movntdq %xmm0, 0x30(%edx) + movntdq %xmm0, 0x40(%edx) + movntdq %xmm0, 0x50(%edx) + movntdq %xmm0, 0x60(%edx) + movntdq %xmm0, 0x70(%edx) + add $0x80, %edx + cmp $0x80, %ecx + jae L(128bytesormore_nt) + sfence +L(shared_cache_loop_end): + POP(%ebx) + BRANCH_TO_JMPTBL_ENTRY(L(table_16_128bytes)) + + + .pushsection .rodata.sse2,"a",@progbits + ALIGN(2) +L(table_16_128bytes): + .int JMPTBL(L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_1bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_2bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_3bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_5bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_6bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_7bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_9bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_10bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_11bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_13bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_14bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_15bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_17bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_18bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_19bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_21bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_22bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_23bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_25bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_26bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_27bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_29bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_30bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_31bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_33bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_34bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_35bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_37bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_38bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_39bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_41bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_42bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_43bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_45bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_46bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_47bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_49bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_50bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_51bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_53bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_54bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_55bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_57bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_58bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_59bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_61bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_62bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_63bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_65bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_66bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_67bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_69bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_70bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_71bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_73bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_74bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_75bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_77bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_78bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_79bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_81bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_82bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_83bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_85bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_86bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_87bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_89bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_90bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_91bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_93bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_94bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_95bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_97bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_98bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_99bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_101bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_102bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_103bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_105bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_106bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_107bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_109bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_110bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_111bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_113bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_114bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_115bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_117bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_118bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_119bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_121bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_122bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_123bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_124bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_125bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_126bytes), L(table_16_128bytes)) + .int JMPTBL(L(aligned_16_127bytes), L(table_16_128bytes)) + .popsection + + ALIGN(4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%edx) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%edx) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%edx) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%edx) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%edx) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%edx) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%edx) +L(aligned_16_0bytes): + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_113bytes): + movdqa %xmm0, -113(%edx) +L(aligned_16_97bytes): + movdqa %xmm0, -97(%edx) +L(aligned_16_81bytes): + movdqa %xmm0, -81(%edx) +L(aligned_16_65bytes): + movdqa %xmm0, -65(%edx) +L(aligned_16_49bytes): + movdqa %xmm0, -49(%edx) +L(aligned_16_33bytes): + movdqa %xmm0, -33(%edx) +L(aligned_16_17bytes): + movdqa %xmm0, -17(%edx) +L(aligned_16_1bytes): + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_114bytes): + movdqa %xmm0, -114(%edx) +L(aligned_16_98bytes): + movdqa %xmm0, -98(%edx) +L(aligned_16_82bytes): + movdqa %xmm0, -82(%edx) +L(aligned_16_66bytes): + movdqa %xmm0, -66(%edx) +L(aligned_16_50bytes): + movdqa %xmm0, -50(%edx) +L(aligned_16_34bytes): + movdqa %xmm0, -34(%edx) +L(aligned_16_18bytes): + movdqa %xmm0, -18(%edx) +L(aligned_16_2bytes): + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_115bytes): + movdqa %xmm0, -115(%edx) +L(aligned_16_99bytes): + movdqa %xmm0, -99(%edx) +L(aligned_16_83bytes): + movdqa %xmm0, -83(%edx) +L(aligned_16_67bytes): + movdqa %xmm0, -67(%edx) +L(aligned_16_51bytes): + movdqa %xmm0, -51(%edx) +L(aligned_16_35bytes): + movdqa %xmm0, -35(%edx) +L(aligned_16_19bytes): + movdqa %xmm0, -19(%edx) +L(aligned_16_3bytes): + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%edx) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%edx) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%edx) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%edx) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%edx) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%edx) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%edx) +L(aligned_16_4bytes): + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_117bytes): + movdqa %xmm0, -117(%edx) +L(aligned_16_101bytes): + movdqa %xmm0, -101(%edx) +L(aligned_16_85bytes): + movdqa %xmm0, -85(%edx) +L(aligned_16_69bytes): + movdqa %xmm0, -69(%edx) +L(aligned_16_53bytes): + movdqa %xmm0, -53(%edx) +L(aligned_16_37bytes): + movdqa %xmm0, -37(%edx) +L(aligned_16_21bytes): + movdqa %xmm0, -21(%edx) +L(aligned_16_5bytes): + movl %eax, -5(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_118bytes): + movdqa %xmm0, -118(%edx) +L(aligned_16_102bytes): + movdqa %xmm0, -102(%edx) +L(aligned_16_86bytes): + movdqa %xmm0, -86(%edx) +L(aligned_16_70bytes): + movdqa %xmm0, -70(%edx) +L(aligned_16_54bytes): + movdqa %xmm0, -54(%edx) +L(aligned_16_38bytes): + movdqa %xmm0, -38(%edx) +L(aligned_16_22bytes): + movdqa %xmm0, -22(%edx) +L(aligned_16_6bytes): + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_119bytes): + movdqa %xmm0, -119(%edx) +L(aligned_16_103bytes): + movdqa %xmm0, -103(%edx) +L(aligned_16_87bytes): + movdqa %xmm0, -87(%edx) +L(aligned_16_71bytes): + movdqa %xmm0, -71(%edx) +L(aligned_16_55bytes): + movdqa %xmm0, -55(%edx) +L(aligned_16_39bytes): + movdqa %xmm0, -39(%edx) +L(aligned_16_23bytes): + movdqa %xmm0, -23(%edx) +L(aligned_16_7bytes): + movl %eax, -7(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%edx) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%edx) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%edx) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%edx) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%edx) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%edx) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%edx) +L(aligned_16_8bytes): + movq %xmm0, -8(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_121bytes): + movdqa %xmm0, -121(%edx) +L(aligned_16_105bytes): + movdqa %xmm0, -105(%edx) +L(aligned_16_89bytes): + movdqa %xmm0, -89(%edx) +L(aligned_16_73bytes): + movdqa %xmm0, -73(%edx) +L(aligned_16_57bytes): + movdqa %xmm0, -57(%edx) +L(aligned_16_41bytes): + movdqa %xmm0, -41(%edx) +L(aligned_16_25bytes): + movdqa %xmm0, -25(%edx) +L(aligned_16_9bytes): + movq %xmm0, -9(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_122bytes): + movdqa %xmm0, -122(%edx) +L(aligned_16_106bytes): + movdqa %xmm0, -106(%edx) +L(aligned_16_90bytes): + movdqa %xmm0, -90(%edx) +L(aligned_16_74bytes): + movdqa %xmm0, -74(%edx) +L(aligned_16_58bytes): + movdqa %xmm0, -58(%edx) +L(aligned_16_42bytes): + movdqa %xmm0, -42(%edx) +L(aligned_16_26bytes): + movdqa %xmm0, -26(%edx) +L(aligned_16_10bytes): + movq %xmm0, -10(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_123bytes): + movdqa %xmm0, -123(%edx) +L(aligned_16_107bytes): + movdqa %xmm0, -107(%edx) +L(aligned_16_91bytes): + movdqa %xmm0, -91(%edx) +L(aligned_16_75bytes): + movdqa %xmm0, -75(%edx) +L(aligned_16_59bytes): + movdqa %xmm0, -59(%edx) +L(aligned_16_43bytes): + movdqa %xmm0, -43(%edx) +L(aligned_16_27bytes): + movdqa %xmm0, -27(%edx) +L(aligned_16_11bytes): + movq %xmm0, -11(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%edx) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%edx) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%edx) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%edx) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%edx) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%edx) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%edx) +L(aligned_16_12bytes): + movq %xmm0, -12(%edx) + movl %eax, -4(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_125bytes): + movdqa %xmm0, -125(%edx) +L(aligned_16_109bytes): + movdqa %xmm0, -109(%edx) +L(aligned_16_93bytes): + movdqa %xmm0, -93(%edx) +L(aligned_16_77bytes): + movdqa %xmm0, -77(%edx) +L(aligned_16_61bytes): + movdqa %xmm0, -61(%edx) +L(aligned_16_45bytes): + movdqa %xmm0, -45(%edx) +L(aligned_16_29bytes): + movdqa %xmm0, -29(%edx) +L(aligned_16_13bytes): + movq %xmm0, -13(%edx) + movl %eax, -5(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_126bytes): + movdqa %xmm0, -126(%edx) +L(aligned_16_110bytes): + movdqa %xmm0, -110(%edx) +L(aligned_16_94bytes): + movdqa %xmm0, -94(%edx) +L(aligned_16_78bytes): + movdqa %xmm0, -78(%edx) +L(aligned_16_62bytes): + movdqa %xmm0, -62(%edx) +L(aligned_16_46bytes): + movdqa %xmm0, -46(%edx) +L(aligned_16_30bytes): + movdqa %xmm0, -30(%edx) +L(aligned_16_14bytes): + movq %xmm0, -14(%edx) + movl %eax, -6(%edx) + movw %ax, -2(%edx) + SETRTNVAL + RETURN + + ALIGN(4) +L(aligned_16_127bytes): + movdqa %xmm0, -127(%edx) +L(aligned_16_111bytes): + movdqa %xmm0, -111(%edx) +L(aligned_16_95bytes): + movdqa %xmm0, -95(%edx) +L(aligned_16_79bytes): + movdqa %xmm0, -79(%edx) +L(aligned_16_63bytes): + movdqa %xmm0, -63(%edx) +L(aligned_16_47bytes): + movdqa %xmm0, -47(%edx) +L(aligned_16_31bytes): + movdqa %xmm0, -31(%edx) +L(aligned_16_15bytes): + movq %xmm0, -15(%edx) + movl %eax, -7(%edx) + movw %ax, -3(%edx) + movb %al, -1(%edx) + SETRTNVAL + RETURN_END + +END(memset_generic) diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpcpy-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpcpy-slm.S new file mode 100755 index 000000000..5c43fa50c --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpcpy-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STPCPY +#define STRCPY stpcpy +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpncpy-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpncpy-slm.S new file mode 100644 index 000000000..af5c0d362 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-stpncpy-slm.S @@ -0,0 +1,34 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define USE_AS_STPCPY +#define STRCPY stpncpy +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S new file mode 100755 index 000000000..22ceeab68 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strcpy-slm.S @@ -0,0 +1,2157 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#ifndef STRCPY +# define STRCPY strcpy_generic +#endif + +#ifdef USE_AS_STPNCPY +# define USE_AS_STRNCPY +# define USE_AS_STPCPY +#endif + +#ifdef USE_AS_STRNCPY +# define PARMS 16 +# define ENTRANCE PUSH(%ebx); PUSH(%esi); PUSH(%edi) +# define RETURN POP(%edi); POP(%esi); POP(%ebx); ret; CFI_PUSH(%ebx); CFI_PUSH(%edi); CFI_PUSH(%edi); +#else +# define PARMS 12 +# define ENTRANCE PUSH(%esi); PUSH(%edi) +# define RETURN POP(%edi); POP(%esi); ret; CFI_PUSH(%esi); CFI_PUSH(%edi); +#endif + +#define STR1 PARMS +#define STR2 STR1+4 +#define LEN STR2+4 + + +#if (defined SHARED || defined __PIC__) +# define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into ECX and branch to it. TABLE is a + jump table with relative offsets. INDEX is a register contains the + index into the jump table. SCALE is the scale of INDEX. */ + +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + /* We first load PC into ECX. */ \ + call __x86.get_pc_thunk.cx; \ + /* Get the address of the jump table. */ \ + addl $(TABLE - .), %ecx; \ + /* Get the entry and convert the relative offset to the \ + absolute address. */ \ + addl (%ecx,INDEX,SCALE), %ecx; \ + /* We loaded the jump table and adjuested ECX. Go. */ \ + jmp *%ecx +#else +# define JMPTBL(I, B) I + +/* Branch to an entry in a jump table. TABLE is a jump table with + absolute offsets. INDEX is a register contains the index into the + jump table. SCALE is the scale of INDEX. */ + +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + jmp *TABLE(,INDEX,SCALE) +#endif + +.text +ENTRY (STRCPY) + ENTRANCE + mov STR1(%esp), %edi + mov STR2(%esp), %esi +#ifdef USE_AS_STRNCPY + movl LEN(%esp), %ebx + test %ebx, %ebx + jz L(ExitZero) +#endif + + mov %esi, %ecx +#ifndef USE_AS_STPCPY + mov %edi, %eax /* save result */ +#endif + and $15, %ecx + jz L(SourceStringAlignmentZero) + + and $-16, %esi + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + + pcmpeqb (%esi), %xmm1 +#ifdef USE_AS_STRNCPY + add %ecx, %ebx +#endif + pmovmskb %xmm1, %edx + shr %cl, %edx +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + cmp $16, %ebx + jbe L(CopyFrom1To16BytesTailCase2OrCase3) +#else + cmp $17, %ebx + jbe L(CopyFrom1To16BytesTailCase2OrCase3) +#endif +#endif + test %edx, %edx + jnz L(CopyFrom1To16BytesTail) + + pcmpeqb 16(%esi), %xmm0 + pmovmskb %xmm0, %edx +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + cmp $32, %ebx + jbe L(CopyFrom1To32BytesCase2OrCase3) +#else + cmp $33, %ebx + jbe L(CopyFrom1To32BytesCase2OrCase3) +#endif +#endif + test %edx, %edx + jnz L(CopyFrom1To32Bytes) + + movdqu (%esi, %ecx), %xmm1 /* copy 16 bytes */ + movdqu %xmm1, (%edi) + + sub %ecx, %edi + mov %edi, %edx + mov $16, %ecx + and $15, %edx + jz L(Align16Both) + +/* If source adress alignment != destination adress alignment */ + .p2align 4 +L(Unalign16Both): + movdqa (%esi, %ecx), %xmm1 + movaps 16(%esi, %ecx), %xmm2 + movdqu %xmm1, (%edi, %ecx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $48, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm2) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%esi, %ecx), %xmm3 + movdqu %xmm2, (%edi, %ecx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm3) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%esi, %ecx), %xmm4 + movdqu %xmm3, (%edi, %ecx) + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm4) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%esi, %ecx), %xmm1 + movdqu %xmm4, (%edi, %ecx) + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm1) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%esi, %ecx), %xmm2 + movdqu %xmm1, (%edi, %ecx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm2) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%esi, %ecx), %xmm3 + movdqu %xmm2, (%edi, %ecx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm3) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqu %xmm3, (%edi, %ecx) + mov %esi, %edx + lea 16(%esi, %ecx), %esi + and $-0x40, %esi + sub %esi, %edx + sub %edx, %edi +#ifdef USE_AS_STRNCPY + lea 64+64(%ebx, %edx), %ebx +#endif +L(Unaligned64Loop): + movaps (%esi), %xmm2 + movaps %xmm2, %xmm4 + movaps 16(%esi), %xmm5 + movaps 32(%esi), %xmm3 + movaps %xmm3, %xmm6 + movaps 48(%esi), %xmm7 + pminub %xmm5, %xmm2 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm0, %xmm3 + pmovmskb %xmm3, %edx +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(UnalignedLeaveCase2OrCase3) +#endif + test %edx, %edx + jnz L(Unaligned64Leave) + +L(Unaligned64Loop_start): + add $64, %edi + add $64, %esi + movdqu %xmm4, -64(%edi) + movaps (%esi), %xmm2 + movdqa %xmm2, %xmm4 + movdqu %xmm5, -48(%edi) + movaps 16(%esi), %xmm5 + pminub %xmm5, %xmm2 + movaps 32(%esi), %xmm3 + movdqu %xmm6, -32(%edi) + movaps %xmm3, %xmm6 + movdqu %xmm7, -16(%edi) + movaps 48(%esi), %xmm7 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(UnalignedLeaveCase2OrCase3) +#endif + test %edx, %edx + jz L(Unaligned64Loop_start) + +L(Unaligned64Leave): + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + + pcmpeqb %xmm4, %xmm0 + pcmpeqb %xmm5, %xmm1 + pmovmskb %xmm0, %edx + pmovmskb %xmm1, %ecx + test %edx, %edx + jnz L(CopyFrom1To16BytesUnaligned_0) + test %ecx, %ecx + jnz L(CopyFrom1To16BytesUnaligned_16) + + pcmpeqb %xmm6, %xmm0 + pcmpeqb %xmm7, %xmm1 + pmovmskb %xmm0, %edx + pmovmskb %xmm1, %ecx + test %edx, %edx + jnz L(CopyFrom1To16BytesUnaligned_32) + + bsf %ecx, %edx + movdqu %xmm4, (%edi) + movdqu %xmm5, 16(%edi) + movdqu %xmm6, 32(%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 48(%edi, %edx), %eax +#endif + movdqu %xmm7, 48(%edi) + add $15, %ebx + sub %edx, %ebx + lea 49(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $48, %esi + add $48, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + +/* If source adress alignment == destination adress alignment */ + +L(SourceStringAlignmentZero): + pxor %xmm0, %xmm0 + movdqa (%esi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %edx + +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + cmp $16, %ebx + jbe L(CopyFrom1To16BytesTail1Case2OrCase3) +#else + cmp $17, %ebx + jbe L(CopyFrom1To16BytesTail1Case2OrCase3) +#endif +#endif + test %edx, %edx + jnz L(CopyFrom1To16BytesTail1) + + pcmpeqb 16(%esi), %xmm0 + movdqu %xmm1, (%edi) + pmovmskb %xmm0, %edx + +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + cmp $32, %ebx + jbe L(CopyFrom1To32Bytes1Case2OrCase3) +#else + cmp $33, %ebx + jbe L(CopyFrom1To32Bytes1Case2OrCase3) +#endif +#endif + test %edx, %edx + jnz L(CopyFrom1To32Bytes1) + + mov %edi, %edx + mov $16, %ecx + and $15, %edx + jnz L(Unalign16Both) + +L(Align16Both): + movdqa (%esi, %ecx), %xmm1 + movdqa 16(%esi, %ecx), %xmm2 + movdqa %xmm1, (%edi, %ecx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %edx + add $16, %ecx +#ifdef USE_AS_STRNCPY + sub $48, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm2) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa 16(%esi, %ecx), %xmm3 + movdqa %xmm2, (%edi, %ecx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm3) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa 16(%esi, %ecx), %xmm4 + movdqa %xmm3, (%edi, %ecx) + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %edx + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm4) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa 16(%esi, %ecx), %xmm1 + movdqa %xmm4, (%edi, %ecx) + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %edx + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm1) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa 16(%esi, %ecx), %xmm2 + movdqa %xmm1, (%edi, %ecx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %edx + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm2) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa 16(%esi, %ecx), %xmm3 + movdqa %xmm2, (%edi, %ecx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx + lea 16(%ecx), %ecx +#ifdef USE_AS_STRNCPY + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm3) +#else + test %edx, %edx + jnz L(CopyFrom1To16Bytes) +#endif + + movdqa %xmm3, (%edi, %ecx) + mov %esi, %edx + lea 16(%esi, %ecx), %esi + and $-0x40, %esi + sub %esi, %edx + sub %edx, %edi +#ifdef USE_AS_STRNCPY + lea 64+64(%ebx, %edx), %ebx +#endif +L(Aligned64Loop): + movdqa (%esi), %xmm2 + movdqa %xmm2, %xmm4 + movaps 16(%esi), %xmm5 + movdqa 32(%esi), %xmm3 + movdqa %xmm3, %xmm6 + movaps 48(%esi), %xmm7 + pminub %xmm5, %xmm2 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm0, %xmm3 + pmovmskb %xmm3, %edx +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(AlignedLeaveCase2OrCase3) +#endif + test %edx, %edx + jnz L(Aligned64Leave) + +L(Aligned64Loop_start): + add $64, %esi + add $64, %edi + movaps %xmm4, -64(%edi) + movdqa (%esi), %xmm2 + movdqa %xmm2, %xmm4 + movaps %xmm5, -48(%edi) + movaps 16(%esi), %xmm5 + pminub %xmm5, %xmm2 + movaps 32(%esi), %xmm3 + movaps %xmm6, -32(%edi) + movdqa %xmm3, %xmm6 + movaps %xmm7, -16(%edi) + movaps 48(%esi), %xmm7 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %edx +#ifdef USE_AS_STRNCPY + sub $64, %ebx + jbe L(AlignedLeaveCase2OrCase3) +#endif + test %edx, %edx + jz L(Aligned64Loop_start) + +L(Aligned64Leave): + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + + pcmpeqb %xmm4, %xmm0 + pcmpeqb %xmm5, %xmm1 + pmovmskb %xmm0, %edx + pmovmskb %xmm1, %ecx + test %edx, %edx + jnz L(CopyFrom1To16Bytes_0) + test %ecx, %ecx + jnz L(CopyFrom1To16Bytes_16) + + pcmpeqb %xmm6, %xmm0 + pcmpeqb %xmm7, %xmm1 + pmovmskb %xmm0, %edx + pmovmskb %xmm1, %ecx + test %edx, %edx + jnz L(CopyFrom1To16Bytes_32) + + bsf %ecx, %edx + movdqa %xmm4, (%edi) + movdqa %xmm5, 16(%edi) + movdqa %xmm6, 32(%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 48(%edi, %edx), %eax +#endif + movdqa %xmm7, 48(%edi) + add $15, %ebx + sub %edx, %ebx + lea 49(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $48, %esi + add $48, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + +/*----------------------------------------------------*/ + +/* Case1 */ +#ifndef USE_AS_STRNCPY + .p2align 4 +L(CopyFrom1To16Bytes): + add %ecx, %edi + add %ecx, %esi + bsf %edx, %edx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + .p2align 4 +L(CopyFrom1To16BytesTail): +#ifdef USE_AS_STRNCPY + sub %ecx, %ebx +#endif + add %ecx, %esi + bsf %edx, %edx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) + + .p2align 4 +L(CopyFrom1To32Bytes1): + add $16, %esi + add $16, %edi +#ifdef USE_AS_STRNCPY + sub $16, %ebx +#endif +L(CopyFrom1To16BytesTail1): + bsf %edx, %edx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) + + .p2align 4 +L(CopyFrom1To32Bytes): +#ifdef USE_AS_STRNCPY + sub %ecx, %ebx +#endif + bsf %edx, %edx + add %ecx, %esi + add $16, %edx + sub %ecx, %edx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) + + .p2align 4 +L(CopyFrom1To16Bytes_0): + bsf %edx, %edx +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea (%edi, %edx), %eax +#endif + movdqa %xmm4, (%edi) + add $63, %ebx + sub %edx, %ebx + lea 1(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16Bytes_16): + bsf %ecx, %edx + movdqa %xmm4, (%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 16(%edi, %edx), %eax +#endif + movdqa %xmm5, 16(%edi) + add $47, %ebx + sub %edx, %ebx + lea 17(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $16, %esi + add $16, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16Bytes_32): + bsf %edx, %edx + movdqa %xmm4, (%edi) + movdqa %xmm5, 16(%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 32(%edi, %edx), %eax +#endif + movdqa %xmm6, 32(%edi) + add $31, %ebx + sub %edx, %ebx + lea 33(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $32, %esi + add $32, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_0): + bsf %edx, %edx +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea (%edi, %edx), %eax +#endif + movdqu %xmm4, (%edi) + add $63, %ebx + sub %edx, %ebx + lea 1(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_16): + bsf %ecx, %edx + movdqu %xmm4, (%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 16(%edi, %edx), %eax +#endif + movdqu %xmm5, 16(%edi) + add $47, %ebx + sub %edx, %ebx + lea 17(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $16, %esi + add $16, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_32): + bsf %edx, %edx + movdqu %xmm4, (%edi) + movdqu %xmm5, 16(%edi) +#ifdef USE_AS_STRNCPY +#ifdef USE_AS_STPCPY + lea 32(%edi, %edx), %eax +#endif + movdqu %xmm6, 32(%edi) + add $31, %ebx + sub %edx, %ebx + lea 33(%edi, %edx), %edi + jmp L(StrncpyFillTailWithZero) +#else + add $32, %esi + add $32, %edi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) +#endif + +#ifdef USE_AS_STRNCPY + .p2align 4 +L(CopyFrom1To16BytesXmm6): + movdqa %xmm6, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesXmm5): + movdqa %xmm5, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesXmm4): + movdqa %xmm4, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesXmm3): + movdqa %xmm3, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesXmm2): + movdqa %xmm2, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesXmm1): + movdqa %xmm1, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm6): + movdqu %xmm6, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm5): + movdqu %xmm5, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm4): + movdqu %xmm4, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm3): + movdqu %xmm3, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm1): + movdqu %xmm1, (%edi, %ecx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesExit): + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %edx, 4) + +/* Case2 */ + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %ebx + add %ecx, %edi + add %ecx, %esi + bsf %edx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(CopyFrom1To32BytesCase2): + sub %ecx, %ebx + add %ecx, %esi + bsf %edx, %edx + add $16, %edx + sub %ecx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + +L(CopyFrom1To16BytesTailCase2): + sub %ecx, %ebx + add %ecx, %esi + bsf %edx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + +L(CopyFrom1To16BytesTail1Case2): + bsf %edx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + +/* Case2 or Case3, Case3 */ + + .p2align 4 +L(CopyFrom1To16BytesCase2OrCase3): + test %edx, %edx + jnz L(CopyFrom1To16BytesCase2) +L(CopyFrom1To16BytesCase3): + add $16, %ebx + add %ecx, %edi + add %ecx, %esi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(CopyFrom1To32BytesCase2OrCase3): + test %edx, %edx + jnz L(CopyFrom1To32BytesCase2) + sub %ecx, %ebx + add %ecx, %esi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(CopyFrom1To16BytesTailCase2OrCase3): + test %edx, %edx + jnz L(CopyFrom1To16BytesTailCase2) + sub %ecx, %ebx + add %ecx, %esi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(CopyFrom1To32Bytes1Case2OrCase3): + add $16, %edi + add $16, %esi + sub $16, %ebx +L(CopyFrom1To16BytesTail1Case2OrCase3): + test %edx, %edx + jnz L(CopyFrom1To16BytesTail1Case2) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + +#endif + +/*-----------------------------------------------------------------*/ + .p2align 4 +L(Exit0): +#ifdef USE_AS_STPCPY + mov %edi, %eax +#endif + RETURN + + .p2align 4 +L(Exit1): + movb %dh, (%edi) +#ifdef USE_AS_STPCPY + lea (%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $1, %ebx + lea 1(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit2): + movw (%esi), %dx + movw %dx, (%edi) +#ifdef USE_AS_STPCPY + lea 1(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $2, %ebx + lea 2(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit3): + movw (%esi), %cx + movw %cx, (%edi) + movb %dh, 2(%edi) +#ifdef USE_AS_STPCPY + lea 2(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $3, %ebx + lea 3(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit4): + movl (%esi), %edx + movl %edx, (%edi) +#ifdef USE_AS_STPCPY + lea 3(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $4, %ebx + lea 4(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit5): + movl (%esi), %ecx + movb %dh, 4(%edi) + movl %ecx, (%edi) +#ifdef USE_AS_STPCPY + lea 4(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $5, %ebx + lea 5(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit6): + movl (%esi), %ecx + movw 4(%esi), %dx + movl %ecx, (%edi) + movw %dx, 4(%edi) +#ifdef USE_AS_STPCPY + lea 5(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $6, %ebx + lea 6(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit7): + movl (%esi), %ecx + movl 3(%esi), %edx + movl %ecx, (%edi) + movl %edx, 3(%edi) +#ifdef USE_AS_STPCPY + lea 6(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $7, %ebx + lea 7(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit8): + movlpd (%esi), %xmm0 + movlpd %xmm0, (%edi) +#ifdef USE_AS_STPCPY + lea 7(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $8, %ebx + lea 8(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit9): + movlpd (%esi), %xmm0 + movb %dh, 8(%edi) + movlpd %xmm0, (%edi) +#ifdef USE_AS_STPCPY + lea 8(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $9, %ebx + lea 9(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit10): + movlpd (%esi), %xmm0 + movw 8(%esi), %dx + movlpd %xmm0, (%edi) + movw %dx, 8(%edi) +#ifdef USE_AS_STPCPY + lea 9(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $10, %ebx + lea 10(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit11): + movlpd (%esi), %xmm0 + movl 7(%esi), %edx + movlpd %xmm0, (%edi) + movl %edx, 7(%edi) +#ifdef USE_AS_STPCPY + lea 10(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $11, %ebx + lea 11(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit12): + movlpd (%esi), %xmm0 + movl 8(%esi), %edx + movlpd %xmm0, (%edi) + movl %edx, 8(%edi) +#ifdef USE_AS_STPCPY + lea 11(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $12, %ebx + lea 12(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit13): + movlpd (%esi), %xmm0 + movlpd 5(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 5(%edi) +#ifdef USE_AS_STPCPY + lea 12(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $13, %ebx + lea 13(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit14): + movlpd (%esi), %xmm0 + movlpd 6(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 6(%edi) +#ifdef USE_AS_STPCPY + lea 13(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $14, %ebx + lea 14(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit15): + movlpd (%esi), %xmm0 + movlpd 7(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 7(%edi) +#ifdef USE_AS_STPCPY + lea 14(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $15, %ebx + lea 15(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit16): + movdqu (%esi), %xmm0 + movdqu %xmm0, (%edi) +#ifdef USE_AS_STPCPY + lea 15(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $16, %ebx + lea 16(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit17): + movdqu (%esi), %xmm0 + xor %cl, %cl + movdqu %xmm0, (%edi) + movb %cl, 16(%edi) +#ifdef USE_AS_STPCPY + lea 16(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $17, %ebx + lea 17(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit18): + movdqu (%esi), %xmm0 + movw 16(%esi), %cx + movdqu %xmm0, (%edi) + movw %cx, 16(%edi) +#ifdef USE_AS_STPCPY + lea 17(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $18, %ebx + lea 18(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit19): + movdqu (%esi), %xmm0 + movl 15(%esi), %ecx + movdqu %xmm0, (%edi) + movl %ecx, 15(%edi) +#ifdef USE_AS_STPCPY + lea 18(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $19, %ebx + lea 19(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit20): + movdqu (%esi), %xmm0 + movl 16(%esi), %ecx + movdqu %xmm0, (%edi) + movl %ecx, 16(%edi) +#ifdef USE_AS_STPCPY + lea 19(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $20, %ebx + lea 20(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit21): + movdqu (%esi), %xmm0 + movl 16(%esi), %ecx + xor %dl, %dl + movdqu %xmm0, (%edi) + movl %ecx, 16(%edi) + movb %dl, 20(%edi) +#ifdef USE_AS_STPCPY + lea 20(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $21, %ebx + lea 21(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit22): + movdqu (%esi), %xmm0 + movlpd 14(%esi), %xmm3 + movdqu %xmm0, (%edi) + movlpd %xmm3, 14(%edi) +#ifdef USE_AS_STPCPY + lea 21(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $22, %ebx + lea 22(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit23): + movdqu (%esi), %xmm0 + movlpd 15(%esi), %xmm3 + movdqu %xmm0, (%edi) + movlpd %xmm3, 15(%edi) +#ifdef USE_AS_STPCPY + lea 22(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $23, %ebx + lea 23(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit24): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) +#ifdef USE_AS_STPCPY + lea 23(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $24, %ebx + lea 24(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit25): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + xor %cl, %cl + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movb %cl, 24(%edi) +#ifdef USE_AS_STPCPY + lea 24(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $25, %ebx + lea 25(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit26): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movw 24(%esi), %cx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movw %cx, 24(%edi) +#ifdef USE_AS_STPCPY + lea 25(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $26, %ebx + lea 26(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit27): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movl 23(%esi), %ecx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movl %ecx, 23(%edi) +#ifdef USE_AS_STPCPY + lea 26(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $27, %ebx + lea 27(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit28): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movl 24(%esi), %ecx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movl %ecx, 24(%edi) +#ifdef USE_AS_STPCPY + lea 27(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $28, %ebx + lea 28(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit29): + movdqu (%esi), %xmm0 + movdqu 13(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 13(%edi) +#ifdef USE_AS_STPCPY + lea 28(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $29, %ebx + lea 29(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit30): + movdqu (%esi), %xmm0 + movdqu 14(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 14(%edi) +#ifdef USE_AS_STPCPY + lea 29(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $30, %ebx + lea 30(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + + .p2align 4 +L(Exit31): + movdqu (%esi), %xmm0 + movdqu 15(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 15(%edi) +#ifdef USE_AS_STPCPY + lea 30(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $31, %ebx + lea 31(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit32): + movdqu (%esi), %xmm0 + movdqu 16(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 16(%edi) +#ifdef USE_AS_STPCPY + lea 31(%edi), %eax +#endif +#ifdef USE_AS_STRNCPY + sub $32, %ebx + lea 32(%edi), %edi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + +#ifdef USE_AS_STRNCPY + + .p2align 4 +L(StrncpyExit1): + movb (%esi), %dl + movb %dl, (%edi) +#ifdef USE_AS_STPCPY + lea 1(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit2): + movw (%esi), %dx + movw %dx, (%edi) +#ifdef USE_AS_STPCPY + lea 2(%edi), %eax +#endif + RETURN + .p2align 4 +L(StrncpyExit3): + movw (%esi), %cx + movb 2(%esi), %dl + movw %cx, (%edi) + movb %dl, 2(%edi) +#ifdef USE_AS_STPCPY + lea 3(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit4): + movl (%esi), %edx + movl %edx, (%edi) +#ifdef USE_AS_STPCPY + lea 4(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit5): + movl (%esi), %ecx + movb 4(%esi), %dl + movl %ecx, (%edi) + movb %dl, 4(%edi) +#ifdef USE_AS_STPCPY + lea 5(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit6): + movl (%esi), %ecx + movw 4(%esi), %dx + movl %ecx, (%edi) + movw %dx, 4(%edi) +#ifdef USE_AS_STPCPY + lea 6(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit7): + movl (%esi), %ecx + movl 3(%esi), %edx + movl %ecx, (%edi) + movl %edx, 3(%edi) +#ifdef USE_AS_STPCPY + lea 7(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit8): + movlpd (%esi), %xmm0 + movlpd %xmm0, (%edi) +#ifdef USE_AS_STPCPY + lea 8(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit9): + movlpd (%esi), %xmm0 + movb 8(%esi), %dl + movlpd %xmm0, (%edi) + movb %dl, 8(%edi) +#ifdef USE_AS_STPCPY + lea 9(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit10): + movlpd (%esi), %xmm0 + movw 8(%esi), %dx + movlpd %xmm0, (%edi) + movw %dx, 8(%edi) +#ifdef USE_AS_STPCPY + lea 10(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit11): + movlpd (%esi), %xmm0 + movl 7(%esi), %edx + movlpd %xmm0, (%edi) + movl %edx, 7(%edi) +#ifdef USE_AS_STPCPY + lea 11(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit12): + movlpd (%esi), %xmm0 + movl 8(%esi), %edx + movlpd %xmm0, (%edi) + movl %edx, 8(%edi) +#ifdef USE_AS_STPCPY + lea 12(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit13): + movlpd (%esi), %xmm0 + movlpd 5(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 5(%edi) +#ifdef USE_AS_STPCPY + lea 13(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit14): + movlpd (%esi), %xmm0 + movlpd 6(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 6(%edi) +#ifdef USE_AS_STPCPY + lea 14(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit15): + movlpd (%esi), %xmm0 + movlpd 7(%esi), %xmm1 + movlpd %xmm0, (%edi) + movlpd %xmm1, 7(%edi) +#ifdef USE_AS_STPCPY + lea 15(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit16): + movdqu (%esi), %xmm0 + movdqu %xmm0, (%edi) +#ifdef USE_AS_STPCPY + lea 16(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit17): + movdqu (%esi), %xmm0 + movb 16(%esi), %cl + movdqu %xmm0, (%edi) + movb %cl, 16(%edi) +#ifdef USE_AS_STPCPY + lea 17(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit18): + movdqu (%esi), %xmm0 + movw 16(%esi), %cx + movdqu %xmm0, (%edi) + movw %cx, 16(%edi) +#ifdef USE_AS_STPCPY + lea 18(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit19): + movdqu (%esi), %xmm0 + movl 15(%esi), %ecx + movdqu %xmm0, (%edi) + movl %ecx, 15(%edi) +#ifdef USE_AS_STPCPY + lea 19(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit20): + movdqu (%esi), %xmm0 + movl 16(%esi), %ecx + movdqu %xmm0, (%edi) + movl %ecx, 16(%edi) +#ifdef USE_AS_STPCPY + lea 20(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit21): + movdqu (%esi), %xmm0 + movl 16(%esi), %ecx + movb 20(%esi), %dl + movdqu %xmm0, (%edi) + movl %ecx, 16(%edi) + movb %dl, 20(%edi) +#ifdef USE_AS_STPCPY + lea 21(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit22): + movdqu (%esi), %xmm0 + movlpd 14(%esi), %xmm3 + movdqu %xmm0, (%edi) + movlpd %xmm3, 14(%edi) +#ifdef USE_AS_STPCPY + lea 22(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit23): + movdqu (%esi), %xmm0 + movlpd 15(%esi), %xmm3 + movdqu %xmm0, (%edi) + movlpd %xmm3, 15(%edi) +#ifdef USE_AS_STPCPY + lea 23(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit24): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) +#ifdef USE_AS_STPCPY + lea 24(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit25): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movb 24(%esi), %cl + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movb %cl, 24(%edi) +#ifdef USE_AS_STPCPY + lea 25(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit26): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movw 24(%esi), %cx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movw %cx, 24(%edi) +#ifdef USE_AS_STPCPY + lea 26(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit27): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movl 23(%esi), %ecx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movl %ecx, 23(%edi) +#ifdef USE_AS_STPCPY + lea 27(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit28): + movdqu (%esi), %xmm0 + movlpd 16(%esi), %xmm2 + movl 24(%esi), %ecx + movdqu %xmm0, (%edi) + movlpd %xmm2, 16(%edi) + movl %ecx, 24(%edi) +#ifdef USE_AS_STPCPY + lea 28(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit29): + movdqu (%esi), %xmm0 + movdqu 13(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 13(%edi) +#ifdef USE_AS_STPCPY + lea 29(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit30): + movdqu (%esi), %xmm0 + movdqu 14(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 14(%edi) +#ifdef USE_AS_STPCPY + lea 30(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit31): + movdqu (%esi), %xmm0 + movdqu 15(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 15(%edi) +#ifdef USE_AS_STPCPY + lea 31(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit32): + movdqu (%esi), %xmm0 + movdqu 16(%esi), %xmm2 + movdqu %xmm0, (%edi) + movdqu %xmm2, 16(%edi) +#ifdef USE_AS_STPCPY + lea 32(%edi), %eax +#endif + RETURN + + .p2align 4 +L(StrncpyExit33): + movdqu (%esi), %xmm0 + movdqu 16(%esi), %xmm2 + movb 32(%esi), %cl + movdqu %xmm0, (%edi) + movdqu %xmm2, 16(%edi) + movb %cl, 32(%edi) + RETURN + + .p2align 4 +L(Fill0): + RETURN + + .p2align 4 +L(Fill1): + movb %dl, (%edi) + RETURN + + .p2align 4 +L(Fill2): + movw %dx, (%edi) + RETURN + + .p2align 4 +L(Fill3): + movl %edx, -1(%edi) + RETURN + + .p2align 4 +L(Fill4): + movl %edx, (%edi) + RETURN + + .p2align 4 +L(Fill5): + movl %edx, (%edi) + movb %dl, 4(%edi) + RETURN + + .p2align 4 +L(Fill6): + movl %edx, (%edi) + movw %dx, 4(%edi) + RETURN + + .p2align 4 +L(Fill7): + movlpd %xmm0, -1(%edi) + RETURN + + .p2align 4 +L(Fill8): + movlpd %xmm0, (%edi) + RETURN + + .p2align 4 +L(Fill9): + movlpd %xmm0, (%edi) + movb %dl, 8(%edi) + RETURN + + .p2align 4 +L(Fill10): + movlpd %xmm0, (%edi) + movw %dx, 8(%edi) + RETURN + + .p2align 4 +L(Fill11): + movlpd %xmm0, (%edi) + movl %edx, 7(%edi) + RETURN + + .p2align 4 +L(Fill12): + movlpd %xmm0, (%edi) + movl %edx, 8(%edi) + RETURN + + .p2align 4 +L(Fill13): + movlpd %xmm0, (%edi) + movlpd %xmm0, 5(%edi) + RETURN + + .p2align 4 +L(Fill14): + movlpd %xmm0, (%edi) + movlpd %xmm0, 6(%edi) + RETURN + + .p2align 4 +L(Fill15): + movdqu %xmm0, -1(%edi) + RETURN + + .p2align 4 +L(Fill16): + movdqu %xmm0, (%edi) + RETURN + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm2): + movdqu %xmm2, (%edi, %ecx) + + .p2align 4 +L(CopyFrom1To16BytesXmmExit): + bsf %edx, %edx + add $15, %ebx + add %ecx, %edi +#ifdef USE_AS_STPCPY + lea (%edi, %edx), %eax +#endif + sub %edx, %ebx + lea 1(%edi, %edx), %edi + + .p2align 4 +L(StrncpyFillTailWithZero): + pxor %xmm0, %xmm0 + xor %edx, %edx + sub $16, %ebx + jbe L(StrncpyFillExit) + + movdqu %xmm0, (%edi) + add $16, %edi + + mov %edi, %esi + and $0xf, %esi + sub %esi, %edi + add %esi, %ebx + sub $64, %ebx + jb L(StrncpyFillLess64) + +L(StrncpyFillLoopMovdqa): + movdqa %xmm0, (%edi) + movdqa %xmm0, 16(%edi) + movdqa %xmm0, 32(%edi) + movdqa %xmm0, 48(%edi) + add $64, %edi + sub $64, %ebx + jae L(StrncpyFillLoopMovdqa) + +L(StrncpyFillLess64): + add $32, %ebx + jl L(StrncpyFillLess32) + movdqa %xmm0, (%edi) + movdqa %xmm0, 16(%edi) + add $32, %edi + sub $16, %ebx + jl L(StrncpyFillExit) + movdqa %xmm0, (%edi) + add $16, %edi + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %ebx, 4) + +L(StrncpyFillLess32): + add $16, %ebx + jl L(StrncpyFillExit) + movdqa %xmm0, (%edi) + add $16, %edi + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %ebx, 4) + +L(StrncpyFillExit): + add $16, %ebx + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %ebx, 4) + + .p2align 4 +L(AlignedLeaveCase2OrCase3): + test %edx, %edx + jnz L(Aligned64LeaveCase2) +L(Aligned64LeaveCase3): + lea 64(%ebx), %ecx + and $-16, %ecx + add $48, %ebx + jl L(CopyFrom1To16BytesCase3) + movdqa %xmm4, (%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqa %xmm5, 16(%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqa %xmm6, 32(%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqa %xmm7, 48(%edi) +#ifdef USE_AS_STPCPY + lea 64(%edi), %eax +#endif + RETURN + + .p2align 4 +L(Aligned64LeaveCase2): + pxor %xmm0, %xmm0 + xor %ecx, %ecx + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %edx + add $48, %ebx + jle L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm4) + + pcmpeqb %xmm5, %xmm0 + pmovmskb %xmm0, %edx + movdqa %xmm4, (%edi) + add $16, %ecx + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm5) + + pcmpeqb %xmm6, %xmm0 + pmovmskb %xmm0, %edx + movdqa %xmm5, 16(%edi) + add $16, %ecx + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesXmm6) + + pcmpeqb %xmm7, %xmm0 + pmovmskb %xmm0, %edx + movdqa %xmm6, 32(%edi) + lea 16(%edi, %ecx), %edi + lea 16(%esi, %ecx), %esi + bsf %edx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(UnalignedLeaveCase2OrCase3): + test %edx, %edx + jnz L(Unaligned64LeaveCase2) +L(Unaligned64LeaveCase3): + lea 64(%ebx), %ecx + and $-16, %ecx + add $48, %ebx + jl L(CopyFrom1To16BytesCase3) + movdqu %xmm4, (%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm5, 16(%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm6, 32(%edi) + sub $16, %ebx + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm7, 48(%edi) +#ifdef USE_AS_STPCPY + lea 64(%edi), %eax +#endif + RETURN + + .p2align 4 +L(Unaligned64LeaveCase2): + pxor %xmm0, %xmm0 + xor %ecx, %ecx + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %edx + add $48, %ebx + jle L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm4) + + pcmpeqb %xmm5, %xmm0 + pmovmskb %xmm0, %edx + movdqu %xmm4, (%edi) + add $16, %ecx + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm5) + + pcmpeqb %xmm6, %xmm0 + pmovmskb %xmm0, %edx + movdqu %xmm5, 16(%edi) + add $16, %ecx + sub $16, %ebx + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %edx, %edx + jnz L(CopyFrom1To16BytesUnalignedXmm6) + + pcmpeqb %xmm7, %xmm0 + pmovmskb %xmm0, %edx + movdqu %xmm6, 32(%edi) + lea 16(%edi, %ecx), %edi + lea 16(%esi, %ecx), %esi + bsf %edx, %edx + cmp %ebx, %edx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %ebx, 4) + + .p2align 4 +L(ExitZero): + movl %edi, %eax + RETURN +#endif + +END (STRCPY) + + .p2align 4 + .section .rodata +L(ExitTable): + .int JMPTBL(L(Exit1), L(ExitTable)) + .int JMPTBL(L(Exit2), L(ExitTable)) + .int JMPTBL(L(Exit3), L(ExitTable)) + .int JMPTBL(L(Exit4), L(ExitTable)) + .int JMPTBL(L(Exit5), L(ExitTable)) + .int JMPTBL(L(Exit6), L(ExitTable)) + .int JMPTBL(L(Exit7), L(ExitTable)) + .int JMPTBL(L(Exit8), L(ExitTable)) + .int JMPTBL(L(Exit9), L(ExitTable)) + .int JMPTBL(L(Exit10), L(ExitTable)) + .int JMPTBL(L(Exit11), L(ExitTable)) + .int JMPTBL(L(Exit12), L(ExitTable)) + .int JMPTBL(L(Exit13), L(ExitTable)) + .int JMPTBL(L(Exit14), L(ExitTable)) + .int JMPTBL(L(Exit15), L(ExitTable)) + .int JMPTBL(L(Exit16), L(ExitTable)) + .int JMPTBL(L(Exit17), L(ExitTable)) + .int JMPTBL(L(Exit18), L(ExitTable)) + .int JMPTBL(L(Exit19), L(ExitTable)) + .int JMPTBL(L(Exit20), L(ExitTable)) + .int JMPTBL(L(Exit21), L(ExitTable)) + .int JMPTBL(L(Exit22), L(ExitTable)) + .int JMPTBL(L(Exit23), L(ExitTable)) + .int JMPTBL(L(Exit24), L(ExitTable)) + .int JMPTBL(L(Exit25), L(ExitTable)) + .int JMPTBL(L(Exit26), L(ExitTable)) + .int JMPTBL(L(Exit27), L(ExitTable)) + .int JMPTBL(L(Exit28), L(ExitTable)) + .int JMPTBL(L(Exit29), L(ExitTable)) + .int JMPTBL(L(Exit30), L(ExitTable)) + .int JMPTBL(L(Exit31), L(ExitTable)) + .int JMPTBL(L(Exit32), L(ExitTable)) +#ifdef USE_AS_STRNCPY +L(ExitStrncpyTable): + .int JMPTBL(L(Exit0), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit1), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit2), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit3), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit4), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit5), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit6), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit7), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit8), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit9), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit10), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit11), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit12), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit13), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit14), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit15), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit16), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit17), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit18), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit19), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit20), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit21), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit22), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit23), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit24), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit25), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit26), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit27), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit28), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit29), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit30), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit31), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit32), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit33), L(ExitStrncpyTable)) + + .p2align 4 +L(FillTable): + .int JMPTBL(L(Fill0), L(FillTable)) + .int JMPTBL(L(Fill1), L(FillTable)) + .int JMPTBL(L(Fill2), L(FillTable)) + .int JMPTBL(L(Fill3), L(FillTable)) + .int JMPTBL(L(Fill4), L(FillTable)) + .int JMPTBL(L(Fill5), L(FillTable)) + .int JMPTBL(L(Fill6), L(FillTable)) + .int JMPTBL(L(Fill7), L(FillTable)) + .int JMPTBL(L(Fill8), L(FillTable)) + .int JMPTBL(L(Fill9), L(FillTable)) + .int JMPTBL(L(Fill10), L(FillTable)) + .int JMPTBL(L(Fill11), L(FillTable)) + .int JMPTBL(L(Fill12), L(FillTable)) + .int JMPTBL(L(Fill13), L(FillTable)) + .int JMPTBL(L(Fill14), L(FillTable)) + .int JMPTBL(L(Fill15), L(FillTable)) + .int JMPTBL(L(Fill16), L(FillTable)) +#endif diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strlen-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strlen-slm.S new file mode 100755 index 000000000..b805ad663 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strlen-slm.S @@ -0,0 +1,328 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef STRLEN +# define STRLEN strlen_generic +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + + .section .text.sse2,"ax",@progbits +ENTRY (STRLEN) + mov 4(%esp), %edx + mov %edx, %ecx + and $0x3f, %ecx + pxor %xmm0, %xmm0 + cmp $0x30, %ecx + ja L(next) + movdqu (%edx), %xmm1 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit_less16) + mov %edx, %eax + and $-16, %eax + jmp L(align16_start) +L(next): + mov %edx, %eax + and $-16, %eax + PUSH (%edi) + pcmpeqb (%eax), %xmm0 + mov $-1, %edi + sub %eax, %ecx + shl %cl, %edi + pmovmskb %xmm0, %ecx + and %edi, %ecx + POP (%edi) + jnz L(exit_unaligned) + pxor %xmm0, %xmm0 +L(align16_start): + pxor %xmm1, %xmm1 + pxor %xmm2, %xmm2 + pxor %xmm3, %xmm3 + pcmpeqb 16(%eax), %xmm0 + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit16) + + pcmpeqb 32(%eax), %xmm1 + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit32) + + pcmpeqb 48(%eax), %xmm2 + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit48) + + pcmpeqb 64(%eax), %xmm3 + pmovmskb %xmm3, %ecx + test %ecx, %ecx + jnz L(exit64) + + pcmpeqb 80(%eax), %xmm0 + add $64, %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit16) + + pcmpeqb 32(%eax), %xmm1 + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit32) + + pcmpeqb 48(%eax), %xmm2 + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit48) + + pcmpeqb 64(%eax), %xmm3 + pmovmskb %xmm3, %ecx + test %ecx, %ecx + jnz L(exit64) + + pcmpeqb 80(%eax), %xmm0 + add $64, %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit16) + + pcmpeqb 32(%eax), %xmm1 + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit32) + + pcmpeqb 48(%eax), %xmm2 + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit48) + + pcmpeqb 64(%eax), %xmm3 + pmovmskb %xmm3, %ecx + test %ecx, %ecx + jnz L(exit64) + + pcmpeqb 80(%eax), %xmm0 + add $64, %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit16) + + pcmpeqb 32(%eax), %xmm1 + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit32) + + pcmpeqb 48(%eax), %xmm2 + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit48) + + pcmpeqb 64(%eax), %xmm3 + pmovmskb %xmm3, %ecx + test %ecx, %ecx + jnz L(exit64) + + + test $0x3f, %eax + jz L(align64_loop) + + pcmpeqb 80(%eax), %xmm0 + add $80, %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit) + + test $0x3f, %eax + jz L(align64_loop) + + pcmpeqb 16(%eax), %xmm1 + add $16, %eax + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit) + + test $0x3f, %eax + jz L(align64_loop) + + pcmpeqb 16(%eax), %xmm2 + add $16, %eax + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit) + + test $0x3f, %eax + jz L(align64_loop) + + pcmpeqb 16(%eax), %xmm3 + add $16, %eax + pmovmskb %xmm3, %ecx + test %ecx, %ecx + jnz L(exit) + + add $16, %eax + .p2align 4 +L(align64_loop): + movaps (%eax), %xmm4 + pminub 16(%eax), %xmm4 + movaps 32(%eax), %xmm5 + pminub 48(%eax), %xmm5 + add $64, %eax + pminub %xmm4, %xmm5 + pcmpeqb %xmm0, %xmm5 + pmovmskb %xmm5, %ecx + test %ecx, %ecx + jz L(align64_loop) + + + pcmpeqb -64(%eax), %xmm0 + sub $80, %eax + pmovmskb %xmm0, %ecx + test %ecx, %ecx + jnz L(exit16) + + pcmpeqb 32(%eax), %xmm1 + pmovmskb %xmm1, %ecx + test %ecx, %ecx + jnz L(exit32) + + pcmpeqb 48(%eax), %xmm2 + pmovmskb %xmm2, %ecx + test %ecx, %ecx + jnz L(exit48) + + pcmpeqb 64(%eax), %xmm3 + pmovmskb %xmm3, %ecx + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + add $64, %eax + ret + + .p2align 4 +L(exit): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + ret + +L(exit_less16): + bsf %ecx, %eax + ret + + .p2align 4 +L(exit_unaligned): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + ret + + .p2align 4 +L(exit16): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + add $16, %eax + ret + + .p2align 4 +L(exit32): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + add $32, %eax + ret + + .p2align 4 +L(exit48): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + add $48, %eax + ret + + .p2align 4 +L(exit64): + sub %edx, %eax + bsf %ecx, %ecx + add %ecx, %eax + add $64, %eax + ret + +END (STRLEN) + diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S new file mode 100755 index 000000000..aff7fb9f7 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse2-strncpy-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define STRCPY strncpy_generic +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S new file mode 100755 index 000000000..f15116894 --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse4-memcmp-slm.S @@ -0,0 +1,1278 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef cfi_remember_state +# define cfi_remember_state .cfi_remember_state +#endif + +#ifndef cfi_restore_state +# define cfi_restore_state .cfi_restore_state +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#ifndef MEMCMP +# define MEMCMP memcmp_sse4 +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) pushl REG; CFI_PUSH (REG) +#define POP(REG) popl REG; CFI_POP (REG) + +#define PARMS 4 +#define BLK1 PARMS +#define BLK2 BLK1 + 4 +#define LEN BLK2 + 4 +#define RETURN POP (%ebx); ret; CFI_PUSH (%ebx) + + +#if (defined SHARED || defined __PIC__) +# define JMPTBL(I, B) I - B + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. INDEX is a register contains the + index into the jump table. SCALE is the scale of INDEX. */ + +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ +/* We first load PC into EBX. */ \ + call __x86.get_pc_thunk.bx; \ +/* Get the address of the jump table. */ \ + addl $(TABLE - .), %ebx; \ +/* Get the entry and convert the relative offset to the \ + absolute address. */ \ + addl (%ebx,INDEX,SCALE), %ebx; \ +/* We loaded the jump table and adjuested EDX/ESI. Go. */ \ + jmp *%ebx +#else +# define JMPTBL(I, B) I + +/* Load an entry in a jump table into EBX and branch to it. TABLE is a + jump table with relative offsets. INDEX is a register contains the + index into the jump table. SCALE is the scale of INDEX. */ +# define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + jmp *TABLE(,INDEX,SCALE) +#endif + + +/* Warning! + wmemcmp has to use SIGNED comparison for elements. + memcmp has to use UNSIGNED comparison for elemnts. +*/ + + .section .text.sse4.2,"ax",@progbits +ENTRY (MEMCMP) + movl BLK1(%esp), %eax + movl BLK2(%esp), %edx + movl LEN(%esp), %ecx + +#ifdef USE_AS_WMEMCMP + shl $2, %ecx + test %ecx, %ecx + jz L(return0) +#else + cmp $1, %ecx + jbe L(less1bytes) +#endif + + pxor %xmm0, %xmm0 + cmp $64, %ecx + ja L(64bytesormore) + cmp $8, %ecx + +#ifndef USE_AS_WMEMCMP + PUSH (%ebx) + jb L(less8bytes) +#else + jb L(less8bytes) + PUSH (%ebx) +#endif + + add %ecx, %edx + add %ecx, %eax + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %ecx, 4) + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(less8bytes): + mov (%eax), %bl + cmpb (%edx), %bl + jne L(nonzero) + + mov 1(%eax), %bl + cmpb 1(%edx), %bl + jne L(nonzero) + + cmp $2, %ecx + jz L(0bytes) + + mov 2(%eax), %bl + cmpb 2(%edx), %bl + jne L(nonzero) + + cmp $3, %ecx + jz L(0bytes) + + mov 3(%eax), %bl + cmpb 3(%edx), %bl + jne L(nonzero) + + cmp $4, %ecx + jz L(0bytes) + + mov 4(%eax), %bl + cmpb 4(%edx), %bl + jne L(nonzero) + + cmp $5, %ecx + jz L(0bytes) + + mov 5(%eax), %bl + cmpb 5(%edx), %bl + jne L(nonzero) + + cmp $6, %ecx + jz L(0bytes) + + mov 6(%eax), %bl + cmpb 6(%edx), %bl + je L(0bytes) + +L(nonzero): + POP (%ebx) + mov $1, %eax + ja L(above) + neg %eax +L(above): + ret + CFI_PUSH (%ebx) +#endif + + .p2align 4 +L(0bytes): + POP (%ebx) + xor %eax, %eax + ret + +#ifdef USE_AS_WMEMCMP + +/* for wmemcmp, case N == 1 */ + + .p2align 4 +L(less8bytes): + mov (%eax), %ecx + cmp (%edx), %ecx + je L(return0) + mov $1, %eax + jg L(find_diff_bigger) + neg %eax + ret + + .p2align 4 +L(find_diff_bigger): + ret + + .p2align 4 +L(return0): + xor %eax, %eax + ret +#endif + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(less1bytes): + jb L(0bytesend) + movzbl (%eax), %eax + movzbl (%edx), %edx + sub %edx, %eax + ret + + .p2align 4 +L(0bytesend): + xor %eax, %eax + ret +#endif + .p2align 4 +L(64bytesormore): + PUSH (%ebx) + mov %ecx, %ebx + mov $64, %ecx + sub $64, %ebx +L(64bytesormore_loop): + movdqu (%eax), %xmm1 + movdqu (%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(find_16diff) + + movdqu 16(%eax), %xmm1 + movdqu 16(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(find_32diff) + + movdqu 32(%eax), %xmm1 + movdqu 32(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(find_48diff) + + movdqu 48(%eax), %xmm1 + movdqu 48(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(find_64diff) + add %ecx, %eax + add %ecx, %edx + sub %ecx, %ebx + jae L(64bytesormore_loop) + add %ebx, %ecx + add %ecx, %edx + add %ecx, %eax + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %ecx, 4) + +#ifdef USE_AS_WMEMCMP + +/* Label needs only for table_64bytes filling */ +L(unreal_case): +/* no code here */ + +#endif + .p2align 4 +L(find_16diff): + sub $16, %ecx +L(find_32diff): + sub $16, %ecx +L(find_48diff): + sub $16, %ecx +L(find_64diff): + add %ecx, %edx + add %ecx, %eax + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(16bytes): + mov -16(%eax), %ecx + mov -16(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(12bytes): + mov -12(%eax), %ecx + mov -12(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(8bytes): + mov -8(%eax), %ecx + mov -8(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(4bytes): + mov -4(%eax), %ecx + mov -4(%edx), %ebx + cmp %ebx, %ecx + mov $0, %eax + jne L(find_diff) + RETURN +#else + .p2align 4 +L(16bytes): + mov -16(%eax), %ecx + cmp -16(%edx), %ecx + jne L(find_diff) +L(12bytes): + mov -12(%eax), %ecx + cmp -12(%edx), %ecx + jne L(find_diff) +L(8bytes): + mov -8(%eax), %ecx + cmp -8(%edx), %ecx + jne L(find_diff) +L(4bytes): + mov -4(%eax), %ecx + cmp -4(%edx), %ecx + mov $0, %eax + jne L(find_diff) + RETURN +#endif + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(49bytes): + movdqu -49(%eax), %xmm1 + movdqu -49(%edx), %xmm2 + mov $-49, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(33bytes): + movdqu -33(%eax), %xmm1 + movdqu -33(%edx), %xmm2 + mov $-33, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(17bytes): + mov -17(%eax), %ecx + mov -17(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(13bytes): + mov -13(%eax), %ecx + mov -13(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(9bytes): + mov -9(%eax), %ecx + mov -9(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(5bytes): + mov -5(%eax), %ecx + mov -5(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzbl -1(%eax), %ecx + cmp -1(%edx), %cl + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(50bytes): + mov $-50, %ebx + movdqu -50(%eax), %xmm1 + movdqu -50(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(34bytes): + mov $-34, %ebx + movdqu -34(%eax), %xmm1 + movdqu -34(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(18bytes): + mov -18(%eax), %ecx + mov -18(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(14bytes): + mov -14(%eax), %ecx + mov -14(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(10bytes): + mov -10(%eax), %ecx + mov -10(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(6bytes): + mov -6(%eax), %ecx + mov -6(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(2bytes): + movzwl -2(%eax), %ecx + movzwl -2(%edx), %ebx + cmp %bl, %cl + jne L(end) + cmp %bh, %ch + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(51bytes): + mov $-51, %ebx + movdqu -51(%eax), %xmm1 + movdqu -51(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(35bytes): + mov $-35, %ebx + movdqu -35(%eax), %xmm1 + movdqu -35(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(19bytes): + movl -19(%eax), %ecx + movl -19(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(15bytes): + movl -15(%eax), %ecx + movl -15(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(11bytes): + movl -11(%eax), %ecx + movl -11(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(7bytes): + movl -7(%eax), %ecx + movl -7(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) +L(3bytes): + movzwl -3(%eax), %ecx + movzwl -3(%edx), %ebx + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) +L(1bytes): + movzbl -1(%eax), %eax + cmpb -1(%edx), %al + mov $0, %eax + jne L(end) + RETURN +#endif + .p2align 4 +L(52bytes): + movdqu -52(%eax), %xmm1 + movdqu -52(%edx), %xmm2 + mov $-52, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(36bytes): + movdqu -36(%eax), %xmm1 + movdqu -36(%edx), %xmm2 + mov $-36, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(20bytes): + movdqu -20(%eax), %xmm1 + movdqu -20(%edx), %xmm2 + mov $-20, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -4(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -4(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -4(%edx), %ecx +#endif + mov $0, %eax + jne L(find_diff) + RETURN + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(53bytes): + movdqu -53(%eax), %xmm1 + movdqu -53(%edx), %xmm2 + mov $-53, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(37bytes): + mov $-37, %ebx + movdqu -37(%eax), %xmm1 + movdqu -37(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(21bytes): + mov $-21, %ebx + movdqu -21(%eax), %xmm1 + movdqu -21(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -5(%eax), %ecx + mov -5(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzbl -1(%eax), %ecx + cmp -1(%edx), %cl + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(54bytes): + movdqu -54(%eax), %xmm1 + movdqu -54(%edx), %xmm2 + mov $-54, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(38bytes): + mov $-38, %ebx + movdqu -38(%eax), %xmm1 + movdqu -38(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(22bytes): + mov $-22, %ebx + movdqu -22(%eax), %xmm1 + movdqu -22(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -6(%eax), %ecx + mov -6(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzwl -2(%eax), %ecx + movzwl -2(%edx), %ebx + cmp %bl, %cl + jne L(end) + cmp %bh, %ch + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(55bytes): + movdqu -55(%eax), %xmm1 + movdqu -55(%edx), %xmm2 + mov $-55, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(39bytes): + mov $-39, %ebx + movdqu -39(%eax), %xmm1 + movdqu -39(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(23bytes): + mov $-23, %ebx + movdqu -23(%eax), %xmm1 + movdqu -23(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + movl -7(%eax), %ecx + movl -7(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzwl -3(%eax), %ecx + movzwl -3(%edx), %ebx + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + movzbl -1(%eax), %eax + cmpb -1(%edx), %al + mov $0, %eax + jne L(end) + RETURN +#endif + .p2align 4 +L(56bytes): + movdqu -56(%eax), %xmm1 + movdqu -56(%edx), %xmm2 + mov $-56, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(40bytes): + mov $-40, %ebx + movdqu -40(%eax), %xmm1 + movdqu -40(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(24bytes): + mov $-24, %ebx + movdqu -24(%eax), %xmm1 + movdqu -24(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -8(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -8(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -8(%edx), %ecx +#endif + jne L(find_diff) + + mov -4(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -4(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -4(%edx), %ecx +#endif + mov $0, %eax + jne L(find_diff) + RETURN + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(57bytes): + movdqu -57(%eax), %xmm1 + movdqu -57(%edx), %xmm2 + mov $-57, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(41bytes): + mov $-41, %ebx + movdqu -41(%eax), %xmm1 + movdqu -41(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(25bytes): + mov $-25, %ebx + movdqu -25(%eax), %xmm1 + movdqu -25(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -9(%eax), %ecx + mov -9(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + mov -5(%eax), %ecx + mov -5(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzbl -1(%eax), %ecx + cmp -1(%edx), %cl + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(58bytes): + movdqu -58(%eax), %xmm1 + movdqu -58(%edx), %xmm2 + mov $-58, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(42bytes): + mov $-42, %ebx + movdqu -42(%eax), %xmm1 + movdqu -42(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(26bytes): + mov $-26, %ebx + movdqu -26(%eax), %xmm1 + movdqu -26(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -10(%eax), %ecx + mov -10(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov -6(%eax), %ecx + mov -6(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + movzwl -2(%eax), %ecx + movzwl -2(%edx), %ebx + cmp %bl, %cl + jne L(end) + cmp %bh, %ch + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(59bytes): + movdqu -59(%eax), %xmm1 + movdqu -59(%edx), %xmm2 + mov $-59, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(43bytes): + mov $-43, %ebx + movdqu -43(%eax), %xmm1 + movdqu -43(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(27bytes): + mov $-27, %ebx + movdqu -27(%eax), %xmm1 + movdqu -27(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + movl -11(%eax), %ecx + movl -11(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movl -7(%eax), %ecx + movl -7(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzwl -3(%eax), %ecx + movzwl -3(%edx), %ebx + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + movzbl -1(%eax), %eax + cmpb -1(%edx), %al + mov $0, %eax + jne L(end) + RETURN +#endif + .p2align 4 +L(60bytes): + movdqu -60(%eax), %xmm1 + movdqu -60(%edx), %xmm2 + mov $-60, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(44bytes): + mov $-44, %ebx + movdqu -44(%eax), %xmm1 + movdqu -44(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(28bytes): + mov $-28, %ebx + movdqu -28(%eax), %xmm1 + movdqu -28(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -12(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -12(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -12(%edx), %ecx +#endif + jne L(find_diff) + + mov -8(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -8(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -8(%edx), %ecx +#endif + jne L(find_diff) + + mov -4(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -4(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -4(%edx), %ecx +#endif + mov $0, %eax + jne L(find_diff) + RETURN + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(61bytes): + movdqu -61(%eax), %xmm1 + movdqu -61(%edx), %xmm2 + mov $-61, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(45bytes): + mov $-45, %ebx + movdqu -45(%eax), %xmm1 + movdqu -45(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(29bytes): + mov $-29, %ebx + movdqu -29(%eax), %xmm1 + movdqu -29(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -13(%eax), %ecx + mov -13(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov -9(%eax), %ecx + mov -9(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov -5(%eax), %ecx + mov -5(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzbl -1(%eax), %ecx + cmp -1(%edx), %cl + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(62bytes): + movdqu -62(%eax), %xmm1 + movdqu -62(%edx), %xmm2 + mov $-62, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(46bytes): + mov $-46, %ebx + movdqu -46(%eax), %xmm1 + movdqu -46(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(30bytes): + mov $-30, %ebx + movdqu -30(%eax), %xmm1 + movdqu -30(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -14(%eax), %ecx + mov -14(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + mov -10(%eax), %ecx + mov -10(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + mov -6(%eax), %ecx + mov -6(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzwl -2(%eax), %ecx + movzwl -2(%edx), %ebx + cmp %bl, %cl + jne L(end) + cmp %bh, %ch + mov $0, %eax + jne L(end) + RETURN + + .p2align 4 +L(63bytes): + movdqu -63(%eax), %xmm1 + movdqu -63(%edx), %xmm2 + mov $-63, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(47bytes): + mov $-47, %ebx + movdqu -47(%eax), %xmm1 + movdqu -47(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(31bytes): + mov $-31, %ebx + movdqu -31(%eax), %xmm1 + movdqu -31(%edx), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + movl -15(%eax), %ecx + movl -15(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movl -11(%eax), %ecx + movl -11(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movl -7(%eax), %ecx + movl -7(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + movzwl -3(%eax), %ecx + movzwl -3(%edx), %ebx + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + movzbl -1(%eax), %eax + cmpb -1(%edx), %al + mov $0, %eax + jne L(end) + RETURN +#endif + + .p2align 4 +L(64bytes): + movdqu -64(%eax), %xmm1 + movdqu -64(%edx), %xmm2 + mov $-64, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(48bytes): + movdqu -48(%eax), %xmm1 + movdqu -48(%edx), %xmm2 + mov $-48, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(32bytes): + movdqu -32(%eax), %xmm1 + movdqu -32(%edx), %xmm2 + mov $-32, %ebx + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -16(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -16(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -16(%edx), %ecx +#endif + jne L(find_diff) + + mov -12(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -12(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -12(%edx), %ecx +#endif + jne L(find_diff) + + mov -8(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -8(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -8(%edx), %ecx +#endif + jne L(find_diff) + + mov -4(%eax), %ecx +#ifndef USE_AS_WMEMCMP + mov -4(%edx), %ebx + cmp %ebx, %ecx +#else + cmp -4(%edx), %ecx +#endif + mov $0, %eax + jne L(find_diff) + RETURN + +#ifndef USE_AS_WMEMCMP + .p2align 4 +L(less16bytes): + add %ebx, %eax + add %ebx, %edx + + mov (%eax), %ecx + mov (%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov 4(%eax), %ecx + mov 4(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov 8(%eax), %ecx + mov 8(%edx), %ebx + cmp %ebx, %ecx + jne L(find_diff) + + mov 12(%eax), %ecx + mov 12(%edx), %ebx + cmp %ebx, %ecx + mov $0, %eax + jne L(find_diff) + RETURN +#else + .p2align 4 +L(less16bytes): + add %ebx, %eax + add %ebx, %edx + + mov (%eax), %ecx + cmp (%edx), %ecx + jne L(find_diff) + + mov 4(%eax), %ecx + cmp 4(%edx), %ecx + jne L(find_diff) + + mov 8(%eax), %ecx + cmp 8(%edx), %ecx + jne L(find_diff) + + mov 12(%eax), %ecx + cmp 12(%edx), %ecx + + mov $0, %eax + jne L(find_diff) + RETURN +#endif + + .p2align 4 +L(find_diff): +#ifndef USE_AS_WMEMCMP + cmpb %bl, %cl + jne L(end) + cmp %bx, %cx + jne L(end) + shr $16,%ecx + shr $16,%ebx + cmp %bl, %cl + jne L(end) + cmp %bx, %cx +L(end): + POP (%ebx) + mov $1, %eax + ja L(bigger) + neg %eax +L(bigger): + ret +#else + POP (%ebx) + mov $1, %eax + jg L(bigger) + neg %eax + ret + + .p2align 4 +L(bigger): + ret +#endif +END (MEMCMP) + + .section .rodata.sse4.2,"a",@progbits + .p2align 2 + .type L(table_64bytes), @object +#ifndef USE_AS_WMEMCMP +L(table_64bytes): + .int JMPTBL (L(0bytes), L(table_64bytes)) + .int JMPTBL (L(1bytes), L(table_64bytes)) + .int JMPTBL (L(2bytes), L(table_64bytes)) + .int JMPTBL (L(3bytes), L(table_64bytes)) + .int JMPTBL (L(4bytes), L(table_64bytes)) + .int JMPTBL (L(5bytes), L(table_64bytes)) + .int JMPTBL (L(6bytes), L(table_64bytes)) + .int JMPTBL (L(7bytes), L(table_64bytes)) + .int JMPTBL (L(8bytes), L(table_64bytes)) + .int JMPTBL (L(9bytes), L(table_64bytes)) + .int JMPTBL (L(10bytes), L(table_64bytes)) + .int JMPTBL (L(11bytes), L(table_64bytes)) + .int JMPTBL (L(12bytes), L(table_64bytes)) + .int JMPTBL (L(13bytes), L(table_64bytes)) + .int JMPTBL (L(14bytes), L(table_64bytes)) + .int JMPTBL (L(15bytes), L(table_64bytes)) + .int JMPTBL (L(16bytes), L(table_64bytes)) + .int JMPTBL (L(17bytes), L(table_64bytes)) + .int JMPTBL (L(18bytes), L(table_64bytes)) + .int JMPTBL (L(19bytes), L(table_64bytes)) + .int JMPTBL (L(20bytes), L(table_64bytes)) + .int JMPTBL (L(21bytes), L(table_64bytes)) + .int JMPTBL (L(22bytes), L(table_64bytes)) + .int JMPTBL (L(23bytes), L(table_64bytes)) + .int JMPTBL (L(24bytes), L(table_64bytes)) + .int JMPTBL (L(25bytes), L(table_64bytes)) + .int JMPTBL (L(26bytes), L(table_64bytes)) + .int JMPTBL (L(27bytes), L(table_64bytes)) + .int JMPTBL (L(28bytes), L(table_64bytes)) + .int JMPTBL (L(29bytes), L(table_64bytes)) + .int JMPTBL (L(30bytes), L(table_64bytes)) + .int JMPTBL (L(31bytes), L(table_64bytes)) + .int JMPTBL (L(32bytes), L(table_64bytes)) + .int JMPTBL (L(33bytes), L(table_64bytes)) + .int JMPTBL (L(34bytes), L(table_64bytes)) + .int JMPTBL (L(35bytes), L(table_64bytes)) + .int JMPTBL (L(36bytes), L(table_64bytes)) + .int JMPTBL (L(37bytes), L(table_64bytes)) + .int JMPTBL (L(38bytes), L(table_64bytes)) + .int JMPTBL (L(39bytes), L(table_64bytes)) + .int JMPTBL (L(40bytes), L(table_64bytes)) + .int JMPTBL (L(41bytes), L(table_64bytes)) + .int JMPTBL (L(42bytes), L(table_64bytes)) + .int JMPTBL (L(43bytes), L(table_64bytes)) + .int JMPTBL (L(44bytes), L(table_64bytes)) + .int JMPTBL (L(45bytes), L(table_64bytes)) + .int JMPTBL (L(46bytes), L(table_64bytes)) + .int JMPTBL (L(47bytes), L(table_64bytes)) + .int JMPTBL (L(48bytes), L(table_64bytes)) + .int JMPTBL (L(49bytes), L(table_64bytes)) + .int JMPTBL (L(50bytes), L(table_64bytes)) + .int JMPTBL (L(51bytes), L(table_64bytes)) + .int JMPTBL (L(52bytes), L(table_64bytes)) + .int JMPTBL (L(53bytes), L(table_64bytes)) + .int JMPTBL (L(54bytes), L(table_64bytes)) + .int JMPTBL (L(55bytes), L(table_64bytes)) + .int JMPTBL (L(56bytes), L(table_64bytes)) + .int JMPTBL (L(57bytes), L(table_64bytes)) + .int JMPTBL (L(58bytes), L(table_64bytes)) + .int JMPTBL (L(59bytes), L(table_64bytes)) + .int JMPTBL (L(60bytes), L(table_64bytes)) + .int JMPTBL (L(61bytes), L(table_64bytes)) + .int JMPTBL (L(62bytes), L(table_64bytes)) + .int JMPTBL (L(63bytes), L(table_64bytes)) + .int JMPTBL (L(64bytes), L(table_64bytes)) +#else +L(table_64bytes): + .int JMPTBL (L(0bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(4bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(8bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(12bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(16bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(20bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(24bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(28bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(32bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(36bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(40bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(44bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(48bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(52bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(56bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(60bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(64bytes), L(table_64bytes)) +#endif diff --git a/aosp/bionic/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S b/aosp/bionic/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S new file mode 100755 index 000000000..2bf92f57e --- /dev/null +++ b/aosp/bionic/libc/arch-x86/silvermont/string/sse4-wmemcmp-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_WMEMCMP +#define MEMCMP wmemcmp_sse4 +#include "sse4-memcmp-slm.S" diff --git a/aosp/bionic/libc/arch-x86/static_function_dispatch.S b/aosp/bionic/libc/arch-x86/static_function_dispatch.S new file mode 100644 index 000000000..1560c042e --- /dev/null +++ b/aosp/bionic/libc/arch-x86/static_function_dispatch.S @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 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 + +#define FUNCTION_DELEGATE(name, impl) \ +ENTRY(name); \ + jmp impl; \ +END(name) + +FUNCTION_DELEGATE(memcmp, memcmp_generic) +FUNCTION_DELEGATE(memset, memset_generic) +FUNCTION_DELEGATE(__memset_chk, __memset_chk_generic) +FUNCTION_DELEGATE(memcpy, memmove_generic) +FUNCTION_DELEGATE(memmove, memmove_generic) +FUNCTION_DELEGATE(strcpy, strcpy_generic) +FUNCTION_DELEGATE(strncpy, strncpy_generic) +FUNCTION_DELEGATE(strlen, strlen_generic) +FUNCTION_DELEGATE(strcmp, strcmp_generic) +FUNCTION_DELEGATE(strncmp, strncmp_generic) +FUNCTION_DELEGATE(strcat, strcat_generic) +FUNCTION_DELEGATE(wmemcmp, wmemcmp_freebsd) +FUNCTION_DELEGATE(wmemset, wmemset_freebsd) +FUNCTION_DELEGATE(wcscat, wcscat_freebsd) +FUNCTION_DELEGATE(strncat, strncat_openbsd) +FUNCTION_DELEGATE(strlcat, strlcat_openbsd) +FUNCTION_DELEGATE(strlcpy, strlcpy_openbsd) +FUNCTION_DELEGATE(wcscpy, wcscpy_freebsd) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/__bionic_clone.S b/aosp/bionic/libc/arch-x86_64/bionic/__bionic_clone.S new file mode 100644 index 000000000..a4245b857 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/__bionic_clone.S @@ -0,0 +1,76 @@ +/* + * 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 + +// pid_t __bionic_clone(int flags, void* child_stack, pid_t* parent_tid, void* tls, pid_t* child_tid, int (*fn)(void*), void* arg); +ENTRY_PRIVATE(__bionic_clone) + # Copy 'fn' and 'arg' onto the child stack. + movq %r9, -16(%rsi) # fn + movq 8(%rsp), %rax # Read 'arg'. + movq %rax, -8(%rsi) # Write 'arg'. + + subq $16, %rsi + + # Translate to the kernel calling convention and swap the 'tls' and 'child_tid' arguments. + # They're flipped for x86-64 compared to all our other architectures and __bionic_clone. + movq %r8, %r10 + movq %rcx, %r8 + + # Make the system call. + movl $__NR_clone, %eax + syscall + + # Check result. + testq %rax, %rax + jz .L_bc_child + jg .L_bc_parent + + # An error occurred, set errno and return -1. + negl %eax + movl %eax, %edi + call __set_errno_internal + ret + +.L_bc_child: + # We don't want anyone to unwind past this point. + .cfi_undefined %rip + .cfi_undefined %rbp + + # We're in the child now, so call __start_thread + # with the arguments from the child stack moved into + # the appropriate registers. + popq %rdi # fn + popq %rsi # arg + call __start_thread + hlt + +.L_bc_parent: + # We're the parent; nothing to do. + ret +END(__bionic_clone) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/__restore_rt.S b/aosp/bionic/libc/arch-x86_64/bionic/__restore_rt.S new file mode 100644 index 000000000..785b3b378 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/__restore_rt.S @@ -0,0 +1,143 @@ +/* + * 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 + +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_breg7 0x77 +#define DW_OP_deref 0x06 + +// Offsets into struct ucontext_t of uc_mcontext.gregs[x]. +#define OFFSET_R8 40 +#define OFFSET_R9 48 +#define OFFSET_R10 56 +#define OFFSET_R11 64 +#define OFFSET_R12 72 +#define OFFSET_R13 80 +#define OFFSET_R14 88 +#define OFFSET_R15 96 +#define OFFSET_RDI 104 +#define OFFSET_RSI 112 +#define OFFSET_RBP 120 +#define OFFSET_RSP 160 +#define OFFSET_RBX 128 +#define OFFSET_RDX 136 +#define OFFSET_RAX 144 +#define OFFSET_RCX 152 +#define OFFSET_RIP 168 + +// Non-standard DWARF constants for the x86-64 registers. +#define DW_x86_64_RAX 0 +#define DW_x86_64_RDX 1 +#define DW_x86_64_RCX 2 +#define DW_x86_64_RBX 3 +#define DW_x86_64_RSI 4 +#define DW_x86_64_RDI 5 +#define DW_x86_64_RBP 6 +#define DW_x86_64_RSP 7 +#define DW_x86_64_R8 8 +#define DW_x86_64_R9 9 +#define DW_x86_64_R10 10 +#define DW_x86_64_R11 11 +#define DW_x86_64_R12 12 +#define DW_x86_64_R13 13 +#define DW_x86_64_R14 14 +#define DW_x86_64_R15 15 +#define DW_x86_64_RIP 16 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -8; /* Data alignment factor. */ \ + .uleb128 DW_x86_64_RIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel | DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: + mov $__NR_rt_sigreturn, %rax + syscall +.L__restore_rt_END: +END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_RSP) + cfi_offset(DW_x86_64_R8, OFFSET_R8) + cfi_offset(DW_x86_64_R9, OFFSET_R9) + cfi_offset(DW_x86_64_R10, OFFSET_R10) + cfi_offset(DW_x86_64_R11, OFFSET_R11) + cfi_offset(DW_x86_64_R12, OFFSET_R12) + cfi_offset(DW_x86_64_R13, OFFSET_R13) + cfi_offset(DW_x86_64_R14, OFFSET_R14) + cfi_offset(DW_x86_64_R15, OFFSET_R15) + cfi_offset(DW_x86_64_RDI, OFFSET_RDI) + cfi_offset(DW_x86_64_RSI, OFFSET_RSI) + cfi_offset(DW_x86_64_RBP, OFFSET_RBP) + cfi_offset(DW_x86_64_RSP, OFFSET_RSP) + cfi_offset(DW_x86_64_RBX, OFFSET_RBX) + cfi_offset(DW_x86_64_RDX, OFFSET_RDX) + cfi_offset(DW_x86_64_RAX, OFFSET_RAX) + cfi_offset(DW_x86_64_RCX, OFFSET_RCX) + cfi_offset(DW_x86_64_RIP, OFFSET_RIP) +cfi_signal_frame_end(__restore_rt) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/__set_tls.c b/aosp/bionic/libc/arch-x86_64/bionic/__set_tls.c new file mode 100644 index 000000000..10fd36f13 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/__set_tls.c @@ -0,0 +1,37 @@ +/* + * 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 +#include +#include + +extern int __arch_prctl(int, unsigned long); + +__LIBC_HIDDEN__ int __set_tls(void* ptr) { + return __arch_prctl(ARCH_SET_FS, (uintptr_t) ptr); +} diff --git a/aosp/bionic/libc/arch-x86_64/bionic/_exit_with_stack_teardown.S b/aosp/bionic/libc/arch-x86_64/bionic/_exit_with_stack_teardown.S new file mode 100644 index 000000000..d1f53afe8 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/_exit_with_stack_teardown.S @@ -0,0 +1,41 @@ +/* + * 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 + +// void _exit_with_stack_teardown(void* stackBase, size_t stackSize) +ENTRY_PRIVATE(_exit_with_stack_teardown) + mov $__NR_munmap, %eax + syscall + // If munmap failed, we ignore the failure and exit anyway. + + mov $0, %rdi + mov $__NR_exit, %eax + syscall + // The exit syscall does not return. +END(_exit_with_stack_teardown) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/setjmp.S b/aosp/bionic/libc/arch-x86_64/bionic/setjmp.S new file mode 100644 index 000000000..1d345617d --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/setjmp.S @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, Inc. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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 + + +// The internal structure of a jmp_buf is totally private. +// Current layout (changes from release to release): +// +// word name description +// 0 rbx registers +// 1 rbp +// 2 r12 +// 3 r13 +// 4 r14 +// 5 r15 +// 6 rsp +// 7 pc +// 8 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit +// 9 sigmask signal mask (includes rt signals as well) +// 10 checksum checksum of the core registers, to give better error messages. + +#define _JB_RBX 0 +#define _JB_RBP 1 +#define _JB_R12 2 +#define _JB_R13 3 +#define _JB_R14 4 +#define _JB_R15 5 +#define _JB_RSP 6 +#define _JB_PC 7 +#define _JB_SIGFLAG 8 +#define _JB_SIGMASK 9 +#define _JB_CHECKSUM 10 + +#define MANGLE_REGISTERS 1 + +.macro m_mangle_registers reg +#if MANGLE_REGISTERS + xorq \reg,%rbx + xorq \reg,%rbp + xorq \reg,%r12 + xorq \reg,%r13 + xorq \reg,%r14 + xorq \reg,%r15 + xorq \reg,%rsp + xorq \reg,%r11 +#endif +.endm + +.macro m_unmangle_registers reg + m_mangle_registers \reg +.endm + +.macro m_calculate_checksum dst, src + movq $0, \dst + .irp i,0,1,2,3,4,5,6,7 + xorq (\i*8)(\src), \dst + .endr +.endm + +ENTRY(setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(setjmp) + movl $1,%esi + jmp PIC_PLT(sigsetjmp) +END(setjmp) + +ENTRY(_setjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_setjmp) + movl $0,%esi + jmp PIC_PLT(sigsetjmp) +END(_setjmp) + +// int sigsetjmp(sigjmp_buf env, int save_signal_mask); +ENTRY(sigsetjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp) + pushq %rdi + movq %rsi,%rdi + call PIC_PLT(__bionic_setjmp_cookie_get) + popq %rdi + + // Record setjmp cookie and whether or not we're saving the signal mask. + movq %rax,(_JB_SIGFLAG * 8)(%rdi) + pushq %rax + + // Do we need to save the signal mask? + testq $1,%rax + jz 2f + + // Save current signal mask. + pushq %rdi // Push 'env'. + // The 'how' argument is ignored if new_mask is NULL. + xorq %rsi,%rsi // NULL. + leaq (_JB_SIGMASK * 8)(%rdi),%rdx // old_mask. + call PIC_PLT(sigprocmask) + popq %rdi // Pop 'env'. + +2: + // Save the callee-save registers. + popq %rax + andq $-2,%rax + movq (%rsp),%r11 + m_mangle_registers %rax + movq %rbx,(_JB_RBX * 8)(%rdi) + movq %rbp,(_JB_RBP * 8)(%rdi) + movq %r12,(_JB_R12 * 8)(%rdi) + movq %r13,(_JB_R13 * 8)(%rdi) + movq %r14,(_JB_R14 * 8)(%rdi) + movq %r15,(_JB_R15 * 8)(%rdi) + movq %rsp,(_JB_RSP * 8)(%rdi) + movq %r11,(_JB_PC * 8)(%rdi) + m_unmangle_registers %rax + + m_calculate_checksum %rax, %rdi + movq %rax, (_JB_CHECKSUM * 8)(%rdi) + + xorl %eax,%eax + ret +END(sigsetjmp) + +// void siglongjmp(sigjmp_buf env, int value); +ENTRY(siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(siglongjmp) + movq %rdi,%r12 + pushq %rsi // Push 'value'. + + m_calculate_checksum %rax, %rdi + xorq (_JB_CHECKSUM * 8)(%rdi), %rax + jnz 3f + + // Do we need to restore the signal mask? + movq (_JB_SIGFLAG * 8)(%rdi), %rdi + pushq %rdi // Push cookie + testq $1, %rdi + jz 2f + + // Restore the signal mask. + movq $2,%rdi // SIG_SETMASK. + leaq (_JB_SIGMASK * 8)(%r12),%rsi // new_mask. + xorq %rdx,%rdx // NULL. + call PIC_PLT(sigprocmask) + +2: + // Fetch the setjmp cookie and clear the signal flag bit. + popq %rcx + andq $-2, %rcx + + popq %rax // Pop 'value'. + + // Restore the callee-save registers. + movq (_JB_RBX * 8)(%r12),%rbx + movq (_JB_RBP * 8)(%r12),%rbp + movq (_JB_R13 * 8)(%r12),%r13 + movq (_JB_R14 * 8)(%r12),%r14 + movq (_JB_R15 * 8)(%r12),%r15 + movq (_JB_RSP * 8)(%r12),%rsp + movq (_JB_PC * 8)(%r12),%r11 + movq (_JB_R12 * 8)(%r12),%r12 + m_unmangle_registers %rcx + + // Check the cookie. + pushq %rax + pushq %r11 + movq %rcx, %rdi + call PIC_PLT(__bionic_setjmp_cookie_check) + popq %r11 + popq %rax + + // Return 1 if value is 0. + testl %eax,%eax + jnz 1f + incl %eax +1: + movq %r11,0(%rsp) + ret + +3: + call PIC_PLT(__bionic_setjmp_checksum_mismatch) +END(siglongjmp) + +ALIAS_SYMBOL(longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp) +ALIAS_SYMBOL(_longjmp, siglongjmp) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/syscall.S b/aosp/bionic/libc/arch-x86_64/bionic/syscall.S new file mode 100644 index 000000000..87939ba35 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/syscall.S @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/* + * Generic syscall call. + * Upon entry: + * %rax: system call number + * %rdi: arg0 to system call + * %rsi: arg1 + * %rdx: arg2 + * %rcx: arg3 - syscall expects it at %r10 + * %r8: arg4 + * %r9: arg5 + */ + +#include + +ENTRY(syscall) + # All arguments are passed via registers. + # (Not all will be valid, depending on the syscall.) + mov %edi, %eax + mov %rsi, %rdi + mov %rdx, %rsi + mov %rcx, %rdx + mov %r8, %r10 + mov %r9, %r8 + mov 8(%rsp), %r9 + + # Make the system call. + syscall + cmpq $-MAX_ERRNO, %rax + jb 1f + negl %eax + movl %eax, %edi + call __set_errno_internal +1: + ret +END(syscall) diff --git a/aosp/bionic/libc/arch-x86_64/bionic/vfork.S b/aosp/bionic/libc/arch-x86_64/bionic/vfork.S new file mode 100644 index 000000000..8cfcc3658 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/bionic/vfork.S @@ -0,0 +1,61 @@ +/* + * 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 +#include + +// This custom code preserves the return address across the system call. + +ENTRY(vfork) +__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork) + popq %rdi // Grab the return address. + + // Set cached_pid_ to 0, vforked_ to 1, and stash the previous value. + mov %fs:0, %r8 + mov (TLS_SLOT_THREAD_ID * 8)(%r8), %r8 + movl 20(%r8), %r9d + movl $0x80000000, 20(%r8) + + movl $__NR_vfork, %eax + syscall + pushq %rdi // Restore the return address. + + test %eax, %eax + jz 1f + + // rc != 0: restore the previous cached_pid_/vforked_ values. + movl %r9d, 20(%r8) + + cmpq $-MAX_ERRNO, %rax + jb 1f + negl %eax + movl %eax, %edi + call __set_errno_internal +1: + ret +END(vfork) diff --git a/aosp/bionic/libc/arch-x86_64/string/avx2-wmemset-kbl.S b/aosp/bionic/libc/arch-x86_64/string/avx2-wmemset-kbl.S new file mode 100644 index 000000000..7c485cf70 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/avx2-wmemset-kbl.S @@ -0,0 +1,140 @@ +/* +Copyright (C) 2019 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 + +#ifndef WMEMSET + #define WMEMSET wmemset_avx2 +#endif + + .section .text.avx2,"ax",@progbits + +ENTRY (WMEMSET) +# BB#0: + testq %rdx, %rdx + je .LBB0_14 +# BB#1: + cmpq $32, %rdx + jae .LBB0_3 +# BB#2: + xorl %r8d, %r8d + movq %rdi, %rax + jmp .LBB0_12 +.LBB0_3: + movq %rdx, %r8 + andq $-32, %r8 + vmovd %esi, %xmm0 + vpbroadcastd %xmm0, %ymm0 + leaq -32(%r8), %rcx + movq %rcx, %rax + shrq $5, %rax + leal 1(%rax), %r9d + andl $7, %r9d + cmpq $224, %rcx + jae .LBB0_5 +# BB#4: + xorl %eax, %eax + testq %r9, %r9 + jne .LBB0_8 + jmp .LBB0_10 +.LBB0_5: + leaq 992(%rdi), %rcx + leaq -1(%r9), %r10 + subq %rax, %r10 + xorl %eax, %eax + .p2align 4, 0x90 +.LBB0_6: # =>This Inner Loop Header: Depth=1 + vmovdqu %ymm0, -992(%rcx,%rax,4) + vmovdqu %ymm0, -960(%rcx,%rax,4) + vmovdqu %ymm0, -928(%rcx,%rax,4) + vmovdqu %ymm0, -896(%rcx,%rax,4) + vmovdqu %ymm0, -864(%rcx,%rax,4) + vmovdqu %ymm0, -832(%rcx,%rax,4) + vmovdqu %ymm0, -800(%rcx,%rax,4) + vmovdqu %ymm0, -768(%rcx,%rax,4) + vmovdqu %ymm0, -736(%rcx,%rax,4) + vmovdqu %ymm0, -704(%rcx,%rax,4) + vmovdqu %ymm0, -672(%rcx,%rax,4) + vmovdqu %ymm0, -640(%rcx,%rax,4) + vmovdqu %ymm0, -608(%rcx,%rax,4) + vmovdqu %ymm0, -576(%rcx,%rax,4) + vmovdqu %ymm0, -544(%rcx,%rax,4) + vmovdqu %ymm0, -512(%rcx,%rax,4) + vmovdqu %ymm0, -480(%rcx,%rax,4) + vmovdqu %ymm0, -448(%rcx,%rax,4) + vmovdqu %ymm0, -416(%rcx,%rax,4) + vmovdqu %ymm0, -384(%rcx,%rax,4) + vmovdqu %ymm0, -352(%rcx,%rax,4) + vmovdqu %ymm0, -320(%rcx,%rax,4) + vmovdqu %ymm0, -288(%rcx,%rax,4) + vmovdqu %ymm0, -256(%rcx,%rax,4) + vmovdqu %ymm0, -224(%rcx,%rax,4) + vmovdqu %ymm0, -192(%rcx,%rax,4) + vmovdqu %ymm0, -160(%rcx,%rax,4) + vmovdqu %ymm0, -128(%rcx,%rax,4) + vmovdqu %ymm0, -96(%rcx,%rax,4) + vmovdqu %ymm0, -64(%rcx,%rax,4) + vmovdqu %ymm0, -32(%rcx,%rax,4) + vmovdqu %ymm0, (%rcx,%rax,4) + addq $256, %rax # imm = 0x100 + addq $8, %r10 + jne .LBB0_6 +# BB#7: + testq %r9, %r9 + je .LBB0_10 +.LBB0_8: + leaq (%rdi,%rax,4), %rax + addq $96, %rax + negq %r9 + .p2align 4, 0x90 +.LBB0_9: # =>This Inner Loop Header: Depth=1 + vmovdqu %ymm0, -96(%rax) + vmovdqu %ymm0, -64(%rax) + vmovdqu %ymm0, -32(%rax) + vmovdqu %ymm0, (%rax) + subq $-128, %rax + addq $1, %r9 + jne .LBB0_9 +.LBB0_10: + cmpq %rdx, %r8 + je .LBB0_14 +# BB#11: + leaq (%rdi,%r8,4), %rax +.LBB0_12: + subq %r8, %rdx + .p2align 4, 0x90 +.LBB0_13: # =>This Inner Loop Header: Depth=1 + movl %esi, (%rax) + addq $4, %rax + addq $-1, %rdx + jne .LBB0_13 +.LBB0_14: + movq %rdi, %rax + vzeroupper + retq +END(WMEMSET) diff --git a/aosp/bionic/libc/arch-x86_64/string/cache.h b/aosp/bionic/libc/arch-x86_64/string/cache.h new file mode 100644 index 000000000..4131509fb --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/cache.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +/* Values are optimized for Core Architecture */ +#define SHARED_CACHE_SIZE (4096*1024) /* Core Architecture L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Core Architecture L1 Data Cache */ + +#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) +#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-memmove-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-memmove-slm.S new file mode 100644 index 000000000..739502888 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-memmove-slm.S @@ -0,0 +1,518 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 "cache.h" + +#ifndef MEMMOVE +# define MEMMOVE memmove +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef cfi_rel_offset +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +#endif + +#ifndef cfi_restore +# define cfi_restore(reg) .cfi_restore reg +#endif + +#ifndef cfi_adjust_cfa_offset +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef ALIAS_SYMBOL +# define ALIAS_SYMBOL(alias, original) \ + .globl alias; \ + .equ alias, original +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define CFI_PUSH(REG) \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (REG, 0) + +#define CFI_POP(REG) \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (REG) + +#define PUSH(REG) push REG; +#define POP(REG) pop REG; + +#define ENTRANCE PUSH (%rbx); +#define RETURN_END POP (%rbx); ret +#define RETURN RETURN_END; + + .section .text.sse2,"ax",@progbits +ENTRY (MEMMOVE) + ENTRANCE + mov %rdi, %rax + +/* Check whether we should copy backward or forward. */ + cmp %rsi, %rdi + je L(mm_return) + jg L(mm_len_0_or_more_backward) + +/* Now do checks for lengths. We do [0..16], [0..32], [0..64], [0..128] + separately. */ + cmp $16, %rdx + jbe L(mm_len_0_16_bytes_forward) + + cmp $32, %rdx + ja L(mm_len_32_or_more_forward) + +/* Copy [0..32] and return. */ + movdqu (%rsi), %xmm0 + movdqu -16(%rsi, %rdx), %xmm1 + movdqu %xmm0, (%rdi) + movdqu %xmm1, -16(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_32_or_more_forward): + cmp $64, %rdx + ja L(mm_len_64_or_more_forward) + +/* Copy [0..64] and return. */ + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm1 + movdqu -16(%rsi, %rdx), %xmm2 + movdqu -32(%rsi, %rdx), %xmm3 + movdqu %xmm0, (%rdi) + movdqu %xmm1, 16(%rdi) + movdqu %xmm2, -16(%rdi, %rdx) + movdqu %xmm3, -32(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_64_or_more_forward): + cmp $128, %rdx + ja L(mm_len_128_or_more_forward) + +/* Copy [0..128] and return. */ + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm1 + movdqu 32(%rsi), %xmm2 + movdqu 48(%rsi), %xmm3 + movdqu -64(%rsi, %rdx), %xmm4 + movdqu -48(%rsi, %rdx), %xmm5 + movdqu -32(%rsi, %rdx), %xmm6 + movdqu -16(%rsi, %rdx), %xmm7 + movdqu %xmm0, (%rdi) + movdqu %xmm1, 16(%rdi) + movdqu %xmm2, 32(%rdi) + movdqu %xmm3, 48(%rdi) + movdqu %xmm4, -64(%rdi, %rdx) + movdqu %xmm5, -48(%rdi, %rdx) + movdqu %xmm6, -32(%rdi, %rdx) + movdqu %xmm7, -16(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_128_or_more_forward): +/* Aligning the address of destination. */ +/* save first unaligned 64 bytes */ + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm1 + movdqu 32(%rsi), %xmm2 + movdqu 48(%rsi), %xmm3 + + lea 64(%rdi), %r8 + and $-64, %r8 /* r8 now aligned to next 64 byte boundary */ + sub %rdi, %rsi /* rsi = src - dst = diff */ + + movdqu (%r8, %rsi), %xmm4 + movdqu 16(%r8, %rsi), %xmm5 + movdqu 32(%r8, %rsi), %xmm6 + movdqu 48(%r8, %rsi), %xmm7 + + movdqu %xmm0, (%rdi) + movdqu %xmm1, 16(%rdi) + movdqu %xmm2, 32(%rdi) + movdqu %xmm3, 48(%rdi) + movdqa %xmm4, (%r8) + movaps %xmm5, 16(%r8) + movaps %xmm6, 32(%r8) + movaps %xmm7, 48(%r8) + add $64, %r8 + + lea (%rdi, %rdx), %rbx + and $-64, %rbx + cmp %r8, %rbx + jbe L(mm_copy_remaining_forward) + + cmp $SHARED_CACHE_SIZE_HALF, %rdx + jae L(mm_large_page_loop_forward) + + .p2align 4 +L(mm_main_loop_forward): + + prefetcht0 128(%r8, %rsi) + + movdqu (%r8, %rsi), %xmm0 + movdqu 16(%r8, %rsi), %xmm1 + movdqu 32(%r8, %rsi), %xmm2 + movdqu 48(%r8, %rsi), %xmm3 + movdqa %xmm0, (%r8) + movaps %xmm1, 16(%r8) + movaps %xmm2, 32(%r8) + movaps %xmm3, 48(%r8) + lea 64(%r8), %r8 + cmp %r8, %rbx + ja L(mm_main_loop_forward) + +L(mm_copy_remaining_forward): + add %rdi, %rdx + sub %r8, %rdx +/* We copied all up till %rdi position in the dst. + In %rdx now is how many bytes are left to copy. + Now we need to advance %r8. */ + lea (%r8, %rsi), %r9 + +L(mm_remaining_0_64_bytes_forward): + cmp $32, %rdx + ja L(mm_remaining_33_64_bytes_forward) + cmp $16, %rdx + ja L(mm_remaining_17_32_bytes_forward) + test %rdx, %rdx + .p2align 4,,2 + je L(mm_return) + + cmpb $8, %dl + ja L(mm_remaining_9_16_bytes_forward) + cmpb $4, %dl + .p2align 4,,5 + ja L(mm_remaining_5_8_bytes_forward) + cmpb $2, %dl + .p2align 4,,1 + ja L(mm_remaining_3_4_bytes_forward) + movzbl -1(%r9,%rdx), %esi + movzbl (%r9), %ebx + movb %sil, -1(%r8,%rdx) + movb %bl, (%r8) + jmp L(mm_return) + +L(mm_remaining_33_64_bytes_forward): + movdqu (%r9), %xmm0 + movdqu 16(%r9), %xmm1 + movdqu -32(%r9, %rdx), %xmm2 + movdqu -16(%r9, %rdx), %xmm3 + movdqu %xmm0, (%r8) + movdqu %xmm1, 16(%r8) + movdqu %xmm2, -32(%r8, %rdx) + movdqu %xmm3, -16(%r8, %rdx) + jmp L(mm_return) + +L(mm_remaining_17_32_bytes_forward): + movdqu (%r9), %xmm0 + movdqu -16(%r9, %rdx), %xmm1 + movdqu %xmm0, (%r8) + movdqu %xmm1, -16(%r8, %rdx) + jmp L(mm_return) + +L(mm_remaining_5_8_bytes_forward): + movl (%r9), %esi + movl -4(%r9,%rdx), %ebx + movl %esi, (%r8) + movl %ebx, -4(%r8,%rdx) + jmp L(mm_return) + +L(mm_remaining_9_16_bytes_forward): + mov (%r9), %rsi + mov -8(%r9, %rdx), %rbx + mov %rsi, (%r8) + mov %rbx, -8(%r8, %rdx) + jmp L(mm_return) + +L(mm_remaining_3_4_bytes_forward): + movzwl -2(%r9,%rdx), %esi + movzwl (%r9), %ebx + movw %si, -2(%r8,%rdx) + movw %bx, (%r8) + jmp L(mm_return) + +L(mm_len_0_16_bytes_forward): + testb $24, %dl + jne L(mm_len_9_16_bytes_forward) + testb $4, %dl + .p2align 4,,5 + jne L(mm_len_5_8_bytes_forward) + test %rdx, %rdx + .p2align 4,,2 + je L(mm_return) + testb $2, %dl + .p2align 4,,1 + jne L(mm_len_2_4_bytes_forward) + movzbl -1(%rsi,%rdx), %ebx + movzbl (%rsi), %esi + movb %bl, -1(%rdi,%rdx) + movb %sil, (%rdi) + jmp L(mm_return) + +L(mm_len_2_4_bytes_forward): + movzwl -2(%rsi,%rdx), %ebx + movzwl (%rsi), %esi + movw %bx, -2(%rdi,%rdx) + movw %si, (%rdi) + jmp L(mm_return) + +L(mm_len_5_8_bytes_forward): + movl (%rsi), %ebx + movl -4(%rsi,%rdx), %esi + movl %ebx, (%rdi) + movl %esi, -4(%rdi,%rdx) + jmp L(mm_return) + +L(mm_len_9_16_bytes_forward): + mov (%rsi), %rbx + mov -8(%rsi, %rdx), %rsi + mov %rbx, (%rdi) + mov %rsi, -8(%rdi, %rdx) + jmp L(mm_return) + +L(mm_recalc_len): +/* Compute in %rdx how many bytes are left to copy after + the main loop stops. */ + mov %rbx, %rdx + sub %rdi, %rdx +/* The code for copying backwards. */ +L(mm_len_0_or_more_backward): + +/* Now do checks for lengths. We do [0..16], [16..32], [32..64], [64..128] + separately. */ + cmp $16, %rdx + jbe L(mm_len_0_16_bytes_backward) + + cmp $32, %rdx + ja L(mm_len_32_or_more_backward) + +/* Copy [0..32] and return. */ + movdqu (%rsi), %xmm0 + movdqu -16(%rsi, %rdx), %xmm1 + movdqu %xmm0, (%rdi) + movdqu %xmm1, -16(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_32_or_more_backward): + cmp $64, %rdx + ja L(mm_len_64_or_more_backward) + +/* Copy [0..64] and return. */ + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm1 + movdqu -16(%rsi, %rdx), %xmm2 + movdqu -32(%rsi, %rdx), %xmm3 + movdqu %xmm0, (%rdi) + movdqu %xmm1, 16(%rdi) + movdqu %xmm2, -16(%rdi, %rdx) + movdqu %xmm3, -32(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_64_or_more_backward): + cmp $128, %rdx + ja L(mm_len_128_or_more_backward) + +/* Copy [0..128] and return. */ + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm1 + movdqu 32(%rsi), %xmm2 + movdqu 48(%rsi), %xmm3 + movdqu -64(%rsi, %rdx), %xmm4 + movdqu -48(%rsi, %rdx), %xmm5 + movdqu -32(%rsi, %rdx), %xmm6 + movdqu -16(%rsi, %rdx), %xmm7 + movdqu %xmm0, (%rdi) + movdqu %xmm1, 16(%rdi) + movdqu %xmm2, 32(%rdi) + movdqu %xmm3, 48(%rdi) + movdqu %xmm4, -64(%rdi, %rdx) + movdqu %xmm5, -48(%rdi, %rdx) + movdqu %xmm6, -32(%rdi, %rdx) + movdqu %xmm7, -16(%rdi, %rdx) + jmp L(mm_return) + +L(mm_len_128_or_more_backward): +/* Aligning the address of destination. We need to save + 16 bits from the source in order not to overwrite them. */ + movdqu -16(%rsi, %rdx), %xmm0 + movdqu -32(%rsi, %rdx), %xmm1 + movdqu -48(%rsi, %rdx), %xmm2 + movdqu -64(%rsi, %rdx), %xmm3 + + lea (%rdi, %rdx), %r9 + and $-64, %r9 /* r9 = aligned dst */ + + mov %rsi, %r8 + sub %rdi, %r8 /* r8 = src - dst, diff */ + + movdqu -16(%r9, %r8), %xmm4 + movdqu -32(%r9, %r8), %xmm5 + movdqu -48(%r9, %r8), %xmm6 + movdqu -64(%r9, %r8), %xmm7 + + movdqu %xmm0, -16(%rdi, %rdx) + movdqu %xmm1, -32(%rdi, %rdx) + movdqu %xmm2, -48(%rdi, %rdx) + movdqu %xmm3, -64(%rdi, %rdx) + movdqa %xmm4, -16(%r9) + movaps %xmm5, -32(%r9) + movaps %xmm6, -48(%r9) + movaps %xmm7, -64(%r9) + lea -64(%r9), %r9 + + lea 64(%rdi), %rbx + and $-64, %rbx + + cmp %r9, %rbx + jae L(mm_recalc_len) + + cmp $SHARED_CACHE_SIZE_HALF, %rdx + jae L(mm_large_page_loop_backward) + + .p2align 4 +L(mm_main_loop_backward): + + prefetcht0 -128(%r9, %r8) + + movdqu -64(%r9, %r8), %xmm0 + movdqu -48(%r9, %r8), %xmm1 + movdqu -32(%r9, %r8), %xmm2 + movdqu -16(%r9, %r8), %xmm3 + movdqa %xmm0, -64(%r9) + movaps %xmm1, -48(%r9) + movaps %xmm2, -32(%r9) + movaps %xmm3, -16(%r9) + lea -64(%r9), %r9 + cmp %r9, %rbx + jb L(mm_main_loop_backward) + jmp L(mm_recalc_len) + +/* Copy [0..16] and return. */ +L(mm_len_0_16_bytes_backward): + testb $24, %dl + jnz L(mm_len_9_16_bytes_backward) + testb $4, %dl + .p2align 4,,5 + jnz L(mm_len_5_8_bytes_backward) + test %rdx, %rdx + .p2align 4,,2 + je L(mm_return) + testb $2, %dl + .p2align 4,,1 + jne L(mm_len_3_4_bytes_backward) + movzbl -1(%rsi,%rdx), %ebx + movzbl (%rsi), %ecx + movb %bl, -1(%rdi,%rdx) + movb %cl, (%rdi) + jmp L(mm_return) + +L(mm_len_3_4_bytes_backward): + movzwl -2(%rsi,%rdx), %ebx + movzwl (%rsi), %ecx + movw %bx, -2(%rdi,%rdx) + movw %cx, (%rdi) + jmp L(mm_return) + +L(mm_len_9_16_bytes_backward): + movl -4(%rsi,%rdx), %ebx + movl -8(%rsi,%rdx), %ecx + movl %ebx, -4(%rdi,%rdx) + movl %ecx, -8(%rdi,%rdx) + sub $8, %rdx + jmp L(mm_len_0_16_bytes_backward) + +L(mm_len_5_8_bytes_backward): + movl (%rsi), %ebx + movl -4(%rsi,%rdx), %ecx + movl %ebx, (%rdi) + movl %ecx, -4(%rdi,%rdx) + +L(mm_return): + RETURN + +/* Big length copy forward part. */ + + .p2align 4 +L(mm_large_page_loop_forward): + movdqu (%r8, %rsi), %xmm0 + movdqu 16(%r8, %rsi), %xmm1 + movdqu 32(%r8, %rsi), %xmm2 + movdqu 48(%r8, %rsi), %xmm3 + movntdq %xmm0, (%r8) + movntdq %xmm1, 16(%r8) + movntdq %xmm2, 32(%r8) + movntdq %xmm3, 48(%r8) + lea 64(%r8), %r8 + cmp %r8, %rbx + ja L(mm_large_page_loop_forward) + sfence + jmp L(mm_copy_remaining_forward) + +/* Big length copy backward part. */ + .p2align 4 +L(mm_large_page_loop_backward): + movdqu -64(%r9, %r8), %xmm0 + movdqu -48(%r9, %r8), %xmm1 + movdqu -32(%r9, %r8), %xmm2 + movdqu -16(%r9, %r8), %xmm3 + movntdq %xmm0, -64(%r9) + movntdq %xmm1, -48(%r9) + movntdq %xmm2, -32(%r9) + movntdq %xmm3, -16(%r9) + lea -64(%r9), %r9 + cmp %r9, %rbx + jb L(mm_large_page_loop_backward) + sfence + jmp L(mm_recalc_len) + +END (MEMMOVE) + +ALIAS_SYMBOL(memcpy, MEMMOVE) diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-memset-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-memset-slm.S new file mode 100644 index 000000000..fc502c021 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-memset-slm.S @@ -0,0 +1,149 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 + +#include "cache.h" + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + + +ENTRY(__memset_chk) + # %rdi = dst, %rsi = byte, %rdx = n, %rcx = dst_len + cmp %rcx, %rdx + ja __memset_chk_fail + // Fall through to memset... +END(__memset_chk) + + + .section .text.sse2,"ax",@progbits +ENTRY(memset) + movq %rdi, %rax + and $0xff, %rsi + mov $0x0101010101010101, %rcx + imul %rsi, %rcx + cmpq $16, %rdx + jae L(16bytesormore) + testb $8, %dl + jnz L(8_15bytes) + testb $4, %dl + jnz L(4_7bytes) + testb $2, %dl + jnz L(2_3bytes) + testb $1, %dl + jz L(return) + movb %cl, (%rdi) +L(return): + ret + +L(8_15bytes): + movq %rcx, (%rdi) + movq %rcx, -8(%rdi, %rdx) + ret + +L(4_7bytes): + movl %ecx, (%rdi) + movl %ecx, -4(%rdi, %rdx) + ret + +L(2_3bytes): + movw %cx, (%rdi) + movw %cx, -2(%rdi, %rdx) + ret + + ALIGN (4) +L(16bytesormore): + movd %rcx, %xmm0 + pshufd $0, %xmm0, %xmm0 + movdqu %xmm0, (%rdi) + movdqu %xmm0, -16(%rdi, %rdx) + cmpq $32, %rdx + jbe L(32bytesless) + movdqu %xmm0, 16(%rdi) + movdqu %xmm0, -32(%rdi, %rdx) + cmpq $64, %rdx + jbe L(64bytesless) + movdqu %xmm0, 32(%rdi) + movdqu %xmm0, 48(%rdi) + movdqu %xmm0, -64(%rdi, %rdx) + movdqu %xmm0, -48(%rdi, %rdx) + cmpq $128, %rdx + ja L(128bytesmore) +L(32bytesless): +L(64bytesless): + ret + + ALIGN (4) +L(128bytesmore): + leaq 64(%rdi), %rcx + andq $-64, %rcx + movq %rdx, %r8 + addq %rdi, %rdx + andq $-64, %rdx + cmpq %rcx, %rdx + je L(return) + +#ifdef SHARED_CACHE_SIZE + cmp $SHARED_CACHE_SIZE, %r8 +#else + cmp __x86_64_shared_cache_size(%rip), %r8 +#endif + ja L(128bytesmore_nt) + + ALIGN (4) +L(128bytesmore_normal): + movdqa %xmm0, (%rcx) + movaps %xmm0, 0x10(%rcx) + movaps %xmm0, 0x20(%rcx) + movaps %xmm0, 0x30(%rcx) + addq $64, %rcx + cmpq %rcx, %rdx + jne L(128bytesmore_normal) + ret + + ALIGN (4) +L(128bytesmore_nt): + movntdq %xmm0, (%rcx) + movntdq %xmm0, 0x10(%rcx) + movntdq %xmm0, 0x20(%rcx) + movntdq %xmm0, 0x30(%rcx) + leaq 64(%rcx), %rcx + cmpq %rcx, %rdx + jne L(128bytesmore_nt) + sfence + ret + +END(memset) diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-stpcpy-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-stpcpy-slm.S new file mode 100644 index 000000000..0ad2d44cf --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-stpcpy-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STPCPY +#define STRCPY stpcpy +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-stpncpy-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-stpncpy-slm.S new file mode 100644 index 000000000..30666850b --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-stpncpy-slm.S @@ -0,0 +1,34 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define USE_AS_STPCPY +#define STRCPY stpncpy +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-strcat-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-strcat-slm.S new file mode 100644 index 000000000..dd8207ff5 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-strcat-slm.S @@ -0,0 +1,87 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef STRCAT +# define STRCAT strcat +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define USE_AS_STRCAT + +.text +ENTRY (STRCAT) + mov %rdi, %r9 +#ifdef USE_AS_STRNCAT + mov %rdx, %r8 +#endif + +#define RETURN jmp L(Strcpy) +#include "sse2-strlen-slm.S" + +#undef RETURN +#define RETURN ret + +L(Strcpy): + lea (%r9, %rax), %rdi + mov %rsi, %rcx + mov %r9, %rax /* save result */ + +#ifdef USE_AS_STRNCAT + test %r8, %r8 + jz L(ExitZero) +# define USE_AS_STRNCPY +#endif +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-strcpy-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-strcpy-slm.S new file mode 100644 index 000000000..3e146bfbc --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-strcpy-slm.S @@ -0,0 +1,1921 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_STRCAT + +# ifndef STRCPY +# define STRCPY strcpy +# endif + +# ifndef L +# define L(label) .L##label +# endif + +# ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +# endif + +# ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +# endif + +# ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +# endif + +# ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +# endif + +#endif + +#define JMPTBL(I, B) I - B +#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + lea TABLE(%rip), %r11; \ + movslq (%r11, INDEX, SCALE), %rcx; \ + lea (%r11, %rcx), %rcx; \ + jmp *%rcx + +#ifndef USE_AS_STRCAT + +# define RETURN ret + +.text +ENTRY (STRCPY) +# ifdef USE_AS_STRNCPY + mov %rdx, %r8 + test %r8, %r8 + jz L(ExitZero) +# endif + mov %rsi, %rcx +# ifndef USE_AS_STPCPY + mov %rdi, %rax /* save result */ +# endif + +#endif + and $63, %rcx + cmp $32, %rcx + jbe L(SourceStringAlignmentLess32) + + and $-16, %rsi + and $15, %rcx + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + + pcmpeqb (%rsi), %xmm1 + pmovmskb %xmm1, %rdx + shr %cl, %rdx +#ifdef USE_AS_STRNCPY +# if defined USE_AS_STPCPY || defined USE_AS_STRCAT + mov $16, %r10 + sub %rcx, %r10 + cmp %r10, %r8 +# else + mov $17, %r10 + sub %rcx, %r10 + cmp %r10, %r8 +# endif + jbe L(CopyFrom1To16BytesTailCase2OrCase3) +#endif + test %rdx, %rdx + jnz L(CopyFrom1To16BytesTail) + + pcmpeqb 16(%rsi), %xmm0 + pmovmskb %xmm0, %rdx +#ifdef USE_AS_STRNCPY + add $16, %r10 + cmp %r10, %r8 + jbe L(CopyFrom1To32BytesCase2OrCase3) +#endif + test %rdx, %rdx + jnz L(CopyFrom1To32Bytes) + + movdqu (%rsi, %rcx), %xmm1 /* copy 16 bytes */ + movdqu %xmm1, (%rdi) + +/* If source adress alignment != destination adress alignment */ + .p2align 4 +L(Unalign16Both): + sub %rcx, %rdi +#ifdef USE_AS_STRNCPY + add %rcx, %r8 +#endif + mov $16, %rcx + movdqa (%rsi, %rcx), %xmm1 + movaps 16(%rsi, %rcx), %xmm2 + movdqu %xmm1, (%rdi, %rcx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $48, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm2) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%rsi, %rcx), %xmm3 + movdqu %xmm2, (%rdi, %rcx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm3) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%rsi, %rcx), %xmm4 + movdqu %xmm3, (%rdi, %rcx) + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm4) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%rsi, %rcx), %xmm1 + movdqu %xmm4, (%rdi, %rcx) + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm1) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%rsi, %rcx), %xmm2 + movdqu %xmm1, (%rdi, %rcx) + pcmpeqb %xmm2, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm2) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movaps 16(%rsi, %rcx), %xmm3 + movdqu %xmm2, (%rdi, %rcx) + pcmpeqb %xmm3, %xmm0 + pmovmskb %xmm0, %rdx + add $16, %rcx +#ifdef USE_AS_STRNCPY + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) +#endif + test %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm3) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + movdqu %xmm3, (%rdi, %rcx) + mov %rsi, %rdx + lea 16(%rsi, %rcx), %rsi + and $-0x40, %rsi + sub %rsi, %rdx + sub %rdx, %rdi +#ifdef USE_AS_STRNCPY + lea 128(%r8, %rdx), %r8 +#endif +L(Unaligned64Loop): + movaps (%rsi), %xmm2 + movaps %xmm2, %xmm4 + movaps 16(%rsi), %xmm5 + movaps 32(%rsi), %xmm3 + movaps %xmm3, %xmm6 + movaps 48(%rsi), %xmm7 + pminub %xmm5, %xmm2 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm0, %xmm3 + pmovmskb %xmm3, %rdx +#ifdef USE_AS_STRNCPY + sub $64, %r8 + jbe L(UnalignedLeaveCase2OrCase3) +#endif + test %rdx, %rdx + jnz L(Unaligned64Leave) + +L(Unaligned64Loop_start): + add $64, %rdi + add $64, %rsi + movdqu %xmm4, -64(%rdi) + movaps (%rsi), %xmm2 + movdqa %xmm2, %xmm4 + movdqu %xmm5, -48(%rdi) + movaps 16(%rsi), %xmm5 + pminub %xmm5, %xmm2 + movaps 32(%rsi), %xmm3 + movdqu %xmm6, -32(%rdi) + movaps %xmm3, %xmm6 + movdqu %xmm7, -16(%rdi) + movaps 48(%rsi), %xmm7 + pminub %xmm7, %xmm3 + pminub %xmm2, %xmm3 + pcmpeqb %xmm0, %xmm3 + pmovmskb %xmm3, %rdx +#ifdef USE_AS_STRNCPY + sub $64, %r8 + jbe L(UnalignedLeaveCase2OrCase3) +#endif + test %rdx, %rdx + jz L(Unaligned64Loop_start) + +L(Unaligned64Leave): + pxor %xmm1, %xmm1 + + pcmpeqb %xmm4, %xmm0 + pcmpeqb %xmm5, %xmm1 + pmovmskb %xmm0, %rdx + pmovmskb %xmm1, %rcx + test %rdx, %rdx + jnz L(CopyFrom1To16BytesUnaligned_0) + test %rcx, %rcx + jnz L(CopyFrom1To16BytesUnaligned_16) + + pcmpeqb %xmm6, %xmm0 + pcmpeqb %xmm7, %xmm1 + pmovmskb %xmm0, %rdx + pmovmskb %xmm1, %rcx + test %rdx, %rdx + jnz L(CopyFrom1To16BytesUnaligned_32) + + bsf %rcx, %rdx + movdqu %xmm4, (%rdi) + movdqu %xmm5, 16(%rdi) + movdqu %xmm6, 32(%rdi) +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT +# ifdef USE_AS_STPCPY + lea 48(%rdi, %rdx), %rax +# endif + movdqu %xmm7, 48(%rdi) + add $15, %r8 + sub %rdx, %r8 + lea 49(%rdi, %rdx), %rdi + jmp L(StrncpyFillTailWithZero) +#else + add $48, %rsi + add $48, %rdi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) +#endif + +/* If source adress alignment == destination adress alignment */ + +L(SourceStringAlignmentLess32): + pxor %xmm0, %xmm0 + movdqu (%rsi), %xmm1 + movdqu 16(%rsi), %xmm2 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %rdx + +#ifdef USE_AS_STRNCPY +# if defined USE_AS_STPCPY || defined USE_AS_STRCAT + cmp $16, %r8 +# else + cmp $17, %r8 +# endif + jbe L(CopyFrom1To16BytesTail1Case2OrCase3) +#endif + test %rdx, %rdx + jnz L(CopyFrom1To16BytesTail1) + + pcmpeqb %xmm2, %xmm0 + movdqu %xmm1, (%rdi) + pmovmskb %xmm0, %rdx + +#ifdef USE_AS_STRNCPY +# if defined USE_AS_STPCPY || defined USE_AS_STRCAT + cmp $32, %r8 +# else + cmp $33, %r8 +# endif + jbe L(CopyFrom1To32Bytes1Case2OrCase3) +#endif + test %rdx, %rdx + jnz L(CopyFrom1To32Bytes1) + + and $15, %rcx + and $-16, %rsi + + jmp L(Unalign16Both) + +/*------End of main part with loops---------------------*/ + +/* Case1 */ + +#if (!defined USE_AS_STRNCPY) || (defined USE_AS_STRCAT) + .p2align 4 +L(CopyFrom1To16Bytes): + add %rcx, %rdi + add %rcx, %rsi + bsf %rdx, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) +#endif + .p2align 4 +L(CopyFrom1To16BytesTail): + add %rcx, %rsi + bsf %rdx, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) + + .p2align 4 +L(CopyFrom1To32Bytes1): + add $16, %rsi + add $16, %rdi +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $16, %r8 +#endif +L(CopyFrom1To16BytesTail1): + bsf %rdx, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) + + .p2align 4 +L(CopyFrom1To32Bytes): + bsf %rdx, %rdx + add %rcx, %rsi + add $16, %rdx + sub %rcx, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_0): + bsf %rdx, %rdx +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT +# ifdef USE_AS_STPCPY + lea (%rdi, %rdx), %rax +# endif + movdqu %xmm4, (%rdi) + add $63, %r8 + sub %rdx, %r8 + lea 1(%rdi, %rdx), %rdi + jmp L(StrncpyFillTailWithZero) +#else + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_16): + bsf %rcx, %rdx + movdqu %xmm4, (%rdi) +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT +# ifdef USE_AS_STPCPY + lea 16(%rdi, %rdx), %rax +# endif + movdqu %xmm5, 16(%rdi) + add $47, %r8 + sub %rdx, %r8 + lea 17(%rdi, %rdx), %rdi + jmp L(StrncpyFillTailWithZero) +#else + add $16, %rsi + add $16, %rdi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) +#endif + + .p2align 4 +L(CopyFrom1To16BytesUnaligned_32): + bsf %rdx, %rdx + movdqu %xmm4, (%rdi) + movdqu %xmm5, 16(%rdi) +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT +# ifdef USE_AS_STPCPY + lea 32(%rdi, %rdx), %rax +# endif + movdqu %xmm6, 32(%rdi) + add $31, %r8 + sub %rdx, %r8 + lea 33(%rdi, %rdx), %rdi + jmp L(StrncpyFillTailWithZero) +#else + add $32, %rsi + add $32, %rdi + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) +#endif + +#ifdef USE_AS_STRNCPY +# ifndef USE_AS_STRCAT + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm6): + movdqu %xmm6, (%rdi, %rcx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm5): + movdqu %xmm5, (%rdi, %rcx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm4): + movdqu %xmm4, (%rdi, %rcx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm3): + movdqu %xmm3, (%rdi, %rcx) + jmp L(CopyFrom1To16BytesXmmExit) + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm1): + movdqu %xmm1, (%rdi, %rcx) + jmp L(CopyFrom1To16BytesXmmExit) +# endif + + .p2align 4 +L(CopyFrom1To16BytesExit): + BRANCH_TO_JMPTBL_ENTRY (L(ExitTable), %rdx, 4) + +/* Case2 */ + + .p2align 4 +L(CopyFrom1To16BytesCase2): + add $16, %r8 + add %rcx, %rdi + add %rcx, %rsi + bsf %rdx, %rdx + cmp %r8, %rdx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + + .p2align 4 +L(CopyFrom1To32BytesCase2): + add %rcx, %rsi + bsf %rdx, %rdx + add $16, %rdx + sub %rcx, %rdx + cmp %r8, %rdx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + +L(CopyFrom1To16BytesTailCase2): + add %rcx, %rsi + bsf %rdx, %rdx + cmp %r8, %rdx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + +L(CopyFrom1To16BytesTail1Case2): + bsf %rdx, %rdx + cmp %r8, %rdx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + +/* Case2 or Case3, Case3 */ + + .p2align 4 +L(CopyFrom1To16BytesCase2OrCase3): + test %rdx, %rdx + jnz L(CopyFrom1To16BytesCase2) +L(CopyFrom1To16BytesCase3): + add $16, %r8 + add %rcx, %rdi + add %rcx, %rsi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + + .p2align 4 +L(CopyFrom1To32BytesCase2OrCase3): + test %rdx, %rdx + jnz L(CopyFrom1To32BytesCase2) + add %rcx, %rsi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + + .p2align 4 +L(CopyFrom1To16BytesTailCase2OrCase3): + test %rdx, %rdx + jnz L(CopyFrom1To16BytesTailCase2) + add %rcx, %rsi + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + + .p2align 4 +L(CopyFrom1To32Bytes1Case2OrCase3): + add $16, %rdi + add $16, %rsi + sub $16, %r8 +L(CopyFrom1To16BytesTail1Case2OrCase3): + test %rdx, %rdx + jnz L(CopyFrom1To16BytesTail1Case2) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + +#endif + +/*------------End labels regarding with copying 1-16 bytes--and 1-32 bytes----*/ + + .p2align 4 +L(Exit1): + mov %dh, (%rdi) +#ifdef USE_AS_STPCPY + lea (%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $1, %r8 + lea 1(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit2): + mov (%rsi), %dx + mov %dx, (%rdi) +#ifdef USE_AS_STPCPY + lea 1(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $2, %r8 + lea 2(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit3): + mov (%rsi), %cx + mov %cx, (%rdi) + mov %dh, 2(%rdi) +#ifdef USE_AS_STPCPY + lea 2(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $3, %r8 + lea 3(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit4): + mov (%rsi), %edx + mov %edx, (%rdi) +#ifdef USE_AS_STPCPY + lea 3(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $4, %r8 + lea 4(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit5): + mov (%rsi), %ecx + mov %dh, 4(%rdi) + mov %ecx, (%rdi) +#ifdef USE_AS_STPCPY + lea 4(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $5, %r8 + lea 5(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit6): + mov (%rsi), %ecx + mov 4(%rsi), %dx + mov %ecx, (%rdi) + mov %dx, 4(%rdi) +#ifdef USE_AS_STPCPY + lea 5(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $6, %r8 + lea 6(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit7): + mov (%rsi), %ecx + mov 3(%rsi), %edx + mov %ecx, (%rdi) + mov %edx, 3(%rdi) +#ifdef USE_AS_STPCPY + lea 6(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $7, %r8 + lea 7(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit8): + mov (%rsi), %rdx + mov %rdx, (%rdi) +#ifdef USE_AS_STPCPY + lea 7(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $8, %r8 + lea 8(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit9): + mov (%rsi), %rcx + mov %dh, 8(%rdi) + mov %rcx, (%rdi) +#ifdef USE_AS_STPCPY + lea 8(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $9, %r8 + lea 9(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit10): + mov (%rsi), %rcx + mov 8(%rsi), %dx + mov %rcx, (%rdi) + mov %dx, 8(%rdi) +#ifdef USE_AS_STPCPY + lea 9(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $10, %r8 + lea 10(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit11): + mov (%rsi), %rcx + mov 7(%rsi), %edx + mov %rcx, (%rdi) + mov %edx, 7(%rdi) +#ifdef USE_AS_STPCPY + lea 10(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $11, %r8 + lea 11(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit12): + mov (%rsi), %rcx + mov 8(%rsi), %edx + mov %rcx, (%rdi) + mov %edx, 8(%rdi) +#ifdef USE_AS_STPCPY + lea 11(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $12, %r8 + lea 12(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit13): + mov (%rsi), %rcx + mov 5(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 5(%rdi) +#ifdef USE_AS_STPCPY + lea 12(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $13, %r8 + lea 13(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit14): + mov (%rsi), %rcx + mov 6(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 6(%rdi) +#ifdef USE_AS_STPCPY + lea 13(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $14, %r8 + lea 14(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit15): + mov (%rsi), %rcx + mov 7(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 7(%rdi) +#ifdef USE_AS_STPCPY + lea 14(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $15, %r8 + lea 15(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit16): + movdqu (%rsi), %xmm0 + movdqu %xmm0, (%rdi) +#ifdef USE_AS_STPCPY + lea 15(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $16, %r8 + lea 16(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit17): + movdqu (%rsi), %xmm0 + movdqu %xmm0, (%rdi) + mov %dh, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 16(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $17, %r8 + lea 17(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit18): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %cx + movdqu %xmm0, (%rdi) + mov %cx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 17(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $18, %r8 + lea 18(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit19): + movdqu (%rsi), %xmm0 + mov 15(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %ecx, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 18(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $19, %r8 + lea 19(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit20): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %ecx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 19(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $20, %r8 + lea 20(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit21): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %ecx, 16(%rdi) + mov %dh, 20(%rdi) +#ifdef USE_AS_STPCPY + lea 20(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $21, %r8 + lea 21(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit22): + movdqu (%rsi), %xmm0 + mov 14(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 14(%rdi) +#ifdef USE_AS_STPCPY + lea 21(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $22, %r8 + lea 22(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit23): + movdqu (%rsi), %xmm0 + mov 15(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 22(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $23, %r8 + lea 23(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit24): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 23(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $24, %r8 + lea 24(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit25): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 16(%rdi) + mov %dh, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 24(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $25, %r8 + lea 25(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit26): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 24(%rsi), %cx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %cx, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 25(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $26, %r8 + lea 26(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit27): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 23(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %ecx, 23(%rdi) +#ifdef USE_AS_STPCPY + lea 26(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $27, %r8 + lea 27(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit28): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 24(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %ecx, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 27(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $28, %r8 + lea 28(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit29): + movdqu (%rsi), %xmm0 + movdqu 13(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 13(%rdi) +#ifdef USE_AS_STPCPY + lea 28(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $29, %r8 + lea 29(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit30): + movdqu (%rsi), %xmm0 + movdqu 14(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 14(%rdi) +#ifdef USE_AS_STPCPY + lea 29(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $30, %r8 + lea 30(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit31): + movdqu (%rsi), %xmm0 + movdqu 15(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 30(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $31, %r8 + lea 31(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + + .p2align 4 +L(Exit32): + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 31(%rdi), %rax +#endif +#if defined USE_AS_STRNCPY && !defined USE_AS_STRCAT + sub $32, %r8 + lea 32(%rdi), %rdi + jnz L(StrncpyFillTailWithZero) +#endif + RETURN + +#ifdef USE_AS_STRNCPY + + .p2align 4 +L(StrncpyExit0): +#ifdef USE_AS_STPCPY + mov %rdi, %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, (%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit1): + mov (%rsi), %dl + mov %dl, (%rdi) +#ifdef USE_AS_STPCPY + lea 1(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 1(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit2): + mov (%rsi), %dx + mov %dx, (%rdi) +#ifdef USE_AS_STPCPY + lea 2(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 2(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit3): + mov (%rsi), %cx + mov 2(%rsi), %dl + mov %cx, (%rdi) + mov %dl, 2(%rdi) +#ifdef USE_AS_STPCPY + lea 3(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 3(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit4): + mov (%rsi), %edx + mov %edx, (%rdi) +#ifdef USE_AS_STPCPY + lea 4(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 4(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit5): + mov (%rsi), %ecx + mov 4(%rsi), %dl + mov %ecx, (%rdi) + mov %dl, 4(%rdi) +#ifdef USE_AS_STPCPY + lea 5(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 5(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit6): + mov (%rsi), %ecx + mov 4(%rsi), %dx + mov %ecx, (%rdi) + mov %dx, 4(%rdi) +#ifdef USE_AS_STPCPY + lea 6(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 6(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit7): + mov (%rsi), %ecx + mov 3(%rsi), %edx + mov %ecx, (%rdi) + mov %edx, 3(%rdi) +#ifdef USE_AS_STPCPY + lea 7(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 7(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit8): + mov (%rsi), %rdx + mov %rdx, (%rdi) +#ifdef USE_AS_STPCPY + lea 8(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 8(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit9): + mov (%rsi), %rcx + mov 8(%rsi), %dl + mov %rcx, (%rdi) + mov %dl, 8(%rdi) +#ifdef USE_AS_STPCPY + lea 9(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 9(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit10): + mov (%rsi), %rcx + mov 8(%rsi), %dx + mov %rcx, (%rdi) + mov %dx, 8(%rdi) +#ifdef USE_AS_STPCPY + lea 10(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 10(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit11): + mov (%rsi), %rcx + mov 7(%rsi), %edx + mov %rcx, (%rdi) + mov %edx, 7(%rdi) +#ifdef USE_AS_STPCPY + lea 11(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 11(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit12): + mov (%rsi), %rcx + mov 8(%rsi), %edx + mov %rcx, (%rdi) + mov %edx, 8(%rdi) +#ifdef USE_AS_STPCPY + lea 12(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 12(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit13): + mov (%rsi), %rcx + mov 5(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 5(%rdi) +#ifdef USE_AS_STPCPY + lea 13(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 13(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit14): + mov (%rsi), %rcx + mov 6(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 6(%rdi) +#ifdef USE_AS_STPCPY + lea 14(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 14(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit15): + mov (%rsi), %rcx + mov 7(%rsi), %rdx + mov %rcx, (%rdi) + mov %rdx, 7(%rdi) +#ifdef USE_AS_STPCPY + lea 15(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 15(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit16): + movdqu (%rsi), %xmm0 + movdqu %xmm0, (%rdi) +#ifdef USE_AS_STPCPY + lea 16(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 16(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit17): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %cl + movdqu %xmm0, (%rdi) + mov %cl, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 17(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 17(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit18): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %cx + movdqu %xmm0, (%rdi) + mov %cx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 18(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 18(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit19): + movdqu (%rsi), %xmm0 + mov 15(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %ecx, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 19(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 19(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit20): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %ecx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 20(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 20(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit21): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %ecx + mov 20(%rsi), %dl + movdqu %xmm0, (%rdi) + mov %ecx, 16(%rdi) + mov %dl, 20(%rdi) +#ifdef USE_AS_STPCPY + lea 21(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 21(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit22): + movdqu (%rsi), %xmm0 + mov 14(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 14(%rdi) +#ifdef USE_AS_STPCPY + lea 22(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 22(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit23): + movdqu (%rsi), %xmm0 + mov 15(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 23(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 23(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit24): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rcx + movdqu %xmm0, (%rdi) + mov %rcx, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 24(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 24(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit25): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 24(%rsi), %cl + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %cl, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 25(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 25(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit26): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 24(%rsi), %cx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %cx, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 26(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 26(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit27): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 23(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %ecx, 23(%rdi) +#ifdef USE_AS_STPCPY + lea 27(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 27(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit28): + movdqu (%rsi), %xmm0 + mov 16(%rsi), %rdx + mov 24(%rsi), %ecx + movdqu %xmm0, (%rdi) + mov %rdx, 16(%rdi) + mov %ecx, 24(%rdi) +#ifdef USE_AS_STPCPY + lea 28(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 28(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit29): + movdqu (%rsi), %xmm0 + movdqu 13(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 13(%rdi) +#ifdef USE_AS_STPCPY + lea 29(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 29(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit30): + movdqu (%rsi), %xmm0 + movdqu 14(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 14(%rdi) +#ifdef USE_AS_STPCPY + lea 30(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 30(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit31): + movdqu (%rsi), %xmm0 + movdqu 15(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 15(%rdi) +#ifdef USE_AS_STPCPY + lea 31(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 31(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit32): + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm2 + movdqu %xmm0, (%rdi) + movdqu %xmm2, 16(%rdi) +#ifdef USE_AS_STPCPY + lea 32(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 32(%rdi) +#endif + RETURN + + .p2align 4 +L(StrncpyExit33): + movdqu (%rsi), %xmm0 + movdqu 16(%rsi), %xmm2 + mov 32(%rsi), %cl + movdqu %xmm0, (%rdi) + movdqu %xmm2, 16(%rdi) + mov %cl, 32(%rdi) +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 33(%rdi) +#endif + RETURN + +#ifndef USE_AS_STRCAT + + .p2align 4 +L(Fill0): + RETURN + + .p2align 4 +L(Fill1): + mov %dl, (%rdi) + RETURN + + .p2align 4 +L(Fill2): + mov %dx, (%rdi) + RETURN + + .p2align 4 +L(Fill3): + mov %edx, -1(%rdi) + RETURN + + .p2align 4 +L(Fill4): + mov %edx, (%rdi) + RETURN + + .p2align 4 +L(Fill5): + mov %edx, (%rdi) + mov %dl, 4(%rdi) + RETURN + + .p2align 4 +L(Fill6): + mov %edx, (%rdi) + mov %dx, 4(%rdi) + RETURN + + .p2align 4 +L(Fill7): + mov %rdx, -1(%rdi) + RETURN + + .p2align 4 +L(Fill8): + mov %rdx, (%rdi) + RETURN + + .p2align 4 +L(Fill9): + mov %rdx, (%rdi) + mov %dl, 8(%rdi) + RETURN + + .p2align 4 +L(Fill10): + mov %rdx, (%rdi) + mov %dx, 8(%rdi) + RETURN + + .p2align 4 +L(Fill11): + mov %rdx, (%rdi) + mov %edx, 7(%rdi) + RETURN + + .p2align 4 +L(Fill12): + mov %rdx, (%rdi) + mov %edx, 8(%rdi) + RETURN + + .p2align 4 +L(Fill13): + mov %rdx, (%rdi) + mov %rdx, 5(%rdi) + RETURN + + .p2align 4 +L(Fill14): + mov %rdx, (%rdi) + mov %rdx, 6(%rdi) + RETURN + + .p2align 4 +L(Fill15): + movdqu %xmm0, -1(%rdi) + RETURN + + .p2align 4 +L(Fill16): + movdqu %xmm0, (%rdi) + RETURN + + .p2align 4 +L(CopyFrom1To16BytesUnalignedXmm2): + movdqu %xmm2, (%rdi, %rcx) + + .p2align 4 +L(CopyFrom1To16BytesXmmExit): + bsf %rdx, %rdx + add $15, %r8 + add %rcx, %rdi +#ifdef USE_AS_STPCPY + lea (%rdi, %rdx), %rax +#endif + sub %rdx, %r8 + lea 1(%rdi, %rdx), %rdi + + .p2align 4 +L(StrncpyFillTailWithZero): + pxor %xmm0, %xmm0 + xor %rdx, %rdx + sub $16, %r8 + jbe L(StrncpyFillExit) + + movdqu %xmm0, (%rdi) + add $16, %rdi + + mov %rdi, %rsi + and $0xf, %rsi + sub %rsi, %rdi + add %rsi, %r8 + sub $64, %r8 + jb L(StrncpyFillLess64) + +L(StrncpyFillLoopMovdqa): + movdqa %xmm0, (%rdi) + movdqa %xmm0, 16(%rdi) + movdqa %xmm0, 32(%rdi) + movdqa %xmm0, 48(%rdi) + add $64, %rdi + sub $64, %r8 + jae L(StrncpyFillLoopMovdqa) + +L(StrncpyFillLess64): + add $32, %r8 + jl L(StrncpyFillLess32) + movdqa %xmm0, (%rdi) + movdqa %xmm0, 16(%rdi) + add $32, %rdi + sub $16, %r8 + jl L(StrncpyFillExit) + movdqa %xmm0, (%rdi) + add $16, %rdi + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %r8, 4) + +L(StrncpyFillLess32): + add $16, %r8 + jl L(StrncpyFillExit) + movdqa %xmm0, (%rdi) + add $16, %rdi + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %r8, 4) + +L(StrncpyFillExit): + add $16, %r8 + BRANCH_TO_JMPTBL_ENTRY (L(FillTable), %r8, 4) + +/* end of ifndef USE_AS_STRCAT */ +#endif + + .p2align 4 +L(UnalignedLeaveCase2OrCase3): + test %rdx, %rdx + jnz L(Unaligned64LeaveCase2) +L(Unaligned64LeaveCase3): + lea 64(%r8), %rcx + and $-16, %rcx + add $48, %r8 + jl L(CopyFrom1To16BytesCase3) + movdqu %xmm4, (%rdi) + sub $16, %r8 + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm5, 16(%rdi) + sub $16, %r8 + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm6, 32(%rdi) + sub $16, %r8 + jb L(CopyFrom1To16BytesCase3) + movdqu %xmm7, 48(%rdi) +#ifdef USE_AS_STPCPY + lea 64(%rdi), %rax +#endif +#ifdef USE_AS_STRCAT + xor %ch, %ch + movb %ch, 64(%rdi) +#endif + RETURN + + .p2align 4 +L(Unaligned64LeaveCase2): + xor %rcx, %rcx + pcmpeqb %xmm4, %xmm0 + pmovmskb %xmm0, %rdx + add $48, %r8 + jle L(CopyFrom1To16BytesCase2OrCase3) + test %rdx, %rdx +#ifndef USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm4) +#else + jnz L(CopyFrom1To16Bytes) +#endif + pcmpeqb %xmm5, %xmm0 + pmovmskb %xmm0, %rdx + movdqu %xmm4, (%rdi) + add $16, %rcx + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %rdx, %rdx +#ifndef USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm5) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + pcmpeqb %xmm6, %xmm0 + pmovmskb %xmm0, %rdx + movdqu %xmm5, 16(%rdi) + add $16, %rcx + sub $16, %r8 + jbe L(CopyFrom1To16BytesCase2OrCase3) + test %rdx, %rdx +#ifndef USE_AS_STRCAT + jnz L(CopyFrom1To16BytesUnalignedXmm6) +#else + jnz L(CopyFrom1To16Bytes) +#endif + + pcmpeqb %xmm7, %xmm0 + pmovmskb %xmm0, %rdx + movdqu %xmm6, 32(%rdi) + lea 16(%rdi, %rcx), %rdi + lea 16(%rsi, %rcx), %rsi + bsf %rdx, %rdx + cmp %r8, %rdx + jb L(CopyFrom1To16BytesExit) + BRANCH_TO_JMPTBL_ENTRY (L(ExitStrncpyTable), %r8, 4) + + .p2align 4 +L(ExitZero): +#ifndef USE_AS_STRCAT + mov %rdi, %rax +#endif + RETURN + +#endif + +#ifndef USE_AS_STRCAT +END (STRCPY) +#else +END (STRCAT) +#endif + .p2align 4 + .section .rodata +L(ExitTable): + .int JMPTBL(L(Exit1), L(ExitTable)) + .int JMPTBL(L(Exit2), L(ExitTable)) + .int JMPTBL(L(Exit3), L(ExitTable)) + .int JMPTBL(L(Exit4), L(ExitTable)) + .int JMPTBL(L(Exit5), L(ExitTable)) + .int JMPTBL(L(Exit6), L(ExitTable)) + .int JMPTBL(L(Exit7), L(ExitTable)) + .int JMPTBL(L(Exit8), L(ExitTable)) + .int JMPTBL(L(Exit9), L(ExitTable)) + .int JMPTBL(L(Exit10), L(ExitTable)) + .int JMPTBL(L(Exit11), L(ExitTable)) + .int JMPTBL(L(Exit12), L(ExitTable)) + .int JMPTBL(L(Exit13), L(ExitTable)) + .int JMPTBL(L(Exit14), L(ExitTable)) + .int JMPTBL(L(Exit15), L(ExitTable)) + .int JMPTBL(L(Exit16), L(ExitTable)) + .int JMPTBL(L(Exit17), L(ExitTable)) + .int JMPTBL(L(Exit18), L(ExitTable)) + .int JMPTBL(L(Exit19), L(ExitTable)) + .int JMPTBL(L(Exit20), L(ExitTable)) + .int JMPTBL(L(Exit21), L(ExitTable)) + .int JMPTBL(L(Exit22), L(ExitTable)) + .int JMPTBL(L(Exit23), L(ExitTable)) + .int JMPTBL(L(Exit24), L(ExitTable)) + .int JMPTBL(L(Exit25), L(ExitTable)) + .int JMPTBL(L(Exit26), L(ExitTable)) + .int JMPTBL(L(Exit27), L(ExitTable)) + .int JMPTBL(L(Exit28), L(ExitTable)) + .int JMPTBL(L(Exit29), L(ExitTable)) + .int JMPTBL(L(Exit30), L(ExitTable)) + .int JMPTBL(L(Exit31), L(ExitTable)) + .int JMPTBL(L(Exit32), L(ExitTable)) +#ifdef USE_AS_STRNCPY +L(ExitStrncpyTable): + .int JMPTBL(L(StrncpyExit0), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit1), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit2), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit3), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit4), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit5), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit6), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit7), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit8), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit9), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit10), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit11), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit12), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit13), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit14), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit15), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit16), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit17), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit18), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit19), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit20), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit21), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit22), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit23), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit24), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit25), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit26), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit27), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit28), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit29), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit30), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit31), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit32), L(ExitStrncpyTable)) + .int JMPTBL(L(StrncpyExit33), L(ExitStrncpyTable)) +# ifndef USE_AS_STRCAT + .p2align 4 +L(FillTable): + .int JMPTBL(L(Fill0), L(FillTable)) + .int JMPTBL(L(Fill1), L(FillTable)) + .int JMPTBL(L(Fill2), L(FillTable)) + .int JMPTBL(L(Fill3), L(FillTable)) + .int JMPTBL(L(Fill4), L(FillTable)) + .int JMPTBL(L(Fill5), L(FillTable)) + .int JMPTBL(L(Fill6), L(FillTable)) + .int JMPTBL(L(Fill7), L(FillTable)) + .int JMPTBL(L(Fill8), L(FillTable)) + .int JMPTBL(L(Fill9), L(FillTable)) + .int JMPTBL(L(Fill10), L(FillTable)) + .int JMPTBL(L(Fill11), L(FillTable)) + .int JMPTBL(L(Fill12), L(FillTable)) + .int JMPTBL(L(Fill13), L(FillTable)) + .int JMPTBL(L(Fill14), L(FillTable)) + .int JMPTBL(L(Fill15), L(FillTable)) + .int JMPTBL(L(Fill16), L(FillTable)) +# endif +#endif diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-strlen-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-strlen-slm.S new file mode 100644 index 000000000..3772fe770 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-strlen-slm.S @@ -0,0 +1,294 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifndef USE_AS_STRCAT + +#ifndef STRLEN +# define STRLEN strlen +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif +#define RETURN ret + .section .text.sse2,"ax",@progbits +ENTRY (STRLEN) +/* end ifndef USE_AS_STRCAT */ +#endif + xor %rax, %rax + mov %edi, %ecx + and $0x3f, %ecx + pxor %xmm0, %xmm0 + cmp $0x30, %ecx + ja L(next) + movdqu (%rdi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit_less16) + mov %rdi, %rax + and $-16, %rax + jmp L(align16_start) +L(next): + mov %rdi, %rax + and $-16, %rax + pcmpeqb (%rax), %xmm0 + mov $-1, %r10d + sub %rax, %rcx + shl %cl, %r10d + pmovmskb %xmm0, %edx + and %r10d, %edx + jnz L(exit) +L(align16_start): + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + pxor %xmm2, %xmm2 + pxor %xmm3, %xmm3 + pcmpeqb 16(%rax), %xmm0 + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit16) + + pcmpeqb 32(%rax), %xmm1 + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit32) + + pcmpeqb 48(%rax), %xmm2 + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit48) + + pcmpeqb 64(%rax), %xmm3 + pmovmskb %xmm3, %edx + test %edx, %edx + jnz L(exit64) + + pcmpeqb 80(%rax), %xmm0 + add $64, %rax + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit16) + + pcmpeqb 32(%rax), %xmm1 + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit32) + + pcmpeqb 48(%rax), %xmm2 + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit48) + + pcmpeqb 64(%rax), %xmm3 + pmovmskb %xmm3, %edx + test %edx, %edx + jnz L(exit64) + + pcmpeqb 80(%rax), %xmm0 + add $64, %rax + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit16) + + pcmpeqb 32(%rax), %xmm1 + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit32) + + pcmpeqb 48(%rax), %xmm2 + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit48) + + pcmpeqb 64(%rax), %xmm3 + pmovmskb %xmm3, %edx + test %edx, %edx + jnz L(exit64) + + pcmpeqb 80(%rax), %xmm0 + add $64, %rax + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit16) + + pcmpeqb 32(%rax), %xmm1 + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit32) + + pcmpeqb 48(%rax), %xmm2 + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit48) + + pcmpeqb 64(%rax), %xmm3 + pmovmskb %xmm3, %edx + test %edx, %edx + jnz L(exit64) + + + test $0x3f, %rax + jz L(align64_loop) + + pcmpeqb 80(%rax), %xmm0 + add $80, %rax + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit) + + test $0x3f, %rax + jz L(align64_loop) + + pcmpeqb 16(%rax), %xmm1 + add $16, %rax + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit) + + test $0x3f, %rax + jz L(align64_loop) + + pcmpeqb 16(%rax), %xmm2 + add $16, %rax + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit) + + test $0x3f, %rax + jz L(align64_loop) + + pcmpeqb 16(%rax), %xmm3 + add $16, %rax + pmovmskb %xmm3, %edx + test %edx, %edx + jnz L(exit) + + add $16, %rax + .p2align 4 + L(align64_loop): + movaps (%rax), %xmm4 + pminub 16(%rax), %xmm4 + movaps 32(%rax), %xmm5 + pminub 48(%rax), %xmm5 + add $64, %rax + pminub %xmm4, %xmm5 + pcmpeqb %xmm0, %xmm5 + pmovmskb %xmm5, %edx + test %edx, %edx + jz L(align64_loop) + + + pcmpeqb -64(%rax), %xmm0 + sub $80, %rax + pmovmskb %xmm0, %edx + test %edx, %edx + jnz L(exit16) + + pcmpeqb 32(%rax), %xmm1 + pmovmskb %xmm1, %edx + test %edx, %edx + jnz L(exit32) + + pcmpeqb 48(%rax), %xmm2 + pmovmskb %xmm2, %edx + test %edx, %edx + jnz L(exit48) + + pcmpeqb 64(%rax), %xmm3 + pmovmskb %xmm3, %edx + sub %rdi, %rax + bsf %rdx, %rdx + add %rdx, %rax + add $64, %rax + RETURN + + .p2align 4 +L(exit): + sub %rdi, %rax +L(exit_less16): + bsf %rdx, %rdx + add %rdx, %rax + RETURN + .p2align 4 +L(exit16): + sub %rdi, %rax + bsf %rdx, %rdx + add %rdx, %rax + add $16, %rax + RETURN + .p2align 4 +L(exit32): + sub %rdi, %rax + bsf %rdx, %rdx + add %rdx, %rax + add $32, %rax + RETURN + .p2align 4 +L(exit48): + sub %rdi, %rax + bsf %rdx, %rdx + add %rdx, %rax + add $48, %rax + RETURN + .p2align 4 +L(exit64): + sub %rdi, %rax + bsf %rdx, %rdx + add %rdx, %rax + add $64, %rax +#ifndef USE_AS_STRCAT + RETURN + +END (STRLEN) +#endif diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-strncat-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-strncat-slm.S new file mode 100644 index 000000000..6b4a43084 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-strncat-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCAT +#define STRCAT strncat +#include "sse2-strcat-slm.S" diff --git a/aosp/bionic/libc/arch-x86_64/string/sse2-strncpy-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse2-strncpy-slm.S new file mode 100644 index 000000000..594e78f74 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse2-strncpy-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCPY +#define STRCPY strncpy +#include "sse2-strcpy-slm.S" diff --git a/aosp/bionic/libc/arch-x86_64/string/sse4-memcmp-slm.S b/aosp/bionic/libc/arch-x86_64/string/sse4-memcmp-slm.S new file mode 100644 index 000000000..8a8b180a2 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/sse4-memcmp-slm.S @@ -0,0 +1,1799 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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 "cache.h" + +#ifndef MEMCMP +# define MEMCMP memcmp +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#define JMPTBL(I, B) (I - B) + +#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + lea TABLE(%rip), %r11; \ + movslq (%r11, INDEX, SCALE), %rcx; \ + add %r11, %rcx; \ + jmp *%rcx; \ + ud2 + + .section .text.sse4.1,"ax",@progbits +ENTRY (MEMCMP) +#ifdef USE_AS_WMEMCMP + shl $2, %rdx +#endif + pxor %xmm0, %xmm0 + cmp $79, %rdx + ja L(79bytesormore) +#ifndef USE_AS_WMEMCMP + cmp $1, %rdx + je L(firstbyte) +#endif + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +#ifndef USE_AS_WMEMCMP + ALIGN (4) +L(firstbyte): + movzbl (%rdi), %eax + movzbl (%rsi), %ecx + sub %ecx, %eax + ret +#endif + + ALIGN (4) +L(79bytesormore): + movdqu (%rsi), %xmm1 + movdqu (%rdi), %xmm2 + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + mov %rsi, %rcx + and $-16, %rsi + add $16, %rsi + sub %rsi, %rcx + + sub %rcx, %rdi + add %rcx, %rdx + test $0xf, %rdi + jz L(2aligned) + + cmp $128, %rdx + ja L(128bytesormore) +L(less128bytes): + sub $64, %rdx + + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqu 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqu 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + cmp $32, %rdx + jb L(less32bytesin64) + + movdqu 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqu 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin64): + add $64, %rdi + add $64, %rsi + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +L(128bytesormore): + cmp $512, %rdx + ja L(512bytesormore) + cmp $256, %rdx + ja L(less512bytes) +L(less256bytes): + sub $128, %rdx + + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqu 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqu 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + + movdqu 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqu 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + + movdqu 96(%rdi), %xmm2 + pxor 96(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(112bytesin256) + + movdqu 112(%rdi), %xmm2 + pxor 112(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(128bytesin256) + + add $128, %rsi + add $128, %rdi + + cmp $64, %rdx + jae L(less128bytes) + + cmp $32, %rdx + jb L(less32bytesin128) + + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin128): + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +L(less512bytes): + sub $256, %rdx + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqu 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqu 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + + movdqu 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqu 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + + movdqu 96(%rdi), %xmm2 + pxor 96(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(112bytesin256) + + movdqu 112(%rdi), %xmm2 + pxor 112(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(128bytesin256) + + movdqu 128(%rdi), %xmm2 + pxor 128(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(144bytesin256) + + movdqu 144(%rdi), %xmm2 + pxor 144(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(160bytesin256) + + movdqu 160(%rdi), %xmm2 + pxor 160(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(176bytesin256) + + movdqu 176(%rdi), %xmm2 + pxor 176(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(192bytesin256) + + movdqu 192(%rdi), %xmm2 + pxor 192(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(208bytesin256) + + movdqu 208(%rdi), %xmm2 + pxor 208(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(224bytesin256) + + movdqu 224(%rdi), %xmm2 + pxor 224(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(240bytesin256) + + movdqu 240(%rdi), %xmm2 + pxor 240(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(256bytesin256) + + add $256, %rsi + add $256, %rdi + + cmp $128, %rdx + jae L(less256bytes) + + cmp $64, %rdx + jae L(less128bytes) + + cmp $32, %rdx + jb L(less32bytesin256) + + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin256): + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + + ALIGN (4) +L(512bytesormore): +#ifdef DATA_CACHE_SIZE_HALF + mov $DATA_CACHE_SIZE_HALF, %r8 +#else + mov __x86_64_data_cache_size_half(%rip), %r8 +#endif + mov %r8, %r9 + shr $1, %r8 + add %r9, %r8 + cmp %r8, %rdx + ja L(L2_L3_cache_unaglined) + sub $64, %rdx + ALIGN (4) +L(64bytesormore_loop): + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + movdqa %xmm2, %xmm1 + + movdqu 16(%rdi), %xmm3 + pxor 16(%rsi), %xmm3 + por %xmm3, %xmm1 + + movdqu 32(%rdi), %xmm4 + pxor 32(%rsi), %xmm4 + por %xmm4, %xmm1 + + movdqu 48(%rdi), %xmm5 + pxor 48(%rsi), %xmm5 + por %xmm5, %xmm1 + + ptest %xmm1, %xmm0 + jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx + jae L(64bytesormore_loop) + + add $64, %rdx + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +L(L2_L3_cache_unaglined): + sub $64, %rdx + ALIGN (4) +L(L2_L3_unaligned_128bytes_loop): + prefetchnta 0x1c0(%rdi) + prefetchnta 0x1c0(%rsi) + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + movdqa %xmm2, %xmm1 + + movdqu 16(%rdi), %xmm3 + pxor 16(%rsi), %xmm3 + por %xmm3, %xmm1 + + movdqu 32(%rdi), %xmm4 + pxor 32(%rsi), %xmm4 + por %xmm4, %xmm1 + + movdqu 48(%rdi), %xmm5 + pxor 48(%rsi), %xmm5 + por %xmm5, %xmm1 + + ptest %xmm1, %xmm0 + jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx + jae L(L2_L3_unaligned_128bytes_loop) + + add $64, %rdx + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + +/* + * This case is for machines which are sensitive for unaligned instructions. + */ + ALIGN (4) +L(2aligned): + cmp $128, %rdx + ja L(128bytesormorein2aligned) +L(less128bytesin2aligned): + sub $64, %rdx + + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqa 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqa 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqa 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + cmp $32, %rdx + jb L(less32bytesin64in2alinged) + + movdqa 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqa 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin64in2alinged): + add $64, %rdi + add $64, %rsi + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + + ALIGN (4) +L(128bytesormorein2aligned): + cmp $512, %rdx + ja L(512bytesormorein2aligned) + cmp $256, %rdx + ja L(256bytesormorein2aligned) +L(less256bytesin2alinged): + sub $128, %rdx + + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqa 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqa 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqa 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + + movdqa 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqa 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + + movdqa 96(%rdi), %xmm2 + pxor 96(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(112bytesin256) + + movdqa 112(%rdi), %xmm2 + pxor 112(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(128bytesin256) + + add $128, %rsi + add $128, %rdi + + cmp $64, %rdx + jae L(less128bytesin2aligned) + + cmp $32, %rdx + jb L(less32bytesin128in2aligned) + + movdqu (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqu 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin128in2aligned): + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + + ALIGN (4) +L(256bytesormorein2aligned): + + sub $256, %rdx + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqa 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + + movdqa 32(%rdi), %xmm2 + pxor 32(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(48bytesin256) + + movdqa 48(%rdi), %xmm2 + pxor 48(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(64bytesin256) + + movdqa 64(%rdi), %xmm2 + pxor 64(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(80bytesin256) + + movdqa 80(%rdi), %xmm2 + pxor 80(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(96bytesin256) + + movdqa 96(%rdi), %xmm2 + pxor 96(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(112bytesin256) + + movdqa 112(%rdi), %xmm2 + pxor 112(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(128bytesin256) + + movdqa 128(%rdi), %xmm2 + pxor 128(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(144bytesin256) + + movdqa 144(%rdi), %xmm2 + pxor 144(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(160bytesin256) + + movdqa 160(%rdi), %xmm2 + pxor 160(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(176bytesin256) + + movdqa 176(%rdi), %xmm2 + pxor 176(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(192bytesin256) + + movdqa 192(%rdi), %xmm2 + pxor 192(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(208bytesin256) + + movdqa 208(%rdi), %xmm2 + pxor 208(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(224bytesin256) + + movdqa 224(%rdi), %xmm2 + pxor 224(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(240bytesin256) + + movdqa 240(%rdi), %xmm2 + pxor 240(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(256bytesin256) + + add $256, %rsi + add $256, %rdi + + cmp $128, %rdx + jae L(less256bytesin2alinged) + + cmp $64, %rdx + jae L(less128bytesin2aligned) + + cmp $32, %rdx + jb L(less32bytesin256in2alinged) + + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(16bytesin256) + + movdqa 16(%rdi), %xmm2 + pxor 16(%rsi), %xmm2 + ptest %xmm2, %xmm0 + jnc L(32bytesin256) + sub $32, %rdx + add $32, %rdi + add $32, %rsi +L(less32bytesin256in2alinged): + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + + ALIGN (4) +L(512bytesormorein2aligned): +#ifdef DATA_CACHE_SIZE_HALF + mov $DATA_CACHE_SIZE_HALF, %r8 +#else + mov __x86_64_data_cache_size_half(%rip), %r8 +#endif + mov %r8, %r9 + shr $1, %r8 + add %r9, %r8 + cmp %r8, %rdx + ja L(L2_L3_cache_aglined) + + sub $64, %rdx + ALIGN (4) +L(64bytesormore_loopin2aligned): + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + movdqa %xmm2, %xmm1 + + movdqa 16(%rdi), %xmm3 + pxor 16(%rsi), %xmm3 + por %xmm3, %xmm1 + + movdqa 32(%rdi), %xmm4 + pxor 32(%rsi), %xmm4 + por %xmm4, %xmm1 + + movdqa 48(%rdi), %xmm5 + pxor 48(%rsi), %xmm5 + por %xmm5, %xmm1 + + ptest %xmm1, %xmm0 + jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx + jae L(64bytesormore_loopin2aligned) + + add $64, %rdx + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) +L(L2_L3_cache_aglined): + sub $64, %rdx + ALIGN (4) +L(L2_L3_aligned_128bytes_loop): + prefetchnta 0x1c0(%rdi) + prefetchnta 0x1c0(%rsi) + movdqa (%rdi), %xmm2 + pxor (%rsi), %xmm2 + movdqa %xmm2, %xmm1 + + movdqa 16(%rdi), %xmm3 + pxor 16(%rsi), %xmm3 + por %xmm3, %xmm1 + + movdqa 32(%rdi), %xmm4 + pxor 32(%rsi), %xmm4 + por %xmm4, %xmm1 + + movdqa 48(%rdi), %xmm5 + pxor 48(%rsi), %xmm5 + por %xmm5, %xmm1 + + ptest %xmm1, %xmm0 + jnc L(64bytesormore_loop_end) + add $64, %rsi + add $64, %rdi + sub $64, %rdx + jae L(L2_L3_aligned_128bytes_loop) + + add $64, %rdx + add %rdx, %rsi + add %rdx, %rdi + BRANCH_TO_JMPTBL_ENTRY(L(table_64bytes), %rdx, 4) + + + ALIGN (4) +L(64bytesormore_loop_end): + add $16, %rdi + add $16, %rsi + ptest %xmm2, %xmm0 + jnc L(16bytes) + + add $16, %rdi + add $16, %rsi + ptest %xmm3, %xmm0 + jnc L(16bytes) + + add $16, %rdi + add $16, %rsi + ptest %xmm4, %xmm0 + jnc L(16bytes) + + add $16, %rdi + add $16, %rsi + jmp L(16bytes) + +L(256bytesin256): + add $256, %rdi + add $256, %rsi + jmp L(16bytes) +L(240bytesin256): + add $240, %rdi + add $240, %rsi + jmp L(16bytes) +L(224bytesin256): + add $224, %rdi + add $224, %rsi + jmp L(16bytes) +L(208bytesin256): + add $208, %rdi + add $208, %rsi + jmp L(16bytes) +L(192bytesin256): + add $192, %rdi + add $192, %rsi + jmp L(16bytes) +L(176bytesin256): + add $176, %rdi + add $176, %rsi + jmp L(16bytes) +L(160bytesin256): + add $160, %rdi + add $160, %rsi + jmp L(16bytes) +L(144bytesin256): + add $144, %rdi + add $144, %rsi + jmp L(16bytes) +L(128bytesin256): + add $128, %rdi + add $128, %rsi + jmp L(16bytes) +L(112bytesin256): + add $112, %rdi + add $112, %rsi + jmp L(16bytes) +L(96bytesin256): + add $96, %rdi + add $96, %rsi + jmp L(16bytes) +L(80bytesin256): + add $80, %rdi + add $80, %rsi + jmp L(16bytes) +L(64bytesin256): + add $64, %rdi + add $64, %rsi + jmp L(16bytes) +L(48bytesin256): + add $16, %rdi + add $16, %rsi +L(32bytesin256): + add $16, %rdi + add $16, %rsi +L(16bytesin256): + add $16, %rdi + add $16, %rsi +L(16bytes): + mov -16(%rdi), %rax + mov -16(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) +L(8bytes): + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(12bytes): + mov -12(%rdi), %rax + mov -12(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) +L(4bytes): + mov -4(%rsi), %ecx + mov -4(%rdi), %eax + cmp %eax, %ecx + jne L(diffin4bytes) +L(0bytes): + xor %eax, %eax + ret + +#ifndef USE_AS_WMEMCMP +/* unreal case for wmemcmp */ + ALIGN (4) +L(65bytes): + movdqu -65(%rdi), %xmm1 + movdqu -65(%rsi), %xmm2 + mov $-65, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(49bytes): + movdqu -49(%rdi), %xmm1 + movdqu -49(%rsi), %xmm2 + mov $-49, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(33bytes): + movdqu -33(%rdi), %xmm1 + movdqu -33(%rsi), %xmm2 + mov $-33, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(17bytes): + mov -17(%rdi), %rax + mov -17(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) +L(9bytes): + mov -9(%rdi), %rax + mov -9(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + movzbl -1(%rdi), %eax + movzbl -1(%rsi), %edx + sub %edx, %eax + ret + + ALIGN (4) +L(13bytes): + mov -13(%rdi), %rax + mov -13(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(5bytes): + mov -5(%rdi), %eax + mov -5(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + movzbl -1(%rdi), %eax + movzbl -1(%rsi), %edx + sub %edx, %eax + ret + + ALIGN (4) +L(66bytes): + movdqu -66(%rdi), %xmm1 + movdqu -66(%rsi), %xmm2 + mov $-66, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(50bytes): + movdqu -50(%rdi), %xmm1 + movdqu -50(%rsi), %xmm2 + mov $-50, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(34bytes): + movdqu -34(%rdi), %xmm1 + movdqu -34(%rsi), %xmm2 + mov $-34, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(18bytes): + mov -18(%rdi), %rax + mov -18(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) +L(10bytes): + mov -10(%rdi), %rax + mov -10(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + movzwl -2(%rdi), %eax + movzwl -2(%rsi), %ecx + cmp %cl, %al + jne L(end) + and $0xffff, %eax + and $0xffff, %ecx + sub %ecx, %eax + ret + + ALIGN (4) +L(14bytes): + mov -14(%rdi), %rax + mov -14(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(6bytes): + mov -6(%rdi), %eax + mov -6(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) +L(2bytes): + movzwl -2(%rsi), %ecx + movzwl -2(%rdi), %eax + cmp %cl, %al + jne L(end) + and $0xffff, %eax + and $0xffff, %ecx + sub %ecx, %eax + ret + + ALIGN (4) +L(67bytes): + movdqu -67(%rdi), %xmm2 + movdqu -67(%rsi), %xmm1 + mov $-67, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(51bytes): + movdqu -51(%rdi), %xmm2 + movdqu -51(%rsi), %xmm1 + mov $-51, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(35bytes): + movdqu -35(%rsi), %xmm1 + movdqu -35(%rdi), %xmm2 + mov $-35, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(19bytes): + mov -19(%rdi), %rax + mov -19(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) +L(11bytes): + mov -11(%rdi), %rax + mov -11(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -4(%rdi), %eax + mov -4(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(15bytes): + mov -15(%rdi), %rax + mov -15(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(7bytes): + mov -7(%rdi), %eax + mov -7(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + mov -4(%rdi), %eax + mov -4(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(3bytes): + movzwl -3(%rdi), %eax + movzwl -3(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin2bytes) +L(1bytes): + movzbl -1(%rdi), %eax + movzbl -1(%rsi), %ecx + sub %ecx, %eax + ret +#endif + + ALIGN (4) +L(68bytes): + movdqu -68(%rdi), %xmm2 + movdqu -68(%rsi), %xmm1 + mov $-68, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(52bytes): + movdqu -52(%rdi), %xmm2 + movdqu -52(%rsi), %xmm1 + mov $-52, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(36bytes): + movdqu -36(%rdi), %xmm2 + movdqu -36(%rsi), %xmm1 + mov $-36, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(20bytes): + movdqu -20(%rdi), %xmm2 + movdqu -20(%rsi), %xmm1 + mov $-20, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -4(%rdi), %eax + mov -4(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret + +#ifndef USE_AS_WMEMCMP +/* unreal cases for wmemcmp */ + ALIGN (4) +L(69bytes): + movdqu -69(%rsi), %xmm1 + movdqu -69(%rdi), %xmm2 + mov $-69, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(53bytes): + movdqu -53(%rsi), %xmm1 + movdqu -53(%rdi), %xmm2 + mov $-53, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(37bytes): + movdqu -37(%rsi), %xmm1 + movdqu -37(%rdi), %xmm2 + mov $-37, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(21bytes): + movdqu -21(%rsi), %xmm1 + movdqu -21(%rdi), %xmm2 + mov $-21, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(70bytes): + movdqu -70(%rsi), %xmm1 + movdqu -70(%rdi), %xmm2 + mov $-70, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(54bytes): + movdqu -54(%rsi), %xmm1 + movdqu -54(%rdi), %xmm2 + mov $-54, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(38bytes): + movdqu -38(%rsi), %xmm1 + movdqu -38(%rdi), %xmm2 + mov $-38, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(22bytes): + movdqu -22(%rsi), %xmm1 + movdqu -22(%rdi), %xmm2 + mov $-22, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(71bytes): + movdqu -71(%rsi), %xmm1 + movdqu -71(%rdi), %xmm2 + mov $-71, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(55bytes): + movdqu -55(%rdi), %xmm2 + movdqu -55(%rsi), %xmm1 + mov $-55, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(39bytes): + movdqu -39(%rdi), %xmm2 + movdqu -39(%rsi), %xmm1 + mov $-39, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(23bytes): + movdqu -23(%rdi), %xmm2 + movdqu -23(%rsi), %xmm1 + mov $-23, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret +#endif + + ALIGN (4) +L(72bytes): + movdqu -72(%rsi), %xmm1 + movdqu -72(%rdi), %xmm2 + mov $-72, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(56bytes): + movdqu -56(%rdi), %xmm2 + movdqu -56(%rsi), %xmm1 + mov $-56, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(40bytes): + movdqu -40(%rdi), %xmm2 + movdqu -40(%rsi), %xmm1 + mov $-40, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(24bytes): + movdqu -24(%rdi), %xmm2 + movdqu -24(%rsi), %xmm1 + mov $-24, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + +#ifndef USE_AS_WMEMCMP +/* unreal cases for wmemcmp */ + ALIGN (4) +L(73bytes): + movdqu -73(%rsi), %xmm1 + movdqu -73(%rdi), %xmm2 + mov $-73, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(57bytes): + movdqu -57(%rdi), %xmm2 + movdqu -57(%rsi), %xmm1 + mov $-57, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(41bytes): + movdqu -41(%rdi), %xmm2 + movdqu -41(%rsi), %xmm1 + mov $-41, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(25bytes): + movdqu -25(%rdi), %xmm2 + movdqu -25(%rsi), %xmm1 + mov $-25, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -9(%rdi), %rax + mov -9(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + movzbl -1(%rdi), %eax + movzbl -1(%rsi), %ecx + sub %ecx, %eax + ret + + ALIGN (4) +L(74bytes): + movdqu -74(%rsi), %xmm1 + movdqu -74(%rdi), %xmm2 + mov $-74, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(58bytes): + movdqu -58(%rdi), %xmm2 + movdqu -58(%rsi), %xmm1 + mov $-58, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(42bytes): + movdqu -42(%rdi), %xmm2 + movdqu -42(%rsi), %xmm1 + mov $-42, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(26bytes): + movdqu -26(%rdi), %xmm2 + movdqu -26(%rsi), %xmm1 + mov $-26, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -10(%rdi), %rax + mov -10(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + movzwl -2(%rdi), %eax + movzwl -2(%rsi), %ecx + jmp L(diffin2bytes) + + ALIGN (4) +L(75bytes): + movdqu -75(%rsi), %xmm1 + movdqu -75(%rdi), %xmm2 + mov $-75, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(59bytes): + movdqu -59(%rdi), %xmm2 + movdqu -59(%rsi), %xmm1 + mov $-59, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(43bytes): + movdqu -43(%rdi), %xmm2 + movdqu -43(%rsi), %xmm1 + mov $-43, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(27bytes): + movdqu -27(%rdi), %xmm2 + movdqu -27(%rsi), %xmm1 + mov $-27, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -11(%rdi), %rax + mov -11(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -4(%rdi), %eax + mov -4(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret +#endif + ALIGN (4) +L(76bytes): + movdqu -76(%rsi), %xmm1 + movdqu -76(%rdi), %xmm2 + mov $-76, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(60bytes): + movdqu -60(%rdi), %xmm2 + movdqu -60(%rsi), %xmm1 + mov $-60, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(44bytes): + movdqu -44(%rdi), %xmm2 + movdqu -44(%rsi), %xmm1 + mov $-44, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(28bytes): + movdqu -28(%rdi), %xmm2 + movdqu -28(%rsi), %xmm1 + mov $-28, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -12(%rdi), %rax + mov -12(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -4(%rdi), %eax + mov -4(%rsi), %ecx + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret + +#ifndef USE_AS_WMEMCMP +/* unreal cases for wmemcmp */ + ALIGN (4) +L(77bytes): + movdqu -77(%rsi), %xmm1 + movdqu -77(%rdi), %xmm2 + mov $-77, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(61bytes): + movdqu -61(%rdi), %xmm2 + movdqu -61(%rsi), %xmm1 + mov $-61, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(45bytes): + movdqu -45(%rdi), %xmm2 + movdqu -45(%rsi), %xmm1 + mov $-45, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(29bytes): + movdqu -29(%rdi), %xmm2 + movdqu -29(%rsi), %xmm1 + mov $-29, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -13(%rdi), %rax + mov -13(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(78bytes): + movdqu -78(%rsi), %xmm1 + movdqu -78(%rdi), %xmm2 + mov $-78, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(62bytes): + movdqu -62(%rdi), %xmm2 + movdqu -62(%rsi), %xmm1 + mov $-62, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(46bytes): + movdqu -46(%rdi), %xmm2 + movdqu -46(%rsi), %xmm1 + mov $-46, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(30bytes): + movdqu -30(%rdi), %xmm2 + movdqu -30(%rsi), %xmm1 + mov $-30, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -14(%rdi), %rax + mov -14(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + + ALIGN (4) +L(79bytes): + movdqu -79(%rsi), %xmm1 + movdqu -79(%rdi), %xmm2 + mov $-79, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(63bytes): + movdqu -63(%rdi), %xmm2 + movdqu -63(%rsi), %xmm1 + mov $-63, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(47bytes): + movdqu -47(%rdi), %xmm2 + movdqu -47(%rsi), %xmm1 + mov $-47, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(31bytes): + movdqu -31(%rdi), %xmm2 + movdqu -31(%rsi), %xmm1 + mov $-31, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + mov -15(%rdi), %rax + mov -15(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret +#endif + ALIGN (4) +L(64bytes): + movdqu -64(%rdi), %xmm2 + movdqu -64(%rsi), %xmm1 + mov $-64, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(48bytes): + movdqu -48(%rdi), %xmm2 + movdqu -48(%rsi), %xmm1 + mov $-48, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) +L(32bytes): + movdqu -32(%rdi), %xmm2 + movdqu -32(%rsi), %xmm1 + mov $-32, %dl + pxor %xmm1, %xmm2 + ptest %xmm2, %xmm0 + jnc L(less16bytes) + + mov -16(%rdi), %rax + mov -16(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + + mov -8(%rdi), %rax + mov -8(%rsi), %rcx + cmp %rax, %rcx + jne L(diffin8bytes) + xor %eax, %eax + ret + +/* + * Aligned 8 bytes to avoid 2 branch "taken" in one 16 alinged code block. + */ + ALIGN (3) +L(less16bytes): + movsbq %dl, %rdx + mov (%rsi, %rdx), %rcx + mov (%rdi, %rdx), %rax + cmp %rax, %rcx + jne L(diffin8bytes) + mov 8(%rsi, %rdx), %rcx + mov 8(%rdi, %rdx), %rax +L(diffin8bytes): + cmp %eax, %ecx + jne L(diffin4bytes) + shr $32, %rcx + shr $32, %rax + +#ifdef USE_AS_WMEMCMP +/* for wmemcmp */ + cmp %eax, %ecx + jne L(diffin4bytes) + xor %eax, %eax + ret +#endif + +L(diffin4bytes): +#ifndef USE_AS_WMEMCMP + cmp %cx, %ax + jne L(diffin2bytes) + shr $16, %ecx + shr $16, %eax +L(diffin2bytes): + cmp %cl, %al + jne L(end) + and $0xffff, %eax + and $0xffff, %ecx + sub %ecx, %eax + ret +#else + +/* for wmemcmp */ + mov $1, %eax + jl L(nequal_bigger) + neg %eax + ret + + ALIGN (4) +L(nequal_bigger): + ret + +L(unreal_case): + xor %eax, %eax + ret +#endif + + ALIGN (4) +L(end): + and $0xff, %eax + and $0xff, %ecx + sub %ecx, %eax + ret + +END (MEMCMP) + + .section .rodata.sse4.1,"a",@progbits + ALIGN (3) +#ifndef USE_AS_WMEMCMP +L(table_64bytes): + .int JMPTBL (L(0bytes), L(table_64bytes)) + .int JMPTBL (L(1bytes), L(table_64bytes)) + .int JMPTBL (L(2bytes), L(table_64bytes)) + .int JMPTBL (L(3bytes), L(table_64bytes)) + .int JMPTBL (L(4bytes), L(table_64bytes)) + .int JMPTBL (L(5bytes), L(table_64bytes)) + .int JMPTBL (L(6bytes), L(table_64bytes)) + .int JMPTBL (L(7bytes), L(table_64bytes)) + .int JMPTBL (L(8bytes), L(table_64bytes)) + .int JMPTBL (L(9bytes), L(table_64bytes)) + .int JMPTBL (L(10bytes), L(table_64bytes)) + .int JMPTBL (L(11bytes), L(table_64bytes)) + .int JMPTBL (L(12bytes), L(table_64bytes)) + .int JMPTBL (L(13bytes), L(table_64bytes)) + .int JMPTBL (L(14bytes), L(table_64bytes)) + .int JMPTBL (L(15bytes), L(table_64bytes)) + .int JMPTBL (L(16bytes), L(table_64bytes)) + .int JMPTBL (L(17bytes), L(table_64bytes)) + .int JMPTBL (L(18bytes), L(table_64bytes)) + .int JMPTBL (L(19bytes), L(table_64bytes)) + .int JMPTBL (L(20bytes), L(table_64bytes)) + .int JMPTBL (L(21bytes), L(table_64bytes)) + .int JMPTBL (L(22bytes), L(table_64bytes)) + .int JMPTBL (L(23bytes), L(table_64bytes)) + .int JMPTBL (L(24bytes), L(table_64bytes)) + .int JMPTBL (L(25bytes), L(table_64bytes)) + .int JMPTBL (L(26bytes), L(table_64bytes)) + .int JMPTBL (L(27bytes), L(table_64bytes)) + .int JMPTBL (L(28bytes), L(table_64bytes)) + .int JMPTBL (L(29bytes), L(table_64bytes)) + .int JMPTBL (L(30bytes), L(table_64bytes)) + .int JMPTBL (L(31bytes), L(table_64bytes)) + .int JMPTBL (L(32bytes), L(table_64bytes)) + .int JMPTBL (L(33bytes), L(table_64bytes)) + .int JMPTBL (L(34bytes), L(table_64bytes)) + .int JMPTBL (L(35bytes), L(table_64bytes)) + .int JMPTBL (L(36bytes), L(table_64bytes)) + .int JMPTBL (L(37bytes), L(table_64bytes)) + .int JMPTBL (L(38bytes), L(table_64bytes)) + .int JMPTBL (L(39bytes), L(table_64bytes)) + .int JMPTBL (L(40bytes), L(table_64bytes)) + .int JMPTBL (L(41bytes), L(table_64bytes)) + .int JMPTBL (L(42bytes), L(table_64bytes)) + .int JMPTBL (L(43bytes), L(table_64bytes)) + .int JMPTBL (L(44bytes), L(table_64bytes)) + .int JMPTBL (L(45bytes), L(table_64bytes)) + .int JMPTBL (L(46bytes), L(table_64bytes)) + .int JMPTBL (L(47bytes), L(table_64bytes)) + .int JMPTBL (L(48bytes), L(table_64bytes)) + .int JMPTBL (L(49bytes), L(table_64bytes)) + .int JMPTBL (L(50bytes), L(table_64bytes)) + .int JMPTBL (L(51bytes), L(table_64bytes)) + .int JMPTBL (L(52bytes), L(table_64bytes)) + .int JMPTBL (L(53bytes), L(table_64bytes)) + .int JMPTBL (L(54bytes), L(table_64bytes)) + .int JMPTBL (L(55bytes), L(table_64bytes)) + .int JMPTBL (L(56bytes), L(table_64bytes)) + .int JMPTBL (L(57bytes), L(table_64bytes)) + .int JMPTBL (L(58bytes), L(table_64bytes)) + .int JMPTBL (L(59bytes), L(table_64bytes)) + .int JMPTBL (L(60bytes), L(table_64bytes)) + .int JMPTBL (L(61bytes), L(table_64bytes)) + .int JMPTBL (L(62bytes), L(table_64bytes)) + .int JMPTBL (L(63bytes), L(table_64bytes)) + .int JMPTBL (L(64bytes), L(table_64bytes)) + .int JMPTBL (L(65bytes), L(table_64bytes)) + .int JMPTBL (L(66bytes), L(table_64bytes)) + .int JMPTBL (L(67bytes), L(table_64bytes)) + .int JMPTBL (L(68bytes), L(table_64bytes)) + .int JMPTBL (L(69bytes), L(table_64bytes)) + .int JMPTBL (L(70bytes), L(table_64bytes)) + .int JMPTBL (L(71bytes), L(table_64bytes)) + .int JMPTBL (L(72bytes), L(table_64bytes)) + .int JMPTBL (L(73bytes), L(table_64bytes)) + .int JMPTBL (L(74bytes), L(table_64bytes)) + .int JMPTBL (L(75bytes), L(table_64bytes)) + .int JMPTBL (L(76bytes), L(table_64bytes)) + .int JMPTBL (L(77bytes), L(table_64bytes)) + .int JMPTBL (L(78bytes), L(table_64bytes)) + .int JMPTBL (L(79bytes), L(table_64bytes)) +#else +L(table_64bytes): + .int JMPTBL (L(0bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(4bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(8bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(12bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(16bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(20bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(24bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(28bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(32bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(36bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(40bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(44bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(48bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(52bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(56bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(60bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(64bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(68bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(72bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(76bytes), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) + .int JMPTBL (L(unreal_case), L(table_64bytes)) +#endif diff --git a/aosp/bionic/libc/arch-x86_64/string/ssse3-strcmp-slm.S b/aosp/bionic/libc/arch-x86_64/string/ssse3-strcmp-slm.S new file mode 100644 index 000000000..e8acd5ba4 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/ssse3-strcmp-slm.S @@ -0,0 +1,1925 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#ifdef USE_AS_STRNCMP +/* Since the counter, %r11, is unsigned, we branch to strcmp_exitz + if the new counter > the old one or is 0. */ +#define UPDATE_STRNCMP_COUNTER \ + /* calculate left number to compare */ \ + lea -16(%rcx, %r11), %r9; \ + cmp %r9, %r11; \ + jb L(strcmp_exitz); \ + test %r9, %r9; \ + je L(strcmp_exitz); \ + mov %r9, %r11 + +#else +#define UPDATE_STRNCMP_COUNTER +#ifndef STRCMP +#define STRCMP strcmp +#endif +#endif + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif +#define RETURN ret + .section .text.ssse3,"ax",@progbits +ENTRY (STRCMP) +/* + * This implementation uses SSE to compare up to 16 bytes at a time. + */ +#ifdef USE_AS_STRNCMP + test %rdx, %rdx + je L(strcmp_exitz) + cmp $1, %rdx + je L(Byte0) + mov %rdx, %r11 +#endif + mov %esi, %ecx + mov %edi, %eax +/* Use 64bit AND here to avoid long NOP padding. */ + and $0x3f, %rcx /* rsi alignment in cache line */ + and $0x3f, %rax /* rdi alignment in cache line */ + cmp $0x30, %ecx + ja L(crosscache) /* rsi: 16-byte load will cross cache line */ + cmp $0x30, %eax + ja L(crosscache) /* rdi: 16-byte load will cross cache line */ + movlpd (%rdi), %xmm1 + movlpd (%rsi), %xmm2 + movhpd 8(%rdi), %xmm1 + movhpd 8(%rsi), %xmm2 + pxor %xmm0, %xmm0 /* clear %xmm0 for null char checks */ + pcmpeqb %xmm1, %xmm0 /* Any null chars? */ + pcmpeqb %xmm2, %xmm1 /* compare first 16 bytes for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %edx + sub $0xffff, %edx /* if first 16 bytes are same, edx == 0xffff */ + jnz L(less16bytes) /* If not, find different value or null char */ +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) /* finish comparision */ +#endif + add $16, %rsi /* prepare to search next 16 bytes */ + add $16, %rdi /* prepare to search next 16 bytes */ + + /* + * Determine source and destination string offsets from 16-byte alignment. + * Use relative offset difference between the two to determine which case + * below to use. + */ + .p2align 4 +L(crosscache): + and $0xfffffffffffffff0, %rsi /* force %rsi is 16 byte aligned */ + and $0xfffffffffffffff0, %rdi /* force %rdi is 16 byte aligned */ + mov $0xffff, %edx /* for equivalent offset */ + xor %r8d, %r8d + and $0xf, %ecx /* offset of rsi */ + and $0xf, %eax /* offset of rdi */ + cmp %eax, %ecx + je L(ashr_0) /* rsi and rdi relative offset same */ + ja L(bigger) + mov %edx, %r8d /* r8d is offset flag for exit tail */ + xchg %ecx, %eax + xchg %rsi, %rdi +L(bigger): + lea 15(%rax), %r9 + sub %rcx, %r9 + lea L(unaligned_table)(%rip), %r10 + movslq (%r10, %r9,4), %r9 + lea (%r10, %r9), %r10 + jmp *%r10 /* jump to corresponding case */ + +/* + * The following cases will be handled by ashr_0 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(0~15) n(0~15) 15(15+ n-n) ashr_0 + */ + .p2align 4 +L(ashr_0): + + movdqa (%rsi), %xmm1 + pxor %xmm0, %xmm0 /* clear %xmm0 for null char check */ + pcmpeqb %xmm1, %xmm0 /* Any null chars? */ + pcmpeqb (%rdi), %xmm1 /* compare 16 bytes for equality */ + psubb %xmm0, %xmm1 /* packed sub of comparison results*/ + pmovmskb %xmm1, %r9d + shr %cl, %edx /* adjust 0xffff for offset */ + shr %cl, %r9d /* adjust for 16-byte offset */ + sub %r9d, %edx + /* + * edx must be the same with r9d if in left byte (16-rcx) is equal to + * the start from (16-rax) and no null char was seen. + */ + jne L(less32bytes) /* mismatch or null char */ + UPDATE_STRNCMP_COUNTER + mov $16, %rcx + mov $16, %r9 + pxor %xmm0, %xmm0 /* clear xmm0, may have changed above */ + + /* + * Now both strings are aligned at 16-byte boundary. Loop over strings + * checking 32-bytes per iteration. + */ + .p2align 4 +L(loop_ashr_0): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) /* mismatch or null char seen */ + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + add $16, %rcx + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + add $16, %rcx + jmp L(loop_ashr_0) + +/* + * The following cases will be handled by ashr_1 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(15) n -15 0(15 +(n-15) - n) ashr_1 + */ + .p2align 4 +L(ashr_1): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 /* Any null chars? */ + pslldq $15, %xmm2 /* shift first string to align with second */ + pcmpeqb %xmm1, %xmm2 /* compare 16 bytes for equality */ + psubb %xmm0, %xmm2 /* packed sub of comparison results*/ + pmovmskb %xmm2, %r9d + shr %cl, %edx /* adjust 0xffff for offset */ + shr %cl, %r9d /* adjust for 16-byte offset */ + sub %r9d, %edx + jnz L(less32bytes) /* mismatch or null char seen */ + movdqa (%rdi), %xmm3 + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads*/ + mov $1, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 1(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_1): + add $16, %r10 + jg L(nibble_ashr_1) /* cross page boundary */ + +L(gobble_ashr_1): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 /* store for next cycle */ + + palignr $1, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_1) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 /* store for next cycle */ + + palignr $1, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_1) + + /* + * Nibble avoids loads across page boundary. This is to avoid a potential + * access into unmapped memory. + */ + .p2align 4 +L(nibble_ashr_1): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char*/ + pmovmskb %xmm0, %edx + test $0xfffe, %edx + jnz L(ashr_1_exittail) /* find null char*/ + +#ifdef USE_AS_STRNCMP + cmp $14, %r11 + jbe L(ashr_1_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 /* substract 4K from %r10 */ + jmp L(gobble_ashr_1) + + /* + * Once find null char, determine if there is a string mismatch + * before the null char. + */ + .p2align 4 +L(ashr_1_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $1, %xmm0 + psrldq $1, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_2 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(14~15) n -14 1(15 +(n-14) - n) ashr_2 + */ + .p2align 4 +L(ashr_2): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $14, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $2, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 2(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_2): + add $16, %r10 + jg L(nibble_ashr_2) + +L(gobble_ashr_2): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $2, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_2) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $2, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_2) + + .p2align 4 +L(nibble_ashr_2): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xfffc, %edx + jnz L(ashr_2_exittail) + +#ifdef USE_AS_STRNCMP + cmp $13, %r11 + jbe L(ashr_2_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_2) + + .p2align 4 +L(ashr_2_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $2, %xmm0 + psrldq $2, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_3 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(13~15) n -13 2(15 +(n-13) - n) ashr_3 + */ + .p2align 4 +L(ashr_3): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $13, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $3, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 3(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_3): + add $16, %r10 + jg L(nibble_ashr_3) + +L(gobble_ashr_3): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $3, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_3) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $3, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_3) + + .p2align 4 +L(nibble_ashr_3): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xfff8, %edx + jnz L(ashr_3_exittail) + +#ifdef USE_AS_STRNCMP + cmp $12, %r11 + jbe L(ashr_3_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_3) + + .p2align 4 +L(ashr_3_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $3, %xmm0 + psrldq $3, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_4 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(12~15) n -12 3(15 +(n-12) - n) ashr_4 + */ + .p2align 4 +L(ashr_4): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $12, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $4, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 4(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_4): + add $16, %r10 + jg L(nibble_ashr_4) + +L(gobble_ashr_4): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $4, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_4) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $4, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_4) + + .p2align 4 +L(nibble_ashr_4): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xfff0, %edx + jnz L(ashr_4_exittail) + +#ifdef USE_AS_STRNCMP + cmp $11, %r11 + jbe L(ashr_4_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_4) + + .p2align 4 +L(ashr_4_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $4, %xmm0 + psrldq $4, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_5 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(11~15) n - 11 4(15 +(n-11) - n) ashr_5 + */ + .p2align 4 +L(ashr_5): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $11, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $5, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 5(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_5): + add $16, %r10 + jg L(nibble_ashr_5) + +L(gobble_ashr_5): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $5, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_5) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $5, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_5) + + .p2align 4 +L(nibble_ashr_5): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xffe0, %edx + jnz L(ashr_5_exittail) + +#ifdef USE_AS_STRNCMP + cmp $10, %r11 + jbe L(ashr_5_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_5) + + .p2align 4 +L(ashr_5_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $5, %xmm0 + psrldq $5, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_6 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(10~15) n - 10 5(15 +(n-10) - n) ashr_6 + */ + .p2align 4 +L(ashr_6): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $10, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $6, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 6(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_6): + add $16, %r10 + jg L(nibble_ashr_6) + +L(gobble_ashr_6): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $6, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_6) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $6, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_6) + + .p2align 4 +L(nibble_ashr_6): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xffc0, %edx + jnz L(ashr_6_exittail) + +#ifdef USE_AS_STRNCMP + cmp $9, %r11 + jbe L(ashr_6_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_6) + + .p2align 4 +L(ashr_6_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $6, %xmm0 + psrldq $6, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_7 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(9~15) n - 9 6(15 +(n - 9) - n) ashr_7 + */ + .p2align 4 +L(ashr_7): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $9, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $7, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 7(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_7): + add $16, %r10 + jg L(nibble_ashr_7) + +L(gobble_ashr_7): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $7, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_7) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $7, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_7) + + .p2align 4 +L(nibble_ashr_7): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xff80, %edx + jnz L(ashr_7_exittail) + +#ifdef USE_AS_STRNCMP + cmp $8, %r11 + jbe L(ashr_7_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_7) + + .p2align 4 +L(ashr_7_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $7, %xmm0 + psrldq $7, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_8 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(8~15) n - 8 7(15 +(n - 8) - n) ashr_8 + */ + .p2align 4 +L(ashr_8): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $8, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $8, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 8(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_8): + add $16, %r10 + jg L(nibble_ashr_8) + +L(gobble_ashr_8): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $8, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_8) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $8, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_8) + + .p2align 4 +L(nibble_ashr_8): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xff00, %edx + jnz L(ashr_8_exittail) + +#ifdef USE_AS_STRNCMP + cmp $7, %r11 + jbe L(ashr_8_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_8) + + .p2align 4 +L(ashr_8_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $8, %xmm0 + psrldq $8, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_9 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(7~15) n - 7 8(15 +(n - 7) - n) ashr_9 + */ + .p2align 4 +L(ashr_9): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $7, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $9, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 9(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_9): + add $16, %r10 + jg L(nibble_ashr_9) + +L(gobble_ashr_9): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $9, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_9) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $9, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 /* store for next cycle */ + jmp L(loop_ashr_9) + + .p2align 4 +L(nibble_ashr_9): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xfe00, %edx + jnz L(ashr_9_exittail) + +#ifdef USE_AS_STRNCMP + cmp $6, %r11 + jbe L(ashr_9_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_9) + + .p2align 4 +L(ashr_9_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $9, %xmm0 + psrldq $9, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_10 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(6~15) n - 6 9(15 +(n - 6) - n) ashr_10 + */ + .p2align 4 +L(ashr_10): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $6, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $10, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 10(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_10): + add $16, %r10 + jg L(nibble_ashr_10) + +L(gobble_ashr_10): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $10, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_10) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $10, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_10) + + .p2align 4 +L(nibble_ashr_10): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xfc00, %edx + jnz L(ashr_10_exittail) + +#ifdef USE_AS_STRNCMP + cmp $5, %r11 + jbe L(ashr_10_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_10) + + .p2align 4 +L(ashr_10_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $10, %xmm0 + psrldq $10, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_11 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(5~15) n - 5 10(15 +(n - 5) - n) ashr_11 + */ + .p2align 4 +L(ashr_11): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $5, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $11, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 11(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_11): + add $16, %r10 + jg L(nibble_ashr_11) + +L(gobble_ashr_11): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $11, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_11) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $11, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_11) + + .p2align 4 +L(nibble_ashr_11): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xf800, %edx + jnz L(ashr_11_exittail) + +#ifdef USE_AS_STRNCMP + cmp $4, %r11 + jbe L(ashr_11_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_11) + + .p2align 4 +L(ashr_11_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $11, %xmm0 + psrldq $11, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_12 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(4~15) n - 4 11(15 +(n - 4) - n) ashr_12 + */ + .p2align 4 +L(ashr_12): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $4, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $12, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 12(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_12): + add $16, %r10 + jg L(nibble_ashr_12) + +L(gobble_ashr_12): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $12, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_12) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $12, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_12) + + .p2align 4 +L(nibble_ashr_12): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xf000, %edx + jnz L(ashr_12_exittail) + +#ifdef USE_AS_STRNCMP + cmp $3, %r11 + jbe L(ashr_12_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_12) + + .p2align 4 +L(ashr_12_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $12, %xmm0 + psrldq $12, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_13 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(3~15) n - 3 12(15 +(n - 3) - n) ashr_13 + */ + .p2align 4 +L(ashr_13): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $3, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $13, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 13(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_13): + add $16, %r10 + jg L(nibble_ashr_13) + +L(gobble_ashr_13): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $13, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_13) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $13, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_13) + + .p2align 4 +L(nibble_ashr_13): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xe000, %edx + jnz L(ashr_13_exittail) + +#ifdef USE_AS_STRNCMP + cmp $2, %r11 + jbe L(ashr_13_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_13) + + .p2align 4 +L(ashr_13_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $13, %xmm0 + psrldq $13, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_14 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(2~15) n - 2 13(15 +(n - 2) - n) ashr_14 + */ + .p2align 4 +L(ashr_14): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $2, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $14, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 14(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_14): + add $16, %r10 + jg L(nibble_ashr_14) + +L(gobble_ashr_14): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $14, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_14) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $14, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_14) + + .p2align 4 +L(nibble_ashr_14): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0xc000, %edx + jnz L(ashr_14_exittail) + +#ifdef USE_AS_STRNCMP + cmp $1, %r11 + jbe L(ashr_14_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_14) + + .p2align 4 +L(ashr_14_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $14, %xmm0 + psrldq $14, %xmm3 + jmp L(aftertail) + +/* + * The following cases will be handled by ashr_15 + * rcx(offset of rsi) rax(offset of rdi) relative offset corresponding case + * n(1~15) n - 1 14(15 +(n - 1) - n) ashr_15 + */ + .p2align 4 +L(ashr_15): + pxor %xmm0, %xmm0 + movdqa (%rdi), %xmm2 + movdqa (%rsi), %xmm1 + pcmpeqb %xmm1, %xmm0 + pslldq $1, %xmm2 + pcmpeqb %xmm1, %xmm2 + psubb %xmm0, %xmm2 + pmovmskb %xmm2, %r9d + shr %cl, %edx + shr %cl, %r9d + sub %r9d, %edx + jnz L(less32bytes) + + movdqa (%rdi), %xmm3 + + UPDATE_STRNCMP_COUNTER + + pxor %xmm0, %xmm0 + mov $16, %rcx /* index for loads */ + mov $15, %r9d /* byte position left over from less32bytes case */ + /* + * Setup %r10 value allows us to detect crossing a page boundary. + * When %r10 goes positive we have crossed a page boundary and + * need to do a nibble. + */ + lea 15(%rdi), %r10 + and $0xfff, %r10 /* offset into 4K page */ + + sub $0x1000, %r10 /* subtract 4K pagesize */ + + .p2align 4 +L(loop_ashr_15): + add $16, %r10 + jg L(nibble_ashr_15) + +L(gobble_ashr_15): + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $15, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + + add $16, %r10 + jg L(nibble_ashr_15) /* cross page boundary */ + + movdqa (%rsi, %rcx), %xmm1 + movdqa (%rdi, %rcx), %xmm2 + movdqa %xmm2, %xmm4 + + palignr $15, %xmm3, %xmm2 /* merge into one 16byte value */ + + pcmpeqb %xmm1, %xmm0 + pcmpeqb %xmm2, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + sub $0xffff, %edx + jnz L(exit) + +#ifdef USE_AS_STRNCMP + sub $16, %r11 + jbe L(strcmp_exitz) +#endif + + add $16, %rcx + movdqa %xmm4, %xmm3 + jmp L(loop_ashr_15) + + .p2align 4 +L(nibble_ashr_15): + pcmpeqb %xmm3, %xmm0 /* check nibble for null char */ + pmovmskb %xmm0, %edx + test $0x8000, %edx + jnz L(ashr_15_exittail) + +#ifdef USE_AS_STRNCMP + test %r11, %r11 + je L(ashr_15_exittail) +#endif + + pxor %xmm0, %xmm0 + sub $0x1000, %r10 + jmp L(gobble_ashr_15) + + .p2align 4 +L(ashr_15_exittail): + movdqa (%rsi, %rcx), %xmm1 + psrldq $15, %xmm3 + psrldq $15, %xmm0 + + .p2align 4 +L(aftertail): + pcmpeqb %xmm3, %xmm1 + psubb %xmm0, %xmm1 + pmovmskb %xmm1, %edx + not %edx + + .p2align 4 +L(exit): + lea -16(%r9, %rcx), %rax /* locate the exact offset for rdi */ +L(less32bytes): + lea (%rdi, %rax), %rdi /* locate the exact address for first operand(rdi) */ + lea (%rsi, %rcx), %rsi /* locate the exact address for second operand(rsi) */ + test %r8d, %r8d + jz L(ret) + xchg %rsi, %rdi /* recover original order according to flag(%r8d) */ + + .p2align 4 +L(ret): +L(less16bytes): + bsf %rdx, %rdx /* find and store bit index in %rdx */ + +#ifdef USE_AS_STRNCMP + sub %rdx, %r11 + jbe L(strcmp_exitz) +#endif + movzbl (%rsi, %rdx), %ecx + movzbl (%rdi, %rdx), %eax + + sub %ecx, %eax + ret + +L(strcmp_exitz): + xor %eax, %eax + ret + + .p2align 4 +L(Byte0): + movzbl (%rsi), %ecx + movzbl (%rdi), %eax + + sub %ecx, %eax + ret +END (STRCMP) + + .section .rodata,"a",@progbits + .p2align 3 +L(unaligned_table): + .int L(ashr_1) - L(unaligned_table) + .int L(ashr_2) - L(unaligned_table) + .int L(ashr_3) - L(unaligned_table) + .int L(ashr_4) - L(unaligned_table) + .int L(ashr_5) - L(unaligned_table) + .int L(ashr_6) - L(unaligned_table) + .int L(ashr_7) - L(unaligned_table) + .int L(ashr_8) - L(unaligned_table) + .int L(ashr_9) - L(unaligned_table) + .int L(ashr_10) - L(unaligned_table) + .int L(ashr_11) - L(unaligned_table) + .int L(ashr_12) - L(unaligned_table) + .int L(ashr_13) - L(unaligned_table) + .int L(ashr_14) - L(unaligned_table) + .int L(ashr_15) - L(unaligned_table) + .int L(ashr_0) - L(unaligned_table) diff --git a/aosp/bionic/libc/arch-x86_64/string/ssse3-strncmp-slm.S b/aosp/bionic/libc/arch-x86_64/string/ssse3-strncmp-slm.S new file mode 100644 index 000000000..0e4077517 --- /dev/null +++ b/aosp/bionic/libc/arch-x86_64/string/ssse3-strncmp-slm.S @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014, Intel Corporation +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. + + * Neither the name of Intel Corporation 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 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. +*/ + +#define USE_AS_STRNCMP +#define STRCMP strncmp +#include "ssse3-strcmp-slm.S" diff --git a/aosp/bionic/libc/async_safe/Android.bp b/aosp/bionic/libc/async_safe/Android.bp new file mode 100644 index 000000000..98da2cc36 --- /dev/null +++ b/aosp/bionic/libc/async_safe/Android.bp @@ -0,0 +1,48 @@ +// ======================================================== +// libasync_safe.a +// ======================================================== +cc_library_static { + defaults: ["libc_defaults"], + srcs: [ + "async_safe_log.cpp", + ], + + name: "libasync_safe", + vendor_available: true, + recovery_available: true, + native_bridge_supported: true, + + include_dirs: ["bionic/libc"], + header_libs: ["libc_headers", "liblog_headers"], + + export_include_dirs: ["include"], + export_header_lib_headers: ["liblog_headers"], + stl: "none", + + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + "com.android.art.debug", + "com.android.art.release", + "com.android.media", + "com.android.media.swcodec", + ], +} + +cc_library_headers { + name: "libasync_safe_headers", + ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + defaults: ["linux_bionic_supported"], + + export_include_dirs: ["include"], + + system_shared_libs: [], + stl: "none", + + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + ], +} diff --git a/aosp/bionic/libc/async_safe/README.md b/aosp/bionic/libc/async_safe/README.md new file mode 100644 index 000000000..b5d55befa --- /dev/null +++ b/aosp/bionic/libc/async_safe/README.md @@ -0,0 +1,10 @@ +# async_safe logging + +This library provides an async_safe implementation for formatting and writing log messages to logd. + +Note that the liblog implementation connects a single socket to logd and uses a RWLock to manage +it among threads, whereas these functions connect to liblog for each log message. While it's +beneficial to have this lock-free and therefore async_safe mechanism to write to logd, connecting +a socket for each message does not scale well under load. It was also determined to be too +costly to connect a socket for each thread as some processes, such as system_server, have over 100 +threads. Therefore, we maintain these two separate mechanisms. diff --git a/aosp/bionic/libc/async_safe/async_safe_log.cpp b/aosp/bionic/libc/async_safe/async_safe_log.cpp new file mode 100644 index 000000000..8b2a32b14 --- /dev/null +++ b/aosp/bionic/libc/async_safe/async_safe_log.cpp @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "private/CachedProperty.h" +#include "private/ErrnoRestorer.h" +#include "private/ScopedPthreadMutexLocker.h" + +// Don't call libc's close or socket, since it might call back into us as a result of fdsan/fdtrack. +#pragma GCC poison close +static int __close(int fd) { + return syscall(__NR_close, fd); +} + +static int __socket(int domain, int type, int protocol) { +#if defined(__i386__) + unsigned long args[3] = {static_cast(domain), static_cast(type), + static_cast(protocol)}; + return syscall(__NR_socketcall, SYS_SOCKET, &args); +#else + return syscall(__NR_socket, domain, type, protocol); +#endif +} + +// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java. +enum AndroidEventLogType { + EVENT_TYPE_INT = 0, + EVENT_TYPE_LONG = 1, + EVENT_TYPE_STRING = 2, + EVENT_TYPE_LIST = 3, + EVENT_TYPE_FLOAT = 4, +}; + +struct BufferOutputStream { + public: + BufferOutputStream(char* buffer, size_t size) : total(0), pos_(buffer), avail_(size) { + if (avail_ > 0) pos_[0] = '\0'; + } + ~BufferOutputStream() = default; + + void Send(const char* data, int len) { + if (len < 0) { + len = strlen(data); + } + total += len; + + if (avail_ <= 1) { + // No space to put anything else. + return; + } + + if (static_cast(len) >= avail_) { + len = avail_ - 1; + } + memcpy(pos_, data, len); + pos_ += len; + pos_[0] = '\0'; + avail_ -= len; + } + + size_t total; + + private: + char* pos_; + size_t avail_; +}; + +struct FdOutputStream { + public: + explicit FdOutputStream(int fd) : total(0), fd_(fd) {} + + void Send(const char* data, int len) { + if (len < 0) { + len = strlen(data); + } + total += len; + + while (len > 0) { + ssize_t bytes = TEMP_FAILURE_RETRY(write(fd_, data, len)); + if (bytes == -1) { + return; + } + data += bytes; + len -= bytes; + } + } + + size_t total; + + private: + int fd_; +}; + +/*** formatted output implementation + ***/ + +/* Parse a decimal string from 'format + *ppos', + * return the value, and writes the new position past + * the decimal string in '*ppos' on exit. + * + * NOTE: Does *not* handle a sign prefix. + */ +static unsigned parse_decimal(const char* format, int* ppos) { + const char* p = format + *ppos; + unsigned result = 0; + + for (;;) { + int ch = *p; + unsigned d = static_cast(ch - '0'); + + if (d >= 10U) { + break; + } + + result = result * 10 + d; + p++; + } + *ppos = p - format; + return result; +} + +// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes. +// Assumes that buf_size > 0. +static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { + char* p = buf; + char* end = buf + buf_size - 1; + + // Generate digit string in reverse order. + while (value) { + unsigned d = value % base; + value /= base; + if (p != end) { + char ch; + if (d < 10) { + ch = '0' + d; + } else { + ch = (caps ? 'A' : 'a') + (d - 10); + } + *p++ = ch; + } + } + + // Special case for 0. + if (p == buf) { + if (p != end) { + *p++ = '0'; + } + } + *p = '\0'; + + // Reverse digit string in-place. + size_t length = p - buf; + for (size_t i = 0, j = length - 1; i < j; ++i, --j) { + char ch = buf[i]; + buf[i] = buf[j]; + buf[j] = ch; + } +} + +static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) { + // Decode the conversion specifier. + int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o'); + int base = 10; + if (conversion == 'x' || conversion == 'X') { + base = 16; + } else if (conversion == 'o') { + base = 8; + } + bool caps = (conversion == 'X'); + + if (is_signed && static_cast(value) < 0) { + buf[0] = '-'; + buf += 1; + buf_size -= 1; + value = static_cast(-static_cast(value)); + } + format_unsigned(buf, buf_size, value, base, caps); +} + +template +static void SendRepeat(Out& o, char ch, int count) { + char pad[8]; + memset(pad, ch, sizeof(pad)); + + const int pad_size = static_cast(sizeof(pad)); + while (count > 0) { + int avail = count; + if (avail > pad_size) { + avail = pad_size; + } + o.Send(pad, avail); + count -= avail; + } +} + +/* Perform formatted output to an output target 'o' */ +template +static void out_vformat(Out& o, const char* format, va_list args) { + int nn = 0; + + for (;;) { + int mm; + int padZero = 0; + int padLeft = 0; + char sign = '\0'; + int width = -1; + int prec = -1; + size_t bytelen = sizeof(int); + int slen; + char buffer[32]; /* temporary buffer used to format numbers */ + + char c; + + /* first, find all characters that are not 0 or '%' */ + /* then send them to the output directly */ + mm = nn; + do { + c = format[mm]; + if (c == '\0' || c == '%') break; + mm++; + } while (1); + + if (mm > nn) { + o.Send(format + nn, mm - nn); + nn = mm; + } + + /* is this it ? then exit */ + if (c == '\0') break; + + /* nope, we are at a '%' modifier */ + nn++; // skip it + + /* parse flags */ + for (;;) { + c = format[nn++]; + if (c == '\0') { /* single trailing '%' ? */ + c = '%'; + o.Send(&c, 1); + return; + } else if (c == '0') { + padZero = 1; + continue; + } else if (c == '-') { + padLeft = 1; + continue; + } else if (c == ' ' || c == '+') { + sign = c; + continue; + } + break; + } + + /* parse field width */ + if ((c >= '0' && c <= '9')) { + nn--; + width = static_cast(parse_decimal(format, &nn)); + c = format[nn++]; + } + + /* parse precision */ + if (c == '.') { + prec = static_cast(parse_decimal(format, &nn)); + c = format[nn++]; + } + + /* length modifier */ + switch (c) { + case 'h': + bytelen = sizeof(short); + if (format[nn] == 'h') { + bytelen = sizeof(char); + nn += 1; + } + c = format[nn++]; + break; + case 'l': + bytelen = sizeof(long); + if (format[nn] == 'l') { + bytelen = sizeof(long long); + nn += 1; + } + c = format[nn++]; + break; + case 'z': + bytelen = sizeof(size_t); + c = format[nn++]; + break; + case 't': + bytelen = sizeof(ptrdiff_t); + c = format[nn++]; + break; + default:; + } + + /* conversion specifier */ + const char* str = buffer; + if (c == 's') { + /* string */ + str = va_arg(args, const char*); + if (str == nullptr) { + str = "(null)"; + } + } else if (c == 'c') { + /* character */ + /* NOTE: char is promoted to int when passed through the stack */ + buffer[0] = static_cast(va_arg(args, int)); + buffer[1] = '\0'; + } else if (c == 'p') { + uint64_t value = reinterpret_cast(va_arg(args, void*)); + buffer[0] = '0'; + buffer[1] = 'x'; + format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); + } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { + /* integers - first read value from stack */ + uint64_t value; + int is_signed = (c == 'd' || c == 'i' || c == 'o'); + + /* NOTE: int8_t and int16_t are promoted to int when passed + * through the stack + */ + switch (bytelen) { + case 1: + value = static_cast(va_arg(args, int)); + break; + case 2: + value = static_cast(va_arg(args, int)); + break; + case 4: + value = va_arg(args, uint32_t); + break; + case 8: + value = va_arg(args, uint64_t); + break; + default: + return; /* should not happen */ + } + + /* sign extension, if needed */ + if (is_signed) { + int shift = 64 - 8 * bytelen; + value = static_cast((static_cast(value << shift)) >> shift); + } + + /* format the number properly into our buffer */ + format_integer(buffer, sizeof(buffer), value, c); + } else if (c == '%') { + buffer[0] = '%'; + buffer[1] = '\0'; + } else { + __assert(__FILE__, __LINE__, "conversion specifier unsupported"); + } + + /* if we are here, 'str' points to the content that must be + * outputted. handle padding and alignment now */ + + slen = strlen(str); + + if (sign != '\0' || prec != -1) { + __assert(__FILE__, __LINE__, "sign/precision unsupported"); + } + + if (slen < width && !padLeft) { + char padChar = padZero ? '0' : ' '; + SendRepeat(o, padChar, width - slen); + } + + o.Send(str, slen); + + if (slen < width && padLeft) { + char padChar = padZero ? '0' : ' '; + SendRepeat(o, padChar, width - slen); + } + } +} + +int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format, + va_list args) { + BufferOutputStream os(buffer, buffer_size); + out_vformat(os, format, args); + return os.total; +} + +int async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) { + va_list args; + va_start(args, format); + int buffer_len = async_safe_format_buffer_va_list(buffer, buffer_size, format, args); + va_end(args); + return buffer_len; +} + +int async_safe_format_fd_va_list(int fd, const char* format, va_list args) { + FdOutputStream os(fd); + out_vformat(os, format, args); + return os.total; +} + +int async_safe_format_fd(int fd, const char* format, ...) { + va_list args; + va_start(args, format); + int result = async_safe_format_fd_va_list(fd, format, args); + va_end(args); + return result; +} + +static int write_stderr(const char* tag, const char* msg) { + iovec vec[4]; + vec[0].iov_base = const_cast(tag); + vec[0].iov_len = strlen(tag); + vec[1].iov_base = const_cast(": "); + vec[1].iov_len = 2; + vec[2].iov_base = const_cast(msg); + vec[2].iov_len = strlen(msg); + vec[3].iov_base = const_cast("\n"); + vec[3].iov_len = 1; + + int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4)); + return result; +} + +static int open_log_socket() { + // ToDo: Ideally we want this to fail if the gid of the current + // process is AID_LOGD, but will have to wait until we have + // registered this in private/android_filesystem_config.h. We have + // found that all logd crashes thus far have had no problem stuffing + // the UNIX domain socket and moving on so not critical *today*. + + int log_fd = TEMP_FAILURE_RETRY(__socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); + if (log_fd == -1) { + return -1; + } + + union { + struct sockaddr addr; + struct sockaddr_un addrUn; + } u; + memset(&u, 0, sizeof(u)); + u.addrUn.sun_family = AF_UNIX; + strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path)); + + if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) { + __close(log_fd); + return -1; + } + + return log_fd; +} + +struct log_time { // Wire format + uint32_t tv_sec; + uint32_t tv_nsec; +}; + +int async_safe_write_log(int priority, const char* tag, const char* msg) { + int main_log_fd = open_log_socket(); + if (main_log_fd == -1) { + // Try stderr instead. + return write_stderr(tag, msg); + } + + iovec vec[6]; + char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN; + vec[0].iov_base = &log_id; + vec[0].iov_len = sizeof(log_id); + uint16_t tid = gettid(); + vec[1].iov_base = &tid; + vec[1].iov_len = sizeof(tid); + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + log_time realtime_ts; + realtime_ts.tv_sec = ts.tv_sec; + realtime_ts.tv_nsec = ts.tv_nsec; + vec[2].iov_base = &realtime_ts; + vec[2].iov_len = sizeof(realtime_ts); + + vec[3].iov_base = &priority; + vec[3].iov_len = 1; + vec[4].iov_base = const_cast(tag); + vec[4].iov_len = strlen(tag) + 1; + vec[5].iov_base = const_cast(msg); + vec[5].iov_len = strlen(msg) + 1; + + int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); + __close(main_log_fd); + return result; +} + +int async_safe_format_log_va_list(int priority, const char* tag, const char* format, va_list args) { + ErrnoRestorer errno_restorer; + char buffer[1024]; + BufferOutputStream os(buffer, sizeof(buffer)); + out_vformat(os, format, args); + return async_safe_write_log(priority, tag, buffer); +} + +int async_safe_format_log(int priority, const char* tag, const char* format, ...) { + va_list args; + va_start(args, format); + int result = async_safe_format_log_va_list(priority, tag, format, args); + va_end(args); + return result; +} + +void async_safe_fatal_va_list(const char* prefix, const char* format, va_list args) { + char msg[1024]; + BufferOutputStream os(msg, sizeof(msg)); + + if (prefix) { + os.Send(prefix, strlen(prefix)); + os.Send(": ", 2); + } + + out_vformat(os, format, args); + + // Log to stderr for the benefit of "adb shell" users and gtests. + struct iovec iov[2] = { + {msg, strlen(msg)}, {const_cast("\n"), 1}, + }; + TEMP_FAILURE_RETRY(writev(2, iov, 2)); + + // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed). + async_safe_write_log(ANDROID_LOG_FATAL, "libc", msg); + + android_set_abort_message(msg); +} + +void async_safe_fatal_no_abort(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + async_safe_fatal_va_list(nullptr, fmt, args); + va_end(args); +} diff --git a/aosp/bionic/libc/async_safe/include/async_safe/CHECK.h b/aosp/bionic/libc/async_safe/include/async_safe/CHECK.h new file mode 100644 index 000000000..bec89a365 --- /dev/null +++ b/aosp/bionic/libc/async_safe/include/async_safe/CHECK.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +#include + +__BEGIN_DECLS + +// TODO: replace this with something more like 's family of macros. + +#define CHECK(predicate) \ + do { \ + if (!(predicate)) { \ + async_safe_fatal("%s:%d: %s CHECK '" #predicate "' failed", \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while(0) + +__END_DECLS diff --git a/aosp/bionic/libc/async_safe/include/async_safe/log.h b/aosp/bionic/libc/async_safe/include/async_safe/log.h new file mode 100644 index 000000000..0e02ea76e --- /dev/null +++ b/aosp/bionic/libc/async_safe/include/async_safe/log.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +// This file is an alternative to , but reuses +// `android_LogPriority` and should not have conflicting identifiers. +#include + +// These functions do not allocate memory to send data to the log. + +__BEGIN_DECLS + +// Formats a message to the log (priority 'fatal'), then aborts. +// Implemented as a macro so that async_safe_fatal isn't on the stack when we crash: +// we appear to go straight from the caller to abort, saving an uninteresting stack +// frame. +#define async_safe_fatal(...) \ + do { \ + async_safe_fatal_no_abort(__VA_ARGS__); \ + abort(); \ + } while (0) \ + + +// These functions do return, so callers that want to abort, must do so themselves, +// or use the macro above. +void async_safe_fatal_no_abort(const char* fmt, ...) __printflike(1, 2); +void async_safe_fatal_va_list(const char* prefix, const char* fmt, va_list args); + +// +// Formatting routines for the C library's internal debugging. +// Unlike the usual alternatives, these don't allocate, and they don't drag in all of stdio. +// These are async signal safe, so they can be called from signal handlers. +// + +int async_safe_format_buffer(char* buf, size_t size, const char* fmt, ...) __printflike(3, 4); +int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format, va_list args); + +int async_safe_format_fd(int fd, const char* format , ...) __printflike(2, 3); +int async_safe_format_fd_va_list(int fd, const char* format, va_list args); +int async_safe_format_log(int priority, const char* tag, const char* fmt, ...) __printflike(3, 4); +int async_safe_format_log_va_list(int priority, const char* tag, const char* fmt, va_list ap); +int async_safe_write_log(int priority, const char* tag, const char* msg); + +__END_DECLS diff --git a/aosp/bionic/libc/bionic/NetdClient.cpp b/aosp/bionic/libc/bionic/NetdClient.cpp new file mode 100644 index 000000000..d9debbfcd --- /dev/null +++ b/aosp/bionic/libc/bionic/NetdClient.cpp @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#ifdef LIBC_STATIC +#error NetdClient.cpp should NOT be included in static libc builds. +#endif + +#include + +#include "private/NetdClientDispatch.h" + +#include +#include +#include +#include + +template +static void netdClientInitFunction(void* handle, const char* symbol, FunctionType* function) { + typedef void (*InitFunctionType)(FunctionType*); + InitFunctionType initFunction = reinterpret_cast(dlsym(handle, symbol)); + if (initFunction != nullptr) { + initFunction(function); + } +} + +static void netdClientInitImpl() { + // Prevent netd from looping back fwmarkd connections to itself. It would work, but it's + // a deadlock hazard and unnecessary overhead for the resolver. + if (getuid() == 0 && strcmp(basename(getprogname()), "netd") == 0) { + async_safe_format_log(ANDROID_LOG_INFO, "netdClient", + "Skipping libnetd_client init since *we* are netd"); + return; + } + + void* handle = dlopen("libnetd_client.so", RTLD_NOW); + if (handle == nullptr) { + // If the library is not available, it's not an error. We'll just use + // default implementations of functions that it would've overridden. + return; + } + + netdClientInitFunction(handle, "netdClientInitAccept4", &__netdClientDispatch.accept4); + netdClientInitFunction(handle, "netdClientInitConnect", &__netdClientDispatch.connect); + netdClientInitFunction(handle, "netdClientInitSendmmsg", &__netdClientDispatch.sendmmsg); + netdClientInitFunction(handle, "netdClientInitSendmsg", &__netdClientDispatch.sendmsg); + netdClientInitFunction(handle, "netdClientInitSendto", &__netdClientDispatch.sendto); + netdClientInitFunction(handle, "netdClientInitSocket", &__netdClientDispatch.socket); + + netdClientInitFunction(handle, "netdClientInitNetIdForResolv", + &__netdClientDispatch.netIdForResolv); + netdClientInitFunction(handle, "netdClientInitDnsOpenProxy", + &__netdClientDispatch.dnsOpenProxy); +} + +static pthread_once_t netdClientInitOnce = PTHREAD_ONCE_INIT; + +extern "C" __LIBC_HIDDEN__ void netdClientInit() { + if (pthread_once(&netdClientInitOnce, netdClientInitImpl)) { + async_safe_format_log(ANDROID_LOG_ERROR, "netdClient", "Failed to initialize libnetd_client"); + } +} diff --git a/aosp/bionic/libc/bionic/NetdClientDispatch.cpp b/aosp/bionic/libc/bionic/NetdClientDispatch.cpp new file mode 100644 index 000000000..e6f4a9782 --- /dev/null +++ b/aosp/bionic/libc/bionic/NetdClientDispatch.cpp @@ -0,0 +1,80 @@ +/* + * 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 "private/NetdClientDispatch.h" + +#include + +#include "private/bionic_fdtrack.h" + +#ifdef __i386__ +#define __socketcall __attribute__((__cdecl__)) +#else +#define __socketcall +#endif + +extern "C" __socketcall int __accept4(int, sockaddr*, socklen_t*, int); +extern "C" __socketcall int __connect(int, const sockaddr*, socklen_t); +extern "C" __socketcall int __sendmmsg(int, const mmsghdr*, unsigned int, int); +extern "C" __socketcall ssize_t __sendmsg(int, const msghdr*, unsigned int); +extern "C" __socketcall int __sendto(int, const void*, size_t, int, const sockaddr*, socklen_t); +extern "C" __socketcall int __socket(int, int, int); + +static unsigned fallBackNetIdForResolv(unsigned netId) { + return netId; +} + +static int fallBackDnsOpenProxy() { + return -1; +} + +// This structure is modified only at startup (when libc.so is loaded) and never +// afterwards, so it's okay that it's read later at runtime without a lock. +__LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = { + __accept4, + __connect, + __sendmmsg, + __sendmsg, + __sendto, + __socket, + fallBackNetIdForResolv, + fallBackDnsOpenProxy, +}; + +int accept4(int fd, sockaddr* addr, socklen_t* addr_length, int flags) { + return FDTRACK_CREATE(__netdClientDispatch.accept4(fd, addr, addr_length, flags)); +} + +int connect(int fd, const sockaddr* addr, socklen_t addr_length) { + return __netdClientDispatch.connect(fd, addr, addr_length); +} + +int sendmmsg(int fd, const struct mmsghdr* msgs, unsigned int msg_count, int flags) { + return __netdClientDispatch.sendmmsg(fd, msgs, msg_count, flags); +} + +ssize_t sendmsg(int fd, const struct msghdr* msg, int flags) { + return __netdClientDispatch.sendmsg(fd, msg, flags); +} + +ssize_t sendto(int fd, const void* buf, size_t n, int flags, + const struct sockaddr* dst_addr, socklen_t dst_addr_length) { + return __netdClientDispatch.sendto(fd, buf, n, flags, dst_addr, dst_addr_length); +} + +int socket(int domain, int type, int protocol) { + return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol)); +} diff --git a/aosp/bionic/libc/bionic/__bionic_get_shell_path.cpp b/aosp/bionic/libc/bionic/__bionic_get_shell_path.cpp new file mode 100644 index 000000000..7aeed182e --- /dev/null +++ b/aosp/bionic/libc/bionic/__bionic_get_shell_path.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 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_get_shell_path.h" + +#include +#include +#include +#include + +#define VENDOR_PREFIX "/vendor/" + +static const char* init_sh_path() { + /* If the device is not treble enabled, return the path to the system shell. + * Vendor code, on non-treble enabled devices could use system() / popen() + * with relative paths for executables on /system. Since /system will not be + * in $PATH for the vendor shell, simply return the system shell. + */ + +#ifdef TREBLE_LINKER_NAMESPACES + /* look for /system or /vendor prefix */ + char exe_path[strlen(VENDOR_PREFIX)]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); + if (len != -1 && !strncmp(exe_path, VENDOR_PREFIX, strlen(VENDOR_PREFIX))) { + return "/vendor/bin/sh"; + } +#endif + return "/system/bin/sh"; +} + +const char* __bionic_get_shell_path() { + static const char* sh_path = init_sh_path(); + return sh_path; +} diff --git a/aosp/bionic/libc/bionic/__cmsg_nxthdr.cpp b/aosp/bionic/libc/bionic/__cmsg_nxthdr.cpp new file mode 100644 index 000000000..354e17e9c --- /dev/null +++ b/aosp/bionic/libc/bionic/__cmsg_nxthdr.cpp @@ -0,0 +1,39 @@ +/* + * 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 + +cmsghdr* __cmsg_nxthdr(msghdr* msg, cmsghdr* cmsg) { + cmsghdr* ptr; + ptr = reinterpret_cast(reinterpret_cast(cmsg) + CMSG_ALIGN(cmsg->cmsg_len)); + size_t len = reinterpret_cast(ptr+1) - reinterpret_cast(msg->msg_control); + if (len > msg->msg_controllen) { + return nullptr; + } + return ptr; +} diff --git a/aosp/bionic/libc/bionic/__cxa_guard.cpp b/aosp/bionic/libc/bionic/__cxa_guard.cpp new file mode 100644 index 000000000..e2e747791 --- /dev/null +++ b/aosp/bionic/libc/bionic/__cxa_guard.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2006 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 +#include +#include +#include + +#include "private/bionic_futex.h" + +// This file contains C++ ABI support functions for one time +// constructors as defined in the "Run-time ABI for the ARM Architecture" +// section 4.4.2 +// +// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for +// one time construction: +// +// ARM C++ ABI defines the LSB of guard variable should be tested +// by compiler-generated code before calling __cxa_guard_acquire et al. +// +// The Itanium/x86 C++ ABI defines the low-order _byte_ should be +// tested instead. +// +// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit +// aligned for x86. +// +// Reference documentation: +// +// section 3.2.3 of ARM IHI 0041C (for ARM) +// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86). +// +// There is no C++ ABI available for other ARCH. But the gcc source +// shows all other ARCH follow the definition of Itanium/x86 C++ ABI. + +#if defined(__arm__) +// The ARM C++ ABI mandates that guard variables are 32-bit aligned, 32-bit +// values. The LSB is tested by the compiler-generated code before calling +// __cxa_guard_acquire. +union _guard_t { + atomic_int state; + int32_t aligner; +}; + +#else +// The Itanium/x86 C++ ABI (used by all other architectures) mandates that +// guard variables are 64-bit aligned, 64-bit values. The LSB is tested by +// the compiler-generated code before calling __cxa_guard_acquire. +union _guard_t { + atomic_int state; + int64_t aligner; +}; + +#endif + +// Set construction state values according to reference documentation. +// 0 is the initialization value. +// Arm requires ((*gv & 1) == 1) after __cxa_guard_release, ((*gv & 3) == 0) after __cxa_guard_abort. +// X86 requires first byte not modified by __cxa_guard_acquire, first byte is non-zero after +// __cxa_guard_release. + +#define CONSTRUCTION_NOT_YET_STARTED 0 +#define CONSTRUCTION_COMPLETE 1 +#define CONSTRUCTION_UNDERWAY_WITHOUT_WAITER 0x100 +#define CONSTRUCTION_UNDERWAY_WITH_WAITER 0x200 + +extern "C" int __cxa_guard_acquire(_guard_t* gv) { + int old_value = atomic_load_explicit(&gv->state, memory_order_acquire); + // In the common CONSTRUCTION_COMPLETE case we have to ensure that all the stores performed by + // the construction function are observable on this CPU after we exit. A similar constraint may + // apply in the CONSTRUCTION_NOT_YET_STARTED case with a prior abort. + + while (true) { + if (old_value == CONSTRUCTION_COMPLETE) { + return 0; + } else if (old_value == CONSTRUCTION_NOT_YET_STARTED) { + if (!atomic_compare_exchange_weak_explicit(&gv->state, &old_value, + CONSTRUCTION_UNDERWAY_WITHOUT_WAITER, + memory_order_acquire /* or relaxed in C++17 */, + memory_order_acquire)) { + continue; + } + return 1; + } else if (old_value == CONSTRUCTION_UNDERWAY_WITHOUT_WAITER) { + if (!atomic_compare_exchange_weak_explicit(&gv->state, &old_value, + CONSTRUCTION_UNDERWAY_WITH_WAITER, + memory_order_acquire /* or relaxed in C++17 */, + memory_order_acquire)) { + continue; + } + } + + __futex_wait_ex(&gv->state, false, CONSTRUCTION_UNDERWAY_WITH_WAITER); + old_value = atomic_load_explicit(&gv->state, memory_order_acquire); + } +} + +extern "C" void __cxa_guard_release(_guard_t* gv) { + // Release fence is used to make all stores performed by the construction function + // visible in other threads. + int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_COMPLETE, memory_order_release); + if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) { + __futex_wake_ex(&gv->state, false, INT_MAX); + } +} + +extern "C" void __cxa_guard_abort(_guard_t* gv) { + // Release fence is used to make all stores performed by the construction function + // visible in other threads. + int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_NOT_YET_STARTED, memory_order_release); + if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) { + __futex_wake_ex(&gv->state, false, INT_MAX); + } +} diff --git a/aosp/bionic/libc/bionic/__cxa_pure_virtual.cpp b/aosp/bionic/libc/bionic/__cxa_pure_virtual.cpp new file mode 100644 index 000000000..00a4d9001 --- /dev/null +++ b/aosp/bionic/libc/bionic/__cxa_pure_virtual.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2008 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 + +extern "C" void __cxa_pure_virtual() { + async_safe_fatal("Pure virtual function called. Are you calling virtual methods from a destructor?"); +} diff --git a/aosp/bionic/libc/bionic/__cxa_thread_atexit_impl.cpp b/aosp/bionic/libc/bionic/__cxa_thread_atexit_impl.cpp new file mode 100644 index 000000000..99077c101 --- /dev/null +++ b/aosp/bionic/libc/bionic/__cxa_thread_atexit_impl.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 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 + +#include + +#include "pthread_internal.h" + +class thread_local_dtor { + public: + void (*func) (void *); + void *arg; + void *dso_handle; // unused... + thread_local_dtor* next; +}; + +extern "C" int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle); +extern "C" void __loader_add_thread_local_dtor(void* dso_handle) __attribute__((weak)); +extern "C" void __loader_remove_thread_local_dtor(void* dso_handle) __attribute__((weak)); + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) { + thread_local_dtor* dtor = new thread_local_dtor(); + + dtor->func = func; + dtor->arg = arg; + dtor->dso_handle = dso_handle; + + pthread_internal_t* thread = __get_thread(); + dtor->next = thread->thread_local_dtors; + thread->thread_local_dtors = dtor; + if (__loader_add_thread_local_dtor != nullptr) { + __loader_add_thread_local_dtor(dso_handle); + } + return 0; +} + +extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() { + pthread_internal_t* thread = __get_thread(); + while (thread->thread_local_dtors != nullptr) { + thread_local_dtor* current = thread->thread_local_dtors; + thread->thread_local_dtors = current->next; + + current->func(current->arg); + if (__loader_remove_thread_local_dtor != nullptr) { + __loader_remove_thread_local_dtor(current->dso_handle); + } + delete current; + } +} diff --git a/aosp/bionic/libc/bionic/__errno.cpp b/aosp/bionic/libc/bionic/__errno.cpp new file mode 100644 index 000000000..15089a449 --- /dev/null +++ b/aosp/bionic/libc/bionic/__errno.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include + +#include "pthread_internal.h" + +int* __errno() { + return &__get_thread()->errno_value; +} diff --git a/aosp/bionic/libc/bionic/__gnu_basename.cpp b/aosp/bionic/libc/bionic/__gnu_basename.cpp new file mode 100644 index 000000000..f9f87a644 --- /dev/null +++ b/aosp/bionic/libc/bionic/__gnu_basename.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#define _GNU_SOURCE 1 +#include + +extern "C" const char* __gnu_basename(const char* path) { + const char* last_slash = strrchr(path, '/'); + return (last_slash != nullptr) ? last_slash + 1 : path; +} diff --git a/aosp/bionic/libc/bionic/__libc_current_sigrtmax.cpp b/aosp/bionic/libc/bionic/__libc_current_sigrtmax.cpp new file mode 100644 index 000000000..32179bb9b --- /dev/null +++ b/aosp/bionic/libc/bionic/__libc_current_sigrtmax.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +int __libc_current_sigrtmax(void) { + // If you change this, also change __ndk_legacy___libc_current_sigrtmax + // in to match. + return __SIGRTMAX; +} diff --git a/aosp/bionic/libc/bionic/__libc_current_sigrtmin.cpp b/aosp/bionic/libc/bionic/__libc_current_sigrtmin.cpp new file mode 100644 index 000000000..e6b3412b7 --- /dev/null +++ b/aosp/bionic/libc/bionic/__libc_current_sigrtmin.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +#include + +int __libc_current_sigrtmin() { + return __SIGRTMIN + __SIGRT_RESERVED; +} diff --git a/aosp/bionic/libc/bionic/__libc_init_main_thread.cpp b/aosp/bionic/libc/bionic/__libc_init_main_thread.cpp new file mode 100644 index 000000000..56a848888 --- /dev/null +++ b/aosp/bionic/libc/bionic/__libc_init_main_thread.cpp @@ -0,0 +1,166 @@ +/* + * 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 "libc_init_common.h" + +#include + +#include "private/KernelArgumentBlock.h" +#include "private/bionic_arc4random.h" +#include "private/bionic_defs.h" +#include "private/bionic_elf_tls.h" +#include "private/bionic_globals.h" +#include "private/bionic_ssp.h" +#include "pthread_internal.h" + +extern "C" pid_t __getpid(); +extern "C" int __set_tid_address(int* tid_address); + +// Declared in "private/bionic_ssp.h". +uintptr_t __stack_chk_guard = 0; + +static pthread_internal_t main_thread; + +// Setup for the main thread. For dynamic executables, this is called by the +// linker _before_ libc is mapped in memory. This means that all writes to +// globals from this function will apply to linker-private copies and will not +// be visible from libc later on. +// +// Note: this function creates a pthread_internal_t for the initial thread and +// stores the pointer in TLS, but does not add it to pthread's thread list. This +// has to be done later from libc itself (see __libc_init_common). +// +// This is in a file by itself because it needs to be built with +// -fno-stack-protector because it's responsible for setting up the main +// thread's TLS (which stack protector relies on). It's also built with +// -ffreestanding because the early init function runs in the linker before +// ifunc resolvers have run. + +// Do enough setup to: +// - Let the dynamic linker invoke system calls (and access errno) +// - Ensure that TLS access functions (__get_{tls,thread}) never return NULL +// - Allow the stack protector to work (with a zero cookie) +// Avoid doing much more because, when this code is called within the dynamic +// linker, the linker binary hasn't been relocated yet, so certain kinds of code +// are hazardous, such as accessing non-hidden global variables or calling +// string.h functions. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +extern "C" void __libc_init_main_thread_early(const KernelArgumentBlock& args, + bionic_tcb* temp_tcb) { + __libc_shared_globals()->auxv = args.auxv; +#if defined(__i386__) + __libc_init_sysinfo(); // uses AT_SYSINFO auxv entry +#endif + __init_tcb(temp_tcb, &main_thread); + __init_tcb_dtv(temp_tcb); + __set_tls(&temp_tcb->tls_slot(0)); + main_thread.tid = __getpid(); + main_thread.set_cached_pid(main_thread.tid); + main_thread.stack_top = reinterpret_cast(args.argv); +} + +// This code is used both by each new pthread and the code that initializes the main thread. +void __init_tcb(bionic_tcb* tcb, pthread_internal_t* thread) { +#ifdef TLS_SLOT_SELF + // On x86, slot 0 must point to itself so code can read the thread pointer by + // loading %fs:0 or %gs:0. + tcb->tls_slot(TLS_SLOT_SELF) = &tcb->tls_slot(TLS_SLOT_SELF); +#endif + tcb->tls_slot(TLS_SLOT_THREAD_ID) = thread; +} + +void __init_tcb_dtv(bionic_tcb* tcb) { + // Initialize the DTV slot to a statically-allocated empty DTV. The first + // access to a dynamic TLS variable allocates a new DTV. + static const TlsDtv zero_dtv = {}; + __set_tcb_dtv(tcb, const_cast(&zero_dtv)); +} + +// Finish initializing the main thread. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +extern "C" void __libc_init_main_thread_late() { + __init_bionic_tls_ptrs(__get_bionic_tcb(), __allocate_temp_bionic_tls()); + + // Tell the kernel to clear our tid field when we exit, so we're like any other pthread. + // For threads created by pthread_create, this setup happens during the clone syscall (i.e. + // CLONE_CHILD_CLEARTID). + __set_tid_address(&main_thread.tid); + + pthread_attr_init(&main_thread.attr); + // We don't want to explicitly set the main thread's scheduler attributes (http://b/68328561). + pthread_attr_setinheritsched(&main_thread.attr, PTHREAD_INHERIT_SCHED); + // The main thread has no guard page. + pthread_attr_setguardsize(&main_thread.attr, 0); + // User code should never see this; we'll compute it when asked. + pthread_attr_setstacksize(&main_thread.attr, 0); + + // The TLS stack guard is set from the global, so ensure that we've initialized the global + // before we initialize the TLS. Dynamic executables will initialize their copy of the global + // stack protector from the one in the main thread's TLS. + __libc_safe_arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard)); + __init_tcb_stack_guard(__get_bionic_tcb()); + + __init_thread(&main_thread); + + __init_additional_stacks(&main_thread); +} + +// Once all ELF modules are loaded, allocate the final copy of the main thread's +// static TLS memory. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +extern "C" void __libc_init_main_thread_final() { + bionic_tcb* temp_tcb = __get_bionic_tcb(); + bionic_tls* temp_tls = &__get_bionic_tls(); + + // Allocate the main thread's static TLS. (This mapping doesn't include a + // stack.) + ThreadMapping mapping = __allocate_thread_mapping(0, PTHREAD_GUARD_SIZE); + if (mapping.mmap_base == nullptr) { + async_safe_fatal("failed to mmap main thread static TLS: %s", strerror(errno)); + } + + const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + auto new_tcb = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tcb()); + auto new_tls = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tls()); + + __init_static_tls(mapping.static_tls); + new_tcb->copy_from_bootstrap(temp_tcb); + new_tls->copy_from_bootstrap(temp_tls); + __init_tcb(new_tcb, &main_thread); + __init_bionic_tls_ptrs(new_tcb, new_tls); + + main_thread.mmap_base = mapping.mmap_base; + main_thread.mmap_size = mapping.mmap_size; + main_thread.mmap_base_unguarded = mapping.mmap_base_unguarded; + main_thread.mmap_size_unguarded = mapping.mmap_size_unguarded; + + __set_tls(&new_tcb->tls_slot(0)); + + __set_stack_and_tls_vma_name(true); + __free_temp_bionic_tls(temp_tls); +} diff --git a/aosp/bionic/libc/bionic/__set_errno.cpp b/aosp/bionic/libc/bionic/__set_errno.cpp new file mode 100644 index 000000000..9ef0047cc --- /dev/null +++ b/aosp/bionic/libc/bionic/__set_errno.cpp @@ -0,0 +1,48 @@ +/* + * 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 + +// This function is called from our assembler syscall stubs. +// C/C++ code should just assign 'errno' instead. + +// The return type is 'long' because we use the same routine in calls +// that return an int as in ones that return a ssize_t. On a 32-bit +// system these are the same size, but on a 64-bit system they're not. +// 'long' gives us 32-bit on 32-bit systems, 64-bit on 64-bit systems. + +// Since __set_errno was mistakenly exposed in in the 32-bit +// NDK, use a differently named internal function for the system call +// stubs. This avoids having the stubs .hidden directives accidentally +// hide __set_errno for old NDK apps. + +// This one is for internal use only and used by both LP32 and LP64 assembler. +extern "C" __LIBC_HIDDEN__ long __set_errno_internal(int n) { + errno = n; + return -1; +} diff --git a/aosp/bionic/libc/bionic/__stack_chk_fail.cpp b/aosp/bionic/libc/bionic/__stack_chk_fail.cpp new file mode 100644 index 000000000..5f5a5f69a --- /dev/null +++ b/aosp/bionic/libc/bionic/__stack_chk_fail.cpp @@ -0,0 +1,37 @@ +/* + * 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 + +#include + +#include "private/bionic_ssp.h" + +void __stack_chk_fail() { + async_safe_fatal("stack corruption detected (-fstack-protector)"); +} diff --git a/aosp/bionic/libc/bionic/abort.cpp b/aosp/bionic/libc/bionic/abort.cpp new file mode 100644 index 000000000..c8bba01fd --- /dev/null +++ b/aosp/bionic/libc/bionic/abort.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1985 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 +#include +#include +#include + +#include "private/bionic_inline_raise.h" + +void abort() { + // Don't block SIGABRT to give any signal handler a chance; we ignore + // any errors -- X311J doesn't allow abort to return anyway. + sigset64_t mask; + sigfillset64(&mask); + sigdelset64(&mask, SIGABRT); + + sigprocmask64(SIG_SETMASK, &mask, nullptr); + inline_raise(SIGABRT); + + // If SIGABRT is ignored or it's caught and the handler returns, + // remove the SIGABRT signal handler and raise SIGABRT again. + struct sigaction64 sa = { .sa_handler = SIG_DFL, .sa_flags = SA_RESTART }; + sigaction64(SIGABRT, &sa, nullptr); + + sigprocmask64(SIG_SETMASK, &mask, nullptr); + inline_raise(SIGABRT); + + // If we get this far, just exit. + _exit(127); +} diff --git a/aosp/bionic/libc/bionic/accept.cpp b/aosp/bionic/libc/bionic/accept.cpp new file mode 100644 index 000000000..7f7aa063b --- /dev/null +++ b/aosp/bionic/libc/bionic/accept.cpp @@ -0,0 +1,21 @@ +/* + * 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 + +int accept(int sockfd, sockaddr* addr, socklen_t* addrlen) { + return accept4(sockfd, addr, addrlen, 0); +} diff --git a/aosp/bionic/libc/bionic/access.cpp b/aosp/bionic/libc/bionic/access.cpp new file mode 100644 index 000000000..360b67252 --- /dev/null +++ b/aosp/bionic/libc/bionic/access.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int access(const char* path, int mode) { + return faccessat(AT_FDCWD, path, mode, 0); +} diff --git a/aosp/bionic/libc/bionic/android_profiling_dynamic.cpp b/aosp/bionic/libc/bionic/android_profiling_dynamic.cpp new file mode 100644 index 000000000..9d92a6dfe --- /dev/null +++ b/aosp/bionic/libc/bionic/android_profiling_dynamic.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020 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. + */ + +#if defined(LIBC_STATIC) +#error This file should not be compiled for static targets. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "malloc_heapprofd.h" + +// This file defines the handler for the reserved signal sent by the Android +// platform's profilers. The accompanying signal value discriminates between +// specific requestors: +// 0: heapprofd heap profiler. +// 1: traced_perf perf profiler. +static constexpr int kHeapprofdSignalValue = 0; +static constexpr int kTracedPerfSignalValue = 1; + +static void HandleProfilingSignal(int, siginfo_t*, void*); + +// Called during dynamic libc preinit. +__LIBC_HIDDEN__ void __libc_init_profiling_handlers() { + struct sigaction action = {}; + action.sa_flags = SA_SIGINFO | SA_RESTART; + action.sa_sigaction = HandleProfilingSignal; + sigaction(BIONIC_SIGNAL_PROFILER, &action, nullptr); + + // The perfetto_hprof ART plugin installs a signal handler to handle this signal. That plugin + // does not get loaded for a) non-apps, b) non-profilable apps on user. The default signal + // disposition is to crash. We do not want the target to crash if we accidentally target a + // non-app or non-profilable process. + // + // This does *not* get run for processes that statically link libc, and those will still crash. + signal(BIONIC_SIGNAL_ART_PROFILER, SIG_IGN); +} + +static void HandleSigsysSeccompOverride(int, siginfo_t*, void*); +static void HandleTracedPerfSignal(); + +static void HandleProfilingSignal(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) { + ErrnoRestorer errno_restorer; + + if (info->si_code != SI_QUEUE) { + return; + } + + int signal_value = info->si_value.sival_int; + async_safe_format_log(ANDROID_LOG_INFO, "libc", "%s: received profiling signal with si_value: %d", + getprogname(), signal_value); + + // Proceed only if the process is considered profileable. + bool profileable = false; + android_mallopt(M_GET_PROCESS_PROFILEABLE, &profileable, sizeof(profileable)); + if (!profileable) { + async_safe_write_log(ANDROID_LOG_ERROR, "libc", "profiling signal rejected (not profileable)"); + return; + } + + // Temporarily override SIGSYS handling, in a best-effort attempt at not + // crashing if we happen to be running in a process with a seccomp filter that + // disallows some of the syscalls done by this signal handler. This protects + // against SECCOMP_RET_TRAP with a crashing SIGSYS handler (typical of android + // minijails). Won't help if the filter is using SECCOMP_RET_KILL_*. + // Note: the override is process-wide, but short-lived. The syscalls are still + // blocked, but the overridden handler recovers from SIGSYS, and fakes the + // syscall return value as ENOSYS. + struct sigaction sigsys_override = {}; + sigsys_override.sa_sigaction = &HandleSigsysSeccompOverride; + sigsys_override.sa_flags = SA_SIGINFO; + + struct sigaction old_act = {}; + sigaction(SIGSYS, &sigsys_override, &old_act); + + if (signal_value == kHeapprofdSignalValue) { + HandleHeapprofdSignal(); + } else if (signal_value == kTracedPerfSignalValue) { + HandleTracedPerfSignal(); + } else { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "unrecognized profiling signal si_value: %d", + signal_value); + } + sigaction(SIGSYS, &old_act, nullptr); +} + +// Open /proc/self/{maps,mem}, connect to traced_perf, send the fds over the +// socket. Everything happens synchronously within the signal handler. Socket +// is made non-blocking, and we do not retry. +static void HandleTracedPerfSignal() { + ScopedFd sock_fd{ socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0 /*protocol*/) }; + if (sock_fd.get() == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create socket: %s", strerror(errno)); + return; + } + + sockaddr_un saddr{ AF_UNIX, "/dev/socket/traced_perf" }; + size_t addrlen = sizeof(sockaddr_un); + if (connect(sock_fd.get(), reinterpret_cast(&saddr), addrlen) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to traced_perf socket: %s", + strerror(errno)); + return; + } + + ScopedFd maps_fd{ open("/proc/self/maps", O_RDONLY | O_CLOEXEC) }; + if (maps_fd.get() == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/self/maps: %s", + strerror(errno)); + return; + } + ScopedFd mem_fd{ open("/proc/self/mem", O_RDONLY | O_CLOEXEC) }; + if (mem_fd.get() == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/self/mem: %s", + strerror(errno)); + return; + } + + // Send 1 byte with auxiliary data carrying two fds. + int send_fds[2] = { maps_fd.get(), mem_fd.get() }; + int num_fds = 2; + char iobuf[1] = {}; + msghdr msg_hdr = {}; + iovec iov = { reinterpret_cast(iobuf), sizeof(iobuf) }; + msg_hdr.msg_iov = &iov; + msg_hdr.msg_iovlen = 1; + alignas(cmsghdr) char control_buf[256] = {}; + const auto raw_ctl_data_sz = num_fds * sizeof(int); + const size_t control_buf_len = static_cast(CMSG_SPACE(raw_ctl_data_sz)); + msg_hdr.msg_control = control_buf; + msg_hdr.msg_controllen = control_buf_len; // used by CMSG_FIRSTHDR + struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = static_cast(CMSG_LEN(raw_ctl_data_sz)); + memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int)); + + if (sendmsg(sock_fd.get(), &msg_hdr, 0) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to sendmsg: %s", strerror(errno)); + } +} + +static void HandleSigsysSeccompOverride(int /*signal_number*/, siginfo_t* info, + void* void_context) { + ErrnoRestorer errno_restorer; + if (info->si_code != SYS_SECCOMP) { + return; + } + + async_safe_format_log( + ANDROID_LOG_WARN, "libc", + "Profiling setup: trapped seccomp SIGSYS for syscall %d. Returning ENOSYS to caller.", + info->si_syscall); + + // The handler is responsible for setting the return value as if the system + // call happened (which is arch-specific). Use a plausible unsuccessful value. + auto ret = -ENOSYS; + ucontext_t* ctx = reinterpret_cast(void_context); + +#if defined(__arm__) + ctx->uc_mcontext.arm_r0 = ret; +#elif defined(__aarch64__) + ctx->uc_mcontext.regs[0] = ret; // x0 +#elif defined(__i386__) + ctx->uc_mcontext.gregs[REG_EAX] = ret; +#elif defined(__x86_64__) + ctx->uc_mcontext.gregs[REG_RAX] = ret; +#else +#error "unsupported architecture" +#endif +} diff --git a/aosp/bionic/libc/bionic/android_set_abort_message.cpp b/aosp/bionic/libc/bionic/android_set_abort_message.cpp new file mode 100644 index 000000000..2ea12ee54 --- /dev/null +++ b/aosp/bionic/libc/bionic/android_set_abort_message.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include + +#include "private/bionic_defs.h" +#include "private/bionic_globals.h" +#include "private/ScopedPthreadMutexLocker.h" + +struct abort_msg_t { + size_t size; + char msg[0]; +}; +static_assert( + offsetof(abort_msg_t, msg) == sizeof(size_t), + "The in-memory layout of abort_msg_t is not consistent with what libdebuggerd expects."); + +struct magic_abort_msg_t { + uint64_t magic1; + uint64_t magic2; + abort_msg_t msg; +}; +static_assert(offsetof(magic_abort_msg_t, msg) == 2 * sizeof(uint64_t), + "The in-memory layout of magic_abort_msg_t is not consistent with what automated " + "tools expect."); + +[[clang::optnone]] +static void fill_abort_message_magic(magic_abort_msg_t* new_magic_abort_message) { + // 128-bit magic for the abort message. Chosen by fair dice roll. + // This function is intentionally deoptimized to avoid the magic to be present + // in the final binary. This causes clang to only use instructions where parts + // of the magic are encoded into immediate arguments for the instructions in + // all supported architectures. + new_magic_abort_message->magic1 = 0xb18e40886ac388f0ULL; + new_magic_abort_message->magic2 = 0xc6dfba755a1de0b5ULL; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void android_set_abort_message(const char* msg) { + ScopedPthreadMutexLocker locker(&__libc_shared_globals()->abort_msg_lock); + + if (__libc_shared_globals()->abort_msg != nullptr) { + // We already have an abort message. + // Assume that the first crash is the one most worth reporting. + return; + } + + size_t size = sizeof(magic_abort_msg_t) + strlen(msg) + 1; + void* map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (map == MAP_FAILED) { + return; + } + + // Name the abort message mapping to make it easier for tools to find the + // mapping. + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, size, "abort message"); + + magic_abort_msg_t* new_magic_abort_message = reinterpret_cast(map); + fill_abort_message_magic(new_magic_abort_message); + new_magic_abort_message->msg.size = size; + strcpy(new_magic_abort_message->msg.msg, msg); + __libc_shared_globals()->abort_msg = &new_magic_abort_message->msg; +} diff --git a/aosp/bionic/libc/bionic/android_unsafe_frame_pointer_chase.cpp b/aosp/bionic/libc/bionic/android_unsafe_frame_pointer_chase.cpp new file mode 100644 index 000000000..e25867b0e --- /dev/null +++ b/aosp/bionic/libc/bionic/android_unsafe_frame_pointer_chase.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 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 "platform/bionic/android_unsafe_frame_pointer_chase.h" + +#include "pthread_internal.h" +#include "platform/bionic/mte.h" + +/* + * Implement fast stack unwinding for stack frames with frame pointers. Stores at most num_entries + * return addresses to buffer buf. Returns the number of available return addresses, which may be + * greater than num_entries. + * + * This function makes no guarantees about its behavior on encountering a frame built without frame + * pointers, except that it should not crash or enter an infinite loop, and that any frames prior to + * the frame built without frame pointers should be correct. + * + * This function is only meant to be used with memory safety tools such as sanitizers which need to + * take stack traces efficiently. Normal applications should use APIs such as libunwindstack or + * _Unwind_Backtrace. + */ +__attribute__((no_sanitize("address", "hwaddress"))) size_t android_unsafe_frame_pointer_chase( + uintptr_t* buf, size_t num_entries) { + // Disable MTE checks for the duration of this function, since we can't be sure that following + // next_frame pointers won't cause us to read from tagged memory. ASAN/HWASAN are disabled here + // for the same reason. + ScopedDisableMTE x; + + struct frame_record { + uintptr_t next_frame, return_addr; + }; + + auto begin = reinterpret_cast(__builtin_frame_address(0)); + uintptr_t end = __get_thread()->stack_top; + + stack_t ss; + if (sigaltstack(nullptr, &ss) == 0 && (ss.ss_flags & SS_ONSTACK)) { + end = reinterpret_cast(ss.ss_sp) + ss.ss_size; + } + + size_t num_frames = 0; + while (1) { + auto* frame = reinterpret_cast(begin); + if (num_frames < num_entries) { + buf[num_frames] = frame->return_addr; + } + ++num_frames; + if (frame->next_frame < begin + sizeof(frame_record) || frame->next_frame >= end || + frame->next_frame % sizeof(void*) != 0) { + break; + } + begin = frame->next_frame; + } + + return num_frames; +} diff --git a/aosp/bionic/libc/bionic/arpa_inet.cpp b/aosp/bionic/libc/bionic/arpa_inet.cpp new file mode 100644 index 000000000..9d4afe321 --- /dev/null +++ b/aosp/bionic/libc/bionic/arpa_inet.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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 +#include +#include + +#include "private/ErrnoRestorer.h" + +// The difference between inet_network(3) and inet_addr(3) is that +// inet_network uses host order and inet_addr network order. +in_addr_t inet_network(const char* cp) { + in_addr_t network_order = inet_addr(cp); + return ntohl(network_order); +} + +in_addr_t inet_addr(const char* cp) { + in_addr addr; + return inet_aton(cp, &addr) ? addr.s_addr : INADDR_NONE; +} + +int inet_aton(const char* cp, in_addr* addr) { + ErrnoRestorer errno_restorer; + + unsigned long parts[4]; + size_t i; + for (i = 0; i < 4; ++i) { + char* end; + errno = 0; + parts[i] = strtoul(cp, &end, 0); + if (errno != 0 || end == cp || (*end != '.' && *end != '\0')) return 0; + if (*end == '\0') break; + cp = end + 1; + } + + uint32_t result = 0; + if (i == 0) { + // a (a 32-bit). + if (parts[0] > 0xffffffff) return 0; + result = parts[0]; + } else if (i == 1) { + // a.b (b 24-bit). + if (parts[0] > 0xff || parts[1] > 0xffffff) return 0; + result = (parts[0] << 24) | parts[1]; + } else if (i == 2) { + // a.b.c (c 16-bit). + if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff) return 0; + result = (parts[0] << 24) | (parts[1] << 16) | parts[2]; + } else if (i == 3) { + // a.b.c.d (d 8-bit). + if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return 0; + result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]; + } else { + return 0; + } + + if (addr != nullptr) addr->s_addr = htonl(result); + return 1; +} diff --git a/aosp/bionic/libc/bionic/assert.cpp b/aosp/bionic/libc/bionic/assert.cpp new file mode 100644 index 000000000..0f4ee9780 --- /dev/null +++ b/aosp/bionic/libc/bionic/assert.cpp @@ -0,0 +1,41 @@ +/* $OpenBSD: assert.c,v 1.8 2005/08/08 08:05:33 espie Exp $ */ +/*- + * Copyright (c) 1992, 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 + +#include + +void __assert(const char* file, int line, const char* failed_expression) { + async_safe_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression); +} + +void __assert2(const char* file, int line, const char* function, const char* failed_expression) { + async_safe_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression); +} diff --git a/aosp/bionic/libc/bionic/atexit.cpp b/aosp/bionic/libc/bionic/atexit.cpp new file mode 100644 index 000000000..5dbf322e3 --- /dev/null +++ b/aosp/bionic/libc/bionic/atexit.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2020 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 "atexit.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "platform/bionic/page.h" + +extern "C" void __libc_stdio_cleanup(); +extern "C" void __unregister_atfork(void* dso); + +namespace { + +struct AtexitEntry { + void (*fn)(void*); // the __cxa_atexit callback + void* arg; // argument for `fn` callback + void* dso; // shared module handle +}; + +class AtexitArray { + public: + size_t size() const { return size_; } + uint64_t total_appends() const { return total_appends_; } + const AtexitEntry& operator[](size_t idx) const { return array_[idx]; } + + bool append_entry(const AtexitEntry& entry); + AtexitEntry extract_entry(size_t idx); + void recompact(); + + private: + AtexitEntry* array_; + size_t size_; + size_t extracted_count_; + size_t capacity_; + + // An entry can be appended by a __cxa_finalize callback. Track the number of appends so we + // restart concurrent __cxa_finalize passes. + uint64_t total_appends_; + + static size_t page_start_of_index(size_t idx) { return PAGE_START(idx * sizeof(AtexitEntry)); } + static size_t page_end_of_index(size_t idx) { return PAGE_END(idx * sizeof(AtexitEntry)); } + + // Recompact the array if it will save at least one page of memory at the end. + bool needs_recompaction() const { + return page_end_of_index(size_ - extracted_count_) < page_end_of_index(size_); + } + + void set_writable(bool writable, size_t start_idx, size_t num_entries); + static bool next_capacity(size_t capacity, size_t* result); + bool expand_capacity(); +}; + +} // anonymous namespace + +bool AtexitArray::append_entry(const AtexitEntry& entry) { + if (size_ >= capacity_ && !expand_capacity()) return false; + + size_t idx = size_++; + + set_writable(true, idx, 1); + array_[idx] = entry; + ++total_appends_; + set_writable(false, idx, 1); + + return true; +} + +// Extract an entry and return it. +AtexitEntry AtexitArray::extract_entry(size_t idx) { + AtexitEntry result = array_[idx]; + + set_writable(true, idx, 1); + array_[idx] = {}; + ++extracted_count_; + set_writable(false, idx, 1); + + return result; +} + +void AtexitArray::recompact() { + if (!needs_recompaction()) return; + + set_writable(true, 0, size_); + + // Optimization: quickly skip over the initial non-null entries. + size_t src = 0, dst = 0; + while (src < size_ && array_[src].fn != nullptr) { + ++src; + ++dst; + } + + // Shift the non-null entries forward, and zero out the removed entries at the end of the array. + for (; src < size_; ++src) { + const AtexitEntry entry = array_[src]; + array_[src] = {}; + if (entry.fn != nullptr) { + array_[dst++] = entry; + } + } + + // If the table uses fewer pages, clean the pages at the end. + size_t old_bytes = page_end_of_index(size_); + size_t new_bytes = page_end_of_index(dst); + if (new_bytes < old_bytes) { + madvise(reinterpret_cast(array_) + new_bytes, old_bytes - new_bytes, MADV_DONTNEED); + } + + set_writable(false, 0, size_); + + size_ = dst; + extracted_count_ = 0; +} + +// Use mprotect to make the array writable or read-only. Returns true on success. Making the array +// read-only could protect against either unintentional or malicious corruption of the array. +void AtexitArray::set_writable(bool writable, size_t start_idx, size_t num_entries) { + if (array_ == nullptr) return; + + const size_t start_byte = page_start_of_index(start_idx); + const size_t stop_byte = page_end_of_index(start_idx + num_entries); + const size_t byte_len = stop_byte - start_byte; + + const int prot = PROT_READ | (writable ? PROT_WRITE : 0); + if (mprotect(reinterpret_cast(array_) + start_byte, byte_len, prot) != 0) { + async_safe_fatal("mprotect failed on atexit array: %s", strerror(errno)); + } +} + +// Approximately double the capacity. Returns true if successful (no overflow). AtexitEntry is +// smaller than a page, but this function should still be correct even if AtexitEntry were larger +// than one. +bool AtexitArray::next_capacity(size_t capacity, size_t* result) { + if (capacity == 0) { + *result = PAGE_END(sizeof(AtexitEntry)) / sizeof(AtexitEntry); + return true; + } + size_t num_bytes; + if (__builtin_mul_overflow(page_end_of_index(capacity), 2, &num_bytes)) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", "__cxa_atexit: capacity calculation overflow"); + return false; + } + *result = num_bytes / sizeof(AtexitEntry); + return true; +} + +bool AtexitArray::expand_capacity() { + size_t new_capacity; + if (!next_capacity(capacity_, &new_capacity)) return false; + const size_t new_capacity_bytes = page_end_of_index(new_capacity); + + set_writable(true, 0, capacity_); + + bool result = false; + void* new_pages; + if (array_ == nullptr) { + new_pages = mmap(nullptr, new_capacity_bytes, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } else { + // mremap fails if the source buffer crosses a boundary between two VMAs. When a single array + // element is modified, the kernel should split then rejoin the buffer's VMA. + new_pages = mremap(array_, page_end_of_index(capacity_), new_capacity_bytes, MREMAP_MAYMOVE); + } + if (new_pages == MAP_FAILED) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "__cxa_atexit: mmap/mremap failed to allocate %zu bytes: %s", + new_capacity_bytes, strerror(errno)); + } else { + result = true; + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, new_pages, new_capacity_bytes, "atexit handlers"); + array_ = static_cast(new_pages); + capacity_ = new_capacity; + } + set_writable(false, 0, capacity_); + return result; +} + +static AtexitArray g_array; +static pthread_mutex_t g_atexit_lock = PTHREAD_MUTEX_INITIALIZER; + +static inline void atexit_lock() { + pthread_mutex_lock(&g_atexit_lock); +} + +static inline void atexit_unlock() { + pthread_mutex_unlock(&g_atexit_lock); +} + +// Register a function to be called either when a library is unloaded (dso != nullptr), or when the +// program exits (dso == nullptr). The `dso` argument is typically the address of a hidden +// __dso_handle variable. This function is also used as the backend for the atexit function. +// +// See https://itanium-cxx-abi.github.io/cxx-abi/abi.html#dso-dtor. +// +int __cxa_atexit(void (*func)(void*), void* arg, void* dso) { + int result = -1; + + if (func != nullptr) { + atexit_lock(); + if (g_array.append_entry({.fn = func, .arg = arg, .dso = dso})) { + result = 0; + } + atexit_unlock(); + } + + return result; +} + +void __cxa_finalize(void* dso) { + atexit_lock(); + + static uint32_t call_depth = 0; + ++call_depth; + +restart: + const uint64_t total_appends = g_array.total_appends(); + + for (ssize_t i = g_array.size() - 1; i >= 0; --i) { + if (g_array[i].fn == nullptr || (dso != nullptr && g_array[i].dso != dso)) continue; + + // Clear the entry in the array because its DSO handle will become invalid, and to avoid calling + // an entry again if __cxa_finalize is called recursively. + const AtexitEntry entry = g_array.extract_entry(i); + + atexit_unlock(); + entry.fn(entry.arg); + atexit_lock(); + + if (g_array.total_appends() != total_appends) goto restart; + } + + // Avoid recompaction on recursive calls because it's unnecessary and would require earlier, + // concurrent __cxa_finalize calls to restart. Skip recompaction on program exit too + // (dso == nullptr), because the memory will be reclaimed soon anyway. + --call_depth; + if (call_depth == 0 && dso != nullptr) { + g_array.recompact(); + } + + atexit_unlock(); + + if (dso != nullptr) { + __unregister_atfork(dso); + } else { + // If called via exit(), flush output of all open files. + __libc_stdio_cleanup(); + } +} diff --git a/aosp/bionic/libc/bionic/atexit.h b/aosp/bionic/libc/bionic/atexit.h new file mode 100644 index 000000000..8abcdc5f3 --- /dev/null +++ b/aosp/bionic/libc/bionic/atexit.h @@ -0,0 +1,42 @@ +/* $OpenBSD: atexit.h,v 1.9 2014/06/18 19:01:10 kettenis Exp $ */ + +/* + * Copyright (c) 2002 Daniel Hartmeier + * 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 HOLDERS 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. + * + */ + +#pragma once + +#include + +__BEGIN_DECLS + +int __cxa_atexit(void (*)(void*), void*, void*); +void __cxa_finalize(void*); + +__END_DECLS diff --git a/aosp/bionic/libc/bionic/atof.cpp b/aosp/bionic/libc/bionic/atof.cpp new file mode 100644 index 000000000..c17deab11 --- /dev/null +++ b/aosp/bionic/libc/bionic/atof.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +double atof(const char* s) { + // Despite the 'f' in the name, this returns a double and is + // specified to be equivalent to strtod. + return strtod(s, nullptr); +} diff --git a/aosp/bionic/libc/bionic/bionic_allocator.cpp b/aosp/bionic/libc/bionic/bionic_allocator.cpp new file mode 100644 index 000000000..b6d6ba73f --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_allocator.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2015 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_allocator.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "platform/bionic/page.h" +#include "platform/bionic/macros.h" + +// +// BionicAllocator is a general purpose allocator designed to provide the same +// functionality as the malloc/free/realloc/memalign libc functions. +// +// On alloc: +// If size is > 1k allocator proxies malloc call directly to mmap. +// If size <= 1k allocator uses BionicSmallObjectAllocator for the size +// rounded up to the nearest power of two. +// +// On free: +// +// For a pointer allocated using proxy-to-mmap allocator unmaps +// the memory. +// +// For a pointer allocated using BionicSmallObjectAllocator it adds +// the block to free_blocks_list in the corresponding page. If the number of +// free pages reaches 2, BionicSmallObjectAllocator munmaps one of the pages +// keeping the other one in reserve. + +// Memory management for large objects is fairly straightforward, but for small +// objects it is more complicated. If you are changing this code, one simple +// way to evaluate the memory usage change is by running 'dd' and examine the +// memory usage by 'showmap $(pidof dd)'. 'dd' is nice in that: +// 1. It links in quite a few libraries, so you get some linker memory use. +// 2. When run with no arguments, it sits waiting for input, so it is easy to +// examine its memory usage with showmap. +// 3. Since it does nothing while waiting for input, the memory usage is +// determinisitic. + +static const char kSignature[4] = {'L', 'M', 'A', 1}; + +static const size_t kSmallObjectMaxSize = 1 << kSmallObjectMaxSizeLog2; + +// This type is used for large allocations (with size >1k) +static const uint32_t kLargeObject = 111; + +// Allocated pointers must be at least 16-byte aligned. Round up the size of +// page_info to multiple of 16. +static constexpr size_t kPageInfoSize = __BIONIC_ALIGN(sizeof(page_info), 16); + +static inline uint16_t log2(size_t number) { + uint16_t result = 0; + number--; + + while (number != 0) { + result++; + number >>= 1; + } + + return result; +} + +BionicSmallObjectAllocator::BionicSmallObjectAllocator(uint32_t type, + size_t block_size) + : type_(type), + block_size_(block_size), + blocks_per_page_((PAGE_SIZE - sizeof(small_object_page_info)) / + block_size), + free_pages_cnt_(0), + page_list_(nullptr) {} + +void* BionicSmallObjectAllocator::alloc() { + CHECK(block_size_ != 0); + + if (page_list_ == nullptr) { + alloc_page(); + } + + // Fully allocated pages are de-managed and removed from the page list, so + // every page from the page list must be useable. Let's just take the first + // one. + small_object_page_info* page = page_list_; + CHECK(page->free_block_list != nullptr); + + small_object_block_record* const block_record = page->free_block_list; + if (block_record->free_blocks_cnt > 1) { + small_object_block_record* next_free = + reinterpret_cast( + reinterpret_cast(block_record) + block_size_); + next_free->next = block_record->next; + next_free->free_blocks_cnt = block_record->free_blocks_cnt - 1; + page->free_block_list = next_free; + } else { + page->free_block_list = block_record->next; + } + + if (page->free_blocks_cnt == blocks_per_page_) { + free_pages_cnt_--; + } + + page->free_blocks_cnt--; + + memset(block_record, 0, block_size_); + + if (page->free_blocks_cnt == 0) { + // De-manage fully allocated pages. These pages will be managed again if + // a block is freed. + remove_from_page_list(page); + } + + return block_record; +} + +void BionicSmallObjectAllocator::free_page(small_object_page_info* page) { + CHECK(page->free_blocks_cnt == blocks_per_page_); + if (page->prev_page) { + page->prev_page->next_page = page->next_page; + } + if (page->next_page) { + page->next_page->prev_page = page->prev_page; + } + if (page_list_ == page) { + page_list_ = page->next_page; + } + munmap(page, PAGE_SIZE); + free_pages_cnt_--; +} + +void BionicSmallObjectAllocator::free(void* ptr) { + small_object_page_info* const page = + reinterpret_cast( + PAGE_START(reinterpret_cast(ptr))); + + if (reinterpret_cast(ptr) % block_size_ != 0) { + async_safe_fatal("invalid pointer: %p (block_size=%zd)", ptr, block_size_); + } + + memset(ptr, 0, block_size_); + small_object_block_record* const block_record = + reinterpret_cast(ptr); + + block_record->next = page->free_block_list; + block_record->free_blocks_cnt = 1; + + page->free_block_list = block_record; + page->free_blocks_cnt++; + + if (page->free_blocks_cnt == blocks_per_page_) { + if (++free_pages_cnt_ > 1) { + // if we already have a free page - unmap this one. + free_page(page); + } + } else if (page->free_blocks_cnt == 1) { + // We just freed from a full page. Add this page back to the list. + add_to_page_list(page); + } +} + +void BionicSmallObjectAllocator::alloc_page() { + void* const map_ptr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_ptr == MAP_FAILED) { + async_safe_fatal("mmap failed: %s", strerror(errno)); + } + + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, PAGE_SIZE, + "bionic_alloc_small_objects"); + + small_object_page_info* const page = + reinterpret_cast(map_ptr); + memcpy(page->info.signature, kSignature, sizeof(kSignature)); + page->info.type = type_; + page->info.allocator_addr = this; + + page->free_blocks_cnt = blocks_per_page_; + + // Align the first block to block_size_. + const uintptr_t first_block_addr = + __BIONIC_ALIGN(reinterpret_cast(page + 1), block_size_); + small_object_block_record* const first_block = + reinterpret_cast(first_block_addr); + + first_block->next = nullptr; + first_block->free_blocks_cnt = blocks_per_page_; + + page->free_block_list = first_block; + + add_to_page_list(page); + + free_pages_cnt_++; +} + +void BionicSmallObjectAllocator::add_to_page_list(small_object_page_info* page) { + page->next_page = page_list_; + page->prev_page = nullptr; + if (page_list_) { + page_list_->prev_page = page; + } + page_list_ = page; +} + +void BionicSmallObjectAllocator::remove_from_page_list( + small_object_page_info* page) { + if (page->prev_page) { + page->prev_page->next_page = page->next_page; + } + if (page->next_page) { + page->next_page->prev_page = page->prev_page; + } + if (page_list_ == page) { + page_list_ = page->next_page; + } + page->prev_page = nullptr; + page->next_page = nullptr; +} + +void BionicAllocator::initialize_allocators() { + if (allocators_ != nullptr) { + return; + } + + BionicSmallObjectAllocator* allocators = + reinterpret_cast(allocators_buf_); + + for (size_t i = 0; i < kSmallObjectAllocatorsCount; ++i) { + uint32_t type = i + kSmallObjectMinSizeLog2; + new (allocators + i) BionicSmallObjectAllocator(type, 1 << type); + } + + allocators_ = allocators; +} + +void* BionicAllocator::alloc_mmap(size_t align, size_t size) { + size_t header_size = __BIONIC_ALIGN(kPageInfoSize, align); + size_t allocated_size; + if (__builtin_add_overflow(header_size, size, &allocated_size) || + PAGE_END(allocated_size) < allocated_size) { + async_safe_fatal("overflow trying to alloc %zu bytes", size); + } + allocated_size = PAGE_END(allocated_size); + void* map_ptr = mmap(nullptr, allocated_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, + -1, 0); + + if (map_ptr == MAP_FAILED) { + async_safe_fatal("mmap failed: %s", strerror(errno)); + } + + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, allocated_size, "bionic_alloc_lob"); + + void* result = static_cast(map_ptr) + header_size; + page_info* info = get_page_info_unchecked(result); + memcpy(info->signature, kSignature, sizeof(kSignature)); + info->type = kLargeObject; + info->allocated_size = allocated_size; + + return result; +} + + +inline void* BionicAllocator::alloc_impl(size_t align, size_t size) { + if (size > kSmallObjectMaxSize) { + return alloc_mmap(align, size); + } + + uint16_t log2_size = log2(size); + + if (log2_size < kSmallObjectMinSizeLog2) { + log2_size = kSmallObjectMinSizeLog2; + } + + return get_small_object_allocator(log2_size)->alloc(); +} + +void* BionicAllocator::alloc(size_t size) { + // treat alloc(0) as alloc(1) + if (size == 0) { + size = 1; + } + return alloc_impl(16, size); +} + +void* BionicAllocator::memalign(size_t align, size_t size) { + // The Bionic allocator only supports alignment up to one page, which is good + // enough for ELF TLS. + align = MIN(align, PAGE_SIZE); + align = MAX(align, 16); + if (!powerof2(align)) { + align = BIONIC_ROUND_UP_POWER_OF_2(align); + } + size = MAX(size, align); + return alloc_impl(align, size); +} + +inline page_info* BionicAllocator::get_page_info_unchecked(void* ptr) { + uintptr_t header_page = PAGE_START(reinterpret_cast(ptr) - kPageInfoSize); + return reinterpret_cast(header_page); +} + +inline page_info* BionicAllocator::get_page_info(void* ptr) { + page_info* info = get_page_info_unchecked(ptr); + if (memcmp(info->signature, kSignature, sizeof(kSignature)) != 0) { + async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr); + } + + return info; +} + +void* BionicAllocator::realloc(void* ptr, size_t size) { + if (ptr == nullptr) { + return alloc(size); + } + + if (size == 0) { + free(ptr); + return nullptr; + } + + page_info* info = get_page_info(ptr); + + size_t old_size = 0; + + if (info->type == kLargeObject) { + old_size = info->allocated_size - (static_cast(ptr) - reinterpret_cast(info)); + } else { + BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type); + if (allocator != info->allocator_addr) { + async_safe_fatal("invalid pointer %p (page signature mismatch)", ptr); + } + + old_size = allocator->get_block_size(); + } + + if (old_size < size) { + void *result = alloc(size); + memcpy(result, ptr, old_size); + free(ptr); + return result; + } + + return ptr; +} + +void BionicAllocator::free(void* ptr) { + if (ptr == nullptr) { + return; + } + + page_info* info = get_page_info(ptr); + + if (info->type == kLargeObject) { + munmap(info, info->allocated_size); + } else { + BionicSmallObjectAllocator* allocator = get_small_object_allocator(info->type); + if (allocator != info->allocator_addr) { + async_safe_fatal("invalid pointer %p (invalid allocator address for the page)", ptr); + } + + allocator->free(ptr); + } +} + +BionicSmallObjectAllocator* BionicAllocator::get_small_object_allocator(uint32_t type) { + if (type < kSmallObjectMinSizeLog2 || type > kSmallObjectMaxSizeLog2) { + async_safe_fatal("invalid type: %u", type); + } + + initialize_allocators(); + return &allocators_[type - kSmallObjectMinSizeLog2]; +} diff --git a/aosp/bionic/libc/bionic/bionic_arc4random.cpp b/aosp/bionic/libc/bionic/bionic_arc4random.cpp new file mode 100644 index 000000000..74ac43cb2 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_arc4random.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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_arc4random.h" + +#include +#include +#include +#include + +#include + +void __libc_safe_arc4random_buf(void* buf, size_t n) { + // Only call arc4random_buf once we have `/dev/urandom` because getentropy(3) + // will fall back to using `/dev/urandom` if getrandom(2) fails, and abort if + // if can't use `/dev/urandom`. + static bool have_urandom = access("/dev/urandom", R_OK) == 0; + if (have_urandom) { + arc4random_buf(buf, n); + return; + } + + static size_t at_random_bytes_consumed = 0; + if (at_random_bytes_consumed + n > 16) { + async_safe_fatal("ran out of AT_RANDOM bytes, have %zu, requested %zu", + 16 - at_random_bytes_consumed, n); + } + + memcpy(buf, reinterpret_cast(getauxval(AT_RANDOM)) + at_random_bytes_consumed, n); + at_random_bytes_consumed += n; + return; +} diff --git a/aosp/bionic/libc/bionic/bionic_call_ifunc_resolver.cpp b/aosp/bionic/libc/bionic/bionic_call_ifunc_resolver.cpp new file mode 100644 index 000000000..437de78ce --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_call_ifunc_resolver.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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_call_ifunc_resolver.h" +#include +#include + +#include "private/bionic_auxv.h" + +// This code is called in the linker before it has been relocated, so minimize calls into other +// parts of Bionic. In particular, we won't ever have two ifunc resolvers called concurrently, so +// initializing the ifunc resolver argument doesn't need to be thread-safe. + +ElfW(Addr) __bionic_call_ifunc_resolver(ElfW(Addr) resolver_addr) { +#if defined(__aarch64__) + typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, __ifunc_arg_t*); + static __ifunc_arg_t arg; + static bool initialized = false; + if (!initialized) { + initialized = true; + arg._size = sizeof(__ifunc_arg_t); + arg._hwcap = getauxval(AT_HWCAP); + arg._hwcap2 = getauxval(AT_HWCAP2); + } + return reinterpret_cast(resolver_addr)(arg._hwcap | _IFUNC_ARG_HWCAP, &arg); +#elif defined(__arm__) + typedef ElfW(Addr) (*ifunc_resolver_t)(unsigned long); + static unsigned long hwcap; + static bool initialized = false; + if (!initialized) { + initialized = true; + hwcap = getauxval(AT_HWCAP); + } + return reinterpret_cast(resolver_addr)(hwcap); +#else + typedef ElfW(Addr) (*ifunc_resolver_t)(void); + return reinterpret_cast(resolver_addr)(); +#endif +} diff --git a/aosp/bionic/libc/bionic/bionic_elf_tls.cpp b/aosp/bionic/libc/bionic/bionic_elf_tls.cpp new file mode 100644 index 000000000..61d826c02 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_elf_tls.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2019 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_elf_tls.h" + +#include +#include +#include +#include + +#include "private/ScopedRWLock.h" +#include "private/ScopedSignalBlocker.h" +#include "private/bionic_globals.h" +#include "platform/bionic/macros.h" +#include "private/bionic_tls.h" +#include "pthread_internal.h" + +// Every call to __tls_get_addr needs to check the generation counter, so +// accesses to the counter need to be as fast as possible. Keep a copy of it in +// a hidden variable, which can be accessed without using the GOT. The linker +// will update this variable when it updates its counter. +// +// To allow the linker to update this variable, libc.so's constructor passes its +// address to the linker. To accommodate a possible __tls_get_addr call before +// libc.so's constructor, this local copy is initialized to SIZE_MAX, forcing +// __tls_get_addr to initially use the slow path. +__LIBC_HIDDEN__ _Atomic(size_t) __libc_tls_generation_copy = SIZE_MAX; + +// Search for a TLS segment in the given phdr table. Returns true if it has a +// TLS segment and false otherwise. +bool __bionic_get_tls_segment(const ElfW(Phdr)* phdr_table, size_t phdr_count, + ElfW(Addr) load_bias, TlsSegment* out) { + for (size_t i = 0; i < phdr_count; ++i) { + const ElfW(Phdr)& phdr = phdr_table[i]; + if (phdr.p_type == PT_TLS) { + *out = TlsSegment { + phdr.p_memsz, + phdr.p_align, + reinterpret_cast(load_bias + phdr.p_vaddr), + phdr.p_filesz, + }; + return true; + } + } + return false; +} + +// Return true if the alignment of a TLS segment is a valid power-of-two. Also +// cap the alignment if it's too high. +bool __bionic_check_tls_alignment(size_t* alignment) { + // N.B. The size does not need to be a multiple of the alignment. With + // ld.bfd (or after using binutils' strip), the TLS segment's size isn't + // rounded up. + if (*alignment == 0 || !powerof2(*alignment)) { + return false; + } + // Bionic only respects TLS alignment up to one page. + *alignment = MIN(*alignment, PAGE_SIZE); + return true; +} + +size_t StaticTlsLayout::offset_thread_pointer() const { + return offset_bionic_tcb_ + (-MIN_TLS_SLOT * sizeof(void*)); +} + +// Reserves space for the Bionic TCB and the executable's TLS segment. Returns +// the offset of the executable's TLS segment. +size_t StaticTlsLayout::reserve_exe_segment_and_tcb(const TlsSegment* exe_segment, + const char* progname __attribute__((unused))) { + // Special case: if the executable has no TLS segment, then just allocate a + // TCB and skip the minimum alignment check on ARM. + if (exe_segment == nullptr) { + offset_bionic_tcb_ = reserve_type(); + return 0; + } + +#if defined(__arm__) || defined(__aarch64__) + + // First reserve enough space for the TCB before the executable segment. + reserve(sizeof(bionic_tcb), 1); + + // Then reserve the segment itself. + const size_t result = reserve(exe_segment->size, exe_segment->alignment); + + // The variant 1 ABI that ARM linkers follow specifies a 2-word TCB between + // the thread pointer and the start of the executable's TLS segment, but both + // the thread pointer and the TLS segment are aligned appropriately for the + // TLS segment. Calculate the distance between the thread pointer and the + // EXE's segment. + const size_t exe_tpoff = __BIONIC_ALIGN(sizeof(void*) * 2, exe_segment->alignment); + + const size_t min_bionic_alignment = BIONIC_ROUND_UP_POWER_OF_2(MAX_TLS_SLOT) * sizeof(void*); + if (exe_tpoff < min_bionic_alignment) { + async_safe_fatal("error: \"%s\": executable's TLS segment is underaligned: " + "alignment is %zu, needs to be at least %zu for %s Bionic", + progname, exe_segment->alignment, min_bionic_alignment, + (sizeof(void*) == 4 ? "ARM" : "ARM64")); + } + + offset_bionic_tcb_ = result - exe_tpoff - (-MIN_TLS_SLOT * sizeof(void*)); + return result; + +#elif defined(__i386__) || defined(__x86_64__) + + // x86 uses variant 2 TLS layout. The executable's segment is located just + // before the TCB. + static_assert(MIN_TLS_SLOT == 0, "First slot of bionic_tcb must be slot #0 on x86"); + const size_t exe_size = round_up_with_overflow_check(exe_segment->size, exe_segment->alignment); + reserve(exe_size, 1); + const size_t max_align = MAX(alignof(bionic_tcb), exe_segment->alignment); + offset_bionic_tcb_ = reserve(sizeof(bionic_tcb), max_align); + return offset_bionic_tcb_ - exe_size; + +#else +#error "Unrecognized architecture" +#endif +} + +void StaticTlsLayout::reserve_bionic_tls() { + offset_bionic_tls_ = reserve_type(); +} + +void StaticTlsLayout::finish_layout() { + // Round the offset up to the alignment. + offset_ = round_up_with_overflow_check(offset_, alignment_); + + if (overflowed_) { + async_safe_fatal("error: TLS segments in static TLS overflowed"); + } +} + +// The size is not required to be a multiple of the alignment. The alignment +// must be a positive power-of-two. +size_t StaticTlsLayout::reserve(size_t size, size_t alignment) { + offset_ = round_up_with_overflow_check(offset_, alignment); + const size_t result = offset_; + if (__builtin_add_overflow(offset_, size, &offset_)) overflowed_ = true; + alignment_ = MAX(alignment_, alignment); + return result; +} + +size_t StaticTlsLayout::round_up_with_overflow_check(size_t value, size_t alignment) { + const size_t old_value = value; + value = __BIONIC_ALIGN(value, alignment); + if (value < old_value) overflowed_ = true; + return value; +} + +// Copy each TLS module's initialization image into a newly-allocated block of +// static TLS memory. To reduce dirty pages, this function only writes to pages +// within the static TLS that need initialization. The memory should already be +// zero-initialized on entry. +void __init_static_tls(void* static_tls) { + // The part of the table we care about (i.e. static TLS modules) never changes + // after startup, but we still need the mutex because the table could grow, + // moving the initial part. If this locking is too slow, we can duplicate the + // static part of the table. + TlsModules& modules = __libc_shared_globals()->tls_modules; + ScopedSignalBlocker ssb; + ScopedReadLock locker(&modules.rwlock); + + for (size_t i = 0; i < modules.module_count; ++i) { + TlsModule& module = modules.module_table[i]; + if (module.static_offset == SIZE_MAX) { + // All of the static modules come before all of the dynamic modules, so + // once we see the first dynamic module, we're done. + break; + } + if (module.segment.init_size == 0) { + // Skip the memcpy call for TLS segments with no initializer, which is + // common. + continue; + } + memcpy(static_cast(static_tls) + module.static_offset, + module.segment.init_ptr, + module.segment.init_size); + } +} + +static inline size_t dtv_size_in_bytes(size_t module_count) { + return sizeof(TlsDtv) + module_count * sizeof(void*); +} + +// Calculates the number of module slots to allocate in a new DTV. For small +// objects (up to 1KiB), the TLS allocator allocates memory in power-of-2 sizes, +// so for better space usage, ensure that the DTV size (header + slots) is a +// power of 2. +// +// The lock on TlsModules must be held. +static size_t calculate_new_dtv_count() { + size_t loaded_cnt = __libc_shared_globals()->tls_modules.module_count; + size_t bytes = dtv_size_in_bytes(MAX(1, loaded_cnt)); + if (!powerof2(bytes)) { + bytes = BIONIC_ROUND_UP_POWER_OF_2(bytes); + } + return (bytes - sizeof(TlsDtv)) / sizeof(void*); +} + +// This function must be called with signals blocked and a write lock on +// TlsModules held. +static void update_tls_dtv(bionic_tcb* tcb) { + const TlsModules& modules = __libc_shared_globals()->tls_modules; + BionicAllocator& allocator = __libc_shared_globals()->tls_allocator; + + // Use the generation counter from the shared globals instead of the local + // copy, which won't be initialized yet if __tls_get_addr is called before + // libc.so's constructor. + if (__get_tcb_dtv(tcb)->generation == atomic_load(&modules.generation)) { + return; + } + + const size_t old_cnt = __get_tcb_dtv(tcb)->count; + + // If the DTV isn't large enough, allocate a larger one. Because a signal + // handler could interrupt the fast path of __tls_get_addr, we don't free the + // old DTV. Instead, we add the old DTV to a list, then free all of a thread's + // DTVs at thread-exit. Each time the DTV is reallocated, its size at least + // doubles. + if (modules.module_count > old_cnt) { + size_t new_cnt = calculate_new_dtv_count(); + TlsDtv* const old_dtv = __get_tcb_dtv(tcb); + TlsDtv* const new_dtv = static_cast(allocator.alloc(dtv_size_in_bytes(new_cnt))); + memcpy(new_dtv, old_dtv, dtv_size_in_bytes(old_cnt)); + new_dtv->count = new_cnt; + new_dtv->next = old_dtv; + __set_tcb_dtv(tcb, new_dtv); + } + + TlsDtv* const dtv = __get_tcb_dtv(tcb); + + const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + char* static_tls = reinterpret_cast(tcb) - layout.offset_bionic_tcb(); + + // Initialize static TLS modules and free unloaded modules. + for (size_t i = 0; i < dtv->count; ++i) { + if (i < modules.module_count) { + const TlsModule& mod = modules.module_table[i]; + if (mod.static_offset != SIZE_MAX) { + dtv->modules[i] = static_tls + mod.static_offset; + continue; + } + if (mod.first_generation != kTlsGenerationNone && + mod.first_generation <= dtv->generation) { + continue; + } + } + allocator.free(dtv->modules[i]); + dtv->modules[i] = nullptr; + } + + dtv->generation = atomic_load(&modules.generation); +} + +__attribute__((noinline)) static void* tls_get_addr_slow_path(const TlsIndex* ti) { + TlsModules& modules = __libc_shared_globals()->tls_modules; + bionic_tcb* tcb = __get_bionic_tcb(); + + // Block signals and lock TlsModules. We may need the allocator, so take + // a write lock. + ScopedSignalBlocker ssb; + ScopedWriteLock locker(&modules.rwlock); + + update_tls_dtv(tcb); + + TlsDtv* dtv = __get_tcb_dtv(tcb); + const size_t module_idx = __tls_module_id_to_idx(ti->module_id); + void* mod_ptr = dtv->modules[module_idx]; + if (mod_ptr == nullptr) { + const TlsSegment& segment = modules.module_table[module_idx].segment; + mod_ptr = __libc_shared_globals()->tls_allocator.memalign(segment.alignment, segment.size); + if (segment.init_size > 0) { + memcpy(mod_ptr, segment.init_ptr, segment.init_size); + } + dtv->modules[module_idx] = mod_ptr; + } + + return static_cast(mod_ptr) + ti->offset; +} + +// Returns the address of a thread's TLS memory given a module ID and an offset +// into that module's TLS segment. This function is called on every access to a +// dynamic TLS variable on targets that don't use TLSDESC. arm64 uses TLSDESC, +// so it only calls this function on a thread's first access to a module's TLS +// segment. +// +// On most targets, this accessor function is __tls_get_addr and +// TLS_GET_ADDR_CCONV is unset. 32-bit x86 uses ___tls_get_addr instead and a +// regparm() calling convention. +extern "C" void* TLS_GET_ADDR(const TlsIndex* ti) TLS_GET_ADDR_CCONV { + TlsDtv* dtv = __get_tcb_dtv(__get_bionic_tcb()); + + // TODO: See if we can use a relaxed memory ordering here instead. + size_t generation = atomic_load(&__libc_tls_generation_copy); + if (__predict_true(generation == dtv->generation)) { + void* mod_ptr = dtv->modules[__tls_module_id_to_idx(ti->module_id)]; + if (__predict_true(mod_ptr != nullptr)) { + return static_cast(mod_ptr) + ti->offset; + } + } + + return tls_get_addr_slow_path(ti); +} + +// This function frees: +// - TLS modules referenced by the current DTV. +// - The list of DTV objects associated with the current thread. +// +// The caller must have already blocked signals. +void __free_dynamic_tls(bionic_tcb* tcb) { + TlsModules& modules = __libc_shared_globals()->tls_modules; + BionicAllocator& allocator = __libc_shared_globals()->tls_allocator; + + // If we didn't allocate any dynamic memory, skip out early without taking + // the lock. + TlsDtv* dtv = __get_tcb_dtv(tcb); + if (dtv->generation == kTlsGenerationNone) { + return; + } + + // We need the write lock to use the allocator. + ScopedWriteLock locker(&modules.rwlock); + + // First free everything in the current DTV. + for (size_t i = 0; i < dtv->count; ++i) { + if (i < modules.module_count && modules.module_table[i].static_offset != SIZE_MAX) { + // This module's TLS memory is allocated statically, so don't free it here. + continue; + } + allocator.free(dtv->modules[i]); + } + + // Now free the thread's list of DTVs. + while (dtv->generation != kTlsGenerationNone) { + TlsDtv* next = dtv->next; + allocator.free(dtv); + dtv = next; + } + + // Clear the DTV slot. The DTV must not be used again with this thread. + tcb->tls_slot(TLS_SLOT_DTV) = nullptr; +} diff --git a/aosp/bionic/libc/bionic/bionic_futex.cpp b/aosp/bionic/libc/bionic/bionic_futex.cpp new file mode 100644 index 000000000..0ac1f6ea6 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_futex.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 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_futex.h" + +#include + +#include "private/bionic_time_conversions.h" + +static inline __always_inline int FutexWithTimeout(volatile void* ftx, int op, int value, + bool use_realtime_clock, + const timespec* abs_timeout, int bitset) { + const timespec* futex_abs_timeout = abs_timeout; + // pthread's and semaphore's default behavior is to use CLOCK_REALTIME, however this behavior is + // essentially never intended, as that clock is prone to change discontinuously. + // + // What users really intend is to use CLOCK_MONOTONIC, however only pthread_cond_timedwait() + // provides this as an option and even there, a large amount of existing code does not opt into + // CLOCK_MONOTONIC. + // + // We have seen numerous bugs directly attributable to this difference. Therefore, we provide + // this general workaround to always use CLOCK_MONOTONIC for waiting, regardless of what the input + // timespec is. + timespec converted_monotonic_abs_timeout; + if (abs_timeout && use_realtime_clock) { + monotonic_time_from_realtime_time(converted_monotonic_abs_timeout, *abs_timeout); + if (converted_monotonic_abs_timeout.tv_sec < 0) { + return -ETIMEDOUT; + } + futex_abs_timeout = &converted_monotonic_abs_timeout; + } + + return __futex(ftx, op, value, futex_abs_timeout, bitset); +} + +int __futex_wait_ex(volatile void* ftx, bool shared, int value, bool use_realtime_clock, + const timespec* abs_timeout) { + return FutexWithTimeout(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE), value, + use_realtime_clock, abs_timeout, FUTEX_BITSET_MATCH_ANY); +} + +int __futex_pi_lock_ex(volatile void* ftx, bool shared, bool use_realtime_clock, + const timespec* abs_timeout) { + return FutexWithTimeout(ftx, (shared ? FUTEX_LOCK_PI : FUTEX_LOCK_PI_PRIVATE), 0, + use_realtime_clock, abs_timeout, 0); +} diff --git a/aosp/bionic/libc/bionic/bionic_netlink.cpp b/aosp/bionic/libc/bionic/bionic_netlink.cpp new file mode 100644 index 000000000..5d5a02624 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_netlink.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 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 "bionic_netlink.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "private/ErrnoRestorer.h" + +NetlinkConnection::NetlinkConnection() { + // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE), + // but that's a bit too large to go on the stack. + size_ = 8192; + data_ = new char[size_]; +} + +NetlinkConnection::~NetlinkConnection() { + delete[] data_; +} + +bool NetlinkConnection::SendRequest(int type) { + // Rather than force all callers to check for the unlikely event of being + // unable to allocate 8KiB, check here. + if (data_ == nullptr) return false; + + // Did we open a netlink socket yet? + if (fd_.get() == -1) { + fd_.reset(socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)); + if (fd_.get() == -1) return false; + } + + // Construct and send the message. + struct NetlinkMessage { + nlmsghdr hdr; + rtgenmsg msg; + } request; + memset(&request, 0, sizeof(request)); + request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + request.hdr.nlmsg_type = type; + request.hdr.nlmsg_len = sizeof(request); + request.msg.rtgen_family = AF_UNSPEC; // All families. + return (TEMP_FAILURE_RETRY(send(fd_.get(), &request, sizeof(request), 0)) == sizeof(request)); +} + +bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* context) { + // Read through all the responses, handing interesting ones to the callback. + ssize_t bytes_read; + while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_.get(), data_, size_, 0))) > 0) { + nlmsghdr* hdr = reinterpret_cast(data_); + for (; NLMSG_OK(hdr, static_cast(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) { + if (hdr->nlmsg_type == NLMSG_DONE) return true; + if (hdr->nlmsg_type == NLMSG_ERROR) { + nlmsgerr* err = reinterpret_cast(NLMSG_DATA(hdr)); + errno = (hdr->nlmsg_len >= NLMSG_LENGTH(sizeof(nlmsgerr))) ? -err->error : EIO; + return false; + } + callback(context, hdr); + } + } + + // We only get here if recv fails before we see a NLMSG_DONE. + return false; +} diff --git a/aosp/bionic/libc/bionic/bionic_netlink.h b/aosp/bionic/libc/bionic/bionic_netlink.h new file mode 100644 index 000000000..fc1bd0fb0 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_netlink.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include + +#include +#include + +#include "private/ScopedFd.h" + +struct nlmsghdr; + +class NetlinkConnection { + public: + NetlinkConnection(); + ~NetlinkConnection(); + + bool SendRequest(int type); + bool ReadResponses(void callback(void*, nlmsghdr*), void* context); + + private: + ScopedFd fd_; + char* data_; + size_t size_; +}; diff --git a/aosp/bionic/libc/bionic/bionic_systrace.cpp b/aosp/bionic/libc/bionic/bionic_systrace.cpp new file mode 100644 index 000000000..fd9771298 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_systrace.cpp @@ -0,0 +1,105 @@ +/* + * 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 +#include +#include +#include +#include + +#include "private/bionic_lock.h" +#include "private/bionic_systrace.h" +#include "private/CachedProperty.h" + +#include +#include // For ATRACE_TAG_BIONIC. + +#define WRITE_OFFSET 32 + +static Lock g_lock; +static CachedProperty g_debug_atrace_tags_enableflags("debug.atrace.tags.enableflags"); +static uint64_t g_tags; +static int g_trace_marker_fd = -1; + +static bool should_trace() { + g_lock.lock(); + if (g_debug_atrace_tags_enableflags.DidChange()) { + g_tags = strtoull(g_debug_atrace_tags_enableflags.Get(), nullptr, 0); + } + g_lock.unlock(); + return ((g_tags & ATRACE_TAG_BIONIC) != 0); +} + +static int get_trace_marker_fd() { + g_lock.lock(); + if (g_trace_marker_fd == -1) { + g_trace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_CLOEXEC | O_WRONLY); + if (g_trace_marker_fd == -1) { + g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY); + } + } + g_lock.unlock(); + return g_trace_marker_fd; +} + +void bionic_trace_begin(const char* message) { + if (!should_trace()) { + return; + } + + int trace_marker_fd = get_trace_marker_fd(); + if (trace_marker_fd == -1) { + return; + } + + // If bionic tracing has been enabled, then write the message to the + // kernel trace_marker. + int length = strlen(message); + char buf[length + WRITE_OFFSET]; + size_t len = async_safe_format_buffer(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message); + + // Tracing may stop just after checking property and before writing the message. + // So the write is acceptable to fail. See b/20666100. + TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len)); +} + +void bionic_trace_end() { + if (!should_trace()) { + return; + } + + int trace_marker_fd = get_trace_marker_fd(); + if (trace_marker_fd == -1) { + return; + } + + TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2)); +} + +ScopedTrace::ScopedTrace(const char* message) : called_end_(false) { + bionic_trace_begin(message); +} + +ScopedTrace::~ScopedTrace() { + End(); +} + +void ScopedTrace::End() { + if (!called_end_) { + bionic_trace_end(); + called_end_ = true; + } +} diff --git a/aosp/bionic/libc/bionic/bionic_time_conversions.cpp b/aosp/bionic/libc/bionic/bionic_time_conversions.cpp new file mode 100644 index 000000000..d21e12eb8 --- /dev/null +++ b/aosp/bionic/libc/bionic/bionic_time_conversions.cpp @@ -0,0 +1,74 @@ +/* + * 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_time_conversions.h" + +#include "private/bionic_constants.h" + +bool timespec_from_timeval(timespec& ts, const timeval& tv) { + // Whole seconds can just be copied. + ts.tv_sec = tv.tv_sec; + + // But we might overflow when converting microseconds to nanoseconds. + if (tv.tv_usec >= 1000000 || tv.tv_usec < 0) { + return false; + } + ts.tv_nsec = tv.tv_usec * 1000; + return true; +} + +void timespec_from_ms(timespec& ts, const int ms) { + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; +} + +void timeval_from_timespec(timeval& tv, const timespec& ts) { + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +} + +void monotonic_time_from_realtime_time(timespec& monotonic_time, const timespec& realtime_time) { + monotonic_time = realtime_time; + + timespec cur_monotonic_time; + clock_gettime(CLOCK_MONOTONIC, &cur_monotonic_time); + timespec cur_realtime_time; + clock_gettime(CLOCK_REALTIME, &cur_realtime_time); + + monotonic_time.tv_nsec -= cur_realtime_time.tv_nsec; + monotonic_time.tv_nsec += cur_monotonic_time.tv_nsec; + if (monotonic_time.tv_nsec >= NS_PER_S) { + monotonic_time.tv_nsec -= NS_PER_S; + monotonic_time.tv_sec += 1; + } else if (monotonic_time.tv_nsec < 0) { + monotonic_time.tv_nsec += NS_PER_S; + monotonic_time.tv_sec -= 1; + } + monotonic_time.tv_sec -= cur_realtime_time.tv_sec; + monotonic_time.tv_sec += cur_monotonic_time.tv_sec; +} diff --git a/aosp/bionic/libc/bionic/brk.cpp b/aosp/bionic/libc/bionic/brk.cpp new file mode 100644 index 000000000..566c33a7a --- /dev/null +++ b/aosp/bionic/libc/bionic/brk.cpp @@ -0,0 +1,76 @@ +/* + * 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 +#include + +#if defined(__LP64__) +static void* __bionic_brk; +#else +void* __bionic_brk; // Accidentally exported by the NDK. +#endif + +extern "C" void* __brk(void* __addr); + +int brk(void* end_data) { + __bionic_brk = __brk(end_data); + if (__bionic_brk < end_data) { + errno = ENOMEM; + return -1; + } + return 0; +} + +void* sbrk(ptrdiff_t increment) { + // Initialize __bionic_brk if necessary. + if (__bionic_brk == nullptr) { + __bionic_brk = __brk(nullptr); + } + + // Don't ask the kernel if we already know the answer. + if (increment == 0) { + return __bionic_brk; + } + + // Avoid overflow. + uintptr_t old_brk = reinterpret_cast(__bionic_brk); + if ((increment > 0 && static_cast(increment) > (UINTPTR_MAX - old_brk)) || + (increment < 0 && static_cast(-increment) > old_brk)) { + errno = ENOMEM; + return reinterpret_cast(-1); + } + + void* desired_brk = reinterpret_cast(old_brk + increment); + __bionic_brk = __brk(desired_brk); + if (__bionic_brk < desired_brk) { + errno = ENOMEM; + return reinterpret_cast(-1); + } + + return reinterpret_cast(old_brk); +} diff --git a/aosp/bionic/libc/bionic/c16rtomb.cpp b/aosp/bionic/libc/bionic/c16rtomb.cpp new file mode 100644 index 000000000..2d6ae938c --- /dev/null +++ b/aosp/bionic/libc/bionic/c16rtomb.cpp @@ -0,0 +1,67 @@ +/* + * 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 +#include +#include + +#include "private/bionic_mbstate.h" + +static inline constexpr bool is_high_surrogate(char16_t c16) { + return c16 >= 0xd800 && c16 < 0xdc00; +} + +static inline constexpr bool is_low_surrogate(char16_t c16) { + return c16 >= 0xdc00 && c16 < 0xe000; +} + +size_t c16rtomb(char* s, char16_t c16, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + if (mbsinit(state)) { + if (is_high_surrogate(c16)) { + char32_t c32 = (c16 & ~0xd800) << 10; + mbstate_set_byte(state, 3, (c32 & 0xff0000) >> 16); + mbstate_set_byte(state, 2, (c32 & 0x00ff00) >> 8); + return 0; + } else if (is_low_surrogate(c16)) { + return mbstate_reset_and_return_illegal(EINVAL, state); + } else { + return c32rtomb(s, static_cast(c16), state); + } + } else { + if (!is_low_surrogate(c16)) { + return mbstate_reset_and_return_illegal(EINVAL, state); + } + + char32_t c32 = ((mbstate_get_byte(state, 3) << 16) | + (mbstate_get_byte(state, 2) << 8) | + (c16 & ~0xdc00)) + 0x10000; + return mbstate_reset_and_return(c32rtomb(s, c32, nullptr), state); + } +} diff --git a/aosp/bionic/libc/bionic/c32rtomb.cpp b/aosp/bionic/libc/bionic/c32rtomb.cpp new file mode 100644 index 000000000..2909d8b36 --- /dev/null +++ b/aosp/bionic/libc/bionic/c32rtomb.cpp @@ -0,0 +1,97 @@ +/* + * 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 +#include +#include + +#include "private/bionic_mbstate.h" + +size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + if (s == nullptr) { + // Equivalent to c32rtomb(buf, U'\0', ps). + return mbstate_reset_and_return(1, state); + } + + // POSIX states that if char32_t is a null wide character, a null byte shall + // be stored, preceded by any shift sequence needed to restore the initial + // shift state. Since shift states are not supported, only the null byte is + // stored. + if (c32 == U'\0') { + *s = '\0'; + return mbstate_reset_and_return(1, state); + } + + if (!mbsinit(state)) { + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + + if ((c32 & ~0x7f) == 0) { + // Fast path for plain ASCII characters. + *s = c32; + return 1; + } + + // Determine the number of octets needed to represent this character. + // We always output the shortest sequence possible. Also specify the + // first few bits of the first octet, which contains the information + // about the sequence length. + uint8_t lead; + size_t length; + if ((c32 & ~0x7f) == 0) { + lead = 0; + length = 1; + } else if ((c32 & ~0x7ff) == 0) { + lead = 0xc0; + length = 2; + } else if ((c32 & ~0xffff) == 0) { + lead = 0xe0; + length = 3; + } else if ((c32 & ~0x1fffff) == 0) { + lead = 0xf0; + length = 4; + } else { + errno = EILSEQ; + return __MB_ERR_ILLEGAL_SEQUENCE; + } + + // Output the octets representing the character in chunks + // of 6 bits, least significant last. The first octet is + // a special case because it contains the sequence length + // information. + for (size_t i = length - 1; i > 0; i--) { + s[i] = (c32 & 0x3f) | 0x80; + c32 >>= 6; + } + *s = (c32 & 0xff) | lead; + + return length; +} diff --git a/aosp/bionic/libc/bionic/chmod.cpp b/aosp/bionic/libc/bionic/chmod.cpp new file mode 100644 index 000000000..d988f48ed --- /dev/null +++ b/aosp/bionic/libc/bionic/chmod.cpp @@ -0,0 +1,35 @@ +/* + * 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 +#include +#include + +int chmod(const char* path, mode_t mode) { + return fchmodat(AT_FDCWD, path, mode, 0); +} diff --git a/aosp/bionic/libc/bionic/chown.cpp b/aosp/bionic/libc/bionic/chown.cpp new file mode 100644 index 000000000..dce167369 --- /dev/null +++ b/aosp/bionic/libc/bionic/chown.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include + +int chown(const char* path, uid_t uid, gid_t gid) { + return fchownat(AT_FDCWD, path, uid, gid, 0); +} diff --git a/aosp/bionic/libc/bionic/clearenv.cpp b/aosp/bionic/libc/bionic/clearenv.cpp new file mode 100644 index 000000000..01c9c3975 --- /dev/null +++ b/aosp/bionic/libc/bionic/clearenv.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 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 +#include + +int clearenv() { + char** e = environ; + if (e != nullptr) { + for (; *e; ++e) { + *e = nullptr; + } + } + return 0; +} diff --git a/aosp/bionic/libc/bionic/clock.cpp b/aosp/bionic/libc/bionic/clock.cpp new file mode 100644 index 000000000..fda070842 --- /dev/null +++ b/aosp/bionic/libc/bionic/clock.cpp @@ -0,0 +1,42 @@ +/* + * 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 +#include +#include + +#include "private/bionic_constants.h" + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock.html +clock_t clock() { + timespec ts; + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) { + return -1; + } + return (ts.tv_sec * CLOCKS_PER_SEC) + (ts.tv_nsec / (NS_PER_S / CLOCKS_PER_SEC)); +} diff --git a/aosp/bionic/libc/bionic/clock_getcpuclockid.cpp b/aosp/bionic/libc/bionic/clock_getcpuclockid.cpp new file mode 100644 index 000000000..9ff1845fb --- /dev/null +++ b/aosp/bionic/libc/bionic/clock_getcpuclockid.cpp @@ -0,0 +1,49 @@ +/* + * 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 +#include + +#include "private/ErrnoRestorer.h" + +int clock_getcpuclockid(pid_t pid, clockid_t* clockid) { + ErrnoRestorer errno_restorer; + + // The tid is stored in the top bits, but negated. + clockid_t result = ~static_cast(pid) << 3; + // Bits 0 and 1: clock type (0 = CPUCLOCK_PROF, 1 = CPUCLOCK_VIRT, 2 = CPUCLOCK_SCHED). + result |= 2; + // Bit 2: thread (set) or process (clear). Bit 2 already 0. + + if (clock_getres(result, nullptr) == -1) { + return ESRCH; + } + + *clockid = result; + return 0; +} diff --git a/aosp/bionic/libc/bionic/clock_nanosleep.cpp b/aosp/bionic/libc/bionic/clock_nanosleep.cpp new file mode 100644 index 000000000..6f77d83ff --- /dev/null +++ b/aosp/bionic/libc/bionic/clock_nanosleep.cpp @@ -0,0 +1,40 @@ +/* + * 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 + +#include "private/ErrnoRestorer.h" + +extern "C" int __clock_nanosleep(clockid_t, int, const timespec*, timespec*); + +int clock_nanosleep(clockid_t clock_id, int flags, const timespec* in, timespec* out) { + if (clock_id == CLOCK_THREAD_CPUTIME_ID) return EINVAL; + + ErrnoRestorer errno_restorer; + return (__clock_nanosleep(clock_id, flags, in, out) == 0) ? 0 : errno; +} diff --git a/aosp/bionic/libc/bionic/clone.cpp b/aosp/bionic/libc/bionic/clone.cpp new file mode 100644 index 000000000..622ca265a --- /dev/null +++ b/aosp/bionic/libc/bionic/clone.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 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. + */ + +#define _GNU_SOURCE 1 +#include +#include +#include +#include + +#include "pthread_internal.h" + +#include "private/bionic_defs.h" +#include "platform/bionic/macros.h" + +extern "C" pid_t __bionic_clone(uint32_t flags, void* child_stack, int* parent_tid, void* tls, int* child_tid, int (*fn)(void*), void* arg); +extern "C" __noreturn void __exit(int status); + +// Called from the __bionic_clone assembler to call the thread function then exit. +__attribute__((no_sanitize("hwaddress"))) +extern "C" __LIBC_HIDDEN__ void __start_thread(int (*fn)(void*), void* arg) { + BIONIC_STOP_UNWIND; + + pthread_internal_t* self = __get_thread(); + if (self && self->tid == -1) { + self->tid = syscall(__NR_gettid); + } + + int status = (*fn)(arg); + __exit(status); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int clone(int (*fn)(void*), void* child_stack, int flags, void* arg, ...) { + int* parent_tid = nullptr; + void* new_tls = nullptr; + int* child_tid = nullptr; + + if (fn != nullptr && child_stack == nullptr) { + errno = EINVAL; + return -1; + } + + // Extract any optional parameters required by the flags. + va_list args; + va_start(args, arg); + if ((flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { + parent_tid = va_arg(args, int*); + } + if ((flags & (CLONE_SETTLS|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { + new_tls = va_arg(args, void*); + } + if ((flags & (CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID)) != 0) { + child_tid = va_arg(args, int*); + } + va_end(args); + + // Align 'child_stack' to 16 bytes. + uintptr_t child_stack_addr = reinterpret_cast(child_stack); + child_stack_addr &= ~0xf; + child_stack = reinterpret_cast(child_stack_addr); + + // Remember the parent pid and invalidate the cached value while we clone. + pthread_internal_t* self = __get_thread(); + pid_t parent_pid = self->invalidate_cached_pid(); + + // Remmber the caller's tid so that it can be restored in the parent after clone. + pid_t caller_tid = self->tid; + // Invalidate the tid before the syscall. The value is lazily cached in gettid(), + // and it will be updated by fork() and pthread_create(). We don't do this if + // we are sharing address space with the child. + if (!(flags & (CLONE_VM|CLONE_VFORK))) { + self->tid = -1; + } + + // Actually do the clone. + int clone_result; + if (fn != nullptr) { + clone_result = __bionic_clone(flags, child_stack, parent_tid, new_tls, child_tid, fn, arg); + } else { +#if defined(__x86_64__) // sys_clone's last two arguments are flipped on x86-64. + clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, child_tid, new_tls); +#else + clone_result = syscall(__NR_clone, flags, child_stack, parent_tid, new_tls, child_tid); +#endif + } + + if (clone_result != 0) { + // We're the parent, so put our known pid and tid back in place. + // We leave the child without a cached pid and tid, but: + // 1. pthread_create gives its children their own pthread_internal_t with the correct pid and tid. + // 2. fork uses CLONE_CHILD_SETTID to get the new pid/tid. + // 3. The tid is lazily fetched in gettid(). + // If any other cases become important, we could use a double trampoline like __pthread_start. + self->set_cached_pid(parent_pid); + self->tid = caller_tid; + } else if (self->tid == -1) { + self->tid = syscall(__NR_gettid); + self->set_cached_pid(self->tid); + } + + return clone_result; +} diff --git a/aosp/bionic/libc/bionic/ctype.cpp b/aosp/bionic/libc/bionic/ctype.cpp new file mode 100644 index 000000000..92a4772be --- /dev/null +++ b/aosp/bionic/libc/bionic/ctype.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#define __BIONIC_CTYPE_INLINE /* Out of line. */ +#include + +#include + +int isalnum_l(int c, locale_t) { + return isalnum(c); +} + +int isalpha_l(int c, locale_t) { + return isalpha(c); +} + +int isblank_l(int c, locale_t) { + return isblank(c); +} + +int iscntrl_l(int c, locale_t) { + return iscntrl(c); +} + +int isdigit_l(int c, locale_t) { + return isdigit(c); +} + +int isgraph_l(int c, locale_t) { + return isgraph(c); +} + +int islower_l(int c, locale_t) { + return islower(c); +} + +int isprint_l(int c, locale_t) { + return isprint(c); +} + +int ispunct_l(int c, locale_t) { + return ispunct(c); +} + +int isspace_l(int c, locale_t) { + return isspace(c); +} + +int isupper_l(int c, locale_t) { + return isupper(c); +} + +int isxdigit_l(int c, locale_t) { + return isxdigit(c); +} + +int toupper_l(int c, locale_t) { + return toupper(c); +} + +int tolower_l(int c, locale_t) { + return tolower(c); +} diff --git a/aosp/bionic/libc/bionic/dirent.cpp b/aosp/bionic/libc/bionic/dirent.cpp new file mode 100644 index 000000000..8921ca0dc --- /dev/null +++ b/aosp/bionic/libc/bionic/dirent.cpp @@ -0,0 +1,204 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "private/bionic_fortify.h" +#include "private/ErrnoRestorer.h" +#include "private/ScopedPthreadMutexLocker.h" + +extern "C" int __getdents64(unsigned int, dirent*, unsigned int); + +// Apportable decided to copy the data structure from this file +// and use it in their own code, but they also call into readdir. +// In order to avoid a lockup, the structure must be maintained in +// the exact same order as in L and below. New structure members +// need to be added to the end of this structure. +// See b/21037208 for more details. +struct DIR { + int fd_; + size_t available_bytes_; + dirent* next_; + pthread_mutex_t mutex_; + dirent buff_[15]; + long current_pos_; +}; + +#define CHECK_DIR(d) if (d == nullptr) __fortify_fatal("%s: null DIR*", __FUNCTION__) + +static uint64_t __get_dir_tag(DIR* dir) { + return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_DIR, + reinterpret_cast(dir)); +} + +static DIR* __allocate_DIR(int fd) { + DIR* d = reinterpret_cast(malloc(sizeof(DIR))); + if (d == nullptr) { + return nullptr; + } + d->fd_ = fd; + android_fdsan_exchange_owner_tag(fd, 0, __get_dir_tag(d)); + d->available_bytes_ = 0; + d->next_ = nullptr; + d->current_pos_ = 0L; + pthread_mutex_init(&d->mutex_, nullptr); + return d; +} + +int dirfd(DIR* d) { + CHECK_DIR(d); + return d->fd_; +} + +DIR* fdopendir(int fd) { + // Is 'fd' actually a directory? + struct stat sb; + if (fstat(fd, &sb) == -1) { + return nullptr; + } + if (!S_ISDIR(sb.st_mode)) { + errno = ENOTDIR; + return nullptr; + } + + return __allocate_DIR(fd); +} + +DIR* opendir(const char* path) { + int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY); + return (fd != -1) ? __allocate_DIR(fd) : nullptr; +} + +static bool __fill_DIR(DIR* d) { + CHECK_DIR(d); + int rc = TEMP_FAILURE_RETRY(__getdents64(d->fd_, d->buff_, sizeof(d->buff_))); + if (rc <= 0) { + return false; + } + d->available_bytes_ = rc; + d->next_ = d->buff_; + return true; +} + +static dirent* __readdir_locked(DIR* d) { + if (d->available_bytes_ == 0 && !__fill_DIR(d)) { + return nullptr; + } + + dirent* entry = d->next_; + d->next_ = reinterpret_cast(reinterpret_cast(entry) + entry->d_reclen); + d->available_bytes_ -= entry->d_reclen; + // The directory entry offset uses 0, 1, 2 instead of real file offset, + // so the value range of long type is enough. + d->current_pos_ = static_cast(entry->d_off); + return entry; +} + +dirent* readdir(DIR* d) { + CHECK_DIR(d); + ScopedPthreadMutexLocker locker(&d->mutex_); + return __readdir_locked(d); +} +__strong_alias(readdir64, readdir); + +int readdir_r(DIR* d, dirent* entry, dirent** result) { + CHECK_DIR(d); + + ErrnoRestorer errno_restorer; + + *result = nullptr; + errno = 0; + + ScopedPthreadMutexLocker locker(&d->mutex_); + + dirent* next = __readdir_locked(d); + if (errno != 0 && next == nullptr) { + return errno; + } + + if (next != nullptr) { + memcpy(entry, next, next->d_reclen); + *result = entry; + } + return 0; +} +__strong_alias(readdir64_r, readdir_r); + +int closedir(DIR* d) { + if (d == nullptr) { + errno = EINVAL; + return -1; + } + + int fd = d->fd_; + pthread_mutex_destroy(&d->mutex_); + int rc = android_fdsan_close_with_tag(fd, __get_dir_tag(d)); + free(d); + return rc; +} + +void rewinddir(DIR* d) { + CHECK_DIR(d); + + ScopedPthreadMutexLocker locker(&d->mutex_); + lseek(d->fd_, 0, SEEK_SET); + d->available_bytes_ = 0; + d->current_pos_ = 0L; +} + +void seekdir(DIR* d, long offset) { + CHECK_DIR(d); + + ScopedPthreadMutexLocker locker(&d->mutex_); + off_t ret = lseek(d->fd_, offset, SEEK_SET); + if (ret != -1L) { + d->available_bytes_ = 0; + d->current_pos_ = ret; + } +} + +long telldir(DIR* d) { + CHECK_DIR(d); + + return d->current_pos_; +} + +int alphasort(const dirent** a, const dirent** b) { + return strcoll((*a)->d_name, (*b)->d_name); +} +__strong_alias(alphasort64, alphasort); diff --git a/aosp/bionic/libc/bionic/dl_iterate_phdr_static.cpp b/aosp/bionic/libc/bionic/dl_iterate_phdr_static.cpp new file mode 100644 index 000000000..7b448106d --- /dev/null +++ b/aosp/bionic/libc/bionic/dl_iterate_phdr_static.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2006 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 +#include +#include +#include +#include + +#include "private/bionic_elf_tls.h" +#include "private/bionic_globals.h" +#include "pthread_internal.h" + +/* ld provides this to us in the default link script */ +extern "C" void* __executable_start; + +int dl_iterate_phdr(int (*cb)(struct dl_phdr_info* info, size_t size, void* data), void* data) { + ElfW(Ehdr)* ehdr = reinterpret_cast(&__executable_start); + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { + return -1; + } + + // Dynamic binaries get their dl_iterate_phdr from the dynamic linker, but + // static binaries get this. We don't have a list of shared objects to + // iterate over, since there's really only a single monolithic blob of + // code/data, plus optionally a VDSO. + + struct dl_phdr_info exe_info; + exe_info.dlpi_addr = 0; + exe_info.dlpi_name = NULL; + exe_info.dlpi_phdr = reinterpret_cast(reinterpret_cast(ehdr) + ehdr->e_phoff); + exe_info.dlpi_phnum = ehdr->e_phnum; + exe_info.dlpi_adds = 0; + exe_info.dlpi_subs = 0; + + const TlsModules& tls_modules = __libc_shared_globals()->tls_modules; + if (tls_modules.module_count == 0) { + exe_info.dlpi_tls_modid = 0; + exe_info.dlpi_tls_data = nullptr; + } else { + const size_t kExeModuleId = 1; + const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + const TlsModule& tls_module = tls_modules.module_table[__tls_module_id_to_idx(kExeModuleId)]; + char* static_tls = reinterpret_cast(__get_bionic_tcb()) - layout.offset_bionic_tcb(); + exe_info.dlpi_tls_modid = kExeModuleId; + exe_info.dlpi_tls_data = static_tls + tls_module.static_offset; + } + + // Try the executable first. + int rc = cb(&exe_info, sizeof(exe_info), data); + if (rc != 0) { + return rc; + } + + // Try the VDSO if that didn't work. + ElfW(Ehdr)* ehdr_vdso = reinterpret_cast(getauxval(AT_SYSINFO_EHDR)); + if (ehdr_vdso == nullptr) { + // There is no VDSO, so there's nowhere left to look. + return rc; + } + + struct dl_phdr_info vdso_info; + vdso_info.dlpi_addr = 0; + vdso_info.dlpi_name = NULL; + vdso_info.dlpi_phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); + vdso_info.dlpi_phnum = ehdr_vdso->e_phnum; + vdso_info.dlpi_adds = 0; + vdso_info.dlpi_subs = 0; + vdso_info.dlpi_tls_modid = 0; + vdso_info.dlpi_tls_data = nullptr; + for (size_t i = 0; i < vdso_info.dlpi_phnum; ++i) { + if (vdso_info.dlpi_phdr[i].p_type == PT_LOAD) { + vdso_info.dlpi_addr = (ElfW(Addr)) ehdr_vdso - vdso_info.dlpi_phdr[i].p_vaddr; + break; + } + } + return cb(&vdso_info, sizeof(vdso_info), data); +} diff --git a/aosp/bionic/libc/bionic/dup.cpp b/aosp/bionic/libc/bionic/dup.cpp new file mode 100644 index 000000000..d9e89a595 --- /dev/null +++ b/aosp/bionic/libc/bionic/dup.cpp @@ -0,0 +1,57 @@ +/* + * 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 +#include + +#include "private/bionic_fdtrack.h" + +extern "C" int __dup(int old_fd); +extern "C" int __dup3(int old_fd, int new_fd, int flags); + +int dup(int old_fd) { + return FDTRACK_CREATE(__dup(old_fd)); +} + +int dup2(int old_fd, int new_fd) { + // If old_fd is equal to new_fd and a valid file descriptor, dup2 returns + // old_fd without closing it. This is not true of dup3, so we have to + // handle this case ourselves. + if (old_fd == new_fd) { + if (fcntl(old_fd, F_GETFD) == -1) { + return -1; + } + return old_fd; + } + + return FDTRACK_CREATE(__dup3(old_fd, new_fd, 0)); +} + +int dup3(int old_fd, int new_fd, int flags) { + return FDTRACK_CREATE(__dup3(old_fd, new_fd, flags)); +} diff --git a/aosp/bionic/libc/bionic/environ.cpp b/aosp/bionic/libc/bionic/environ.cpp new file mode 100644 index 000000000..243af6221 --- /dev/null +++ b/aosp/bionic/libc/bionic/environ.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +#include "private/bionic_defs.h" +// Keep that variable in separate .o file to make sure programs which define +// their own "environ" are compileable. +__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE +char** environ; diff --git a/aosp/bionic/libc/bionic/error.cpp b/aosp/bionic/libc/bionic/error.cpp new file mode 100644 index 000000000..a8adc1b39 --- /dev/null +++ b/aosp/bionic/libc/bionic/error.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 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 + +#include +#include +#include +#include + +unsigned int error_message_count = 0; +void (*error_print_progname)(void) = nullptr; +int error_one_per_line = 0; + +static void __error_head() { + ++error_message_count; + + if (error_print_progname != nullptr) { + error_print_progname(); + } else { + fflush(stdout); + fprintf(stderr, "%s:", getprogname()); + } +} + +static void __error_tail(int status, int error) { + if (error != 0) { + fprintf(stderr, ": %s", strerror(error)); + } + + putc('\n', stderr); + fflush(stderr); + + if (status != 0) { + exit(status); + } +} + +void error(int status, int error, const char* fmt, ...) { + __error_head(); + putc(' ', stderr); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + __error_tail(status, error); +} + +void error_at_line(int status, int error, const char* file, unsigned int line, const char* fmt, ...) { + if (error_one_per_line) { + static const char* last_file; + static unsigned int last_line; + if (last_line == line && last_file != nullptr && strcmp(last_file, file) == 0) { + return; + } + last_file = file; + last_line = line; + } + + __error_head(); + fprintf(stderr, "%s:%d: ", file, line); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + __error_tail(status, error); +} diff --git a/aosp/bionic/libc/bionic/ether_aton.c b/aosp/bionic/libc/bionic/ether_aton.c new file mode 100644 index 000000000..edd6b11b7 --- /dev/null +++ b/aosp/bionic/libc/bionic/ether_aton.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 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 + +#include +#include +#include + +static inline int +xdigit (char c) { + unsigned d; + d = (unsigned)(c-'0'); + if (d < 10) return (int)d; + d = (unsigned)(c-'a'); + if (d < 6) return (int)(10+d); + d = (unsigned)(c-'A'); + if (d < 6) return (int)(10+d); + return -1; +} + +/* + * Convert Ethernet address in the standard hex-digits-and-colons to binary + * representation. + * Re-entrant version (GNU extensions) + */ +struct ether_addr * +ether_aton_r (const char *asc, struct ether_addr * addr) +{ + int i, val0, val1; + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + val0 = xdigit(*asc); + asc++; + if (val0 < 0) + return NULL; + + val1 = xdigit(*asc); + asc++; + if (val1 < 0) + return NULL; + + addr->ether_addr_octet[i] = (u_int8_t)((val0 << 4) + val1); + + if (i < ETHER_ADDR_LEN - 1) { + if (*asc != ':') + return NULL; + asc++; + } + } + if (*asc != '\0') + return NULL; + return addr; +} + +/* + * Convert Ethernet address in the standard hex-digits-and-colons to binary + * representation. + */ +struct ether_addr * +ether_aton (const char *asc) +{ + static struct ether_addr addr; + return ether_aton_r(asc, &addr); +} diff --git a/aosp/bionic/libc/bionic/ether_ntoa.c b/aosp/bionic/libc/bionic/ether_ntoa.c new file mode 100644 index 000000000..7c31af3b4 --- /dev/null +++ b/aosp/bionic/libc/bionic/ether_ntoa.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 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 +#include +#include + +/* + * Convert Ethernet address to standard hex-digits-and-colons printable form. + * Re-entrant version (GNU extensions). + */ +char * +ether_ntoa_r (const struct ether_addr *addr, char * buf) +{ + snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + addr->ether_addr_octet[0], addr->ether_addr_octet[1], + addr->ether_addr_octet[2], addr->ether_addr_octet[3], + addr->ether_addr_octet[4], addr->ether_addr_octet[5]); + return buf; +} + +/* + * Convert Ethernet address to standard hex-digits-and-colons printable form. + */ +char * +ether_ntoa (const struct ether_addr *addr) +{ + static char buf[18]; + return ether_ntoa_r(addr, buf); +} diff --git a/aosp/bionic/libc/bionic/eventfd.cpp b/aosp/bionic/libc/bionic/eventfd.cpp new file mode 100644 index 000000000..f13c6a309 --- /dev/null +++ b/aosp/bionic/libc/bionic/eventfd.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 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 +#include + +#include "private/bionic_fdtrack.h" + +extern "C" int __eventfd(unsigned int initval, int flags); + +int eventfd(unsigned int initval, int flags) { + return FDTRACK_CREATE(__eventfd(initval, flags)); +} + +int eventfd_read(int fd, eventfd_t* value) { + return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1; +} + +int eventfd_write(int fd, eventfd_t value) { + return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1; +} diff --git a/aosp/bionic/libc/bionic/eventfd_write.cpp b/aosp/bionic/libc/bionic/eventfd_write.cpp new file mode 100644 index 000000000..6d86d8ca9 --- /dev/null +++ b/aosp/bionic/libc/bionic/eventfd_write.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 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 +#include + diff --git a/aosp/bionic/libc/bionic/exec.cpp b/aosp/bionic/libc/bionic/exec.cpp new file mode 100644 index 000000000..3309585d5 --- /dev/null +++ b/aosp/bionic/libc/bionic/exec.cpp @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1991, 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/__bionic_get_shell_path.h" +#include "private/FdPath.h" + +extern "C" char** environ; + +enum ExecVariant { kIsExecL, kIsExecLE, kIsExecLP }; + +static int __execl(const char* name, const char* argv0, ExecVariant variant, va_list ap) { + // Count the arguments. + va_list count_ap; + va_copy(count_ap, ap); + size_t n = 1; + while (va_arg(count_ap, char*) != nullptr) { + ++n; + } + va_end(count_ap); + + // Construct the new argv. + char* argv[n + 1]; + argv[0] = const_cast(argv0); + n = 1; + while ((argv[n] = va_arg(ap, char*)) != nullptr) { + ++n; + } + + // Collect the argp too. + char** argp = (variant == kIsExecLE) ? va_arg(ap, char**) : environ; + + va_end(ap); + + return (variant == kIsExecLP) ? execvp(name, argv) : execve(name, argv, argp); +} + +int execl(const char* name, const char* arg, ...) { + va_list ap; + va_start(ap, arg); + int result = __execl(name, arg, kIsExecL, ap); + va_end(ap); + return result; +} + +int execle(const char* name, const char* arg, ...) { + va_list ap; + va_start(ap, arg); + int result = __execl(name, arg, kIsExecLE, ap); + va_end(ap); + return result; +} + +int execlp(const char* name, const char* arg, ...) { + va_list ap; + va_start(ap, arg); + int result = __execl(name, arg, kIsExecLP, ap); + va_end(ap); + return result; +} + +int execv(const char* name, char* const* argv) { + return execve(name, argv, environ); +} + +int execvp(const char* name, char* const* argv) { + return execvpe(name, argv, environ); +} + +static int __exec_as_script(const char* buf, char* const* argv, char* const* envp) { + size_t arg_count = 1; + while (argv[arg_count] != nullptr) ++arg_count; + + const char* script_argv[arg_count + 2]; + script_argv[0] = "sh"; + script_argv[1] = buf; + memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*)); + return execve(__bionic_get_shell_path(), const_cast(script_argv), envp); +} + +int execvpe(const char* name, char* const* argv, char* const* envp) { + // Do not allow null name. + if (name == nullptr || *name == '\0') { + errno = ENOENT; + return -1; + } + + // If it's an absolute or relative path name, it's easy. + if (strchr(name, '/') && execve(name, argv, envp) == -1) { + if (errno == ENOEXEC) return __exec_as_script(name, argv, envp); + return -1; + } + + // Get the path we're searching. + const char* path = getenv("PATH"); + if (path == nullptr) path = _PATH_DEFPATH; + + // Make a writable copy. + size_t len = strlen(path) + 1; + char writable_path[len]; + memcpy(writable_path, path, len); + + bool saw_EACCES = false; + + // Try each element of $PATH in turn... + char* strsep_buf = writable_path; + const char* dir; + while ((dir = strsep(&strsep_buf, ":"))) { + // It's a shell path: double, leading and trailing colons + // mean the current directory. + if (*dir == '\0') dir = const_cast("."); + + size_t dir_len = strlen(dir); + size_t name_len = strlen(name); + + char buf[dir_len + 1 + name_len + 1]; + mempcpy(mempcpy(mempcpy(buf, dir, dir_len), "/", 1), name, name_len + 1); + + execve(buf, argv, envp); + switch (errno) { + case EISDIR: + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOTDIR: + break; + case ENOEXEC: + return __exec_as_script(buf, argv, envp); + case EACCES: + saw_EACCES = true; + break; + default: + return -1; + } + } + if (saw_EACCES) errno = EACCES; + return -1; +} + +int fexecve(int fd, char* const* argv, char* const* envp) { + // execveat with AT_EMPTY_PATH (>= 3.19) seems to offer no advantages. + execve(FdPath(fd).c_str(), argv, envp); + if (errno == ENOENT) errno = EBADF; + return -1; +} diff --git a/aosp/bionic/libc/bionic/faccessat.cpp b/aosp/bionic/libc/bionic/faccessat.cpp new file mode 100644 index 000000000..bfaec51fe --- /dev/null +++ b/aosp/bionic/libc/bionic/faccessat.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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 +#include +#include + +extern "C" int __faccessat(int, const char*, int); + +int faccessat(int dirfd, const char* pathname, int mode, int flags) { + // "The mode specifies the accessibility check(s) to be performed, + // and is either the value F_OK, or a mask consisting of the + // bitwise OR of one or more of R_OK, W_OK, and X_OK." + if ((mode != F_OK) && ((mode & ~(R_OK | W_OK | X_OK)) != 0) && + ((mode & (R_OK | W_OK | X_OK)) == 0)) { + errno = EINVAL; + return -1; + } + + if (flags != 0) { + // We deliberately don't support AT_SYMLINK_NOFOLLOW, a glibc + // only feature which is error prone and dangerous. + // More details at http://permalink.gmane.org/gmane.linux.lib.musl.general/6952 + // + // AT_EACCESS isn't supported either. Android doesn't have setuid + // programs, and never runs code with euid!=uid. It could be + // implemented in an expensive way, following the model at + // https://gitlab.com/bminor/musl/commit/0a05eace163cee9b08571d2ff9d90f5e82d9c228 + // but not worth it. + errno = EINVAL; + return -1; + } + + return __faccessat(dirfd, pathname, mode); +} diff --git a/aosp/bionic/libc/bionic/fchmod.cpp b/aosp/bionic/libc/bionic/fchmod.cpp new file mode 100644 index 000000000..0326fc2a2 --- /dev/null +++ b/aosp/bionic/libc/bionic/fchmod.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include + +#include "private/FdPath.h" + +extern "C" int __fchmod(int, mode_t); + +int fchmod(int fd, mode_t mode) { + int saved_errno = errno; + int result = __fchmod(fd, mode); + if (result == 0 || errno != EBADF) { + return result; + } + + // fd could be an O_PATH file descriptor, and the kernel + // may not directly support fchmod() on such a file descriptor. + // Use /proc/self/fd instead to emulate this support. + // https://sourceware.org/bugzilla/show_bug.cgi?id=14578 + // + // As of February 2015, there are no kernels which support fchmod + // on an O_PATH file descriptor, and "man open" documents fchmod + // on O_PATH file descriptors as returning EBADF. + int fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + errno = saved_errno; + result = chmod(FdPath(fd).c_str(), mode); + if (result == -1 && errno == ELOOP) { + // Linux does not support changing the mode of a symlink. + // For fchmodat(AT_SYMLINK_NOFOLLOW), POSIX requires a return + // value of ENOTSUP. Assume that's true here too. + errno = ENOTSUP; + } + + return result; +} diff --git a/aosp/bionic/libc/bionic/fchmodat.cpp b/aosp/bionic/libc/bionic/fchmodat.cpp new file mode 100644 index 000000000..632d2ac85 --- /dev/null +++ b/aosp/bionic/libc/bionic/fchmodat.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include + +#include "private/ScopedFd.h" + +extern "C" int __fchmodat(int, const char*, mode_t); + +int fchmodat(int dirfd, const char* pathname, mode_t mode, int flags) { + if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0) { + errno = EINVAL; + return -1; + } + + if (flags & AT_SYMLINK_NOFOLLOW) { + // Emulate AT_SYMLINK_NOFOLLOW using the mechanism described + // at https://sourceware.org/bugzilla/show_bug.cgi?id=14578 + // comment #10 + + ScopedFd fd(openat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC)); + if (fd.get() == -1) return -1; + + // POSIX requires that ENOTSUP be returned when the system + // doesn't support setting the mode of a symbolic link. + // This is true for all Linux kernels. + // We rely on the O_PATH compatibility layer added in the + // fchmod() function to get errno correct. + return fchmod(fd.get(), mode); + } + + return __fchmodat(dirfd, pathname, mode); +} diff --git a/aosp/bionic/libc/bionic/fcntl.cpp b/aosp/bionic/libc/bionic/fcntl.cpp new file mode 100644 index 000000000..c50813186 --- /dev/null +++ b/aosp/bionic/libc/bionic/fcntl.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 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 +#include + +#include "private/bionic_fdtrack.h" + +#if defined(__LP64__) + +extern "C" int __fcntl(int fd, int cmd, ...); + +int fcntl(int fd, int cmd, ...) { + va_list args; + va_start(args, cmd); + + // This is a bit sketchy, especially because arg can be an int, but all of our + // supported 64-bit ABIs pass arg in a register. + void* arg = va_arg(args, void*); + va_end(args); + + int rc = __fcntl(fd, cmd, arg); + if (cmd == F_DUPFD) { + return FDTRACK_CREATE_NAME("F_DUPFD", rc); + } else if (cmd == F_DUPFD_CLOEXEC) { + return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", rc); + } + return rc; +} + +#else + +extern "C" int __fcntl64(int, int, ...); + +// For fcntl we use the fcntl64 system call to signal that we're using struct flock64. +int fcntl(int fd, int cmd, ...) { + va_list ap; + + va_start(ap, cmd); + void* arg = va_arg(ap, void*); + va_end(ap); + + if (cmd == F_DUPFD) { + return FDTRACK_CREATE_NAME("F_DUPFD", __fcntl64(fd, cmd, arg)); + } else if (cmd == F_DUPFD_CLOEXEC) { + return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", __fcntl64(fd, cmd, arg)); + } + return __fcntl64(fd, cmd, arg); +} + +#endif diff --git a/aosp/bionic/libc/bionic/fdsan.cpp b/aosp/bionic/libc/bionic/fdsan.cpp new file mode 100644 index 000000000..4b8991872 --- /dev/null +++ b/aosp/bionic/libc/bionic/fdsan.cpp @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2018 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "private/bionic_fdtrack.h" +#include "private/bionic_globals.h" +#include "private/bionic_inline_raise.h" +#include "pthread_internal.h" + +extern "C" int __close(int fd); +pid_t __get_cached_pid(); + +static constexpr const char* kFdsanPropertyName = "debug.fdsan"; + +template +FdEntry* FdTableImpl::at(size_t idx) { + if (idx < inline_fds) { + return &entries[idx]; + } + + // Try to create the overflow table ourselves. + FdTableOverflow* local_overflow = atomic_load(&overflow); + if (__predict_false(!local_overflow)) { + struct rlimit rlim = { .rlim_max = 32768 }; + getrlimit(RLIMIT_NOFILE, &rlim); + rlim_t max = rlim.rlim_max; + + if (max == RLIM_INFINITY) { + // This isn't actually possible (the kernel has a hard limit), but just + // in case... + max = 32768; + } + + if (idx > max) { + // This can happen if an fd is created and then the rlimit is lowered. + // In this case, just return nullptr and ignore the fd. + return nullptr; + } + + size_t required_count = max - inline_fds; + size_t required_size = sizeof(FdTableOverflow) + required_count * sizeof(FdEntry); + size_t aligned_size = __BIONIC_ALIGN(required_size, PAGE_SIZE); + size_t aligned_count = (aligned_size - sizeof(FdTableOverflow)) / sizeof(FdEntry); + + void* allocation = + mmap(nullptr, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (allocation == MAP_FAILED) { + async_safe_fatal("fdsan: mmap failed: %s", strerror(errno)); + } + + FdTableOverflow* new_overflow = reinterpret_cast(allocation); + new_overflow->len = aligned_count; + + if (atomic_compare_exchange_strong(&overflow, &local_overflow, new_overflow)) { + local_overflow = new_overflow; + } else { + // Someone beat us to it. Deallocate and use theirs. + munmap(allocation, aligned_size); + } + } + + size_t offset = idx - inline_fds; + if (local_overflow->len < offset) { + return nullptr; + } + return &local_overflow->entries[offset]; +} + +void __libc_init_fdsan() { + constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_FATAL; + android_fdsan_set_error_level_from_property(default_level); +} + +static FdTable& GetFdTable() { + return __libc_shared_globals()->fd_table; +} + +// Exposed to the platform to allow crash_dump to print out the fd table. +extern "C" void* android_fdsan_get_fd_table() { + return &GetFdTable(); +} + +static FdEntry* GetFdEntry(int fd) { + if (fd < 0) { + return nullptr; + } + + return GetFdTable().at(fd); +} + +__printflike(1, 0) static void fdsan_error(const char* fmt, ...) { + auto& fd_table = GetFdTable(); + + auto error_level = atomic_load(&fd_table.error_level); + if (error_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) { + return; + } + + // Lots of code will (sensibly) fork, blindly call close on all of their fds, + // and then exec. Compare our cached pid value against the real one to detect + // this scenario and permit it. + pid_t cached_pid = __get_cached_pid(); + if (cached_pid == 0 || cached_pid != syscall(__NR_getpid)) { + return; + } + + struct { + size_t size; + char buf[512]; + } abort_message; + + va_list va; + va_start(va, fmt); + if (error_level == ANDROID_FDSAN_ERROR_LEVEL_FATAL) { + async_safe_fatal_va_list("fdsan", fmt, va); + } else { + async_safe_format_log_va_list(ANDROID_LOG_ERROR, "fdsan", fmt, va); + va_end(va); + va_start(va, fmt); + size_t len = + async_safe_format_buffer_va_list(abort_message.buf, sizeof(abort_message.buf), fmt, va); + abort_message.size = len + sizeof(size_t); + } + va_end(va); + + switch (error_level) { + case ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE: + atomic_compare_exchange_strong(&fd_table.error_level, &error_level, + ANDROID_FDSAN_ERROR_LEVEL_DISABLED); + __BIONIC_FALLTHROUGH; + case ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS: + inline_raise(BIONIC_SIGNAL_DEBUGGER, &abort_message); + break; + + case ANDROID_FDSAN_ERROR_LEVEL_FATAL: + inline_raise(SIGABRT); + abort(); + + case ANDROID_FDSAN_ERROR_LEVEL_DISABLED: + break; + } +} + +uint64_t android_fdsan_create_owner_tag(android_fdsan_owner_type type, uint64_t tag) { + if (tag == 0) { + return 0; + } + + if (__predict_false((type & 0xff) != type)) { + async_safe_fatal("invalid android_fdsan_owner_type value: %x", type); + } + + uint64_t result = static_cast(type) << 56; + uint64_t mask = (static_cast(1) << 56) - 1; + result |= tag & mask; + return result; +} + +const char* android_fdsan_get_tag_type(uint64_t tag) { + uint64_t type = tag >> 56; + switch (type) { + case ANDROID_FDSAN_OWNER_TYPE_FILE: + return "FILE*"; + case ANDROID_FDSAN_OWNER_TYPE_DIR: + return "DIR*"; + case ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD: + return "unique_fd"; + case ANDROID_FDSAN_OWNER_TYPE_FILEINPUTSTREAM: + return "FileInputStream"; + case ANDROID_FDSAN_OWNER_TYPE_FILEOUTPUTSTREAM: + return "FileOutputStream"; + case ANDROID_FDSAN_OWNER_TYPE_RANDOMACCESSFILE: + return "RandomAccessFile"; + case ANDROID_FDSAN_OWNER_TYPE_PARCELFILEDESCRIPTOR: + return "ParcelFileDescriptor"; + case ANDROID_FDSAN_OWNER_TYPE_SQLITE: + return "sqlite"; + case ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE: + return "ART FdFile"; + case ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL: + return "DatagramSocketImpl"; + case ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL: + return "SocketImpl"; + case ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE: + return "ZipArchive"; + + case ANDROID_FDSAN_OWNER_TYPE_GENERIC_00: + default: + return "native object of unknown type"; + + case ANDROID_FDSAN_OWNER_TYPE_GENERIC_FF: + // If bits 48 to 56 are set, this is a sign-extended generic native pointer + uint64_t high_bits = tag >> 48; + if (high_bits == (1 << 16) - 1) { + return "native object of unknown type"; + } + + return "Java object of unknown type"; + } +} + +uint64_t android_fdsan_get_tag_value(uint64_t tag) { + // Lop off the most significant byte and sign extend. + return static_cast(static_cast(tag << 8) >> 8); +} + +int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) { + if (__get_thread()->is_vforked()) { + return __close(fd); + } + + FDTRACK_CLOSE(fd); + FdEntry* fde = GetFdEntry(fd); + if (!fde) { + return __close(fd); + } + + uint64_t tag = expected_tag; + if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, 0)) { + const char* expected_type = android_fdsan_get_tag_type(expected_tag); + uint64_t expected_owner = android_fdsan_get_tag_value(expected_tag); + const char* actual_type = android_fdsan_get_tag_type(tag); + uint64_t actual_owner = android_fdsan_get_tag_value(tag); + if (expected_tag && tag) { + fdsan_error( + "attempted to close file descriptor %d, " + "expected to be owned by %s 0x%" PRIx64 ", actually owned by %s 0x%" PRIx64, + fd, expected_type, expected_owner, actual_type, actual_owner); + } else if (expected_tag && !tag) { + fdsan_error( + "attempted to close file descriptor %d, " + "expected to be owned by %s 0x%" PRIx64 ", actually unowned", + fd, expected_type, expected_owner); + } else if (!expected_tag && tag) { + fdsan_error( + "attempted to close file descriptor %d, " + "expected to be unowned, actually owned by %s 0x%" PRIx64, + fd, actual_type, actual_owner); + } else if (!expected_tag && !tag) { + // This should never happen: our CAS failed, but expected == actual? + async_safe_fatal("fdsan atomic_compare_exchange_strong failed unexpectedly while closing"); + } + } + + int rc = __close(fd); + // If we were expecting to close with a tag, abort on EBADF. + if (expected_tag && rc == -1 && errno == EBADF) { + fdsan_error("double-close of file descriptor %d detected", fd); + } + return rc; +} + +uint64_t android_fdsan_get_owner_tag(int fd) { + FdEntry* fde = GetFdEntry(fd); + if (!fde) { + return 0; + } + return fde->close_tag; +} + +void android_fdsan_exchange_owner_tag(int fd, uint64_t expected_tag, uint64_t new_tag) { + if (__get_thread()->is_vforked()) { + return; + } + + FdEntry* fde = GetFdEntry(fd); + if (!fde) { + return; + } + + uint64_t tag = expected_tag; + if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, new_tag)) { + if (expected_tag && tag) { + fdsan_error( + "failed to exchange ownership of file descriptor: fd %d is " + "owned by %s 0x%" PRIx64 ", was expected to be owned by %s 0x%" PRIx64, + fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag), + android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag)); + } else if (expected_tag && !tag) { + fdsan_error( + "failed to exchange ownership of file descriptor: fd %d is " + "unowned, was expected to be owned by %s 0x%" PRIx64, + fd, android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag)); + } else if (!expected_tag && tag) { + fdsan_error( + "failed to exchange ownership of file descriptor: fd %d is " + "owned by %s 0x%" PRIx64 ", was expected to be unowned", + fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag)); + } else if (!expected_tag && !tag) { + // This should never happen: our CAS failed, but expected == actual? + async_safe_fatal( + "fdsan atomic_compare_exchange_strong failed unexpectedly while exchanging owner tag"); + } + } +} + +android_fdsan_error_level android_fdsan_get_error_level() { + return GetFdTable().error_level; +} + +android_fdsan_error_level android_fdsan_set_error_level(android_fdsan_error_level new_level) { + if (__get_thread()->is_vforked()) { + return android_fdsan_get_error_level(); + } + + return atomic_exchange(&GetFdTable().error_level, new_level); +} + +android_fdsan_error_level android_fdsan_set_error_level_from_property( + android_fdsan_error_level default_level) { + const prop_info* pi = __system_property_find(kFdsanPropertyName); + if (!pi) { + return android_fdsan_set_error_level(default_level); + } + + struct callback_data { + android_fdsan_error_level default_value; + android_fdsan_error_level result; + }; + + callback_data data; + data.default_value = default_level; + + __system_property_read_callback( + pi, + [](void* arg, const char*, const char* value, uint32_t) { + callback_data* data = static_cast(arg); + + if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) { + data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL); + } else if (strcasecmp(value, "warn") == 0) { + data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); + } else if (strcasecmp(value, "warn_once") == 0) { + data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE); + } else { + if (strlen(value) != 0 && strcasecmp(value, "0") != 0) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "debug.fdsan set to unknown value '%s', disabling", value); + } + data->result = android_fdsan_set_error_level(data->default_value); + } + }, + &data); + + return data.result; +} + +int close(int fd) { + int rc = android_fdsan_close_with_tag(fd, 0); + if (rc == -1 && errno == EINTR) { + return 0; + } + return rc; +} diff --git a/aosp/bionic/libc/bionic/fdtrack.cpp b/aosp/bionic/libc/bionic/fdtrack.cpp new file mode 100644 index 000000000..11235129d --- /dev/null +++ b/aosp/bionic/libc/bionic/fdtrack.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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 + +#include +#include + +#include "private/bionic_fdtrack.h" +#include "private/bionic_tls.h" +#include "private/bionic_globals.h" + +_Atomic(android_fdtrack_hook_t) __android_fdtrack_hook; + +bool android_fdtrack_get_enabled() { + return !__get_bionic_tls().fdtrack_disabled; +} + +bool android_fdtrack_set_enabled(bool new_value) { + auto& tls = __get_bionic_tls(); + bool prev = !tls.fdtrack_disabled; + tls.fdtrack_disabled = !new_value; + return prev; +} + +bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected, + android_fdtrack_hook_t value) { + return atomic_compare_exchange_strong(&__android_fdtrack_hook, expected, value); +} + +void __libc_init_fdtrack() { + // Register a no-op signal handler. + signal(BIONIC_SIGNAL_FDTRACK, [](int) {}); +} diff --git a/aosp/bionic/libc/bionic/ffs.cpp b/aosp/bionic/libc/bionic/ffs.cpp new file mode 100644 index 000000000..b2270e548 --- /dev/null +++ b/aosp/bionic/libc/bionic/ffs.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int ffs(int x) { + return __builtin_ffs(x); +} diff --git a/aosp/bionic/libc/bionic/fgetxattr.cpp b/aosp/bionic/libc/bionic/fgetxattr.cpp new file mode 100644 index 000000000..c7532355b --- /dev/null +++ b/aosp/bionic/libc/bionic/fgetxattr.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include + +#include "private/FdPath.h" + +extern "C" ssize_t __fgetxattr(int, const char*, void*, size_t); + +ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) { + int saved_errno = errno; + ssize_t result = __fgetxattr(fd, name, value, size); + + if (result != -1 || errno != EBADF) { + return result; + } + + // fd could be an O_PATH file descriptor, and the kernel + // may not directly support fgetxattr() on such a file descriptor. + // Use /proc/self/fd instead to emulate this support. + int fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + errno = saved_errno; + return getxattr(FdPath(fd).c_str(), name, value, size); +} diff --git a/aosp/bionic/libc/bionic/flistxattr.cpp b/aosp/bionic/libc/bionic/flistxattr.cpp new file mode 100644 index 000000000..3bad3835d --- /dev/null +++ b/aosp/bionic/libc/bionic/flistxattr.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include + +#include "private/FdPath.h" + +extern "C" ssize_t __flistxattr(int, char*, size_t); + +ssize_t flistxattr(int fd, char *list, size_t size) { + int saved_errno = errno; + ssize_t result = __flistxattr(fd, list, size); + if (result != -1 || errno != EBADF) { + return result; + } + + // fd could be an O_PATH file descriptor, and the kernel + // may not directly support fgetxattr() on such a file descriptor. + // Use /proc/self/fd instead to emulate this support. + int fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + errno = saved_errno; + return listxattr(FdPath(fd).c_str(), list, size); +} diff --git a/aosp/bionic/libc/bionic/flockfile.cpp b/aosp/bionic/libc/bionic/flockfile.cpp new file mode 100644 index 000000000..db5382859 --- /dev/null +++ b/aosp/bionic/libc/bionic/flockfile.cpp @@ -0,0 +1,58 @@ +/* + * 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 +#include + +#include "local.h" + +// We can't use the OpenBSD implementation which uses kernel-specific +// APIs not available on Linux. Instead we use a pthread_mutex_t within +// struct __sfileext (see fileext.h). + +void flockfile(FILE* fp) { + if (fp != nullptr) { + pthread_mutex_lock(&_FLOCK(fp)); + } +} + +int ftrylockfile(FILE* fp) { + // The specification for ftrylockfile() says it returns 0 on success, + // or non-zero on error. So return an errno code directly on error. + if (fp == nullptr) { + return EINVAL; + } + + return pthread_mutex_trylock(&_FLOCK(fp)); +} + +void funlockfile(FILE* fp) { + if (fp != nullptr) { + pthread_mutex_unlock(&_FLOCK(fp)); + } +} diff --git a/aosp/bionic/libc/bionic/fork.cpp b/aosp/bionic/libc/bionic/fork.cpp new file mode 100644 index 000000000..3814ed0ac --- /dev/null +++ b/aosp/bionic/libc/bionic/fork.cpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include + +#include "private/bionic_defs.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __clone_for_fork() { + pthread_internal_t* self = __get_thread(); + + int result = clone(nullptr, nullptr, (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD), + nullptr, nullptr, nullptr, &(self->tid)); + + if (result == 0) { + // Update the cached pid in child, since clone() will not set it directly (as + // self->tid is updated by the kernel). + self->set_cached_pid(gettid()); + } + + return result; +} + +int fork() { + __bionic_atfork_run_prepare(); + + int result = __clone_for_fork(); + + if (result == 0) { + // Disable fdsan post-fork, so we don't falsely trigger on processes that + // fork, close all of their fds blindly, and then exec. + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED); + + // Reset the stack_and_tls VMA name so it doesn't end with a tid from the + // parent process. + __set_stack_and_tls_vma_name(true); + + __bionic_atfork_run_child(); + } else { + __bionic_atfork_run_parent(); + } + return result; +} diff --git a/aosp/bionic/libc/bionic/fortify.cpp b/aosp/bionic/libc/bionic/fortify.cpp new file mode 100644 index 000000000..3b804b0b2 --- /dev/null +++ b/aosp/bionic/libc/bionic/fortify.cpp @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Copyright (c) 1988 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/bionic_fortify.h" + +// +// For more about FORTIFY see: +// +// https://android-developers.googleblog.com/2017/04/fortify-in-android.html +// +// http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html +// http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html +// + +int __FD_ISSET_chk(int fd, const fd_set* set, size_t set_size) { + __check_fd_set("FD_ISSET", fd, set_size); + return __FD_ISSET(fd, set); +} + +void __FD_CLR_chk(int fd, fd_set* set, size_t set_size) { + __check_fd_set("FD_CLR", fd, set_size); + __FD_CLR(fd, set); +} + +void __FD_SET_chk(int fd, fd_set* set, size_t set_size) { + __check_fd_set("FD_SET", fd, set_size); + __FD_SET(fd, set); +} + +char* __fgets_chk(char* dst, int supplied_size, FILE* stream, size_t dst_len_from_compiler) { + if (supplied_size < 0) { + __fortify_fatal("fgets: buffer size %d < 0", supplied_size); + } + __check_buffer_access("fgets", "write into", supplied_size, dst_len_from_compiler); + return fgets(dst, supplied_size, stream); +} + +size_t __fread_chk(void* buf, size_t size, size_t count, FILE* stream, size_t buf_size) { + size_t total; + if (__predict_false(__size_mul_overflow(size, count, &total))) { + // overflow: trigger the error path in fread + return fread(buf, size, count, stream); + } + __check_buffer_access("fread", "write into", total, buf_size); + return fread(buf, size, count, stream); +} + +size_t __fwrite_chk(const void* buf, size_t size, size_t count, FILE* stream, size_t buf_size) { + size_t total; + if (__predict_false(__size_mul_overflow(size, count, &total))) { + // overflow: trigger the error path in fwrite + return fwrite(buf, size, count, stream); + } + __check_buffer_access("fwrite", "read from", total, buf_size); + return fwrite(buf, size, count, stream); +} + +extern char* __getcwd_chk(char* buf, size_t len, size_t actual_size) { + __check_buffer_access("getcwd", "write into", len, actual_size); + return getcwd(buf, len); +} + +void* __memchr_chk(const void* s, int c, size_t n, size_t actual_size) { + __check_buffer_access("memchr", "read from", n, actual_size); + return const_cast(memchr(s, c, n)); +} + +// Runtime implementation of __builtin____memmove_chk (used directly by compiler, not in headers). +extern "C" void* __memmove_chk(void* dst, const void* src, size_t len, size_t dst_len) { + __check_buffer_access("memmove", "write into", len, dst_len); + return memmove(dst, src, len); +} + +// memcpy is performance-critical enough that we have assembler __memcpy_chk implementations. +// This function is used to give better diagnostics than we can easily do from assembler. +extern "C" void* __memcpy_chk_fail(void* /*dst*/, const void* /*src*/, size_t count, size_t dst_len) { + __check_count("memcpy", "count", count); + __check_buffer_access("memcpy", "write into", count, dst_len); + abort(); // One of the above is supposed to have failed, otherwise we shouldn't have been called. +} + +void* __memrchr_chk(const void* s, int c, size_t n, size_t actual_size) { + __check_buffer_access("memrchr", "read from", n, actual_size); + return memrchr(const_cast(s), c, n); +} + +// memset is performance-critical enough that we have assembler __memset_chk implementations. +// This function is used to give better diagnostics than we can easily do from assembler. +extern "C" void* __memset_chk_fail(void* /*dst*/, int /*byte*/, size_t count, size_t dst_len) { + __check_count("memset", "count", count); + __check_buffer_access("memset", "write into", count, dst_len); + abort(); // One of the above is supposed to have failed, otherwise we shouldn't have been called. +} + +int __poll_chk(pollfd* fds, nfds_t fd_count, int timeout, size_t fds_size) { + __check_pollfd_array("poll", fds_size, fd_count); + return poll(fds, fd_count, timeout); +} + +int __ppoll_chk(pollfd* fds, nfds_t fd_count, const timespec* timeout, + const sigset_t* mask, size_t fds_size) { + __check_pollfd_array("ppoll", fds_size, fd_count); + return ppoll(fds, fd_count, timeout, mask); +} + +int __ppoll64_chk(pollfd* fds, nfds_t fd_count, const timespec* timeout, + const sigset64_t* mask, size_t fds_size) { + __check_pollfd_array("ppoll64", fds_size, fd_count); + return ppoll64(fds, fd_count, timeout, mask); +} + +ssize_t __pread64_chk(int fd, void* buf, size_t count, off64_t offset, size_t buf_size) { + __check_count("pread64", "count", count); + __check_buffer_access("pread64", "write into", count, buf_size); + return pread64(fd, buf, count, offset); +} + +ssize_t __pread_chk(int fd, void* buf, size_t count, off_t offset, size_t buf_size) { + __check_count("pread", "count", count); + __check_buffer_access("pread", "write into", count, buf_size); + return pread(fd, buf, count, offset); +} + +ssize_t __pwrite64_chk(int fd, const void* buf, size_t count, off64_t offset, + size_t buf_size) { + __check_count("pwrite64", "count", count); + __check_buffer_access("pwrite64", "read from", count, buf_size); + return pwrite64(fd, buf, count, offset); +} + +ssize_t __pwrite_chk(int fd, const void* buf, size_t count, off_t offset, + size_t buf_size) { + __check_count("pwrite", "count", count); + __check_buffer_access("pwrite", "read from", count, buf_size); + return pwrite(fd, buf, count, offset); +} + +ssize_t __read_chk(int fd, void* buf, size_t count, size_t buf_size) { + __check_count("read", "count", count); + __check_buffer_access("read", "write into", count, buf_size); + return read(fd, buf, count); +} + +ssize_t __readlinkat_chk(int dirfd, const char* path, char* buf, size_t size, size_t buf_size) { + __check_count("readlinkat", "size", size); + __check_buffer_access("readlinkat", "write into", size, buf_size); + return readlinkat(dirfd, path, buf, size); +} + +ssize_t __readlink_chk(const char* path, char* buf, size_t size, size_t buf_size) { + __check_count("readlink", "size", size); + __check_buffer_access("readlink", "write into", size, buf_size); + return readlink(path, buf, size); +} + +ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buf_size, + int flags, sockaddr* src_addr, socklen_t* addrlen) { + __check_buffer_access("recvfrom", "write into", len, buf_size); + return recvfrom(socket, buf, len, flags, src_addr, addrlen); +} + +ssize_t __sendto_chk(int socket, const void* buf, size_t len, size_t buflen, + int flags, const struct sockaddr* dest_addr, + socklen_t addrlen) { + __check_buffer_access("sendto", "read from", len, buflen); + return sendto(socket, buf, len, flags, dest_addr, addrlen); +} + +// Runtime implementation of __builtin____stpcpy_chk (used directly by compiler, not in headers).. +extern "C" char* __stpcpy_chk(char* dst, const char* src, size_t dst_len) { + // TODO: optimize so we don't scan src twice. + size_t src_len = strlen(src) + 1; + __check_buffer_access("stpcpy", "write into", src_len, dst_len); + return stpcpy(dst, src); +} + +// Runtime implementation of __builtin____stpncpy_chk (used directly by compiler, not in headers). +extern "C" char* __stpncpy_chk(char* dst, const char* src, size_t len, size_t dst_len) { + __check_buffer_access("stpncpy", "write into", len, dst_len); + return stpncpy(dst, src, len); +} + +// This is a variant of __stpncpy_chk, but it also checks to make +// sure we don't read beyond the end of "src". The code for this is +// based on the original version of stpncpy, but modified to check +// how much we read from "src" during the copy operation. +char* __stpncpy_chk2(char* dst, const char* src, size_t n, size_t dst_len, size_t src_len) { + __check_buffer_access("stpncpy", "write into", n, dst_len); + if (n != 0) { + char* d = dst; + const char* s = src; + + do { + size_t s_copy_len = static_cast(s - src); + if (__predict_false(s_copy_len >= src_len)) { + __fortify_fatal("stpncpy: detected read past end of %zu-byte buffer", src_len); + } + + if ((*d++ = *s++) == 0) { + // NUL pad the remaining n-1 bytes. + while (--n != 0) { + *d++ = 0; + } + break; + } + } while (--n != 0); + } + + return dst; +} + +// strcat is performance-critical enough that we have assembler __strcat_chk implementations. +// This function is used to give better diagnostics than we can easily do from assembler. +extern "C" void __strcat_chk_fail(size_t dst_buf_size) { + __fortify_fatal("strcat: prevented write past end of %zu-byte buffer", dst_buf_size); +} + +char* __strchr_chk(const char* p, int ch, size_t s_len) { + for (;; ++p, s_len--) { + if (__predict_false(s_len == 0)) { + __fortify_fatal("strchr: prevented read past end of buffer"); + } + if (*p == static_cast(ch)) { + return const_cast(p); + } + if (*p == '\0') { + return nullptr; + } + } +} + +// strcpy is performance-critical enough that we have assembler __strcpy_chk implementations. +// This function is used to give better diagnostics than we can easily do from assembler. +extern "C" void __strcpy_chk_fail(size_t dst_buf_size) { + __fortify_fatal("strcpy: prevented write past end of %zu-byte buffer", dst_buf_size); +} + +size_t __strlcat_chk(char* dst, const char* src, + size_t supplied_size, size_t dst_len_from_compiler) { + __check_buffer_access("strlcat", "write into", supplied_size, dst_len_from_compiler); + return strlcat(dst, src, supplied_size); +} + +size_t __strlcpy_chk(char* dst, const char* src, + size_t supplied_size, size_t dst_len_from_compiler) { + __check_buffer_access("strlcpy", "write into", supplied_size, dst_len_from_compiler); + return strlcpy(dst, src, supplied_size); +} + +size_t __strlen_chk(const char* s, size_t s_len) { + // TODO: "prevented" here would be a lie because this strlen can run off the end. + // strlen is too important to be expensive, so we wanted to be able to call the optimized + // implementation, but I think we need to implement optimized assembler __strlen_chk routines. + size_t ret = strlen(s); + if (__predict_false(ret >= s_len)) { + __fortify_fatal("strlen: detected read past end of buffer"); + } + return ret; +} + +// Runtime implementation of __builtin____strncat_chk (used directly by compiler, not in headers). +extern "C" char* __strncat_chk(char* dst, const char* src, size_t len, size_t dst_buf_size) { + if (len == 0) { + return dst; + } + + size_t dst_len = __strlen_chk(dst, dst_buf_size); + char* d = dst + dst_len; + dst_buf_size -= dst_len; + + while (*src != '\0') { + *d++ = *src++; + len--; dst_buf_size--; + + if (__predict_false(dst_buf_size == 0)) { + __fortify_fatal("strncat: prevented write past end of buffer"); + } + + if (len == 0) { + break; + } + } + + *d = '\0'; + return dst; +} + +// Runtime implementation of __builtin____strncpy_chk (used directly by compiler, not in headers). +extern "C" char* __strncpy_chk(char* dst, const char* src, size_t len, size_t dst_len) { + __check_buffer_access("strncpy", "write into", len, dst_len); + return strncpy(dst, src, len); +} + +// This is a variant of __strncpy_chk, but it also checks to make +// sure we don't read beyond the end of "src". The code for this is +// based on the original version of strncpy, but modified to check +// how much we read from "src" during the copy operation. +char* __strncpy_chk2(char* dst, const char* src, size_t n, size_t dst_len, size_t src_len) { + __check_buffer_access("strncpy", "write into", n, dst_len); + if (n != 0) { + char* d = dst; + const char* s = src; + + do { + size_t s_copy_len = static_cast(s - src); + if (__predict_false(s_copy_len >= src_len)) { + __fortify_fatal("strncpy: detected read past end of %zu-byte buffer", src_len); + } + + if ((*d++ = *s++) == 0) { + // NUL pad the remaining n-1 bytes. + while (--n != 0) { + *d++ = 0; + } + break; + } + } while (--n != 0); + } + + return dst; +} + +char* __strrchr_chk(const char* p, int ch, size_t s_len) { + for (const char* save = nullptr;; ++p, s_len--) { + if (s_len == 0) { + __fortify_fatal("strrchr: prevented read past end of buffer"); + } + if (*p == static_cast(ch)) { + save = p; + } + if (!*p) { + return const_cast(save); + } + } +} + +mode_t __umask_chk(mode_t mode) { + if (__predict_false((mode & 0777) != mode)) { + __fortify_fatal("umask: called with invalid mask %o", mode); + } + + return umask(mode); +} + +// Runtime implementation of __builtin____vsnprintf_chk (used directly by compiler, not in headers). +extern "C" int __vsnprintf_chk(char* dst, size_t supplied_size, int /*flags*/, + size_t dst_len_from_compiler, const char* format, va_list va) { + __check_buffer_access("vsnprintf", "write into", supplied_size, dst_len_from_compiler); + return vsnprintf(dst, supplied_size, format, va); +} + +// Runtime implementation of __builtin____snprintf_chk (used directly by compiler, not in headers). +extern "C" int __snprintf_chk(char* dst, size_t supplied_size, int flags, + size_t dst_len_from_compiler, const char* format, ...) { + va_list va; + va_start(va, format); + int result = __vsnprintf_chk(dst, supplied_size, flags, dst_len_from_compiler, format, va); + va_end(va); + return result; +} + +// Runtime implementation of __builtin____vsprintf_chk (used directly by compiler, not in headers). +extern "C" int __vsprintf_chk(char* dst, int /*flags*/, + size_t dst_len_from_compiler, const char* format, va_list va) { + // The compiler uses SIZE_MAX to mean "no idea", but our vsnprintf rejects sizes that large. + int result = vsnprintf(dst, + dst_len_from_compiler == SIZE_MAX ? SSIZE_MAX : dst_len_from_compiler, + format, va); + + // Try to catch failures after the fact... + __check_buffer_access("vsprintf", "write into", result + 1, dst_len_from_compiler); + return result; +} + +// Runtime implementation of __builtin____sprintf_chk (used directly by compiler, not in headers). +extern "C" int __sprintf_chk(char* dst, int flags, size_t dst_len_from_compiler, + const char* format, ...) { + va_list va; + va_start(va, format); + int result = __vsprintf_chk(dst, flags, dst_len_from_compiler, format, va); + va_end(va); + return result; +} + +ssize_t __write_chk(int fd, const void* buf, size_t count, size_t buf_size) { + __check_count("write", "count", count); + __check_buffer_access("write", "read from", count, buf_size); + return write(fd, buf, count); +} + +#if defined(RENAME___STRCAT_CHK) +#define __STRCAT_CHK __strcat_chk_generic +#else +#define __STRCAT_CHK __strcat_chk +#endif // RENAME___STRCAT_CHK + +// Runtime implementation of __builtin____strcat_chk (used directly by compiler, not in headers). +extern "C" char* __STRCAT_CHK(char* dst, const char* src, size_t dst_buf_size) { + char* save = dst; + size_t dst_len = __strlen_chk(dst, dst_buf_size); + + dst += dst_len; + dst_buf_size -= dst_len; + + while ((*dst++ = *src++) != '\0') { + dst_buf_size--; + if (__predict_false(dst_buf_size == 0)) { + __fortify_fatal("strcat: prevented write past end of %zu-byte buffer", dst_buf_size); + } + } + + return save; +} + +#if defined(RENAME___STRCPY_CHK) +#define __STRCPY_CHK __strcpy_chk_generic +#else +#define __STRCPY_CHK __strcpy_chk +#endif // RENAME___STRCPY_CHK + +// Runtime implementation of __builtin____strcpy_chk (used directly by compiler, not in headers). +extern "C" char* __STRCPY_CHK(char* dst, const char* src, size_t dst_len) { + // TODO: optimize so we don't scan src twice. + size_t src_len = strlen(src) + 1; + __check_buffer_access("strcpy", "write into", src_len, dst_len); + return strcpy(dst, src); +} + +#if !defined(NO___MEMCPY_CHK) +// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers). +extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) { + __check_count("memcpy", "count", count); + __check_buffer_access("memcpy", "write into", count, dst_len); + return memcpy(dst, src, count); +} +#endif // NO___MEMCPY_CHK + +// Runtime implementation of __mempcpy_chk (used directly by compiler, not in headers). +extern "C" void* __mempcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) { + __check_count("mempcpy", "count", count); + __check_buffer_access("mempcpy", "write into", count, dst_len); + return mempcpy(dst, src, count); +} diff --git a/aosp/bionic/libc/bionic/fpclassify.cpp b/aosp/bionic/libc/bionic/fpclassify.cpp new file mode 100644 index 000000000..7aa53f3e8 --- /dev/null +++ b/aosp/bionic/libc/bionic/fpclassify.cpp @@ -0,0 +1,106 @@ +/* + * 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 + +// Legacy cruft from before we had builtin implementations of the standard macros. +// No longer declared in our . + +extern "C" int __fpclassifyd(double d) { + return fpclassify(d); +} +__strong_alias(__fpclassify, __fpclassifyd); // glibc uses __fpclassify, BSD __fpclassifyd. + +extern "C" int __fpclassifyf(float f) { + return fpclassify(f); +} + +extern "C" int __isinf(double d) { + return isinf(d); +} +__strong_alias(isinf, __isinf); + +extern "C" int __isinff(float f) { + return isinf(f); +} +__strong_alias(isinff, __isinff); + +extern "C" int __isnan(double d) { + return isnan(d); +} +__strong_alias(isnan, __isnan); + +extern "C" int __isnanf(float f) { + return isnan(f); +} +__strong_alias(isnanf, __isnanf); + +extern "C" int __isfinite(double d) { + return isfinite(d); +} +__strong_alias(isfinite, __isfinite); + +extern "C" int __isfinitef(float f) { + return isfinite(f); +} +__strong_alias(isfinitef, __isfinitef); + +extern "C" int __isnormal(double d) { + return isnormal(d); +} +__strong_alias(isnormal, __isnormal); + +extern "C" int __isnormalf(float f) { + return isnormal(f); +} +__strong_alias(isnormalf, __isnormalf); + +extern "C" int __fpclassifyl(long double ld) { + return fpclassify(ld); +} + +extern "C" int __isinfl(long double ld) { + return isinf(ld); +} + +extern "C" int __isnanl(long double ld) { + return isnan(ld); +} + +extern "C" int __isfinitel(long double ld) { + return isfinite(ld); +} + +extern "C" int __isnormall(long double ld) { + return isnormal(ld); +} + +__strong_alias(isinfl, __isinfl); +__strong_alias(isnanl, __isnanl); +__strong_alias(isfinitel, __isfinitel); +__strong_alias(isnormall, __isnormall); diff --git a/aosp/bionic/libc/bionic/fsetxattr.cpp b/aosp/bionic/libc/bionic/fsetxattr.cpp new file mode 100644 index 000000000..00955bd16 --- /dev/null +++ b/aosp/bionic/libc/bionic/fsetxattr.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include + +#include "private/FdPath.h" + +extern "C" int __fsetxattr(int, const char*, const void*, size_t, int); + +int fsetxattr(int fd, const char* name, const void* value, size_t size, int flags) { + int saved_errno = errno; + int result = __fsetxattr(fd, name, value, size, flags); + if (result == 0 || errno != EBADF) { + return result; + } + + // fd could be an O_PATH file descriptor, and the kernel + // may not directly support fsetxattr() on such a file descriptor. + // Use /proc/self/fd instead to emulate this support. + int fd_flag = fcntl(fd, F_GETFL); + if (fd_flag == -1 || (fd_flag & O_PATH) == 0) { + errno = EBADF; + return -1; + } + + errno = saved_errno; + return setxattr(FdPath(fd).c_str(), name, value, size, flags); +} diff --git a/aosp/bionic/libc/bionic/ftruncate.cpp b/aosp/bionic/libc/bionic/ftruncate.cpp new file mode 100644 index 000000000..9936df042 --- /dev/null +++ b/aosp/bionic/libc/bionic/ftruncate.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 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 +#include +#include + +#if !defined(__LP64__) +static_assert(sizeof(off_t) == 4, + "libc can't be built with _FILE_OFFSET_BITS=64."); + +// The kernel's implementation of ftruncate uses an unsigned long for the length +// parameter, so it will not catch negative values. On the other hand +// ftruncate64 does check for this, so just forward the call. +int ftruncate(int filedes, off_t length) { + return ftruncate64(filedes, length); +} +#endif // !defined(__LP64__) diff --git a/aosp/bionic/libc/bionic/fts.c b/aosp/bionic/libc/bionic/fts.c new file mode 100644 index 000000000..8888ab18a --- /dev/null +++ b/aosp/bionic/libc/bionic/fts.c @@ -0,0 +1,1048 @@ +/* $OpenBSD: fts.c,v 1.48 2014/11/20 04:14:15 guenther Exp $ */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static FTSENT *fts_alloc(FTS *, char *, size_t); +static FTSENT *fts_build(FTS *, int); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS *, FTSENT *); +static int fts_palloc(FTS *, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, int); +static u_short fts_stat(FTS *, FTSENT *, int, int); +static int fts_safe_changedir(FTS *, FTSENT *, int, char *); + +#define ALIGNBYTES (sizeof(uintptr_t) - 1) +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) +void* reallocarray(void*, size_t, size_t); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +FTS* __fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, const FTSENT**)) { + FTS *sp; + FTSENT *p, *root; + int nitems; + FTSENT *parent, *tmp; + size_t len; + + /* Allocate/initialize the stream */ + if ((sp = calloc(1, sizeof(FTS))) == NULL) + return (NULL); + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + if ((p = fts_alloc(sp, *argv, len)) == NULL) + goto mem3; + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); + + // For ftw/nftw we need to fail early: http://b/31152735 + if ((options & FTS_FOR_FTW) != 0 && p->fts_info == FTS_NS) goto mem3; + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) + SET(FTS_NOCHDIR); + + if (nitems == 0) + free(parent); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + int rfd, error = 0; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Stash the original directory fd if needed. */ + rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd; + + /* Free up child linked list, sort array, path buffer, stream ptr.*/ + fts_lfree(sp->fts_child); + free(sp->fts_array); + free(sp->fts_path); + free(sp); + + /* Return to original directory, checking for error. */ + if (rfd != -1) { + int saved_errno; + error = fchdir(rfd); + saved_errno = errno; + (void)close(rfd); + errno = saved_errno; + } + + return (error); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0, -1); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p; p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link)) { + free(tmp); + + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + sp->fts_cur = p; + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + sp->fts_cur = p; + return (NULL); + } + (void)close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + sp->fts_cur = p; + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp __unused, FTSENT *p, int instr) +{ + if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + if (instr && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY|O_CLOEXEC, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void)close(fd); + return (NULL); + } + (void)close(fd); + return (sp->fts_child); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct dirent *dp; + FTSENT *p, *head; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t len, maxlen; + int nitems, cderrno, descend, level, nlinks, nostat = 0, doadjust; + int saved_errno; + char *cp = NULL; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ + if ((dirp = opendir(cur->fts_accpath)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) + nlinks = 0; + else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + (void)closedir(dirp); + dirp = NULL; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } + len++; + maxlen = sp->fts_pathlen - len; + + /* + * fts_level is signed so we must prevent it from wrapping + * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. + */ + level = cur->fts_level; + if (level < FTS_MAXLEVEL) + level++; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name)))) + goto mem1; + if (strlen(dp->d_name) >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + strlen(dp->d_name); + if (p->fts_pathlen < len) { + /* + * If we wrap, free up the current structure and + * the structures already allocated, then error + * out with ENAMETOOLONG. + */ + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + assert(cp && "cp should be non-null if FTS_NOCHDIR is set"); + memmove(cp, p->fts_name, p->fts_namelen + 1); // NOLINT + p->fts_info = fts_stat(sp, p, 0, dirfd(dirp)); + } else { + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, 0, -1); + } + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static u_short +fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) +{ + FTSENT *t; + dev_t dev; + ino_t ino; + struct stat *sbp, sb; + int saved_errno; + const char *path; + + if (dfd == -1) { + path = p->fts_accpath; + dfd = AT_FDCWD; + } else + path = p->fts_name; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (fstatat(dfd, path, sbp, 0) == -1) { + saved_errno = errno; + if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW) == 0) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(struct stat)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, int nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + struct _ftsent **a; + + sp->fts_nitems = nitems + 40; + if ((a = reallocarray(sp->fts_array, + sp->fts_nitems, sizeof(FTSENT *))) == NULL) { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + sp->fts_array = a; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, char *name, size_t namelen) +{ + FTSENT *p; + size_t len; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(struct stat) + ALIGNBYTES; + if ((p = calloc(1, len)) == NULL) + return (NULL); + + p->fts_path = sp->fts_path; + p->fts_namelen = namelen; + p->fts_instr = FTS_NOINSTR; + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); + memcpy(p->fts_name, name, namelen); + + return (p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than PATH_MAX, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more) +{ + char *p; + + /* + * Check for possible wraparound. + */ + more += 256; + if (sp->fts_pathlen + more < sp->fts_pathlen) { + free(sp->fts_path); + sp->fts_path = NULL; + errno = ENAMETOOLONG; + return (1); + } + sp->fts_pathlen += more; + p = realloc(sp->fts_path, sp->fts_pathlen); + if (p == NULL) { + free(sp->fts_path); + sp->fts_path = NULL; + return (1); + } + sp->fts_path = p; + return (0); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) +{ + int ret, oerrno, newfd; + struct stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0)) < 0) + return (-1); + if (fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)close(newfd); + errno = oerrno; + return (ret); +} + +FTS* fts_open(char* const* argv, int options, int (*compar)(const FTSENT**, const FTSENT**)) { + // Options check. + if ((options & ~FTS_OPTIONMASK) != 0) { + errno = EINVAL; + return NULL; + } + return __fts_open(argv, options, compar); +} diff --git a/aosp/bionic/libc/bionic/ftw.cpp b/aosp/bionic/libc/bionic/ftw.cpp new file mode 100644 index 000000000..71882b310 --- /dev/null +++ b/aosp/bionic/libc/bionic/ftw.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2003, 2004 Todd C. Miller + * + * 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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include +#include +#include +#include +#include +#include + +extern "C" FTS* __fts_open(char* const*, int, int (*)(const FTSENT**, const FTSENT**)); + +static int do_nftw(const char* path, + int (*ftw_fn)(const char*, const struct stat*, int), + int (*nftw_fn)(const char*, const struct stat*, int, FTW*), + int nfds, + int nftw_flags) { + // TODO: nfds is currently unused. + if (nfds < 1) { + errno = EINVAL; + return -1; + } + + // Translate to fts_open options. + int fts_options = FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR; + if (nftw_fn) { + fts_options = FTS_COMFOLLOW | ((nftw_flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL); + if (!(nftw_flags & FTW_CHDIR)) fts_options |= FTS_NOCHDIR; + if (nftw_flags & FTW_MOUNT) fts_options |= FTS_XDEV; + } + bool postorder = (nftw_flags & FTW_DEPTH) != 0; + + // Call fts_open. + char* const paths[2] = { const_cast(path), nullptr }; + FTS* fts = __fts_open(paths, fts_options | FTS_FOR_FTW, nullptr); + if (fts == nullptr) { + return -1; + } + + // Translate fts_read results into ftw/nftw callbacks. + int error = 0; + FTSENT* cur; + while (error == 0 && (cur = fts_read(fts)) != nullptr) { + int fn_flag; + switch (cur->fts_info) { + case FTS_D: + // In the postorder case, we'll translate FTS_DP to FTW_DP later. + // In the can't-access case, we'll translate FTS_DNR to FTW_DNR later. + if (postorder || access(cur->fts_path, R_OK) == -1) continue; + fn_flag = FTW_D; + break; + case FTS_DC: + // POSIX says nftw "shall not report" directories causing loops (http://b/31152735). + continue; + case FTS_DNR: + fn_flag = FTW_DNR; + break; + case FTS_DP: + if (!postorder) continue; + fn_flag = FTW_DP; + break; + case FTS_F: + case FTS_DEFAULT: + fn_flag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + fn_flag = FTW_NS; + break; + case FTS_SL: + fn_flag = FTW_SL; + break; + case FTS_SLNONE: + fn_flag = (nftw_fn != nullptr) ? FTW_SLN : FTW_NS; + break; + default: + error = -1; + continue; + } + + // Call the appropriate function. + if (nftw_fn != nullptr) { + FTW ftw; + ftw.base = cur->fts_pathlen - cur->fts_namelen; + ftw.level = cur->fts_level; + error = nftw_fn(cur->fts_path, cur->fts_statp, fn_flag, &ftw); + } else { + error = ftw_fn(cur->fts_path, cur->fts_statp, fn_flag); + } + } + + int saved_errno = errno; + if (fts_close(fts) != 0 && error == 0) { + error = -1; + } else { + errno = saved_errno; + } + return error; +} + +int ftw(const char* path, int (*ftw_fn)(const char*, const struct stat*, int), int nfds) { + return do_nftw(path, ftw_fn, nullptr, nfds, 0); +} + +int nftw(const char* path, int (*nftw_fn)(const char*, const struct stat*, int, FTW*), + int nfds, int nftw_flags) { + return do_nftw(path, nullptr, nftw_fn, nfds, nftw_flags); +} diff --git a/aosp/bionic/libc/bionic/futimens.cpp b/aosp/bionic/libc/bionic/futimens.cpp new file mode 100644 index 000000000..03f7e3865 --- /dev/null +++ b/aosp/bionic/libc/bionic/futimens.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int futimens(int fd, const struct timespec times[2]) { + return utimensat(fd, nullptr, times, 0); +} diff --git a/aosp/bionic/libc/bionic/get_device_api_level.cpp b/aosp/bionic/libc/bionic/get_device_api_level.cpp new file mode 100644 index 000000000..dd955d602 --- /dev/null +++ b/aosp/bionic/libc/bionic/get_device_api_level.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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. + */ + +#define __BIONIC_GET_DEVICE_API_LEVEL_INLINE /* Out of line. */ +#include diff --git a/aosp/bionic/libc/bionic/getauxval.cpp b/aosp/bionic/libc/bionic/getauxval.cpp new file mode 100644 index 000000000..d6f75f83a --- /dev/null +++ b/aosp/bionic/libc/bionic/getauxval.cpp @@ -0,0 +1,56 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +// This function needs to be safe to call before TLS is set up, so it can't +// access errno or the stack protector. +__LIBC_HIDDEN__ unsigned long __bionic_getauxval(unsigned long type, bool& exists) { + for (ElfW(auxv_t)* v = __libc_shared_globals()->auxv; v->a_type != AT_NULL; ++v) { + if (v->a_type == type) { + exists = true; + return v->a_un.a_val; + } + } + exists = false; + return 0; +} + +extern "C" unsigned long getauxval(unsigned long type) { + bool exists; + unsigned long result = __bionic_getauxval(type, exists); + if (!exists) errno = ENOENT; + return result; +} diff --git a/aosp/bionic/libc/bionic/getcwd.cpp b/aosp/bionic/libc/bionic/getcwd.cpp new file mode 100644 index 000000000..c42d4d582 --- /dev/null +++ b/aosp/bionic/libc/bionic/getcwd.cpp @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include +#include + +extern "C" int __getcwd(char* buf, size_t size); + +char* getcwd(char* buf, size_t size) { + // You can't specify size 0 unless you're asking us to allocate for you. + if (buf != nullptr && size == 0) { + errno = EINVAL; + return nullptr; + } + + // Allocate a buffer if necessary. + char* allocated_buf = nullptr; + size_t allocated_size = size; + if (buf == nullptr) { + if (size == 0) { + // The Linux kernel won't return more than a page, so translate size 0 to 4KiB. + // TODO: if we need to support paths longer than that, we'll have to walk the tree ourselves. + allocated_size = getpagesize(); + } + buf = allocated_buf = static_cast(malloc(allocated_size)); + if (buf == nullptr) { + return nullptr; + } + } + + // Ask the kernel to fill our buffer. + int rc = __getcwd(buf, allocated_size); + if (rc == -1) { + free(allocated_buf); + // __getcwd set errno. + return nullptr; + } + + // If we allocated a whole page, only return as large an allocation as necessary. + if (allocated_buf != nullptr) { + if (size == 0) { + buf = strdup(allocated_buf); + free(allocated_buf); + } else { + buf = allocated_buf; + } + } + + return buf; +} diff --git a/aosp/bionic/libc/bionic/getdomainname.cpp b/aosp/bionic/libc/bionic/getdomainname.cpp new file mode 100644 index 000000000..761a99926 --- /dev/null +++ b/aosp/bionic/libc/bionic/getdomainname.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 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 +#include +#include +#include + +int getdomainname(char* name, size_t len) { + utsname uts; + if (uname(&uts) == -1) return -1; + + // Note: getdomainname()'s behavior varies across implementations when len is + // too small. bionic follows the historical libc policy of returning EINVAL, + // instead of glibc's policy of copying the first len bytes without a NULL + // terminator. + if (strlen(uts.domainname) >= len) { + errno = EINVAL; + return -1; + } + + strncpy(name, uts.domainname, len); + return 0; +} diff --git a/aosp/bionic/libc/bionic/getentropy.cpp b/aosp/bionic/libc/bionic/getentropy.cpp new file mode 100644 index 000000000..9c93e713b --- /dev/null +++ b/aosp/bionic/libc/bionic/getentropy.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include + +#include "private/ScopedFd.h" + +static int getentropy_urandom(void* buffer, size_t buffer_size, int saved_errno) { + ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0))); + if (fd.get() == -1) return -1; + + size_t collected = 0; + while (collected < buffer_size) { + ssize_t count = TEMP_FAILURE_RETRY(read(fd.get(), static_cast(buffer) + collected, + buffer_size - collected)); + if (count == -1) return -1; + collected += count; + } + + errno = saved_errno; + return 0; +} + +int getentropy(void* buffer, size_t buffer_size) { + if (buffer_size > 256) { + errno = EIO; + return -1; + } + + int saved_errno = errno; + + size_t collected = 0; + while (collected < buffer_size) { + long count = TEMP_FAILURE_RETRY(getrandom(static_cast(buffer) + collected, + buffer_size - collected, GRND_NONBLOCK)); + if (count == -1) { + // EAGAIN: there isn't enough entropy right now. + // ENOSYS/EINVAL: getrandom(2) or GRND_NONBLOCK isn't supported. + // EFAULT: `buffer` is invalid. + // Try /dev/urandom regardless because it can't hurt, + // and we don't need to optimize the EFAULT case. + // See http://b/33059407 and http://b/67015565. + return getentropy_urandom(buffer, buffer_size, saved_errno); + } + collected += count; + } + + errno = saved_errno; + return 0; +} diff --git a/aosp/bionic/libc/bionic/gethostname.cpp b/aosp/bionic/libc/bionic/gethostname.cpp new file mode 100644 index 000000000..962fea1b1 --- /dev/null +++ b/aosp/bionic/libc/bionic/gethostname.cpp @@ -0,0 +1,48 @@ +/* + * 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 +#include +#include +#include + +int gethostname(char* buf, size_t n) { + struct utsname name; + if (uname(&name) == -1) { + return -1; + } + + size_t name_length = static_cast(strlen(name.nodename) + 1); + if (name_length > n) { + errno = ENAMETOOLONG; + return -1; + } + + memcpy(buf, name.nodename, name_length); + return 0; +} diff --git a/aosp/bionic/libc/bionic/getloadavg.cpp b/aosp/bionic/libc/bionic/getloadavg.cpp new file mode 100644 index 000000000..28d316cfa --- /dev/null +++ b/aosp/bionic/libc/bionic/getloadavg.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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 + +#include + +int getloadavg(double averages[], int n) { + if (n < 0) return -1; + if (n > 3) n = 3; + + struct sysinfo si; + if (sysinfo(&si) == -1) return -1; + + for (int i = 0; i < n; ++i) { + averages[i] = static_cast(si.loads[i]) / static_cast(1 << SI_LOAD_SHIFT); + } + return n; +} diff --git a/aosp/bionic/libc/bionic/getpagesize.cpp b/aosp/bionic/libc/bionic/getpagesize.cpp new file mode 100644 index 000000000..3a5990025 --- /dev/null +++ b/aosp/bionic/libc/bionic/getpagesize.cpp @@ -0,0 +1,35 @@ +/* + * 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 + +// Portable code should use sysconf(_SC_PAGE_SIZE) directly instead. +int getpagesize() { + // We dont use sysconf(3) here because that drags in stdio, which makes static binaries fat. + return PAGE_SIZE; +} diff --git a/aosp/bionic/libc/bionic/getpgrp.cpp b/aosp/bionic/libc/bionic/getpgrp.cpp new file mode 100644 index 000000000..9bacbb388 --- /dev/null +++ b/aosp/bionic/libc/bionic/getpgrp.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +pid_t getpgrp() { + return getpgid(0); +} diff --git a/aosp/bionic/libc/bionic/getpid.cpp b/aosp/bionic/libc/bionic/getpid.cpp new file mode 100644 index 000000000..c6eb586f1 --- /dev/null +++ b/aosp/bionic/libc/bionic/getpid.cpp @@ -0,0 +1,55 @@ +/* + * 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 + +#include "pthread_internal.h" + +extern "C" pid_t __getpid(); + +pid_t __get_cached_pid() { + pthread_internal_t* self = __get_thread(); + if (__predict_true(self)) { + pid_t cached_pid; + if (__predict_true(self->get_cached_pid(&cached_pid))) { + return cached_pid; + } + } + return 0; +} + +pid_t getpid() { + pid_t cached_pid = __get_cached_pid(); + if (__predict_true(cached_pid != 0)) { + return cached_pid; + } + + // We're still in the dynamic linker or we're in the middle of forking, so ask the kernel. + // We don't know whether it's safe to update the cached value, so don't try. + return __getpid(); +} diff --git a/aosp/bionic/libc/bionic/getpriority.cpp b/aosp/bionic/libc/bionic/getpriority.cpp new file mode 100644 index 000000000..7f0eb1c9d --- /dev/null +++ b/aosp/bionic/libc/bionic/getpriority.cpp @@ -0,0 +1,36 @@ +/* + * 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 + +extern "C" int __getpriority(int, id_t); + +int getpriority(int which, id_t who) { + int result = __getpriority(which, who); + return (result < 0) ? result : 20-result; +} diff --git a/aosp/bionic/libc/bionic/gettid.cpp b/aosp/bionic/libc/bionic/gettid.cpp new file mode 100644 index 000000000..eb5cfd6ab --- /dev/null +++ b/aosp/bionic/libc/bionic/gettid.cpp @@ -0,0 +1,45 @@ +/* + * 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 +#include + +#include "pthread_internal.h" + +pid_t gettid() { + pthread_internal_t* self = __get_thread(); + if (__predict_true(self)) { + pid_t tid = self->tid; + if (__predict_true(tid != -1)) { + return tid; + } + self->tid = syscall(__NR_gettid); + return self->tid; + } + return syscall(__NR_gettid); +} diff --git a/aosp/bionic/libc/bionic/grp_pwd.cpp b/aosp/bionic/libc/bionic/grp_pwd.cpp new file mode 100644 index 000000000..dd8df95f2 --- /dev/null +++ b/aosp/bionic/libc/bionic/grp_pwd.cpp @@ -0,0 +1,816 @@ +/* + * 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/grp_pwd.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/ErrnoRestorer.h" +#include "private/android_filesystem_config.h" +#include "platform/bionic/macros.h" + +// Generated android_ids array +#include "generated_android_ids.h" +#include "grp_pwd_file.h" + +static PasswdFile passwd_files[] = { + { "/system/etc/passwd", "system_" }, + { "/vendor/etc/passwd", "vendor_" }, + { "/odm/etc/passwd", "odm_" }, + { "/product/etc/passwd", "product_" }, + { "/system_ext/etc/passwd", "system_ext_" }, +}; + +static GroupFile group_files[] = { + { "/system/etc/group", "system_" }, + { "/vendor/etc/group", "vendor_" }, + { "/odm/etc/group", "odm_" }, + { "/product/etc/group", "product_" }, + { "/system_ext/etc/group", "system_ext_" }, +}; + +// POSIX seems to envisage an implementation where the functions are +// implemented by brute-force searching with getpwent(3), and the +// functions are implemented similarly with getgrent(3). This means that it's +// okay for all the functions to share state, and all the +// functions to share state, but functions can't clobber +// functions' state and vice versa. +#include "bionic/pthread_internal.h" + +static void init_group_state(group_state_t* state) { + memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx)); + state->group_.gr_name = state->group_name_buffer_; + state->group_.gr_mem = state->group_members_; + state->group_.gr_mem[0] = state->group_.gr_name; +} + +static group_state_t* get_group_tls_buffer() { + auto result = &__get_bionic_tls().group; + init_group_state(result); + return result; +} + +static void init_passwd_state(passwd_state_t* state) { + memset(state, 0, sizeof(passwd_state_t) - sizeof(state->getpwent_idx)); + state->passwd_.pw_name = state->name_buffer_; + state->passwd_.pw_dir = state->dir_buffer_; + state->passwd_.pw_shell = state->sh_buffer_; +} + +static passwd_state_t* get_passwd_tls_buffer() { + auto result = &__get_bionic_tls().passwd; + init_passwd_state(result); + return result; +} + +static passwd* android_iinfo_to_passwd(passwd_state_t* state, + const android_id_info* iinfo) { + snprintf(state->name_buffer_, sizeof(state->name_buffer_), "%s", iinfo->name); + snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/"); + snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh"); + + passwd* pw = &state->passwd_; + pw->pw_uid = iinfo->aid; + pw->pw_gid = iinfo->aid; + return pw; +} + +static group* android_iinfo_to_group(group_state_t* state, + const android_id_info* iinfo) { + snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), "%s", iinfo->name); + + group* gr = &state->group_; + gr->gr_gid = iinfo->aid; + return gr; +} + +static const android_id_info* find_android_id_info(unsigned id) { + for (size_t n = 0; n < android_id_count; ++n) { + if (android_ids[n].aid == id) { + return &android_ids[n]; + } + } + return nullptr; +} + +static const android_id_info* find_android_id_info(const char* name) { + for (size_t n = 0; n < android_id_count; ++n) { + if (!strcmp(android_ids[n].name, name)) { + return &android_ids[n]; + } + } + return nullptr; +} + +// These are a list of the reserved app ranges, and should never contain anything below +// AID_APP_START. They exist per user, so a given uid/gid modulo AID_USER_OFFSET will map +// to these ranges. +struct IdRange { + id_t start; + id_t end; +}; + +static constexpr IdRange user_ranges[] = { + { AID_APP_START, AID_APP_END }, + { AID_ISOLATED_START, AID_ISOLATED_END }, +}; + +static constexpr IdRange group_ranges[] = { + { AID_APP_START, AID_APP_END }, + { AID_CACHE_GID_START, AID_CACHE_GID_END }, + { AID_EXT_GID_START, AID_EXT_GID_END }, + { AID_EXT_CACHE_GID_START, AID_EXT_CACHE_GID_END }, + { AID_SHARED_GID_START, AID_SHARED_GID_END }, + { AID_ISOLATED_START, AID_ISOLATED_END }, +}; + +template +static constexpr bool verify_user_ranges_ascending(T (&ranges)[N]) { + auto array_size = N; + if (array_size < 2) return false; + + if (ranges[0].start > ranges[0].end) return false; + + for (size_t i = 1; i < array_size; ++i) { + if (ranges[i].start > ranges[i].end) return false; + if (ranges[i - 1].end > ranges[i].start) return false; + } + return true; +} + +static_assert(verify_user_ranges_ascending(user_ranges), "user_ranges must have ascending ranges"); +static_assert(verify_user_ranges_ascending(group_ranges), "user_ranges must have ascending ranges"); + +// This list comes from PackageManagerService.java, where platform AIDs are added to list of valid +// AIDs for packages via addSharedUserLPw(). +static constexpr const id_t secondary_user_platform_ids[] = { + AID_SYSTEM, AID_RADIO, AID_LOG, AID_NFC, AID_BLUETOOTH, + AID_SHELL, AID_SECURE_ELEMENT, AID_NETWORK_STACK, +}; + +static bool platform_id_secondary_user_allowed(id_t id) { + for (const auto& allowed_id : secondary_user_platform_ids) { + if (allowed_id == id) { + return true; + } + } + return false; +} + +static bool is_valid_app_id(id_t id, bool is_group) { + id_t appid = id % AID_USER_OFFSET; + + // AID_OVERFLOWUID is never a valid app id, so we explicitly return false to ensure this. + // This is true across all users, as there is no reason to ever map this id into any user range. + if (appid == AID_OVERFLOWUID) { + return false; + } + + auto ranges_size = is_group ? arraysize(group_ranges) : arraysize(user_ranges); + auto ranges = is_group ? group_ranges : user_ranges; + + // If we're checking an appid that resolves below the user range, then it's a platform AID for a + // seconary user. We only allow a reduced set of these, so we must check that it is allowed. + if (appid < ranges[0].start && platform_id_secondary_user_allowed(appid)) { + return true; + } + + // The shared GID range is only valid for the first user. + if (appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END && appid != id) { + return false; + } + + // Otherwise check that the appid is in one of the reserved ranges. + for (size_t i = 0; i < ranges_size; ++i) { + if (appid >= ranges[i].start && appid <= ranges[i].end) { + return true; + } + } + + return false; +} + +// This provides an iterater for app_ids within the first user's app id's. +static id_t get_next_app_id(id_t current_id, bool is_group) { + auto ranges_size = is_group ? arraysize(group_ranges) : arraysize(user_ranges); + auto ranges = is_group ? group_ranges : user_ranges; + + // If current_id is below the first of the ranges, then we're uninitialized, and return the first + // valid id. + if (current_id < ranges[0].start) { + return ranges[0].start; + } + + id_t incremented_id = current_id + 1; + + // Check to see if our incremented_id is between two ranges, and if so, return the beginning of + // the next valid range. + for (size_t i = 1; i < ranges_size; ++i) { + if (incremented_id > ranges[i - 1].end && incremented_id < ranges[i].start) { + return ranges[i].start; + } + } + + // Check to see if our incremented_id is above final range, and return -1 to indicate that we've + // completed if so. + if (incremented_id > ranges[ranges_size - 1].end) { + return -1; + } + + // Otherwise the incremented_id is valid, so return it. + return incremented_id; +} + +// Translate a user/group name to the corresponding user/group id. +// all_a1234 -> 0 * AID_USER_OFFSET + AID_SHARED_GID_START + 1234 (group name only) +// u0_a1234_ext_cache -> 0 * AID_USER_OFFSET + AID_EXT_CACHE_GID_START + 1234 (group name only) +// u0_a1234_ext -> 0 * AID_USER_OFFSET + AID_EXT_GID_START + 1234 (group name only) +// u0_a1234_cache -> 0 * AID_USER_OFFSET + AID_CACHE_GID_START + 1234 (group name only) +// u0_a1234 -> 0 * AID_USER_OFFSET + AID_APP_START + 1234 +// u2_i1000 -> 2 * AID_USER_OFFSET + AID_ISOLATED_START + 1000 +// u1_system -> 1 * AID_USER_OFFSET + android_ids['system'] +// returns 0 and sets errno to ENOENT in case of error. +static id_t app_id_from_name(const char* name, bool is_group) { + char* end; + unsigned long userid; + bool is_shared_gid = false; + + if (is_group && name[0] == 'a' && name[1] == 'l' && name[2] == 'l') { + end = const_cast(name+3); + userid = 0; + is_shared_gid = true; + } else if (name[0] == 'u' && isdigit(name[1])) { + userid = strtoul(name+1, &end, 10); + } else { + errno = ENOENT; + return 0; + } + + if (end[0] != '_' || end[1] == 0) { + errno = ENOENT; + return 0; + } + + unsigned long appid = 0; + if (end[1] == 'a' && isdigit(end[2])) { + if (is_shared_gid) { + // end will point to \0 if the strtoul below succeeds. + appid = strtoul(end+2, &end, 10) + AID_SHARED_GID_START; + if (appid > AID_SHARED_GID_END) { + errno = ENOENT; + return 0; + } + } else { + // end will point to \0 if the strtoul below succeeds. + appid = strtoul(end+2, &end, 10); + if (is_group) { + if (!strcmp(end, "_ext_cache")) { + end += 10; + appid += AID_EXT_CACHE_GID_START; + } else if (!strcmp(end, "_ext")) { + end += 4; + appid += AID_EXT_GID_START; + } else if (!strcmp(end, "_cache")) { + end += 6; + appid += AID_CACHE_GID_START; + } else { + appid += AID_APP_START; + } + } else { + appid += AID_APP_START; + } + } + } else if (end[1] == 'i' && isdigit(end[2])) { + // end will point to \0 if the strtoul below succeeds. + appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START; + } else if (auto* android_id_info = find_android_id_info(end + 1); android_id_info != nullptr) { + appid = android_id_info->aid; + end += strlen(android_id_info->name) + 1; + if (!platform_id_secondary_user_allowed(appid)) { + errno = ENOENT; + return 0; + } + } + + // Check that the entire string was consumed by one of the 3 cases above. + if (end[0] != 0) { + errno = ENOENT; + return 0; + } + + // Check that user id won't overflow. + if (userid > 1000) { + errno = ENOENT; + return 0; + } + + // Check that app id is within range. + if (appid >= AID_USER_OFFSET) { + errno = ENOENT; + return 0; + } + + return (appid + userid*AID_USER_OFFSET); +} + +static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) { + const uid_t appid = uid % AID_USER_OFFSET; + const uid_t userid = uid / AID_USER_OFFSET; + if (appid >= AID_ISOLATED_START) { + snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START); + } else if (appid < AID_APP_START) { + if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) { + snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name); + } + } else { + snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START); + } +} + +static void print_app_name_from_gid(const gid_t gid, char* buffer, const int bufferlen) { + const uid_t appid = gid % AID_USER_OFFSET; + const uid_t userid = gid / AID_USER_OFFSET; + if (appid >= AID_ISOLATED_START) { + snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START); + } else if (userid == 0 && appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END) { + snprintf(buffer, bufferlen, "all_a%u", appid - AID_SHARED_GID_START); + } else if (appid >= AID_EXT_CACHE_GID_START && appid <= AID_EXT_CACHE_GID_END) { + snprintf(buffer, bufferlen, "u%u_a%u_ext_cache", userid, appid - AID_EXT_CACHE_GID_START); + } else if (appid >= AID_EXT_GID_START && appid <= AID_EXT_GID_END) { + snprintf(buffer, bufferlen, "u%u_a%u_ext", userid, appid - AID_EXT_GID_START); + } else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) { + snprintf(buffer, bufferlen, "u%u_a%u_cache", userid, appid - AID_CACHE_GID_START); + } else if (appid < AID_APP_START) { + if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) { + snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name); + } + } else { + snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START); + } +} + +static bool device_launched_before_api_29() { + // Check if ro.product.first_api_level is set to a value > 0 and < 29, if so, this device was + // launched before API 29 (Q). Any other value is considered to be either in development or + // launched after. + // Cache the value as __system_property_get() is expensive and this may be called often. + static bool result = [] { + char value[PROP_VALUE_MAX] = { 0 }; + if (__system_property_get("ro.product.first_api_level", value) == 0) { + return false; + } + int value_int = atoi(value); + return value_int != 0 && value_int < 29; + }(); + return result; +} + +// oem_XXXX -> uid +// Supported ranges: +// AID_OEM_RESERVED_START to AID_OEM_RESERVED_END (2900-2999) +// AID_OEM_RESERVED_2_START to AID_OEM_RESERVED_2_END (5000-5999) +// Check OEM id is within range. +static bool is_oem_id(id_t id) { + // Upgrading devices launched before API level 29 may not comply with the below check. + // Due to the difficulty in changing uids after launch, it is waived for these devices. + // The legacy range: + // AID_OEM_RESERVED_START to AID_EVERYBODY (2900-9996), excluding builtin AIDs. + if (device_launched_before_api_29() && id >= AID_OEM_RESERVED_START && id < AID_EVERYBODY && + find_android_id_info(id) == nullptr) { + return true; + } + + return (id >= AID_OEM_RESERVED_START && id <= AID_OEM_RESERVED_END) || + (id >= AID_OEM_RESERVED_2_START && id <= AID_OEM_RESERVED_2_END); +} + +// Translate an OEM name to the corresponding user/group id. +static id_t oem_id_from_name(const char* name) { + unsigned int id; + if (sscanf(name, "oem_%u", &id) != 1) { + return 0; + } + if (!is_oem_id(id)) { + return 0; + } + return static_cast(id); +} + +static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) { + for (auto& passwd_file : passwd_files) { + if (passwd_file.FindById(uid, state)) { + return &state->passwd_; + } + } + + if (!is_oem_id(uid)) { + return nullptr; + } + + snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u", uid); + snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/"); + snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh"); + + passwd* pw = &state->passwd_; + pw->pw_uid = uid; + pw->pw_gid = uid; + return pw; +} + +static group* oem_id_to_group(gid_t gid, group_state_t* state) { + for (auto& group_file : group_files) { + if (group_file.FindById(gid, state)) { + return &state->group_; + } + } + + if (!is_oem_id(gid)) { + return nullptr; + } + + snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), + "oem_%u", gid); + + group* gr = &state->group_; + gr->gr_gid = gid; + return gr; +} + +// Translate a uid into the corresponding name. +// 0 to AID_APP_START-1 -> "system", "radio", etc. +// AID_APP_START to AID_ISOLATED_START-1 -> u0_a1234 +// AID_ISOLATED_START to AID_USER_OFFSET-1 -> u0_i1234 +// AID_USER_OFFSET+ -> u1_radio, u1_a1234, u2_i1234, etc. +// returns a passwd structure (sets errno to ENOENT on failure). +static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) { + if (uid < AID_APP_START || !is_valid_app_id(uid, false)) { + errno = ENOENT; + return nullptr; + } + + print_app_name_from_uid(uid, state->name_buffer_, sizeof(state->name_buffer_)); + + const uid_t appid = uid % AID_USER_OFFSET; + if (appid < AID_APP_START) { + snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/"); + } else { + snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data"); + } + + snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh"); + + passwd* pw = &state->passwd_; + pw->pw_uid = uid; + pw->pw_gid = uid; + return pw; +} + +// Translate a gid into the corresponding app_ +// group structure (sets errno to ENOENT on failure). +static group* app_id_to_group(gid_t gid, group_state_t* state) { + if (gid < AID_APP_START || !is_valid_app_id(gid, true)) { + errno = ENOENT; + return nullptr; + } + + print_app_name_from_gid(gid, state->group_name_buffer_, sizeof(state->group_name_buffer_)); + + group* gr = &state->group_; + gr->gr_gid = gid; + return gr; +} + +passwd* getpwuid_internal(uid_t uid, passwd_state_t* state) { + if (auto* android_id_info = find_android_id_info(uid); android_id_info != nullptr) { + return android_iinfo_to_passwd(state, android_id_info); + } + + // Handle OEM range. + passwd* pw = oem_id_to_passwd(uid, state); + if (pw != nullptr) { + return pw; + } + return app_id_to_passwd(uid, state); +} + +passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function. + passwd_state_t* state = get_passwd_tls_buffer(); + return getpwuid_internal(uid, state); +} + +passwd* getpwnam_internal(const char* login, passwd_state_t* state) { + if (auto* android_id_info = find_android_id_info(login); android_id_info != nullptr) { + return android_iinfo_to_passwd(state, android_id_info); + } + + for (auto& passwd_file : passwd_files) { + if (passwd_file.FindByName(login, state)) { + return &state->passwd_; + } + } + + // Handle OEM range. + passwd* pw = oem_id_to_passwd(oem_id_from_name(login), state); + if (pw != nullptr) { + return pw; + } + return app_id_to_passwd(app_id_from_name(login, false), state); +} + +passwd* getpwnam(const char* login) { // NOLINT: implementing bad function. + passwd_state_t* state = get_passwd_tls_buffer(); + return getpwnam_internal(login, state); +} + +static int getpasswd_r(bool by_name, const char* name, uid_t uid, struct passwd* pwd, char* buf, + size_t buflen, struct passwd** result) { + ErrnoRestorer errno_restorer; + *result = nullptr; + char* p = + reinterpret_cast(__BIONIC_ALIGN(reinterpret_cast(buf), sizeof(uintptr_t))); + if (p + sizeof(passwd_state_t) > buf + buflen) { + return ERANGE; + } + passwd_state_t* state = reinterpret_cast(p); + init_passwd_state(state); + passwd* retval = (by_name ? getpwnam_internal(name, state) : getpwuid_internal(uid, state)); + if (retval != nullptr) { + *pwd = *retval; + *result = pwd; + return 0; + } + return errno; +} + +int getpwnam_r(const char* name, passwd* pwd, char* buf, size_t byte_count, passwd** result) { + return getpasswd_r(true, name, -1, pwd, buf, byte_count, result); +} + +int getpwuid_r(uid_t uid, passwd* pwd, char* buf, size_t byte_count, passwd** result) { + return getpasswd_r(false, nullptr, uid, pwd, buf, byte_count, result); +} + +// All users are in just one group, the one passed in. +int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) { + if (*ngroups < 1) { + *ngroups = 1; + return -1; + } + groups[0] = group; + return (*ngroups = 1); +} + +char* getlogin() { // NOLINT: implementing bad function. + passwd *pw = getpwuid(getuid()); // NOLINT: implementing bad function in terms of bad function. + return pw ? pw->pw_name : nullptr; +} + +int getlogin_r(char* buf, size_t size) { + char* login = getlogin(); + if (login == nullptr) return errno; + size_t login_length = strlen(login) + 1; + if (login_length > size) return ERANGE; + memcpy(buf, login, login_length); + return 0; +} + +void setpwent() { + passwd_state_t* state = get_passwd_tls_buffer(); + if (state) { + state->getpwent_idx = 0; + } +} + +void endpwent() { + setpwent(); +} + +passwd* getpwent() { + passwd_state_t* state = get_passwd_tls_buffer(); + if (state->getpwent_idx < 0) { + return nullptr; + } + + size_t start = 0; + ssize_t end = android_id_count; + if (state->getpwent_idx < end) { + return android_iinfo_to_passwd(state, android_ids + state->getpwent_idx++); + } + + start = end; + end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1; + + if (state->getpwent_idx < end) { + return oem_id_to_passwd( + state->getpwent_idx++ - start + AID_OEM_RESERVED_START, state); + } + + start = end; + end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1; + + if (state->getpwent_idx < end) { + return oem_id_to_passwd( + state->getpwent_idx++ - start + AID_OEM_RESERVED_2_START, state); + } + + start = end; + end += AID_SYSTEM_EXT_RESERVED_END - AID_SYSTEM_RESERVED_START + 1; + + if (state->getpwent_idx < end) { + // No one calls this enough to worry about how inefficient the below is. + auto* oem_passwd = + oem_id_to_passwd(state->getpwent_idx++ - start + AID_SYSTEM_RESERVED_START, state); + while (oem_passwd == nullptr && state->getpwent_idx < end) { + oem_passwd = + oem_id_to_passwd(state->getpwent_idx++ - start + AID_SYSTEM_RESERVED_START, state); + } + if (oem_passwd != nullptr) { + return oem_passwd; + } + } + + state->getpwent_idx = get_next_app_id(state->getpwent_idx, false); + + if (state->getpwent_idx != -1) { + return app_id_to_passwd(state->getpwent_idx, state); + } + + // We are not reporting u1_a* and higher or we will be here forever + return nullptr; +} + +static group* getgrgid_internal(gid_t gid, group_state_t* state) { + if (auto* android_id_info = find_android_id_info(gid); android_id_info != nullptr) { + return android_iinfo_to_group(state, android_id_info); + } + + // Handle OEM range. + group* grp = oem_id_to_group(gid, state); + if (grp != nullptr) { + return grp; + } + return app_id_to_group(gid, state); +} + +group* getgrgid(gid_t gid) { // NOLINT: implementing bad function. + group_state_t* state = get_group_tls_buffer(); + return getgrgid_internal(gid, state); +} + +static group* getgrnam_internal(const char* name, group_state_t* state) { + if (auto* android_id_info = find_android_id_info(name); android_id_info != nullptr) { + return android_iinfo_to_group(state, android_id_info); + } + + for (auto& group_file : group_files) { + if (group_file.FindByName(name, state)) { + return &state->group_; + } + } + + // Handle OEM range. + group* grp = oem_id_to_group(oem_id_from_name(name), state); + if (grp != nullptr) { + return grp; + } + return app_id_to_group(app_id_from_name(name, true), state); +} + +group* getgrnam(const char* name) { // NOLINT: implementing bad function. + group_state_t* state = get_group_tls_buffer(); + return getgrnam_internal(name, state); +} + +static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf, + size_t buflen, struct group** result) { + ErrnoRestorer errno_restorer; + *result = nullptr; + char* p = reinterpret_cast( + __BIONIC_ALIGN(reinterpret_cast(buf), sizeof(uintptr_t))); + if (p + sizeof(group_state_t) > buf + buflen) { + return ERANGE; + } + group_state_t* state = reinterpret_cast(p); + init_group_state(state); + group* retval = (by_name ? getgrnam_internal(name, state) : getgrgid_internal(gid, state)); + if (retval != nullptr) { + *grp = *retval; + *result = grp; + return 0; + } + return errno; +} + +int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) { + return getgroup_r(false, nullptr, gid, grp, buf, buflen, result); +} + +int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen, + struct group **result) { + return getgroup_r(true, name, 0, grp, buf, buflen, result); +} + +void setgrent() { + group_state_t* state = get_group_tls_buffer(); + if (state) { + state->getgrent_idx = 0; + } +} + +void endgrent() { + setgrent(); +} + +group* getgrent() { + group_state_t* state = get_group_tls_buffer(); + if (state->getgrent_idx < 0) { + return nullptr; + } + + size_t start = 0; + ssize_t end = android_id_count; + if (state->getgrent_idx < end) { + return android_iinfo_to_group(state, android_ids + state->getgrent_idx++); + } + + start = end; + end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1; + + if (state->getgrent_idx < end) { + return oem_id_to_group( + state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state); + } + + start = end; + end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1; + + if (state->getgrent_idx < end) { + return oem_id_to_group( + state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state); + } + + start = end; + end += AID_SYSTEM_EXT_RESERVED_END - AID_SYSTEM_RESERVED_START + 1; + + if (state->getgrent_idx < end) { + // No one calls this enough to worry about how inefficient the below is. + init_group_state(state); + auto* oem_group = + oem_id_to_group(state->getgrent_idx++ - start + AID_SYSTEM_RESERVED_START, state); + while (oem_group == nullptr && state->getgrent_idx < end) { + oem_group = oem_id_to_group(state->getgrent_idx++ - start + AID_SYSTEM_RESERVED_START, state); + } + if (oem_group != nullptr) { + return oem_group; + } + } + + start = end; + end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher groups + + state->getgrent_idx = get_next_app_id(state->getgrent_idx, true); + + if (state->getgrent_idx != -1) { + return app_id_to_group(state->getgrent_idx, state); + } + + // We are not reporting u1_a* and higher or we will be here forever + return nullptr; +} diff --git a/aosp/bionic/libc/bionic/grp_pwd_file.cpp b/aosp/bionic/libc/bionic/grp_pwd_file.cpp new file mode 100644 index 000000000..81cf8936d --- /dev/null +++ b/aosp/bionic/libc/bionic/grp_pwd_file.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2018 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 "grp_pwd_file.h" + +#include +#include +#include +#include +#include + +#include + +#include "private/ErrnoRestorer.h" +#include "private/ScopedFd.h" + +// This file mmap's /*/etc/passwd and /*/etc/group in order to return their contents without any +// allocations. Note that these files and the strings contained within them are explicitly not +// null-terminated. ':'s are used to deliminate fields and '\n's are used to deliminate lines. +// There is a check that the file ends with '\n', such that terminating loops at '\n' ensures that +// memory will be not read beyond the mmap region. + +namespace { + +void CopyFieldToString(char* dest, const char* source, size_t max) { + while (*source != ':' && *source != '\n' && max > 1) { + *dest++ = *source++; + --max; + } + *dest = '\0'; +} + +bool FieldToUid(const char* field, uid_t* uid) { + if (field == nullptr) { + return false; + } + + char* end = nullptr; + errno = 0; + uid_t result = strtoul(field, &end, 0); + if (errno != 0 || field == end || *end != ':') { + return false; + } + *uid = result; + return true; +} + +// Returns a pointer to one past the end of line. +const char* ParseLine(const char* begin, const char* end, const char** fields, size_t num_fields) { + size_t fields_written = 0; + const char* position = begin; + fields[fields_written++] = position; + + while (position < end && fields_written < num_fields) { + if (*position == '\n') { + return position + 1; + } + if (*position == ':') { + fields[fields_written++] = position + 1; + } + position++; + } + + while (position < end && *position != '\n') { + position++; + } + + return position + 1; +} + +struct PasswdLine { + const char* name() const { + return fields[0]; + } + // Password is not supported. + const char* uid() const { + return fields[2]; + } + const char* gid() const { + return fields[3]; + } + // User Info is not supported + const char* dir() const { + return fields[5]; + } + const char* shell() const { + return fields[6]; + } + + bool ToPasswdState(passwd_state_t* passwd_state) { + if (name() == nullptr || dir() == nullptr || shell() == nullptr) { + return false; + } + + uid_t uid; + if (!FieldToUid(this->uid(), &uid)) { + return false; + } + + gid_t gid; + if (!FieldToUid(this->gid(), &gid)) { + return false; + } + + passwd_state->passwd_.pw_uid = uid; + passwd_state->passwd_.pw_gid = gid; + + CopyFieldToString(passwd_state->name_buffer_, name(), sizeof(passwd_state->name_buffer_)); + passwd_state->passwd_.pw_name = passwd_state->name_buffer_; + + passwd_state->passwd_.pw_passwd = nullptr; + +#ifdef __LP64__ + passwd_state->passwd_.pw_gecos = nullptr; +#endif + + CopyFieldToString(passwd_state->dir_buffer_, dir(), sizeof(passwd_state->dir_buffer_)); + passwd_state->passwd_.pw_dir = passwd_state->dir_buffer_; + + CopyFieldToString(passwd_state->sh_buffer_, shell(), sizeof(passwd_state->sh_buffer_)); + passwd_state->passwd_.pw_shell = passwd_state->sh_buffer_; + + return true; + } + + static constexpr size_t kNumFields = 7; + const char* fields[kNumFields] = {}; +}; + +struct GroupLine { + const char* name() const { + return fields[0]; + } + // Password is not supported. + const char* gid() const { + return fields[2]; + } + // User list is not supported (returns simply name) + + bool ToGroupState(group_state_t* group_state) { + if (name() == nullptr || gid() == nullptr) { + return false; + } + + gid_t gid; + if (!FieldToUid(this->gid(), &gid)) { + return false; + } + + group_state->group_.gr_gid = gid; + + CopyFieldToString(group_state->group_name_buffer_, name(), + sizeof(group_state->group_name_buffer_)); + group_state->group_.gr_name = group_state->group_name_buffer_; + + group_state->group_.gr_passwd = nullptr; + + group_state->group_.gr_mem = group_state->group_members_; + group_state->group_.gr_mem[0] = group_state->group_.gr_name; + group_state->group_.gr_mem[1] = nullptr; + + return true; + } + + static constexpr size_t kNumFields = 4; + const char* fields[kNumFields] = {}; +}; + +} // namespace + +MmapFile::MmapFile(const char* filename, const char* required_prefix) + : filename_(filename), required_prefix_(required_prefix) { + lock_.init(false); +} + +void MmapFile::Unmap() { + if (status_ == FileStatus::Initialized) { + size_t size = end_ - start_ + 1; + munmap(const_cast(start_), size); + status_ = FileStatus::Uninitialized; + start_ = nullptr; + end_ = nullptr; + } +} + +bool MmapFile::GetFile(const char** start, const char** end) { + LockGuard guard(lock_); + if (status_ == FileStatus::Initialized) { + *start = start_; + *end = end_; + return true; + } + if (status_ == FileStatus::Error) { + return false; + } + + if (!DoMmap()) { + status_ = FileStatus::Error; + return false; + } + + status_ = FileStatus::Initialized; + *start = start_; + *end = end_; + return true; +} + +bool MmapFile::DoMmap() { + ScopedFd fd(open(filename_, O_CLOEXEC | O_NOFOLLOW | O_RDONLY)); + + struct stat fd_stat; + if (fstat(fd.get(), &fd_stat) == -1) { + return false; + } + + auto mmap_size = fd_stat.st_size; + + void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd.get(), 0); + if (map_result == MAP_FAILED) { + return false; + } + + start_ = static_cast(map_result); + end_ = start_ + mmap_size - 1; + + if (*end_ != '\n') { + munmap(map_result, mmap_size); + return false; + } + + return true; +} + +template +bool MmapFile::Find(Line* line, Predicate predicate) { + const char* start; + const char* end; + if (!GetFile(&start, &end)) { + return false; + } + + const char* line_beginning = start; + + while (line_beginning < end) { + line_beginning = ParseLine(line_beginning, end, line->fields, line->kNumFields); + // To comply with Treble, users/groups from each partition need to be prefixed with + // the partition name. + if (required_prefix_ != nullptr) { + if (strncmp(line->fields[0], required_prefix_, strlen(required_prefix_)) != 0) { + char name[kGrpPwdBufferSize]; + CopyFieldToString(name, line->fields[0], sizeof(name)); + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "Found user/group name '%s' in '%s' without required prefix '%s'", + name, filename_, required_prefix_); + continue; + } + } + if (predicate(line)) return true; + } + + return false; +} + +template +bool MmapFile::FindById(uid_t uid, Line* line) { + return Find(line, [uid](const auto& line) { + uid_t line_id; + if (!FieldToUid(line->fields[2], &line_id)) { + return false; + } + + return line_id == uid; + }); +} + +template +bool MmapFile::FindByName(const char* name, Line* line) { + return Find(line, [name](const auto& line) { + const char* line_name = line->fields[0]; + if (line_name == nullptr) { + return false; + } + + const char* match_name = name; + while (*line_name != '\n' && *line_name != ':' && *match_name != '\0') { + if (*line_name++ != *match_name++) { + return false; + } + } + + return *line_name == ':' && *match_name == '\0'; + }); +} + +PasswdFile::PasswdFile(const char* filename, const char* required_prefix) + : mmap_file_(filename, required_prefix) { +} + +bool PasswdFile::FindById(uid_t id, passwd_state_t* passwd_state) { + ErrnoRestorer errno_restorer; + PasswdLine passwd_line; + return mmap_file_.FindById(id, &passwd_line) && passwd_line.ToPasswdState(passwd_state); +} + +bool PasswdFile::FindByName(const char* name, passwd_state_t* passwd_state) { + ErrnoRestorer errno_restorer; + PasswdLine passwd_line; + return mmap_file_.FindByName(name, &passwd_line) && passwd_line.ToPasswdState(passwd_state); +} + +GroupFile::GroupFile(const char* filename, const char* required_prefix) + : mmap_file_(filename, required_prefix) { +} + +bool GroupFile::FindById(gid_t id, group_state_t* group_state) { + ErrnoRestorer errno_restorer; + GroupLine group_line; + return mmap_file_.FindById(id, &group_line) && group_line.ToGroupState(group_state); +} + +bool GroupFile::FindByName(const char* name, group_state_t* group_state) { + ErrnoRestorer errno_restorer; + GroupLine group_line; + return mmap_file_.FindByName(name, &group_line) && group_line.ToGroupState(group_state); +} diff --git a/aosp/bionic/libc/bionic/grp_pwd_file.h b/aosp/bionic/libc/bionic/grp_pwd_file.h new file mode 100644 index 000000000..69c771bc3 --- /dev/null +++ b/aosp/bionic/libc/bionic/grp_pwd_file.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include +#include + +#include "private/bionic_lock.h" +#include "platform/bionic/macros.h" +#include "private/grp_pwd.h" + +class MmapFile { + public: + MmapFile(const char* filename, const char* required_prefix); + + template + bool FindById(uid_t uid, Line* line); + template + bool FindByName(const char* name, Line* line); + void Unmap(); + + BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(MmapFile); + + private: + enum class FileStatus { + Uninitialized, + Initialized, + Error, + }; + + bool GetFile(const char** start, const char** end); + bool DoMmap(); + + template + bool Find(Line* line, Predicate predicate); + + FileStatus status_ = FileStatus::Uninitialized; + Lock lock_; + const char* filename_ = nullptr; + const char* start_ = nullptr; + const char* end_ = nullptr; + const char* required_prefix_; +}; + +class PasswdFile { + public: + PasswdFile(const char* filename, const char* required_prefix); + + bool FindById(uid_t id, passwd_state_t* passwd_state); + bool FindByName(const char* name, passwd_state_t* passwd_state); + void Unmap() { + mmap_file_.Unmap(); + } + + BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(PasswdFile); + + private: + MmapFile mmap_file_; +}; + +class GroupFile { + public: + GroupFile(const char* filename, const char* required_prefix); + + bool FindById(gid_t id, group_state_t* group_state); + bool FindByName(const char* name, group_state_t* group_state); + void Unmap() { + mmap_file_.Unmap(); + } + + BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(GroupFile); + + private: + MmapFile mmap_file_; +}; diff --git a/aosp/bionic/libc/bionic/gwp_asan_wrappers.cpp b/aosp/bionic/libc/bionic/gwp_asan_wrappers.cpp new file mode 100644 index 000000000..d3e6a14ce --- /dev/null +++ b/aosp/bionic/libc/bionic/gwp_asan_wrappers.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2020 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bionic/gwp_asan_wrappers.h" +#include "gwp_asan/guarded_pool_allocator.h" +#include "gwp_asan/options.h" +#include "gwp_asan/random.h" +#include "malloc_common.h" + +#ifndef LIBC_STATIC +#include "bionic/malloc_common_dynamic.h" +#endif // LIBC_STATIC + +static gwp_asan::GuardedPoolAllocator GuardedAlloc; +static const MallocDispatch* prev_dispatch; + +using Options = gwp_asan::options::Options; + +// ============================================================================ +// Implementation of gFunctions. +// ============================================================================ + +// This function handles initialisation as asked for by MallocInitImpl. This +// should always be called in a single-threaded context. +bool gwp_asan_initialize(const MallocDispatch* dispatch, bool*, const char*) { + prev_dispatch = dispatch; + + Options Opts; + Opts.Enabled = true; + Opts.MaxSimultaneousAllocations = 32; + Opts.SampleRate = 2500; + Opts.InstallSignalHandlers = false; + Opts.InstallForkHandlers = true; + Opts.Backtrace = android_unsafe_frame_pointer_chase; + + GuardedAlloc.init(Opts); + // TODO(b/149790891): The log line below causes ART tests to fail as they're + // not expecting any output. Disable the output for now. + // info_log("GWP-ASan has been enabled."); + + __libc_shared_globals()->gwp_asan_state = GuardedAlloc.getAllocatorState(); + __libc_shared_globals()->gwp_asan_metadata = GuardedAlloc.getMetadataRegion(); + return true; +} + +void gwp_asan_finalize() { +} + +void gwp_asan_get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*) { +} + +void gwp_asan_free_malloc_leak_info(uint8_t*) { +} + +ssize_t gwp_asan_malloc_backtrace(void*, uintptr_t*, size_t) { + // TODO(mitchp): GWP-ASan might be able to return the backtrace for the + // provided address. + return -1; +} + +bool gwp_asan_write_malloc_leak_info(FILE*) { + return false; +} + +void* gwp_asan_gfunctions[] = { + (void*)gwp_asan_initialize, (void*)gwp_asan_finalize, + (void*)gwp_asan_get_malloc_leak_info, (void*)gwp_asan_free_malloc_leak_info, + (void*)gwp_asan_malloc_backtrace, (void*)gwp_asan_write_malloc_leak_info, +}; + +// ============================================================================ +// Implementation of GWP-ASan malloc wrappers. +// ============================================================================ + +void* gwp_asan_calloc(size_t n_elements, size_t elem_size) { + if (__predict_false(GuardedAlloc.shouldSample())) { + size_t bytes; + if (!__builtin_mul_overflow(n_elements, elem_size, &bytes)) { + if (void* result = GuardedAlloc.allocate(bytes)) { + return result; + } + } + } + return prev_dispatch->calloc(n_elements, elem_size); +} + +void gwp_asan_free(void* mem) { + if (__predict_false(GuardedAlloc.pointerIsMine(mem))) { + GuardedAlloc.deallocate(mem); + return; + } + prev_dispatch->free(mem); +} + +void* gwp_asan_malloc(size_t bytes) { + if (__predict_false(GuardedAlloc.shouldSample())) { + if (void* result = GuardedAlloc.allocate(bytes)) { + return result; + } + } + return prev_dispatch->malloc(bytes); +} + +size_t gwp_asan_malloc_usable_size(const void* mem) { + if (__predict_false(GuardedAlloc.pointerIsMine(mem))) { + return GuardedAlloc.getSize(mem); + } + return prev_dispatch->malloc_usable_size(mem); +} + +void* gwp_asan_realloc(void* old_mem, size_t bytes) { + if (__predict_false(GuardedAlloc.pointerIsMine(old_mem))) { + size_t old_size = GuardedAlloc.getSize(old_mem); + void* new_ptr = gwp_asan_malloc(bytes); + if (new_ptr) memcpy(new_ptr, old_mem, (bytes < old_size) ? bytes : old_size); + GuardedAlloc.deallocate(old_mem); + return new_ptr; + } + return prev_dispatch->realloc(old_mem, bytes); +} + +int gwp_asan_malloc_iterate(uintptr_t base, size_t size, + void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) { + if (__predict_false(GuardedAlloc.pointerIsMine(reinterpret_cast(base)))) { + // TODO(mitchp): GPA::iterate() returns void, but should return int. + // TODO(mitchp): GPA::iterate() should take uintptr_t, not void*. + GuardedAlloc.iterate(reinterpret_cast(base), size, callback, arg); + return 0; + } + return prev_dispatch->malloc_iterate(base, size, callback, arg); +} + +void gwp_asan_malloc_disable() { + GuardedAlloc.disable(); + prev_dispatch->malloc_disable(); +} + +void gwp_asan_malloc_enable() { + GuardedAlloc.enable(); + prev_dispatch->malloc_enable(); +} + +static const MallocDispatch gwp_asan_dispatch __attribute__((unused)) = { + gwp_asan_calloc, + gwp_asan_free, + Malloc(mallinfo), + gwp_asan_malloc, + gwp_asan_malloc_usable_size, + Malloc(memalign), + Malloc(posix_memalign), +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + Malloc(pvalloc), +#endif + gwp_asan_realloc, +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + Malloc(valloc), +#endif + gwp_asan_malloc_iterate, + gwp_asan_malloc_disable, + gwp_asan_malloc_enable, + Malloc(mallopt), + Malloc(aligned_alloc), + Malloc(malloc_info), +}; + +// The probability (1 / kProcessSampleRate) that a process will be ranodmly +// selected for sampling. kProcessSampleRate should always be a power of two to +// avoid modulo bias. +static constexpr uint8_t kProcessSampleRate = 128; + +bool ShouldGwpAsanSampleProcess() { + uint8_t random_number; + __libc_safe_arc4random_buf(&random_number, sizeof(random_number)); + return random_number % kProcessSampleRate == 0; +} + +bool MaybeInitGwpAsanFromLibc(libc_globals* globals) { + // Never initialize the Zygote here. A Zygote chosen for sampling would also + // have all of its children sampled. Instead, the Zygote child will choose + // whether it samples or not just after the Zygote forks. For + // libc_scudo-preloaded executables (like mediaswcodec), the program name + // might not be available yet. The zygote never uses dynamic libc_scudo. + const char* progname = getprogname(); + if (progname && strncmp(progname, "app_process", 11) == 0) { + return false; + } + return MaybeInitGwpAsan(globals); +} + +static bool GwpAsanInitialized = false; + +// Maybe initializes GWP-ASan. Called by android_mallopt() and libc's +// initialisation. This should always be called in a single-threaded context. +bool MaybeInitGwpAsan(libc_globals* globals, bool force_init) { + if (GwpAsanInitialized) { + error_log("GWP-ASan was already initialized for this process."); + return false; + } + + // If the caller hasn't forced GWP-ASan on, check whether we should sample + // this process. + if (!force_init && !ShouldGwpAsanSampleProcess()) { + return false; + } + + // GWP-ASan is compatible with heapprofd/malloc_debug/malloc_hooks iff + // GWP-ASan was installed first. If one of these other libraries was already + // installed, we don't enable GWP-ASan. These libraries are normally enabled + // in libc_init after GWP-ASan, but if the new process is a zygote child and + // trying to initialize GWP-ASan through mallopt(), one of these libraries may + // be installed. It may be possible to change this in future by modifying the + // internal dispatch pointers of these libraries at this point in time, but + // given that they're all debug-only, we don't really mind for now. + if (GetDefaultDispatchTable() != nullptr) { + // Something else is installed. + return false; + } + + // GWP-ASan's initialization is always called in a single-threaded context, so + // we can initialize lock-free. + // Set GWP-ASan as the malloc dispatch table. + globals->malloc_dispatch_table = gwp_asan_dispatch; + atomic_store(&globals->default_dispatch_table, &gwp_asan_dispatch); + + // If malloc_limit isn't installed, we can skip the default_dispatch_table + // lookup. + if (GetDispatchTable() == nullptr) { + atomic_store(&globals->current_dispatch_table, &gwp_asan_dispatch); + } + +#ifndef LIBC_STATIC + SetGlobalFunctions(gwp_asan_gfunctions); +#endif // LIBC_STATIC + + GwpAsanInitialized = true; + + gwp_asan_initialize(NativeAllocatorDispatch(), nullptr, nullptr); + + return true; +} + +bool DispatchIsGwpAsan(const MallocDispatch* dispatch) { + return dispatch == &gwp_asan_dispatch; +} diff --git a/aosp/bionic/libc/bionic/gwp_asan_wrappers.h b/aosp/bionic/libc/bionic/gwp_asan_wrappers.h new file mode 100644 index 000000000..a39d50b8b --- /dev/null +++ b/aosp/bionic/libc/bionic/gwp_asan_wrappers.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include +#include +#include + +// Hooks for libc to possibly install GWP-ASan. +bool MaybeInitGwpAsanFromLibc(libc_globals* globals); + +// Maybe initialize GWP-ASan. Set force_init to true to bypass process sampling. +bool MaybeInitGwpAsan(libc_globals* globals, bool force_init = false); + +// Returns whether GWP-ASan is the provided dispatch table pointer. Used in +// heapprofd's signal-initialization sequence to determine the intermediate +// dispatch pointer to use when initing. +bool DispatchIsGwpAsan(const MallocDispatch* dispatch); diff --git a/aosp/bionic/libc/bionic/heap_tagging.cpp b/aosp/bionic/libc/bionic/heap_tagging.cpp new file mode 100644 index 000000000..62b5f5cbf --- /dev/null +++ b/aosp/bionic/libc/bionic/heap_tagging.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 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 "heap_tagging.h" +#include "malloc_common.h" +#include "malloc_tagged_pointers.h" + +#include +#include + +extern "C" void scudo_malloc_disable_memory_tagging(); + +static HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; + +void SetDefaultHeapTaggingLevel() { +#if defined(__aarch64__) +#define PR_SET_TAGGED_ADDR_CTRL 55 +#define PR_TAGGED_ADDR_ENABLE (1UL << 0) +#ifdef ANDROID_EXPERIMENTAL_MTE + // First, try enabling MTE in asynchronous mode, with tag 0 excluded. This will fail if the kernel + // or hardware doesn't support MTE, and we will fall back to just enabling tagged pointers in + // syscall arguments. + if (prctl(PR_SET_TAGGED_ADDR_CTRL, + PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_ASYNC | (1 << PR_MTE_EXCL_SHIFT), 0, 0, 0) == 0) { + heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC; + return; + } +#endif // ANDROID_EXPERIMENTAL_MTE + + // Allow the kernel to accept tagged pointers in syscall arguments. This is a no-op (kernel + // returns -EINVAL) if the kernel doesn't understand the prctl. + if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0) { +#if !__has_feature(hwaddress_sanitizer) + heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI; + __libc_globals.mutate([](libc_globals* globals) { + // Arrange for us to set pointer tags to POINTER_TAG, check tags on + // deallocation and untag when passing pointers to the allocator. + globals->heap_pointer_tag = (reinterpret_cast(POINTER_TAG) << TAG_SHIFT) | + (0xffull << CHECK_SHIFT) | (0xffull << UNTAG_SHIFT); + }); +#endif // hwaddress_sanitizer + } +#endif // aarch64 +} + +bool SetHeapTaggingLevel(void* arg, size_t arg_size) { + if (arg_size != sizeof(HeapTaggingLevel)) { + return false; + } + + auto tag_level = *reinterpret_cast(arg); + if (tag_level == heap_tagging_level) { + return true; + } + + switch (tag_level) { + case M_HEAP_TAGGING_LEVEL_NONE: + break; + case M_HEAP_TAGGING_LEVEL_TBI: + case M_HEAP_TAGGING_LEVEL_ASYNC: + if (heap_tagging_level == M_HEAP_TAGGING_LEVEL_NONE) { + error_log( + "SetHeapTaggingLevel: re-enabling tagging after it was disabled is not supported"); + } else { + error_log("SetHeapTaggingLevel: switching between TBI and ASYNC is not supported"); + } + return false; + default: + error_log("SetHeapTaggingLevel: unknown tagging level"); + return false; + } + heap_tagging_level = tag_level; + info_log("SetHeapTaggingLevel: tag level set to %d", tag_level); + + if (heap_tagging_level == M_HEAP_TAGGING_LEVEL_NONE) { +#if defined(USE_SCUDO) + scudo_malloc_disable_memory_tagging(); +#endif + __libc_globals.mutate([](libc_globals* globals) { + // Preserve the untag mask (we still want to untag pointers when passing them to the + // allocator if we were doing so before), but clear the fixed tag and the check mask, + // so that pointers are no longer tagged and checks no longer happen. + globals->heap_pointer_tag &= 0xffull << UNTAG_SHIFT; + }); + } + + return true; +} diff --git a/aosp/bionic/libc/bionic/heap_tagging.h b/aosp/bionic/libc/bionic/heap_tagging.h new file mode 100644 index 000000000..2aaf6086e --- /dev/null +++ b/aosp/bionic/libc/bionic/heap_tagging.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +void SetDefaultHeapTaggingLevel(); +bool SetHeapTaggingLevel(void* arg, size_t arg_size); diff --git a/aosp/bionic/libc/bionic/iconv.cpp b/aosp/bionic/libc/bionic/iconv.cpp new file mode 100644 index 000000000..015d70f5e --- /dev/null +++ b/aosp/bionic/libc/bionic/iconv.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include + +#include "private/bionic_mbstate.h" + +#define INVALID_ICONV_T reinterpret_cast(-1) + +// Ideally we'd use icu4c but the API mismatch seems too great. So we just offer something +// equivalent to (but slightly easier to use for runs of text than) . If you're +// here to add more encodings, consider working on finishing the icu4c NDK wrappers instead. +enum Encoding { + US_ASCII, + UTF_8, + UTF_16_LE, + UTF_16_BE, + UTF_32_LE, + UTF_32_BE, + WCHAR_T, +}; + +enum Mode { + ERROR, + IGNORE, + TRANSLIT, +}; + +// This matching is strange but true. +// See http://www.unicode.org/reports/tr22/#Charset_Alias_Matching. +static bool __match_encoding(const char* lhs, const char* rhs) { + while (*lhs && *rhs) { + // Skip non-alnum in lhs; "UTF-8", "UTF_8", "UTF8", "UTF 8" are all equivalent. + // Also implement the "delete each 0 that is not preceded by a digit" rule. + for (; *lhs; ++lhs) { + if (isalnum(*lhs) && (*lhs != '0' || !isdigit(*(lhs + 1)))) break; + } + // Case doesn't matter either. + if (tolower(*lhs) != tolower(*rhs)) break; + ++lhs; + ++rhs; + } + // As a special case we treat the GNU "//" extensions as end of string. + if ((*lhs == '\0' || strstr(lhs, "//") == lhs) && *rhs == '\0') return true; + return false; +} + +static bool __parse_encoding(const char* s, Encoding* encoding, Mode* mode) { + const char* suffix = strstr(s, "//"); + if (suffix) { + if (!mode) return false; + if (strcmp(suffix, "//IGNORE") == 0) { + *mode = IGNORE; + } else if (strcmp(suffix, "//TRANSLIT") == 0) { + *mode = TRANSLIT; + } else { + return false; + } + } + if (__match_encoding(s, "utf8")) { + *encoding = UTF_8; + } else if (__match_encoding(s, "ascii") || __match_encoding(s, "usascii")) { + *encoding = US_ASCII; + } else if (__match_encoding(s, "utf16le")) { + *encoding = UTF_16_LE; + } else if (__match_encoding(s, "utf16be")) { + *encoding = UTF_16_BE; + } else if (__match_encoding(s, "utf32le")) { + *encoding = UTF_32_LE; + } else if (__match_encoding(s, "utf32be")) { + *encoding = UTF_32_BE; + } else if (__match_encoding(s, "wchart")) { + *encoding = WCHAR_T; + } else { + return false; + } + return true; +} + +struct __iconv_t { + Encoding src_encoding; + Encoding dst_encoding; + Mode mode; + + __iconv_t() : mode(ERROR) { + } + + int Convert(char** src_buf0, size_t* src_bytes_left0, char** dst_buf0, size_t* dst_bytes_left0) { + // Reset state. + wc = 0; + memset(&ps, 0, sizeof(ps)); + replacement_count = 0; + ignored = false; + src_buf = src_buf0; + src_bytes_left = src_bytes_left0; + dst_buf = dst_buf0; + dst_bytes_left = dst_bytes_left0; + + while (*src_bytes_left > 0) { + if (!GetNext() || !Convert()) return -1; + } + return Done(); + } + + private: + char32_t wc; + char buf[16]; + size_t src_bytes_used; + size_t dst_bytes_used; + mbstate_t ps; + + size_t replacement_count; + bool ignored; + + char** src_buf; + size_t* src_bytes_left; + char** dst_buf; + size_t* dst_bytes_left; + + bool GetNext() { + errno = 0; + switch (src_encoding) { + case US_ASCII: + wc = **src_buf; + src_bytes_used = 1; + if (wc > 0x7f) errno = EILSEQ; + break; + + case UTF_8: + src_bytes_used = mbrtoc32(&wc, *src_buf, *src_bytes_left, &ps); + if (src_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) { + break; // EILSEQ already set. + } else if (src_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) { + errno = EINVAL; + return false; + } + break; + + case UTF_16_BE: + case UTF_16_LE: { + if (*src_bytes_left < 2) { + errno = EINVAL; + return false; + } + bool swap = (src_encoding == UTF_16_BE); + wc = In16(*src_buf, swap); + // 0xd800-0xdbff: high surrogates + // 0xdc00-0xdfff: low surrogates + if (wc >= 0xd800 && wc <= 0xdfff) { + if (wc >= 0xdc00) { // Low surrogate before high surrogate. + errno = EILSEQ; + return false; + } + if (*src_bytes_left < 4) { + errno = EINVAL; + return false; + } + uint16_t hi = wc; + uint16_t lo = In16(*src_buf + 2, swap); + wc = 0x10000 + ((hi - 0xd800) << 10) + (lo - 0xdc00); + src_bytes_used = 4; + } + break; + } + + case UTF_32_BE: + case UTF_32_LE: + case WCHAR_T: + if (*src_bytes_left < 4) { + errno = EINVAL; + return false; + } + wc = In32(*src_buf, (src_encoding == UTF_32_BE)); + break; + } + + if (errno == EILSEQ) { + switch (mode) { + case ERROR: + return false; + case IGNORE: + *src_buf += src_bytes_used; + *src_bytes_left -= src_bytes_used; + ignored = true; + return GetNext(); + case TRANSLIT: + wc = '?'; + ++replacement_count; + return true; + } + } + return true; + } + + bool Convert() { + errno = 0; + switch (dst_encoding) { + case US_ASCII: + buf[0] = wc; + dst_bytes_used = 1; + if (wc > 0x7f) errno = EILSEQ; + break; + + case UTF_8: + dst_bytes_used = c32rtomb(buf, wc, &ps); + if (dst_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) { + break; // EILSEQ already set. + } else if (dst_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) { + errno = EINVAL; + return false; + } + break; + + case UTF_16_BE: + case UTF_16_LE: { + bool swap = (dst_encoding == UTF_16_BE); + if (wc < 0x10000) { // BMP. + Out16(buf, wc, swap); + } else { // Supplementary plane; output surrogate pair. + wc -= 0x10000; + char16_t hi = 0xd800 | (wc >> 10); + char16_t lo = 0xdc00 | (wc & 0x3ff); + Out16(buf + 0, hi, swap); + Out16(buf + 2, lo, swap); + dst_bytes_used = 4; + } + } break; + + case UTF_32_BE: + case UTF_32_LE: + case WCHAR_T: + Out32(wc, (dst_encoding == UTF_32_BE)); + break; + } + + if (errno == EILSEQ) { + if (mode == IGNORE) { + *src_buf += src_bytes_used; + *src_bytes_left -= src_bytes_used; + ignored = true; + return true; + } else if (mode == TRANSLIT) { + wc = '?'; + ++replacement_count; + return Convert(); + } + return false; + } + + return Emit(); + } + + uint16_t In16(const char* buf, bool swap) { + const uint8_t* src = reinterpret_cast(buf); + uint16_t wc = (src[0]) | (src[1] << 8); + if (swap) wc = __swap16(wc); + src_bytes_used = 2; + return wc; + } + + uint32_t In32(const char* buf, bool swap) { + const uint8_t* src = reinterpret_cast(buf); + uint32_t wc = (src[0]) | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + if (swap) wc = __swap32(wc); + src_bytes_used = 4; + return wc; + } + + void Out16(char* dst, char16_t ch, bool swap) { + if (swap) ch = __swap16(ch); + dst[0] = ch; + dst[1] = ch >> 8; + dst_bytes_used = 2; + } + + void Out32(char32_t ch, bool swap) { + if (swap) ch = __swap32(ch); + buf[0] = ch; + buf[1] = ch >> 8; + buf[2] = ch >> 16; + buf[3] = ch >> 24; + dst_bytes_used = 4; + } + + bool Emit() { + if (dst_bytes_used > *dst_bytes_left) { + errno = E2BIG; + return false; + } + + memcpy(*dst_buf, buf, dst_bytes_used); + *src_buf += src_bytes_used; + *src_bytes_left -= src_bytes_used; + *dst_buf += dst_bytes_used; + *dst_bytes_left -= dst_bytes_used; + return true; + } + + int Done() { + if (mode == TRANSLIT) return replacement_count; + if (ignored) { + errno = EILSEQ; + return -1; + } + return 0; + } +}; + +iconv_t iconv_open(const char* __dst_encoding, const char* __src_encoding) { + iconv_t result = new __iconv_t; + if (!__parse_encoding(__src_encoding, &result->src_encoding, nullptr) || + !__parse_encoding(__dst_encoding, &result->dst_encoding, &result->mode)) { + delete result; + errno = EINVAL; + return INVALID_ICONV_T; + } + return result; +} + +size_t iconv(iconv_t __converter, + char** __src_buf, size_t* __src_bytes_left, + char** __dst_buf, size_t* __dst_bytes_left) { + if (__converter == INVALID_ICONV_T) { + errno = EBADF; + return -1; + } + return __converter->Convert(__src_buf, __src_bytes_left, __dst_buf, __dst_bytes_left); +} + +int iconv_close(iconv_t __converter) { + if (__converter == INVALID_ICONV_T) { + errno = EBADF; + return -1; + } + delete __converter; + return 0; +} diff --git a/aosp/bionic/libc/bionic/icu.cpp b/aosp/bionic/libc/bionic/icu.cpp new file mode 100644 index 000000000..72dac9b5a --- /dev/null +++ b/aosp/bionic/libc/bionic/icu.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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/icu.h" + +#include +#include +#include +#include +#include + +#include + +static void* g_libicuuc_handle = nullptr; + +static bool __find_icu() { + g_libicuuc_handle = dlopen("libandroidicu.so", RTLD_LOCAL); + if (g_libicuuc_handle == nullptr) { + async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libandroidicu.so: %s", + dlerror()); + return false; + } + + return true; +} + +void* __find_icu_symbol(const char* symbol_name) { + static bool found_icu = __find_icu(); + if (!found_icu) return nullptr; + + char versioned_symbol_name[strlen(symbol_name) + strlen("_android") + 1]; + snprintf(versioned_symbol_name, sizeof(versioned_symbol_name), "%s_android", + symbol_name); + + void* symbol = dlsym(g_libicuuc_handle, versioned_symbol_name); + if (symbol == nullptr) { + async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s", + versioned_symbol_name); + } + return symbol; +} diff --git a/aosp/bionic/libc/bionic/icu_static.cpp b/aosp/bionic/libc/bionic/icu_static.cpp new file mode 100644 index 000000000..e81e291c7 --- /dev/null +++ b/aosp/bionic/libc/bionic/icu_static.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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/icu.h" + +// We don't have dlopen/dlsym for static binaries yet. +__attribute__((weak)) void* __find_icu_symbol(const char*) { + return nullptr; +} diff --git a/aosp/bionic/libc/bionic/icu_wrappers.cpp b/aosp/bionic/libc/bionic/icu_wrappers.cpp new file mode 100644 index 000000000..d9f274594 --- /dev/null +++ b/aosp/bionic/libc/bionic/icu_wrappers.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 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/icu.h" + +int8_t __icu_charType(wint_t wc) { + typedef int8_t (*u_charType_t)(UChar32); + static auto u_charType = reinterpret_cast(__find_icu_symbol("u_charType")); + return u_charType ? u_charType(wc) : -1; +} + +int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property) { + typedef int32_t (*u_getIntPropertyValue_t)(UChar32, UProperty); + static auto u_getIntPropertyValue = + reinterpret_cast(__find_icu_symbol("u_getIntPropertyValue")); + return u_getIntPropertyValue ? u_getIntPropertyValue(wc, property) : 0; +} + +bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) { + typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty); + static auto u_hasBinaryProperty = + reinterpret_cast(__find_icu_symbol("u_hasBinaryProperty")); + return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc); +} diff --git a/aosp/bionic/libc/bionic/ifaddrs.cpp b/aosp/bionic/libc/bionic/ifaddrs.cpp new file mode 100644 index 000000000..153633353 --- /dev/null +++ b/aosp/bionic/libc/bionic/ifaddrs.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2015 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 + +#include +#include // FIRST_APPLICATION_UID +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/ErrnoRestorer.h" + +#include "bionic_netlink.h" + +// The public ifaddrs struct is full of pointers. Rather than track several +// different allocations, we use a maximally-sized structure with the public +// part at offset 0, and pointers into its hidden tail. +struct ifaddrs_storage { + // Must come first, so that `ifaddrs_storage` is-a `ifaddrs`. + ifaddrs ifa; + + // The interface index, so we can match RTM_NEWADDR messages with + // earlier RTM_NEWLINK messages (to copy the interface flags). + int interface_index; + + // Storage for the pointers in `ifa`. + sockaddr_storage addr; + sockaddr_storage netmask; + sockaddr_storage ifa_ifu; + char name[IFNAMSIZ + 1]; + + explicit ifaddrs_storage(ifaddrs** list) { + memset(this, 0, sizeof(*this)); + + // push_front onto `list`. + ifa.ifa_next = *list; + *list = reinterpret_cast(this); + } + + void SetAddress(int family, const void* data, size_t byteCount) { + // The kernel currently uses the order IFA_ADDRESS, IFA_LOCAL, IFA_BROADCAST + // in inet_fill_ifaddr, but let's not assume that will always be true... + if (ifa.ifa_addr == nullptr) { + // This is an IFA_ADDRESS and haven't seen an IFA_LOCAL yet, so assume this is the + // local address. SetLocalAddress will fix things if we later see an IFA_LOCAL. + ifa.ifa_addr = CopyAddress(family, data, byteCount, &addr); + } else { + // We already saw an IFA_LOCAL, which implies this is a destination address. + ifa.ifa_dstaddr = CopyAddress(family, data, byteCount, &ifa_ifu); + } + } + + void SetBroadcastAddress(int family, const void* data, size_t byteCount) { + // ifa_broadaddr and ifa_dstaddr overlap in a union. Unfortunately, it's possible + // to have an interface with both. Keeping the last thing the kernel gives us seems + // to be glibc 2.19's behavior too, so our choice is being source compatible with + // badly-written code that assumes ifa_broadaddr and ifa_dstaddr are interchangeable + // or supporting interfaces with both addresses configured. My assumption is that + // bad code is more common than weird network interfaces... + ifa.ifa_broadaddr = CopyAddress(family, data, byteCount, &ifa_ifu); + } + + void SetLocalAddress(int family, const void* data, size_t byteCount) { + // The kernel source says "for point-to-point IFA_ADDRESS is DESTINATION address, + // local address is supplied in IFA_LOCAL attribute". + // -- http://lxr.free-electrons.com/source/include/uapi/linux/if_addr.h#L17 + + // So copy any existing IFA_ADDRESS into ifa_dstaddr... + if (ifa.ifa_addr != nullptr) { + ifa.ifa_dstaddr = reinterpret_cast(memcpy(&ifa_ifu, &addr, sizeof(addr))); + } + // ...and then put this IFA_LOCAL into ifa_addr. + ifa.ifa_addr = CopyAddress(family, data, byteCount, &addr); + } + + // Netlink gives us the prefix length as a bit count. We need to turn + // that into a BSD-compatible netmask represented by a sockaddr*. + void SetNetmask(int family, size_t prefix_length) { + // ...and work out the netmask from the prefix length. + netmask.ss_family = family; + uint8_t* dst = SockaddrBytes(family, &netmask); + memset(dst, 0xff, prefix_length / 8); + if ((prefix_length % 8) != 0) { + dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8))); + } + ifa.ifa_netmask = reinterpret_cast(&netmask); + } + + void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) { + sockaddr_ll* sll = reinterpret_cast(&addr); + sll->sll_ifindex = ifindex; + sll->sll_hatype = hatype; + sll->sll_halen = halen; + } + + private: + sockaddr* CopyAddress(int family, const void* data, size_t byteCount, sockaddr_storage* ss) { + // Netlink gives us the address family in the header, and the + // sockaddr_in or sockaddr_in6 bytes as the payload. We need to + // stitch the two bits together into the sockaddr that's part of + // our portable interface. + ss->ss_family = family; + memcpy(SockaddrBytes(family, ss), data, byteCount); + + // For IPv6 we might also have to set the scope id. + if (family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(data) || IN6_IS_ADDR_MC_LINKLOCAL(data))) { + reinterpret_cast(ss)->sin6_scope_id = interface_index; + } + + return reinterpret_cast(ss); + } + + // Returns a pointer to the first byte in the address data (which is + // stored in network byte order). + uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) { + if (family == AF_INET) { + sockaddr_in* ss4 = reinterpret_cast(ss); + return reinterpret_cast(&ss4->sin_addr); + } else if (family == AF_INET6) { + sockaddr_in6* ss6 = reinterpret_cast(ss); + return reinterpret_cast(&ss6->sin6_addr); + } else if (family == AF_PACKET) { + sockaddr_ll* sll = reinterpret_cast(ss); + return reinterpret_cast(&sll->sll_addr); + } + return nullptr; + } +}; + +static void __getifaddrs_callback(void* context, nlmsghdr* hdr) { + ifaddrs** out = reinterpret_cast(context); + + if (hdr->nlmsg_type == RTM_NEWLINK) { + ifinfomsg* ifi = reinterpret_cast(NLMSG_DATA(hdr)); + + // Create a new ifaddr entry, and set the interface index and flags. + ifaddrs_storage* new_addr = new ifaddrs_storage(out); + new_addr->interface_index = ifi->ifi_index; + new_addr->ifa.ifa_flags = ifi->ifi_flags; + + // Go through the various bits of information and find the name. + rtattr* rta = IFLA_RTA(ifi); + size_t rta_len = IFLA_PAYLOAD(hdr); + while (RTA_OK(rta, rta_len)) { + if (rta->rta_type == IFLA_ADDRESS) { + if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) { + new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); + } + } else if (rta->rta_type == IFLA_BROADCAST) { + if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) { + new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); + } + } else if (rta->rta_type == IFLA_IFNAME) { + if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) { + memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->ifa.ifa_name = new_addr->name; + } + } + rta = RTA_NEXT(rta, rta_len); + } + } else if (hdr->nlmsg_type == RTM_NEWADDR) { + ifaddrmsg* msg = reinterpret_cast(NLMSG_DATA(hdr)); + + // We might already know about this interface from an RTM_NEWLINK message. + const ifaddrs_storage* known_addr = reinterpret_cast(*out); + while (known_addr != nullptr && known_addr->interface_index != static_cast(msg->ifa_index)) { + known_addr = reinterpret_cast(known_addr->ifa.ifa_next); + } + + // Create a new ifaddr entry, and set the interface index. + ifaddrs_storage* new_addr = new ifaddrs_storage(out); + new_addr->interface_index = static_cast(msg->ifa_index); + + // If this is a known interface, copy what we already know. + // If we don't know about this interface yet, we try to resolve the name and flags using ioctl + // calls during postprocessing. + if (known_addr != nullptr) { + strcpy(new_addr->name, known_addr->name); + new_addr->ifa.ifa_name = new_addr->name; + new_addr->ifa.ifa_flags = known_addr->ifa.ifa_flags; + } + + // Go through the various bits of information and find the name, address + // and any broadcast/destination address. + rtattr* rta = IFA_RTA(msg); + size_t rta_len = IFA_PAYLOAD(hdr); + while (RTA_OK(rta, rta_len)) { + if (rta->rta_type == IFA_ADDRESS) { + if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { + new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen); + } + } else if (rta->rta_type == IFA_BROADCAST) { + if (msg->ifa_family == AF_INET) { + new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + if (known_addr == nullptr) { + // We did not read the broadcast flag from an RTM_NEWLINK message. + // Ensure that it is set. + new_addr->ifa.ifa_flags |= IFF_BROADCAST; + } + } + } else if (rta->rta_type == IFA_LOCAL) { + if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { + new_addr->SetLocalAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + } else if (rta->rta_type == IFA_LABEL) { + if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) { + memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta)); + new_addr->ifa.ifa_name = new_addr->name; + } + } + rta = RTA_NEXT(rta, rta_len); + } + } +} + +static void resolve_or_remove_nameless_interfaces(ifaddrs** list) { + ifaddrs_storage* addr = reinterpret_cast(*list); + ifaddrs_storage* prev_addr = nullptr; + while (addr != nullptr) { + ifaddrs* next_addr = addr->ifa.ifa_next; + + // Try resolving interfaces without a name first. + if (strlen(addr->name) == 0) { + if (if_indextoname(addr->interface_index, addr->name) != nullptr) { + addr->ifa.ifa_name = addr->name; + } + } + + // If the interface could not be resolved, remove it. + if (strlen(addr->name) == 0) { + if (prev_addr == nullptr) { + *list = next_addr; + } else { + prev_addr->ifa.ifa_next = next_addr; + } + free(addr); + } else { + prev_addr = addr; + } + + addr = reinterpret_cast(next_addr); + } +} + +static void get_interface_flags_via_ioctl(ifaddrs** list) { + ScopedFd s(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)); + if (s.get() == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC) failed in ifaddrs: %s", + strerror(errno)); + return; + } + + for (ifaddrs_storage* addr = reinterpret_cast(*list); addr != nullptr; + addr = reinterpret_cast(addr->ifa.ifa_next)) { + ifreq ifr = {}; + strlcpy(ifr.ifr_name, addr->ifa.ifa_name, sizeof(ifr.ifr_name)); + if (ioctl(s.get(), SIOCGIFFLAGS, &ifr) != -1) { + addr->ifa.ifa_flags = ifr.ifr_flags; + } else { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", + "ioctl(SIOCGIFFLAGS) for \"%s\" failed in ifaddrs: %s", + addr->ifa.ifa_name, strerror(errno)); + } + } +} + +int getifaddrs(ifaddrs** out) { + // We construct the result directly into `out`, so terminate the list. + *out = nullptr; + + // Open the netlink socket and ask for all the links and addresses. + NetlinkConnection nc; + // SELinux policy only allows RTM_GETLINK messages to be sent by: + // - System apps + // - Apps with a target SDK version lower than R + bool getlink_success = false; + if (getuid() < FIRST_APPLICATION_UID || + android_get_application_target_sdk_version() < __ANDROID_API_R__) { + getlink_success = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__getifaddrs_callback, out); + } + bool getaddr_success = + nc.SendRequest(RTM_GETADDR) && nc.ReadResponses(__getifaddrs_callback, out); + + if (!getaddr_success) { + freeifaddrs(*out); + // Ensure that callers crash if they forget to check for success. + *out = nullptr; + return -1; + } + + if (!getlink_success) { + // If we weren't able to depend on GETLINK messages, it's possible some + // interfaces never got their name set. Resolve them using if_indextoname or remove them. + resolve_or_remove_nameless_interfaces(out); + // Similarly, without GETLINK messages, interfaces will not have their flags set. + // Resolve them using the SIOCGIFFLAGS ioctl call. + get_interface_flags_via_ioctl(out); + } + + return 0; +} + +void freeifaddrs(ifaddrs* list) { + while (list != nullptr) { + ifaddrs* current = list; + list = list->ifa_next; + free(current); + } +} diff --git a/aosp/bionic/libc/bionic/initgroups.c b/aosp/bionic/libc/bionic/initgroups.c new file mode 100644 index 000000000..dea6d966d --- /dev/null +++ b/aosp/bionic/libc/bionic/initgroups.c @@ -0,0 +1,58 @@ +/* + * 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 +#include +#include + +#define INIT_GROUPS 2 + +int +initgroups (const char *user, gid_t group) +{ + gid_t groups0[ INIT_GROUPS ]; + gid_t* groups = groups0; + int ret = -1; + int numgroups = INIT_GROUPS; + + if (getgrouplist(user, group, groups, &numgroups) < 0) { + groups = malloc(numgroups*sizeof(groups[0])); + if (groups == NULL) + return -1; + if (getgrouplist(user,group,groups,&numgroups) < 0) { + goto EXIT; + } + } + + ret = setgroups(numgroups, groups); + +EXIT: + if (groups != groups0) + free(groups); + + return ret; +} diff --git a/aosp/bionic/libc/bionic/inotify_init.cpp b/aosp/bionic/libc/bionic/inotify_init.cpp new file mode 100644 index 000000000..b045984c6 --- /dev/null +++ b/aosp/bionic/libc/bionic/inotify_init.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int inotify_init() { + return inotify_init1(0); +} diff --git a/aosp/bionic/libc/bionic/ioctl.cpp b/aosp/bionic/libc/bionic/ioctl.cpp new file mode 100644 index 000000000..db851329b --- /dev/null +++ b/aosp/bionic/libc/bionic/ioctl.cpp @@ -0,0 +1,40 @@ +/* + * 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 +#include + +extern "C" int __ioctl(int, int, void *); + +int ioctl(int fd, int request, ...) { + va_list ap; + va_start(ap, request); + void* arg = va_arg(ap, void*); + va_end(ap); + return __ioctl(fd, request, arg); +} diff --git a/aosp/bionic/libc/bionic/isatty.c b/aosp/bionic/libc/bionic/isatty.c new file mode 100644 index 000000000..93af6c52c --- /dev/null +++ b/aosp/bionic/libc/bionic/isatty.c @@ -0,0 +1,39 @@ +/* + * 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 +#include +#include + +int +isatty (int fd) +{ + struct termios term; + + return tcgetattr (fd, &term) == 0; +} diff --git a/aosp/bionic/libc/bionic/jemalloc.h b/aosp/bionic/libc/bionic/jemalloc.h new file mode 100644 index 000000000..4ce51c0a8 --- /dev/null +++ b/aosp/bionic/libc/bionic/jemalloc.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#pragma once + +#include +#include // For struct mallinfo. + +// Need to wrap memalign since je_memalign fails on non-power of 2 alignments. +#define je_memalign je_memalign_round_up_boundary + +// Need to wrap aligned_alloc since je_aligned_alloc does not enforce +// that size is a multiple of alignment. +#define je_aligned_alloc je_aligned_alloc_wrapper + +__BEGIN_DECLS + +void* je_aligned_alloc_wrapper(size_t, size_t); +int je_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); +int je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((nothrow)); +struct mallinfo je_mallinfo(); +void je_malloc_disable(); +void je_malloc_enable(); +int je_malloc_info(int options, FILE* fp); +int je_mallopt(int, int); +void* je_memalign_round_up_boundary(size_t, size_t); +void* je_pvalloc(size_t); + +__END_DECLS diff --git a/aosp/bionic/libc/bionic/jemalloc_wrapper.cpp b/aosp/bionic/libc/bionic/jemalloc_wrapper.cpp new file mode 100644 index 000000000..ef488eecc --- /dev/null +++ b/aosp/bionic/libc/bionic/jemalloc_wrapper.cpp @@ -0,0 +1,174 @@ +/* + * 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 +#include +#include +#include + +#include + +#include "jemalloc.h" + +void* je_pvalloc(size_t bytes) { + size_t pagesize = getpagesize(); + size_t size = __BIONIC_ALIGN(bytes, pagesize); + if (size < bytes) { + return nullptr; + } + return je_memalign(pagesize, size); +} + +#ifdef je_memalign +#undef je_memalign +#endif + +// The man page for memalign says it fails if boundary is not a power of 2, +// but this is not true. Both glibc and dlmalloc round up to the next power +// of 2, so we'll do the same. +void* je_memalign_round_up_boundary(size_t boundary, size_t size) { + if (boundary != 0) { + if (!powerof2(boundary)) { + boundary = BIONIC_ROUND_UP_POWER_OF_2(boundary); + } + } else { + boundary = 1; + } + return je_memalign(boundary, size); +} + +#ifdef je_aligned_alloc +#undef je_aligned_alloc +#endif + +// The aligned_alloc function requires that size is a multiple of alignment. +// jemalloc doesn't enforce this, so add enforcement here. +void* je_aligned_alloc_wrapper(size_t alignment, size_t size) { + if ((size % alignment) != 0) { + errno = EINVAL; + return nullptr; + } + return je_aligned_alloc(alignment, size); +} + +int je_mallopt(int param, int value) { + // The only parameter we currently understand is M_DECAY_TIME. + if (param == M_DECAY_TIME) { + // Only support setting the value to 1 or 0. + ssize_t decay_time_ms; + if (value) { + decay_time_ms = 1000; + } else { + decay_time_ms = 0; + } + // First get the total number of arenas. + unsigned narenas; + size_t sz = sizeof(unsigned); + if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) { + return 0; + } + + // Set the decay time for any arenas that will be created in the future. + if (je_mallctl("arenas.dirty_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) { + return 0; + } + if (je_mallctl("arenas.muzzy_decay_ms", nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) { + return 0; + } + + // Change the decay on the already existing arenas. + char buffer[100]; + for (unsigned i = 0; i < narenas; i++) { + snprintf(buffer, sizeof(buffer), "arena.%d.dirty_decay_ms", i); + if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) { + break; + } + snprintf(buffer, sizeof(buffer), "arena.%d.muzzy_decay_ms", i); + if (je_mallctl(buffer, nullptr, nullptr, &decay_time_ms, sizeof(decay_time_ms)) != 0) { + break; + } + } + return 1; + } else if (param == M_PURGE) { + // Only clear the current thread cache since there is no easy way to + // clear the caches of other threads. + // This must be done first so that cleared allocations get purged + // in the next calls. + // Ignore the return call since this will fail if the tcache is disabled. + je_mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0); + + unsigned narenas; + size_t sz = sizeof(unsigned); + if (je_mallctl("arenas.narenas", &narenas, &sz, nullptr, 0) != 0) { + return 0; + } + char buffer[100]; + snprintf(buffer, sizeof(buffer), "arena.%u.purge", narenas); + if (je_mallctl(buffer, nullptr, nullptr, nullptr, 0) != 0) { + return 0; + } + return 1; + } + return 0; +} + +__BEGIN_DECLS + +size_t je_mallinfo_narenas(); +size_t je_mallinfo_nbins(); +struct mallinfo je_mallinfo_arena_info(size_t); +struct mallinfo je_mallinfo_bin_info(size_t, size_t); + +__END_DECLS + +int je_malloc_info(int options, FILE* fp) { + if (options != 0) { + errno = EINVAL; + return -1; + } + + fflush(fp); + int fd = fileno(fp); + MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\""); + + // Dump all of the large allocations in the arenas. + for (size_t i = 0; i < je_mallinfo_narenas(); i++) { + struct mallinfo mi = je_mallinfo_arena_info(i); + if (mi.hblkhd != 0) { + MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i); + { + MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks); + + size_t total = 0; + for (size_t j = 0; j < je_mallinfo_nbins(); j++) { + struct mallinfo mi = je_mallinfo_bin_info(i, j); + if (mi.ordblks != 0) { + MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j); + MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks); + total += mi.ordblks; + } + } + MallocXmlElem(fd, "bins-total").Contents("%zu", total); + } + } + } + + return 0; +} diff --git a/aosp/bionic/libc/bionic/killpg.cpp b/aosp/bionic/libc/bionic/killpg.cpp new file mode 100644 index 000000000..01a58b318 --- /dev/null +++ b/aosp/bionic/libc/bionic/killpg.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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 +#include + +int killpg(pid_t pgrp, int sig) { + if (pgrp < 0) { + errno = EINVAL; + return -1; + } + return kill(-pgrp, sig); +} diff --git a/aosp/bionic/libc/bionic/langinfo.cpp b/aosp/bionic/libc/bionic/langinfo.cpp new file mode 100644 index 000000000..6f5057cbd --- /dev/null +++ b/aosp/bionic/libc/bionic/langinfo.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 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 + +#include + +char* nl_langinfo(nl_item item) { + const char* result = ""; + switch (item) { + case CODESET: result = (MB_CUR_MAX == 1) ? "ASCII" : "UTF-8"; break; + + case D_T_FMT: result = "%F %T %z"; break; + case D_FMT: result = "%F"; break; + case T_FMT: result = "%T"; break; + case T_FMT_AMPM: result = "%I:%M:%S %p"; break; + case AM_STR: result = "AM"; break; + case PM_STR: result = "PM"; break; + case DAY_1: result = "Sunday"; break; + case DAY_2: result = "Monday"; break; + case DAY_3: result = "Tuesday"; break; + case DAY_4: result = "Wednesday"; break; + case DAY_5: result = "Thursday"; break; + case DAY_6: result = "Friday"; break; + case DAY_7: result = "Saturday"; break; + case ABDAY_1: result = "Sun"; break; + case ABDAY_2: result = "Mon"; break; + case ABDAY_3: result = "Tue"; break; + case ABDAY_4: result = "Wed"; break; + case ABDAY_5: result = "Thu"; break; + case ABDAY_6: result = "Fri"; break; + case ABDAY_7: result = "Sat"; break; + case MON_1: result = "January"; break; + case MON_2: result = "February"; break; + case MON_3: result = "March"; break; + case MON_4: result = "April"; break; + case MON_5: result = "May"; break; + case MON_6: result = "June"; break; + case MON_7: result = "July"; break; + case MON_8: result = "August"; break; + case MON_9: result = "September"; break; + case MON_10: result = "October"; break; + case MON_11: result = "November"; break; + case MON_12: result = "December"; break; + case ABMON_1: result = "Jan"; break; + case ABMON_2: result = "Feb"; break; + case ABMON_3: result = "Mar"; break; + case ABMON_4: result = "Apr"; break; + case ABMON_5: result = "May"; break; + case ABMON_6: result = "Jun"; break; + case ABMON_7: result = "Jul"; break; + case ABMON_8: result = "Aug"; break; + case ABMON_9: result = "Sep"; break; + case ABMON_10: result = "Oct"; break; + case ABMON_11: result = "Nov"; break; + case ABMON_12: result = "Dec"; break; + case ERA: result = ""; break; + case ERA_D_FMT: result = ""; break; + case ERA_D_T_FMT: result = ""; break; + case ERA_T_FMT: result = ""; break; + case ALT_DIGITS: result = ""; break; + + case RADIXCHAR: result = "."; break; + case THOUSEP: result = ""; break; + + case YESEXPR: result = "^[yY]"; break; + case NOEXPR: result = "^[nN]"; break; + + case CRNCYSTR: result = ""; break; + + default: break; + } + return const_cast(result); +} + +char* nl_langinfo_l(nl_item item, locale_t) { + return nl_langinfo(item); +} diff --git a/aosp/bionic/libc/bionic/lchown.cpp b/aosp/bionic/libc/bionic/lchown.cpp new file mode 100644 index 000000000..24611a5b9 --- /dev/null +++ b/aosp/bionic/libc/bionic/lchown.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include + +int lchown(const char* path, uid_t uid, gid_t gid) { + return fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); +} diff --git a/aosp/bionic/libc/bionic/legacy_32_bit_support.cpp b/aosp/bionic/libc/bionic/legacy_32_bit_support.cpp new file mode 100644 index 000000000..f08e58266 --- /dev/null +++ b/aosp/bionic/libc/bionic/legacy_32_bit_support.cpp @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#undef _FORTIFY_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/bionic_fdtrack.h" + +#if defined(__LP64__) +#error This code is only needed on 32-bit systems! +#endif + +// System calls we need. +extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int); +extern "C" int __preadv64(int, const struct iovec*, int, long, long); +extern "C" int __pwritev64(int, const struct iovec*, int, long, long); + +// For lseek64 we need to use the llseek system call which splits the off64_t in two and +// returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results. +off64_t lseek64(int fd, off64_t off, int whence) { + off64_t result; + unsigned long off_hi = static_cast(off >> 32); + unsigned long off_lo = static_cast(off); + if (__llseek(fd, off_hi, off_lo, &result, whence) < 0) { + return -1; + } + return result; +} + +// There is no pread for 32-bit off_t, so we need to widen and call pread64. +ssize_t pread(int fd, void* buf, size_t byte_count, off_t offset) { + return pread64(fd, buf, byte_count, static_cast(offset)); +} + +// There is no pwrite for 32-bit off_t, so we need to widen and call pwrite64. +ssize_t pwrite(int fd, const void* buf, size_t byte_count, off_t offset) { + return pwrite64(fd, buf, byte_count, static_cast(offset)); +} + +// On LP32, there is no off_t preadv/pwritev, and even the 64-bit preadv/pwritev +// don't use off64_t (see SYSCALLS.TXT for more). Here, this means that we need +// to implement all four functions because the two system calls don't match any +// of the userspace functions. Unlike llseek, the pair is split lo-hi, not hi-lo. +ssize_t preadv(int fd, const struct iovec* ios, int count, off_t offset) { + return preadv64(fd, ios, count, offset); +} +ssize_t preadv64(int fd, const struct iovec* ios, int count, off64_t offset) { + return __preadv64(fd, ios, count, offset, offset >> 32); +} +ssize_t pwritev(int fd, const struct iovec* ios, int count, off_t offset) { + return pwritev64(fd, ios, count, offset); +} +ssize_t pwritev64(int fd, const struct iovec* ios, int count, off64_t offset) { + return __pwritev64(fd, ios, count, offset, offset >> 32); +} + +// There is no fallocate for 32-bit off_t, so we need to widen and call fallocate64. +int fallocate(int fd, int mode, off_t offset, off_t length) { + return fallocate64(fd, mode, static_cast(offset), static_cast(length)); +} + +// There is no getrlimit64 system call, so we need to use prlimit64. +int getrlimit64(int resource, rlimit64* limits64) { + return prlimit64(0, resource, nullptr, limits64); +} + +// There is no setrlimit64 system call, so we need to use prlimit64. +int setrlimit64(int resource, const rlimit64* limits64) { + return prlimit64(0, resource, limits64, nullptr); +} + +// There is no prlimit system call, so we need to use prlimit64. +int prlimit(pid_t pid, int resource, const rlimit* n32, rlimit* o32) { + rlimit64 n64; + if (n32 != nullptr) { + n64.rlim_cur = (n32->rlim_cur == RLIM_INFINITY) ? RLIM64_INFINITY : n32->rlim_cur; + n64.rlim_max = (n32->rlim_max == RLIM_INFINITY) ? RLIM64_INFINITY : n32->rlim_max; + } + + rlimit64 o64; + int result = prlimit64(pid, resource, + (n32 != nullptr) ? &n64 : nullptr, + (o32 != nullptr) ? &o64 : nullptr); + if (result != -1 && o32 != nullptr) { + o32->rlim_cur = (o64.rlim_cur == RLIM64_INFINITY) ? RLIM_INFINITY : o64.rlim_cur; + o32->rlim_max = (o64.rlim_max == RLIM64_INFINITY) ? RLIM_INFINITY : o64.rlim_max; + } + return result; +} diff --git a/aosp/bionic/libc/bionic/lfs64_support.cpp b/aosp/bionic/libc/bionic/lfs64_support.cpp new file mode 100644 index 000000000..45d4f7f1b --- /dev/null +++ b/aosp/bionic/libc/bionic/lfs64_support.cpp @@ -0,0 +1,48 @@ +/* + * 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 +#include + +// Delegation will work in these cases because all the transitive dependencies +// are already 64-bit ready. In particular, we don't have non-O_LARGEFILE +// open (our open is actually open64) and stat and stat64 are the same. +int mkstemp64(char* path) { + return mkstemp(path); +} +int mkostemp64(char* path, int flags) { + return mkostemp(path, flags); +} +int mkstemps64(char* path, int suffix_length) { + return mkstemps(path, suffix_length); +} +int mkostemps64(char* path, int suffix_length, int flags) { + return mkostemps(path, suffix_length, flags); +} + +typedef int (*ftw_fn)(const char*, const struct stat*, int); +typedef int (*nftw_fn)(const char*, const struct stat*, int, struct FTW*); + +int ftw64(const char *dirpath, + int (*fn)(const char*, const struct stat64*, int), int nopenfd) { + return ftw(dirpath, reinterpret_cast(fn), nopenfd); +} + +int nftw64(const char * dirpath, + int (*fn)(const char*, const struct stat64*, int, struct FTW*), + int nopenfd, int flags) { + return nftw(dirpath, reinterpret_cast(fn), nopenfd, flags); +} diff --git a/aosp/bionic/libc/bionic/libc_init_common.cpp b/aosp/bionic/libc/bionic/libc_init_common.cpp new file mode 100644 index 000000000..a82ca50b6 --- /dev/null +++ b/aosp/bionic/libc/bionic/libc_init_common.cpp @@ -0,0 +1,376 @@ +/* + * 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 "libc_init_common.h" +#include "heap_tagging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "private/WriteProtected.h" +#include "private/bionic_defs.h" +#include "private/bionic_globals.h" +#include "private/bionic_tls.h" +#include "private/thread_private.h" +#include "pthread_internal.h" + +extern "C" int __system_properties_init(void); + +__LIBC_HIDDEN__ WriteProtected __libc_globals; + +// Not public, but well-known in the BSDs. +const char* __progname; + +void __libc_init_globals() { + // Initialize libc globals that are needed in both the linker and in libc. + // In dynamic binaries, this is run at least twice for different copies of the + // globals, once for the linker's copy and once for the one in libc.so. + __libc_globals.initialize(); + __libc_globals.mutate([](libc_globals* globals) { + __libc_init_vdso(globals); + __libc_init_setjmp_cookie(globals); + }); +} + +#if !defined(__LP64__) +static void __check_max_thread_id() { + if (gettid() > 65535) { + async_safe_fatal("Limited by the size of pthread_mutex_t, 32 bit bionic libc only accepts " + "pid <= 65535, but current pid is %d", gettid()); + } +} +#endif + +static void arc4random_fork_handler() { + _rs_forked = 1; + _thread_arc4_lock(); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void __libc_add_main_thread() { + // Get the main thread from TLS and add it to the thread list. + pthread_internal_t* main_thread = __get_thread(); + __pthread_internal_add(main_thread); +} + +void __libc_init_common() { + // Initialize various globals. + environ = __libc_shared_globals()->init_environ; + errno = 0; + setprogname(__libc_shared_globals()->init_progname ?: ""); + +#if !defined(__LP64__) + __check_max_thread_id(); +#endif + + __libc_add_main_thread(); + + __system_properties_init(); // Requires 'environ'. + __libc_init_fdsan(); // Requires system properties (for debug.fdsan). + __libc_init_fdtrack(); + + SetDefaultHeapTaggingLevel(); +} + +void __libc_init_fork_handler() { + // Register atfork handlers to take and release the arc4random lock. + pthread_atfork(arc4random_fork_handler, _thread_arc4_unlock, _thread_arc4_unlock); +} + +__noreturn static void __early_abort(int line) { + // We can't write to stdout or stderr because we're aborting before we've checked that + // it's safe for us to use those file descriptors. We probably can't strace either, so + // we rely on the fact that if we dereference a low address, either debuggerd or the + // kernel's crash dump will show the fault address. + *reinterpret_cast(line) = 0; + _exit(EXIT_FAILURE); +} + +// Force any of the closed stdin, stdout and stderr to be associated with /dev/null. +static void __nullify_closed_stdio() { + int dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); + if (dev_null == -1) { + // init won't have /dev/null available, but SELinux provides an equivalent. + dev_null = TEMP_FAILURE_RETRY(open("/sys/fs/selinux/null", O_RDWR)); + } + if (dev_null == -1) { + __early_abort(__LINE__); + } + + // If any of the stdio file descriptors is valid and not associated + // with /dev/null, dup /dev/null to it. + for (int i = 0; i < 3; i++) { + // If it is /dev/null already, we are done. + if (i == dev_null) { + continue; + } + + // Is this fd already open? + int status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL)); + if (status != -1) { + continue; + } + + // The only error we allow is that the file descriptor does not + // exist, in which case we dup /dev/null to it. + if (errno == EBADF) { + // Try dupping /dev/null to this stdio file descriptor and + // repeat if there is a signal. Note that any errors in closing + // the stdio descriptor are lost. + status = TEMP_FAILURE_RETRY(dup2(dev_null, i)); + if (status == -1) { + __early_abort(__LINE__); + } + } else { + __early_abort(__LINE__); + } + } + + // If /dev/null is not one of the stdio file descriptors, close it. + if (dev_null > 2) { + if (close(dev_null) == -1) { + __early_abort(__LINE__); + } + } +} + +// Check if the environment variable definition at 'envstr' +// starts with '=', and if so return the address of the +// first character after the equal sign. Otherwise return null. +static const char* env_match(const char* envstr, const char* name) { + size_t i = 0; + + while (envstr[i] == name[i] && name[i] != '\0') { + ++i; + } + + if (name[i] == '\0' && envstr[i] == '=') { + return envstr + i + 1; + } + + return nullptr; +} + +static bool __is_valid_environment_variable(const char* name) { + // According to the kernel source, by default the kernel uses 32*PAGE_SIZE + // as the maximum size for an environment variable definition. + const int MAX_ENV_LEN = 32*4096; + + if (name == nullptr) { + return false; + } + + // Parse the string, looking for the first '=' there, and its size. + int pos = 0; + int first_equal_pos = -1; + while (pos < MAX_ENV_LEN) { + if (name[pos] == '\0') { + break; + } + if (name[pos] == '=' && first_equal_pos < 0) { + first_equal_pos = pos; + } + pos++; + } + + // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings). + if (pos >= MAX_ENV_LEN) { + return false; + } + + // Check that it contains at least one equal sign that is not the first character + if (first_equal_pos < 1) { + return false; + } + + return true; +} + +static bool __is_unsafe_environment_variable(const char* name) { + // None of these should be allowed when the AT_SECURE auxv + // flag is set. This flag is set to inform userspace that a + // security transition has occurred, for example, as a result + // of executing a setuid program or the result of an SELinux + // security transition. + static constexpr const char* UNSAFE_VARIABLE_NAMES[] = { + "ANDROID_DNS_MODE", + "GCONV_PATH", + "GETCONF_DIR", + "HOSTALIASES", + "JE_MALLOC_CONF", + "LD_AOUT_LIBRARY_PATH", + "LD_AOUT_PRELOAD", + "LD_AUDIT", + "LD_CONFIG_FILE", + "LD_DEBUG", + "LD_DEBUG_OUTPUT", + "LD_DYNAMIC_WEAK", + "LD_LIBRARY_PATH", + "LD_ORIGIN_PATH", + "LD_PRELOAD", + "LD_PROFILE", + "LD_SHOW_AUXV", + "LD_USE_LOAD_BIAS", + "LIBC_DEBUG_MALLOC_OPTIONS", + "LIBC_HOOKS_ENABLE", + "LOCALDOMAIN", + "LOCPATH", + "MALLOC_CHECK_", + "MALLOC_CONF", + "MALLOC_TRACE", + "NIS_PATH", + "NLSPATH", + "RESOLV_HOST_CONF", + "RES_OPTIONS", + "SCUDO_OPTIONS", + "TMPDIR", + "TZDIR", + }; + for (const auto& unsafe_variable_name : UNSAFE_VARIABLE_NAMES) { + if (env_match(name, unsafe_variable_name) != nullptr) { + return true; + } + } + return false; +} + +static void __sanitize_environment_variables(char** env) { + char** src = env; + char** dst = env; + for (; src[0] != nullptr; ++src) { + if (!__is_valid_environment_variable(src[0])) { + continue; + } + // Remove various unsafe environment variables if we're loading a setuid program. + if (__is_unsafe_environment_variable(src[0])) { + continue; + } + dst[0] = src[0]; + ++dst; + } + dst[0] = nullptr; +} + +static void __initialize_personality() { +#if !defined(__LP64__) + int old_value = personality(0xffffffff); + if (old_value == -1) { + async_safe_fatal("error getting old personality value: %s", strerror(errno)); + } + + if (personality((static_cast(old_value) & ~PER_MASK) | PER_LINUX32) == -1) { + async_safe_fatal("error setting PER_LINUX32 personality: %s", strerror(errno)); + } +#endif +} + +void __libc_init_AT_SECURE(char** env) { + // Check that the kernel provided a value for AT_SECURE. + errno = 0; + unsigned long is_AT_SECURE = getauxval(AT_SECURE); + if (errno != 0) __early_abort(__LINE__); + + // Always ensure that STDIN/STDOUT/STDERR exist. This prevents file + // descriptor confusion bugs where a parent process closes + // STD*, the exec()d process calls open() for an unrelated reason, + // the newly created file descriptor is assigned + // 0<=FD<=2, and unrelated code attempts to read / write to the STD* + // FDs. + // In particular, this can be a security bug for setuid/setgid programs. + // For example: + // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc + // However, for robustness reasons, we don't limit these protections to + // just security critical executables. + // + // Init is excluded from these protections unless AT_SECURE is set, as + // /dev/null and/or /sys/fs/selinux/null will not be available at + // early boot. + if ((getpid() != 1) || is_AT_SECURE) { + __nullify_closed_stdio(); + } + + if (is_AT_SECURE) { + __sanitize_environment_variables(env); + } + + // Now the environment has been sanitized, make it available. + environ = __libc_shared_globals()->init_environ = env; + + __initialize_personality(); +} + +/* This function will be called during normal program termination + * to run the destructors that are listed in the .fini_array section + * of the executable, if any. + * + * 'fini_array' points to a list of function addresses. The first + * entry in the list has value -1, the last one has value 0. + */ +void __libc_fini(void* array) { + typedef void (*Dtor)(); + Dtor* fini_array = reinterpret_cast(array); + const Dtor minus1 = reinterpret_cast(static_cast(-1)); + + // Sanity check - first entry must be -1. + if (array == nullptr || fini_array[0] != minus1) { + return; + } + + // Skip over it. + fini_array += 1; + + // Count the number of destructors. + int count = 0; + while (fini_array[count] != nullptr) { + ++count; + } + + // Now call each destructor in reverse order. + while (count > 0) { + Dtor dtor = fini_array[--count]; + + // Sanity check, any -1 in the list is ignored. + if (dtor == minus1) { + continue; + } + + dtor(); + } +} diff --git a/aosp/bionic/libc/bionic/libc_init_common.h b/aosp/bionic/libc/bionic/libc_init_common.h new file mode 100644 index 000000000..0c2e78a01 --- /dev/null +++ b/aosp/bionic/libc/bionic/libc_init_common.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#pragma once + +#include + +typedef struct { + void (**preinit_array)(void); + void (**init_array)(void); + void (**fini_array)(void); +} structors_array_t; + +__BEGIN_DECLS + +extern int main(int argc, char** argv, char** env); + +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void), + int (*slingshot)(int, char**, char**), + structors_array_t const* const structors); +__LIBC_HIDDEN__ void __libc_fini(void* finit_array); + +__END_DECLS + +#if defined(__cplusplus) + +__LIBC_HIDDEN__ void __libc_init_globals(); + +__LIBC_HIDDEN__ void __libc_init_common(); + +__LIBC_HIDDEN__ void __libc_init_AT_SECURE(char** envp); + +// The fork handler must be initialised after __libc_init_malloc, as +// pthread_atfork may call malloc() during its once-init. +__LIBC_HIDDEN__ void __libc_init_fork_handler(); + +#endif diff --git a/aosp/bionic/libc/bionic/libc_init_dynamic.cpp b/aosp/bionic/libc/bionic/libc_init_dynamic.cpp new file mode 100644 index 000000000..c9da02eab --- /dev/null +++ b/aosp/bionic/libc/bionic/libc_init_dynamic.cpp @@ -0,0 +1,160 @@ +/* + * 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. + */ + +/* + * This source files provides two important functions for dynamic + * executables: + * + * - a C runtime initializer (__libc_preinit), which is called by + * the dynamic linker when libc.so is loaded. This happens before + * any other initializer (e.g. static C++ constructors in other + * shared libraries the program depends on). + * + * - a program launch function (__libc_init), which is called after + * all dynamic linking has been performed. + */ + +#include +#include +#include +#include +#include +#include "libc_init_common.h" + +#include "private/bionic_elf_tls.h" +#include "private/bionic_globals.h" +#include "platform/bionic/macros.h" +#include "private/bionic_ssp.h" +#include "private/bionic_tls.h" +#include "private/KernelArgumentBlock.h" + +extern "C" { + extern void netdClientInit(void); + extern int __cxa_atexit(void (*)(void *), void *, void *); +}; + +// Use an initializer so __libc_sysinfo will have a fallback implementation +// while .preinit_array constructors run. +#if defined(__i386__) +__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast(__libc_int0x80); +#endif + +extern "C" __attribute__((weak)) void __hwasan_library_loaded(ElfW(Addr) base, + const ElfW(Phdr)* phdr, + ElfW(Half) phnum); +extern "C" __attribute__((weak)) void __hwasan_library_unloaded(ElfW(Addr) base, + const ElfW(Phdr)* phdr, + ElfW(Half) phnum); + +// We need a helper function for __libc_preinit because compiling with LTO may +// inline functions requiring a stack protector check, but __stack_chk_guard is +// not initialized at the start of __libc_preinit. __libc_preinit_impl will run +// after __stack_chk_guard is initialized and therefore can safely have a stack +// protector. +__attribute__((noinline)) +static void __libc_preinit_impl() { +#if defined(__i386__) + __libc_init_sysinfo(); +#endif + + // Register libc.so's copy of the TLS generation variable so the linker can + // update it when it loads or unloads a shared object. + TlsModules& tls_modules = __libc_shared_globals()->tls_modules; + tls_modules.generation_libc_so = &__libc_tls_generation_copy; + __libc_tls_generation_copy = tls_modules.generation; + + __libc_init_globals(); + __libc_init_common(); + + // Hooks for various libraries to let them know that we're starting up. + __libc_globals.mutate(__libc_init_malloc); + + // Install reserved signal handlers for assisting the platform's profilers. + __libc_init_profiling_handlers(); + + __libc_init_fork_handler(); + +#if __has_feature(hwaddress_sanitizer) + // Notify the HWASan runtime library whenever a library is loaded or unloaded + // so that it can update its shadow memory. + __libc_shared_globals()->load_hook = __hwasan_library_loaded; + __libc_shared_globals()->unload_hook = __hwasan_library_unloaded; +#endif + + netdClientInit(); +} + +// We flag the __libc_preinit function as a constructor to ensure that +// its address is listed in libc.so's .init_array section. +// This ensures that the function is called by the dynamic linker as +// soon as the shared library is loaded. +// We give this constructor priority 1 because we want libc's constructor +// to run before any others (such as the jemalloc constructor), and lower +// is better (http://b/68046352). +__attribute__((constructor(1))) static void __libc_preinit() { + // The linker has initialized its copy of the global stack_chk_guard, and filled in the main + // thread's TLS slot with that value. Initialize the local global stack guard with its value. + __stack_chk_guard = reinterpret_cast(__get_tls()[TLS_SLOT_STACK_GUARD]); + + __libc_preinit_impl(); +} + +// This function is called from the executable's _start entry point +// (see arch-$ARCH/bionic/crtbegin.c), which is itself called by the dynamic +// linker after it has loaded all shared libraries the executable depends on. +// +// Note that the dynamic linker has also run all constructors in the +// executable at this point. +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void) __unused, + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors) { + BIONIC_STOP_UNWIND; + + KernelArgumentBlock args(raw_args); + + // Several Linux ABIs don't pass the onexit pointer, and the ones that + // do never use it. Therefore, we ignore it. + + // The executable may have its own destructors listed in its .fini_array + // so we need to ensure that these are called when the program exits + // normally. + if (structors->fini_array) { + __cxa_atexit(__libc_fini,structors->fini_array,nullptr); + } + + exit(slingshot(args.argc - __libc_shared_globals()->initial_linker_arg_count, + args.argv + __libc_shared_globals()->initial_linker_arg_count, + args.envp)); +} + +extern "C" libc_shared_globals* __loader_shared_globals(); + +__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals() { + return __loader_shared_globals(); +} diff --git a/aosp/bionic/libc/bionic/libc_init_static.cpp b/aosp/bionic/libc/bionic/libc_init_static.cpp new file mode 100644 index 000000000..cf5423e00 --- /dev/null +++ b/aosp/bionic/libc/bionic/libc_init_static.cpp @@ -0,0 +1,238 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libc_init_common.h" +#include "pthread_internal.h" + +#include "platform/bionic/page.h" +#include "private/bionic_call_ifunc_resolver.h" +#include "private/bionic_elf_tls.h" +#include "private/bionic_globals.h" +#include "platform/bionic/macros.h" +#include "private/bionic_tls.h" +#include "private/KernelArgumentBlock.h" + +#if __has_feature(hwaddress_sanitizer) +#include +#endif + +// Leave the variable uninitialized for the sake of the dynamic loader, which +// links in this file. The loader will initialize this variable before +// relocating itself. +#if defined(__i386__) +__LIBC_HIDDEN__ void* __libc_sysinfo; +#endif + +extern "C" int __cxa_atexit(void (*)(void *), void *, void *); + +static void call_array(void(**list)()) { + // First element is -1, list is null-terminated + while (*++list) { + (*list)(); + } +} + +#if defined(__aarch64__) || defined(__x86_64__) +extern __LIBC_HIDDEN__ __attribute__((weak)) ElfW(Rela) __rela_iplt_start[], __rela_iplt_end[]; + +static void call_ifunc_resolvers() { + if (__rela_iplt_start == nullptr || __rela_iplt_end == nullptr) { + // These symbols are not emitted by gold. Gold has code to do so, but for + // whatever reason it is not being run. In these cases ifuncs cannot be + // resolved, so we do not support using ifuncs in static executables linked + // with gold. + // + // Since they are weak, they will be non-null when linked with bfd/lld and + // null when linked with gold. + return; + } + + for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast(r->r_offset); + ElfW(Addr) resolver = r->r_addend; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#else +extern __LIBC_HIDDEN__ __attribute__((weak)) ElfW(Rel) __rel_iplt_start[], __rel_iplt_end[]; + +static void call_ifunc_resolvers() { + if (__rel_iplt_start == nullptr || __rel_iplt_end == nullptr) { + // These symbols are not emitted by gold. Gold has code to do so, but for + // whatever reason it is not being run. In these cases ifuncs cannot be + // resolved, so we do not support using ifuncs in static executables linked + // with gold. + // + // Since they are weak, they will be non-null when linked with bfd/lld and + // null when linked with gold. + return; + } + + for (ElfW(Rel) *r = __rel_iplt_start; r != __rel_iplt_end; ++r) { + ElfW(Addr)* offset = reinterpret_cast(r->r_offset); + ElfW(Addr) resolver = *offset; + *offset = __bionic_call_ifunc_resolver(resolver); + } +} +#endif + +static void apply_gnu_relro() { + ElfW(Phdr)* phdr_start = reinterpret_cast(getauxval(AT_PHDR)); + unsigned long int phdr_ct = getauxval(AT_PHNUM); + + for (ElfW(Phdr)* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) { + if (phdr->p_type != PT_GNU_RELRO) { + continue; + } + + ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr); + ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz); + + // Check return value here? What do we do if we fail? + mprotect(reinterpret_cast(seg_page_start), seg_page_end - seg_page_start, PROT_READ); + } +} + +static void layout_static_tls(KernelArgumentBlock& args) { + StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + layout.reserve_bionic_tls(); + + const char* progname = args.argv[0]; + ElfW(Phdr)* phdr_start = reinterpret_cast(getauxval(AT_PHDR)); + size_t phdr_ct = getauxval(AT_PHNUM); + + static TlsModule mod; + TlsModules& modules = __libc_shared_globals()->tls_modules; + if (__bionic_get_tls_segment(phdr_start, phdr_ct, 0, &mod.segment)) { + if (!__bionic_check_tls_alignment(&mod.segment.alignment)) { + async_safe_fatal("error: TLS segment alignment in \"%s\" is not a power of 2: %zu\n", + progname, mod.segment.alignment); + } + mod.static_offset = layout.reserve_exe_segment_and_tcb(&mod.segment, progname); + mod.first_generation = kTlsGenerationFirst; + + modules.module_count = 1; + modules.module_table = &mod; + } else { + layout.reserve_exe_segment_and_tcb(nullptr, progname); + } + // Enable the fast path in __tls_get_addr. + __libc_tls_generation_copy = modules.generation; + + layout.finish_layout(); +} + +__noreturn static void __real_libc_init(void *raw_args, + void (*onexit)(void) __unused, + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors, + bionic_tcb* temp_tcb) { + BIONIC_STOP_UNWIND; + + // Initialize TLS early so system calls and errno work. + KernelArgumentBlock args(raw_args); + __libc_init_main_thread_early(args, temp_tcb); + __libc_init_main_thread_late(); + __libc_init_globals(); + __libc_shared_globals()->init_progname = args.argv[0]; + __libc_init_AT_SECURE(args.envp); + layout_static_tls(args); + __libc_init_main_thread_final(); + __libc_init_common(); + __libc_init_fork_handler(); + + call_ifunc_resolvers(); + apply_gnu_relro(); + + // Several Linux ABIs don't pass the onexit pointer, and the ones that + // do never use it. Therefore, we ignore it. + + call_array(structors->preinit_array); + call_array(structors->init_array); + + // The executable may have its own destructors listed in its .fini_array + // so we need to ensure that these are called when the program exits + // normally. + if (structors->fini_array != nullptr) { + __cxa_atexit(__libc_fini,structors->fini_array,nullptr); + } + + exit(slingshot(args.argc, args.argv, args.envp)); +} + +extern "C" void __hwasan_init_static(); + +// This __libc_init() is only used for static executables, and is called from crtbegin.c. +// +// The 'structors' parameter contains pointers to various initializer +// arrays that must be run before the program's 'main' routine is launched. +__attribute__((no_sanitize("hwaddress"))) +__noreturn void __libc_init(void* raw_args, + void (*onexit)(void) __unused, + int (*slingshot)(int, char**, char**), + structors_array_t const * const structors) { + bionic_tcb temp_tcb = {}; +#if __has_feature(hwaddress_sanitizer) + // Install main thread TLS early. It will be initialized later in __libc_init_main_thread. For now + // all we need is access to TLS_SLOT_SANITIZER. + __set_tls(&temp_tcb.tls_slot(0)); + // Initialize HWASan enough to run instrumented code. This sets up TLS_SLOT_SANITIZER, among other + // things. + __hwasan_init_static(); + // We are ready to run HWASan-instrumented code, proceed with libc initialization... +#endif + __real_libc_init(raw_args, onexit, slingshot, structors, &temp_tcb); +} + +static int g_target_sdk_version{__ANDROID_API__}; + +extern "C" int android_get_application_target_sdk_version() { + return g_target_sdk_version; +} + +extern "C" void android_set_application_target_sdk_version(int target) { + g_target_sdk_version = target; +} + +// This function is called in the dynamic linker before ifunc resolvers have run, so this file is +// compiled with -ffreestanding to avoid implicit string.h function calls. (It shouldn't strictly +// be necessary, though.) +__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals() { + static libc_shared_globals globals; + return &globals; +} diff --git a/aosp/bionic/libc/bionic/libgen.cpp b/aosp/bionic/libc/bionic/libgen.cpp new file mode 100644 index 000000000..b9528227d --- /dev/null +++ b/aosp/bionic/libc/bionic/libgen.cpp @@ -0,0 +1,170 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +#include "bionic/pthread_internal.h" + +static int __basename_r(const char* path, char* buffer, size_t buffer_size) { + const char* startp = nullptr; + const char* endp = nullptr; + int len; + int result; + + // Empty or NULL string gets treated as ".". + if (path == nullptr || *path == '\0') { + startp = "."; + len = 1; + goto Exit; + } + + // Strip trailing slashes. + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') { + endp--; + } + + // All slashes becomes "/". + if (endp == path && *endp == '/') { + startp = "/"; + len = 1; + goto Exit; + } + + // Find the start of the base. + startp = endp; + while (startp > path && *(startp - 1) != '/') { + startp--; + } + + len = endp - startp +1; + + Exit: + result = len; + if (buffer == nullptr) { + return result; + } + if (len > static_cast(buffer_size) - 1) { + len = buffer_size - 1; + result = -1; + errno = ERANGE; + } + + if (len >= 0) { + memcpy(buffer, startp, len); + buffer[len] = 0; + } + return result; +} + +// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable. +__LIBC32_LEGACY_PUBLIC__ int basename_r(const char* path, char* buffer, size_t buffer_size) { + return __basename_r(path, buffer, buffer_size); +} + +static int __dirname_r(const char* path, char* buffer, size_t buffer_size) { + const char* endp = nullptr; + int len; + int result; + + // Empty or NULL string gets treated as ".". + if (path == nullptr || *path == '\0') { + path = "."; + len = 1; + goto Exit; + } + + // Strip trailing slashes. + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') { + endp--; + } + + // Find the start of the dir. + while (endp > path && *endp != '/') { + endp--; + } + + // Either the dir is "/" or there are no slashes. + if (endp == path) { + path = (*endp == '/') ? "/" : "."; + len = 1; + goto Exit; + } + + do { + endp--; + } while (endp > path && *endp == '/'); + + len = endp - path + 1; + + Exit: + result = len; + if (len + 1 > MAXPATHLEN) { + errno = ENAMETOOLONG; + return -1; + } + if (buffer == nullptr) { + return result; + } + + if (len > static_cast(buffer_size) - 1) { + len = buffer_size - 1; + result = -1; + errno = ERANGE; + } + + if (len >= 0) { + memcpy(buffer, path, len); + buffer[len] = 0; + } + return result; +} + +// Since this is a non-standard symbol, it might be hijacked by a basename_r in the executable. +__LIBC32_LEGACY_PUBLIC__ int dirname_r(const char* path, char* buffer, size_t buffer_size) { + return __dirname_r(path, buffer, buffer_size); +} + +char* basename(const char* path) { + char* buf = __get_bionic_tls().basename_buf; + int rc = __basename_r(path, buf, sizeof(__get_bionic_tls().basename_buf)); + return (rc < 0) ? nullptr : buf; +} + +char* dirname(const char* path) { + char* buf = __get_bionic_tls().dirname_buf; + int rc = __dirname_r(path, buf, sizeof(__get_bionic_tls().dirname_buf)); + return (rc < 0) ? nullptr : buf; +} diff --git a/aosp/bionic/libc/bionic/link.cpp b/aosp/bionic/libc/bionic/link.cpp new file mode 100644 index 000000000..65ad374e5 --- /dev/null +++ b/aosp/bionic/libc/bionic/link.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int link(const char* old_path, const char* new_path) { + return linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} diff --git a/aosp/bionic/libc/bionic/locale.cpp b/aosp/bionic/libc/bionic/locale.cpp new file mode 100644 index 000000000..0b7037afe --- /dev/null +++ b/aosp/bionic/libc/bionic/locale.cpp @@ -0,0 +1,199 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "platform/bionic/macros.h" + +#if defined(__BIONIC_BUILD_FOR_ANDROID_SUPPORT) +#define USE_TLS_SLOT 0 +#else +#define USE_TLS_SLOT 1 +#endif + +#if USE_TLS_SLOT +#include "bionic/pthread_internal.h" +#endif + +// We only support two locales, the "C" locale (also known as "POSIX"), +// and the "C.UTF-8" locale (also known as "en_US.UTF-8"). + +static bool __bionic_current_locale_is_utf8 = true; + +struct __locale_t { + size_t mb_cur_max; + + explicit __locale_t(size_t mb_cur_max) : mb_cur_max(mb_cur_max) { + } + + explicit __locale_t(const __locale_t* other) { + if (other == LC_GLOBAL_LOCALE) { + mb_cur_max = __bionic_current_locale_is_utf8 ? 4 : 1; + } else { + mb_cur_max = other->mb_cur_max; + } + } + + BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(__locale_t); +}; + +size_t __ctype_get_mb_cur_max() { + locale_t l = uselocale(nullptr); + if (l == LC_GLOBAL_LOCALE) { + return __bionic_current_locale_is_utf8 ? 4 : 1; + } else { + return l->mb_cur_max; + } +} + +#if !USE_TLS_SLOT +static thread_local locale_t g_current_locale; +#endif + +static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT; +static lconv g_locale; + +static void __locale_init() { + g_locale.decimal_point = const_cast("."); + + char* not_available = const_cast(""); + g_locale.thousands_sep = not_available; + g_locale.grouping = not_available; + g_locale.int_curr_symbol = not_available; + g_locale.currency_symbol = not_available; + g_locale.mon_decimal_point = not_available; + g_locale.mon_thousands_sep = not_available; + g_locale.mon_grouping = not_available; + g_locale.positive_sign = not_available; + g_locale.negative_sign = not_available; + + g_locale.int_frac_digits = CHAR_MAX; + g_locale.frac_digits = CHAR_MAX; + g_locale.p_cs_precedes = CHAR_MAX; + g_locale.p_sep_by_space = CHAR_MAX; + g_locale.n_cs_precedes = CHAR_MAX; + g_locale.n_sep_by_space = CHAR_MAX; + g_locale.p_sign_posn = CHAR_MAX; + g_locale.n_sign_posn = CHAR_MAX; + g_locale.int_p_cs_precedes = CHAR_MAX; + g_locale.int_p_sep_by_space = CHAR_MAX; + g_locale.int_n_cs_precedes = CHAR_MAX; + g_locale.int_n_sep_by_space = CHAR_MAX; + g_locale.int_p_sign_posn = CHAR_MAX; + g_locale.int_n_sign_posn = CHAR_MAX; +} + +static bool __is_supported_locale(const char* locale_name) { + return (strcmp(locale_name, "") == 0 || + strcmp(locale_name, "C") == 0 || + strcmp(locale_name, "C.UTF-8") == 0 || + strcmp(locale_name, "en_US.UTF-8") == 0 || + strcmp(locale_name, "POSIX") == 0); +} + +static bool __is_utf8_locale(const char* locale_name) { + return (*locale_name == '\0' || strstr(locale_name, "UTF-8")); +} + +lconv* localeconv() { + pthread_once(&g_locale_once, __locale_init); + return &g_locale; +} + +locale_t duplocale(locale_t l) { + return new __locale_t(l); +} + +void freelocale(locale_t l) { + delete l; +} + +locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/) { + // Are 'category_mask' and 'locale_name' valid? + if ((category_mask & ~LC_ALL_MASK) != 0 || locale_name == nullptr) { + errno = EINVAL; + return nullptr; + } + + if (!__is_supported_locale(locale_name)) { + errno = ENOENT; + return nullptr; + } + + return new __locale_t(__is_utf8_locale(locale_name) ? 4 : 1); +} + +char* setlocale(int category, const char* locale_name) { + // Is 'category' valid? + if (category < LC_CTYPE || category > LC_IDENTIFICATION) { + errno = EINVAL; + return nullptr; + } + + // Caller wants to set the locale rather than just query? + if (locale_name != nullptr) { + if (!__is_supported_locale(locale_name)) { + // We don't support this locale. + errno = ENOENT; + return nullptr; + } + __bionic_current_locale_is_utf8 = __is_utf8_locale(locale_name); + } + + return const_cast(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C"); +} + +static locale_t* get_current_locale_ptr() { +#if USE_TLS_SLOT + return &__get_bionic_tls().locale; +#else + return &g_current_locale; +#endif +} + +locale_t uselocale(locale_t new_locale) { + locale_t old_locale = *get_current_locale_ptr(); + + // If this is the first call to uselocale(3) on this thread, we return LC_GLOBAL_LOCALE. + if (old_locale == nullptr) { + old_locale = LC_GLOBAL_LOCALE; + } + + if (new_locale != nullptr) { + *get_current_locale_ptr() = new_locale; + } + + return old_locale; +} diff --git a/aosp/bionic/libc/bionic/lockf.cpp b/aosp/bionic/libc/bionic/lockf.cpp new file mode 100644 index 000000000..804ad68bd --- /dev/null +++ b/aosp/bionic/libc/bionic/lockf.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 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 + +#include +#include +#include + +int lockf64(int fd, int cmd, off64_t length) { + // Translate POSIX lockf into fcntl. + struct flock64 fl; + memset(&fl, 0, sizeof(fl)); + fl.l_whence = SEEK_CUR; + fl.l_start = 0; + fl.l_len = length; + + if (cmd == F_ULOCK) { + fl.l_type = F_UNLCK; + cmd = F_SETLK64; + return fcntl(fd, F_SETLK64, &fl); + } + + if (cmd == F_LOCK) { + fl.l_type = F_WRLCK; + return fcntl(fd, F_SETLKW64, &fl); + } + + if (cmd == F_TLOCK) { + fl.l_type = F_WRLCK; + return fcntl(fd, F_SETLK64, &fl); + } + + if (cmd == F_TEST) { + fl.l_type = F_RDLCK; + if (fcntl(fd, F_GETLK64, &fl) == -1) return -1; + if (fl.l_type == F_UNLCK || fl.l_pid == getpid()) return 0; + errno = EACCES; + return -1; + } + + errno = EINVAL; + return -1; +} + +int lockf(int fd, int cmd, off_t length) { + return lockf64(fd, cmd, length); +} diff --git a/aosp/bionic/libc/bionic/lstat.cpp b/aosp/bionic/libc/bionic/lstat.cpp new file mode 100644 index 000000000..84d17e262 --- /dev/null +++ b/aosp/bionic/libc/bionic/lstat.cpp @@ -0,0 +1,37 @@ +/* + * 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 +#include +#include +#include + +int lstat(const char* path, struct stat* sb) { + return fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW); +} +__strong_alias(lstat64, lstat); diff --git a/aosp/bionic/libc/bionic/malloc_common.cpp b/aosp/bionic/libc/bionic/malloc_common.cpp new file mode 100644 index 000000000..ed5537f5f --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_common.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2009 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. + */ + +// Contains a thin layer that calls whatever real native allocator +// has been defined. For the libc shared library, this allows the +// implementation of a debug malloc that can intercept all of the allocation +// calls and add special debugging code to attempt to catch allocation +// errors. All of the debugging code is implemented in a separate shared +// library that is only loaded when the property "libc.debug.malloc.options" +// is set to a non-zero value. + +#include +#include +#include + +#include +#include + +#include "gwp_asan_wrappers.h" +#include "heap_tagging.h" +#include "malloc_common.h" +#include "malloc_limit.h" +#include "malloc_tagged_pointers.h" + +// ============================================================================= +// Global variables instantations. +// ============================================================================= + +// Malloc hooks globals. +void* (*volatile __malloc_hook)(size_t, const void*); +void* (*volatile __realloc_hook)(void*, size_t, const void*); +void (*volatile __free_hook)(void*, const void*); +void* (*volatile __memalign_hook)(size_t, size_t, const void*); +// ============================================================================= + +// ============================================================================= +// Allocation functions +// ============================================================================= +extern "C" void* calloc(size_t n_elements, size_t elem_size) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->calloc(n_elements, elem_size)); + } + void* result = Malloc(calloc)(n_elements, elem_size); + if (__predict_false(result == nullptr)) { + warning_log("calloc(%zu, %zu) failed: returning null pointer", n_elements, elem_size); + } + return MaybeTagPointer(result); +} + +extern "C" void free(void* mem) { + auto dispatch_table = GetDispatchTable(); + mem = MaybeUntagAndCheckPointer(mem); + if (__predict_false(dispatch_table != nullptr)) { + dispatch_table->free(mem); + } else { + Malloc(free)(mem); + } +} + +extern "C" struct mallinfo mallinfo() { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->mallinfo(); + } + return Malloc(mallinfo)(); +} + +extern "C" int malloc_info(int options, FILE* fp) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_info(options, fp); + } + return Malloc(malloc_info)(options, fp); +} + +extern "C" int mallopt(int param, int value) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->mallopt(param, value); + } + return Malloc(mallopt)(param, value); +} + +extern "C" void* malloc(size_t bytes) { + auto dispatch_table = GetDispatchTable(); + void *result; + if (__predict_false(dispatch_table != nullptr)) { + result = dispatch_table->malloc(bytes); + } else { + result = Malloc(malloc)(bytes); + } + if (__predict_false(result == nullptr)) { + warning_log("malloc(%zu) failed: returning null pointer", bytes); + return nullptr; + } + return MaybeTagPointer(result); +} + +extern "C" size_t malloc_usable_size(const void* mem) { + auto dispatch_table = GetDispatchTable(); + mem = MaybeUntagAndCheckPointer(mem); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_usable_size(mem); + } + return Malloc(malloc_usable_size)(mem); +} + +extern "C" void* memalign(size_t alignment, size_t bytes) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->memalign(alignment, bytes)); + } + void* result = Malloc(memalign)(alignment, bytes); + if (__predict_false(result == nullptr)) { + warning_log("memalign(%zu, %zu) failed: returning null pointer", alignment, bytes); + } + return MaybeTagPointer(result); +} + +extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) { + auto dispatch_table = GetDispatchTable(); + int result; + if (__predict_false(dispatch_table != nullptr)) { + result = dispatch_table->posix_memalign(memptr, alignment, size); + } else { + result = Malloc(posix_memalign)(memptr, alignment, size); + } + if (result == 0) { + *memptr = MaybeTagPointer(*memptr); + } + return result; +} + +extern "C" void* aligned_alloc(size_t alignment, size_t size) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->aligned_alloc(alignment, size)); + } + void* result = Malloc(aligned_alloc)(alignment, size); + if (__predict_false(result == nullptr)) { + warning_log("aligned_alloc(%zu, %zu) failed: returning null pointer", alignment, size); + } + return MaybeTagPointer(result); +} + +extern "C" __attribute__((__noinline__)) void* realloc(void* old_mem, size_t bytes) { + auto dispatch_table = GetDispatchTable(); + old_mem = MaybeUntagAndCheckPointer(old_mem); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->realloc(old_mem, bytes)); + } + void* result = Malloc(realloc)(old_mem, bytes); + if (__predict_false(result == nullptr && bytes != 0)) { + warning_log("realloc(%p, %zu) failed: returning null pointer", old_mem, bytes); + } + return MaybeTagPointer(result); +} + +extern "C" void* reallocarray(void* old_mem, size_t item_count, size_t item_size) { + size_t new_size; + if (__builtin_mul_overflow(item_count, item_size, &new_size)) { + warning_log("reallocaray(%p, %zu, %zu) failed: returning null pointer", + old_mem, item_count, item_size); + errno = ENOMEM; + return nullptr; + } + return realloc(old_mem, new_size); +} + +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +extern "C" void* pvalloc(size_t bytes) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->pvalloc(bytes)); + } + void* result = Malloc(pvalloc)(bytes); + if (__predict_false(result == nullptr)) { + warning_log("pvalloc(%zu) failed: returning null pointer", bytes); + } + return MaybeTagPointer(result); +} + +extern "C" void* valloc(size_t bytes) { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return MaybeTagPointer(dispatch_table->valloc(bytes)); + } + void* result = Malloc(valloc)(bytes); + if (__predict_false(result == nullptr)) { + warning_log("valloc(%zu) failed: returning null pointer", bytes); + } + return MaybeTagPointer(result); +} +#endif +// ============================================================================= + +struct CallbackWrapperArg { + void (*callback)(uintptr_t base, size_t size, void* arg); + void* arg; +}; + +void CallbackWrapper(uintptr_t base, size_t size, void* arg) { + CallbackWrapperArg* wrapper_arg = reinterpret_cast(arg); + wrapper_arg->callback( + reinterpret_cast(MaybeTagPointer(reinterpret_cast(base))), + size, wrapper_arg->arg); +} + +// ============================================================================= +// Exported for use by libmemunreachable. +// ============================================================================= + +// Calls callback for every allocation in the anonymous heap mapping +// [base, base+size). Must be called between malloc_disable and malloc_enable. +// `base` in this can take either a tagged or untagged pointer, but we always +// provide a tagged pointer to the `base` argument of `callback` if the kernel +// supports tagged pointers. +extern "C" int malloc_iterate(uintptr_t base, size_t size, + void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) { + auto dispatch_table = GetDispatchTable(); + // Wrap the malloc_iterate callback we were provided, in order to provide + // pointer tagging support. + CallbackWrapperArg wrapper_arg; + wrapper_arg.callback = callback; + wrapper_arg.arg = arg; + uintptr_t untagged_base = + reinterpret_cast(UntagPointer(reinterpret_cast(base))); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_iterate( + untagged_base, size, CallbackWrapper, &wrapper_arg); + } + return Malloc(malloc_iterate)( + untagged_base, size, CallbackWrapper, &wrapper_arg); +} + +// Disable calls to malloc so malloc_iterate gets a consistent view of +// allocated memory. +extern "C" void malloc_disable() { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_disable(); + } + return Malloc(malloc_disable)(); +} + +// Re-enable calls to malloc after a previous call to malloc_disable. +extern "C" void malloc_enable() { + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_enable(); + } + return Malloc(malloc_enable)(); +} + +#if defined(LIBC_STATIC) +extern "C" ssize_t malloc_backtrace(void*, uintptr_t*, size_t) { + return 0; +} +#endif + +#if __has_feature(hwaddress_sanitizer) +// FIXME: implement these in HWASan allocator. +extern "C" int __sanitizer_malloc_iterate(uintptr_t base __unused, size_t size __unused, + void (*callback)(uintptr_t base, size_t size, void* arg) + __unused, + void* arg __unused) { + return 0; +} + +extern "C" void __sanitizer_malloc_disable() { +} + +extern "C" void __sanitizer_malloc_enable() { +} + +extern "C" int __sanitizer_malloc_info(int, FILE*) { + errno = ENOTSUP; + return -1; +} +#endif +// ============================================================================= + +// ============================================================================= +// Platform-internal mallopt variant. +// ============================================================================= +#if defined(LIBC_STATIC) +extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { + if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) { + return LimitEnable(arg, arg_size); + } + if (opcode == M_SET_HEAP_TAGGING_LEVEL) { + return SetHeapTaggingLevel(arg, arg_size); + } + if (opcode == M_INITIALIZE_GWP_ASAN) { + if (arg == nullptr || arg_size != sizeof(bool)) { + errno = EINVAL; + return false; + } + __libc_globals.mutate([&](libc_globals* globals) { + return MaybeInitGwpAsan(globals, *reinterpret_cast(arg)); + }); + } + errno = ENOTSUP; + return false; +} +#endif +// ============================================================================= + +static constexpr MallocDispatch __libc_malloc_default_dispatch __attribute__((unused)) = { + Malloc(calloc), + Malloc(free), + Malloc(mallinfo), + Malloc(malloc), + Malloc(malloc_usable_size), + Malloc(memalign), + Malloc(posix_memalign), +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + Malloc(pvalloc), +#endif + Malloc(realloc), +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + Malloc(valloc), +#endif + Malloc(malloc_iterate), + Malloc(malloc_disable), + Malloc(malloc_enable), + Malloc(mallopt), + Malloc(aligned_alloc), + Malloc(malloc_info), +}; + +const MallocDispatch* NativeAllocatorDispatch() { + return &__libc_malloc_default_dispatch; +} diff --git a/aosp/bionic/libc/bionic/malloc_common.h b/aosp/bionic/libc/bionic/malloc_common.h new file mode 100644 index 000000000..4afcc4a8d --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_common.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#if __has_feature(hwaddress_sanitizer) + +#include + +__BEGIN_DECLS + +// FIXME: implement these in HWASan allocator. +int __sanitizer_malloc_iterate(uintptr_t base, size_t size, + void (*callback)(uintptr_t base, size_t size, void* arg), + void* arg); +void __sanitizer_malloc_disable(); +void __sanitizer_malloc_enable(); +int __sanitizer_malloc_info(int options, FILE* fp); + +__END_DECLS + +#define Malloc(function) __sanitizer_ ## function + +#else // __has_feature(hwaddress_sanitizer) + +#if defined(USE_SCUDO) + +#include "scudo.h" +#define Malloc(function) scudo_ ## function + +#elif defined(USE_SCUDO_SVELTE) + +#include "scudo.h" +#define Malloc(function) scudo_svelte_ ## function + +#else + +#include "jemalloc.h" +#define Malloc(function) je_ ## function + +#endif + +#endif + +const MallocDispatch* NativeAllocatorDispatch(); + +static inline const MallocDispatch* GetDispatchTable() { + return atomic_load_explicit(&__libc_globals->current_dispatch_table, memory_order_acquire); +} + +static inline const MallocDispatch* GetDefaultDispatchTable() { + return atomic_load_explicit(&__libc_globals->default_dispatch_table, memory_order_acquire); +} + +// ============================================================================= +// Log functions +// ============================================================================= +#define error_log(format, ...) \ + async_safe_format_log(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ ) +#define info_log(format, ...) \ + async_safe_format_log(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ ) +#define warning_log(format, ...) \ + async_safe_format_log(ANDROID_LOG_WARN, "libc", (format), ##__VA_ARGS__ ) +// ============================================================================= diff --git a/aosp/bionic/libc/bionic/malloc_common_dynamic.cpp b/aosp/bionic/libc/bionic/malloc_common_dynamic.cpp new file mode 100644 index 000000000..da87c332e --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_common_dynamic.cpp @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2009 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. + */ + +#if defined(LIBC_STATIC) +#error This file should not be compiled for static targets. +#endif + +// Contains a thin layer that calls whatever real native allocator +// has been defined. For the libc shared library, this allows the +// implementation of a debug malloc that can intercept all of the allocation +// calls and add special debugging code to attempt to catch allocation +// errors. All of the debugging code is implemented in a separate shared +// library that is only loaded when the property "libc.debug.malloc.options" +// is set to a non-zero value. There are three functions exported to +// allow ddms, or other external users to get information from the debug +// allocation. +// get_malloc_leak_info: Returns information about all of the known native +// allocations that are currently in use. +// free_malloc_leak_info: Frees the data allocated by the call to +// get_malloc_leak_info. +// write_malloc_leak_info: Writes the leak info data to a file. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "gwp_asan_wrappers.h" +#include "heap_tagging.h" +#include "malloc_common.h" +#include "malloc_common_dynamic.h" +#include "malloc_heapprofd.h" +#include "malloc_limit.h" + +// ============================================================================= +// Global variables instantations. +// ============================================================================= +pthread_mutex_t gGlobalsMutateLock = PTHREAD_MUTEX_INITIALIZER; + +_Atomic bool gGlobalsMutating = false; + +static bool gZygoteChild = false; + +// In a Zygote child process, this is set to true if profiling of this process +// is allowed. Note that this is set at a later time than gZygoteChild. The +// latter is set during the fork (while still in zygote's SELinux domain). While +// this bit is set after the child is specialized (and has transferred SELinux +// domains if applicable). These two flags are read by the +// BIONIC_SIGNAL_PROFILER handler, which does nothing if the process is not +// profileable. +static _Atomic bool gZygoteChildProfileable = false; + +// ============================================================================= + +static constexpr char kHooksSharedLib[] = "libc_malloc_hooks.so"; +static constexpr char kHooksPrefix[] = "hooks"; +static constexpr char kHooksPropertyEnable[] = "libc.debug.hooks.enable"; +static constexpr char kHooksEnvEnable[] = "LIBC_HOOKS_ENABLE"; + +static constexpr char kDebugSharedLib[] = "libc_malloc_debug.so"; +static constexpr char kDebugPrefix[] = "debug"; +static constexpr char kDebugPropertyOptions[] = "libc.debug.malloc.options"; +static constexpr char kDebugPropertyProgram[] = "libc.debug.malloc.program"; +static constexpr char kDebugEnvOptions[] = "LIBC_DEBUG_MALLOC_OPTIONS"; + +typedef void (*finalize_func_t)(); +typedef bool (*init_func_t)(const MallocDispatch*, bool*, const char*); +typedef void (*get_malloc_leak_info_func_t)(uint8_t**, size_t*, size_t*, size_t*, size_t*); +typedef void (*free_malloc_leak_info_func_t)(uint8_t*); +typedef bool (*write_malloc_leak_info_func_t)(FILE*); +typedef ssize_t (*malloc_backtrace_func_t)(void*, uintptr_t*, size_t); + +enum FunctionEnum : uint8_t { + FUNC_INITIALIZE, + FUNC_FINALIZE, + FUNC_GET_MALLOC_LEAK_INFO, + FUNC_FREE_MALLOC_LEAK_INFO, + FUNC_MALLOC_BACKTRACE, + FUNC_WRITE_LEAK_INFO, + FUNC_LAST, +}; +static void* gFunctions[FUNC_LAST]; + +extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso); + +template +static bool InitMallocFunction(void* malloc_impl_handler, FunctionType* func, const char* prefix, const char* suffix) { + char symbol[128]; + snprintf(symbol, sizeof(symbol), "%s_%s", prefix, suffix); + *func = reinterpret_cast(dlsym(malloc_impl_handler, symbol)); + if (*func == nullptr) { + error_log("%s: dlsym(\"%s\") failed", getprogname(), symbol); + return false; + } + return true; +} + +static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const char* prefix) { + if (!InitMallocFunction(impl_handler, &table->free, prefix, "free")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->calloc, prefix, "calloc")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->mallinfo, prefix, "mallinfo")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->mallopt, prefix, "mallopt")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc, prefix, "malloc")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc_info, prefix, + "malloc_info")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc_usable_size, prefix, + "malloc_usable_size")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->memalign, prefix, "memalign")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->posix_memalign, prefix, + "posix_memalign")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->aligned_alloc, + prefix, "aligned_alloc")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->realloc, prefix, "realloc")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc_iterate, prefix, + "malloc_iterate")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc_disable, prefix, + "malloc_disable")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->malloc_enable, prefix, + "malloc_enable")) { + return false; + } +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + if (!InitMallocFunction(impl_handler, &table->pvalloc, prefix, "pvalloc")) { + return false; + } + if (!InitMallocFunction(impl_handler, &table->valloc, prefix, "valloc")) { + return false; + } +#endif + + return true; +} + +static void MallocFiniImpl(void*) { + // Our BSD stdio implementation doesn't close the standard streams, + // it only flushes them. Other unclosed FILE*s will show up as + // malloc leaks, but to avoid the standard streams showing up in + // leak reports, close them here. + fclose(stdin); + fclose(stdout); + fclose(stderr); + + reinterpret_cast(gFunctions[FUNC_FINALIZE])(); +} + +static bool CheckLoadMallocHooks(char** options) { + char* env = getenv(kHooksEnvEnable); + if ((env == nullptr || env[0] == '\0' || env[0] == '0') && + (__system_property_get(kHooksPropertyEnable, *options) == 0 || *options[0] == '\0' || *options[0] == '0')) { + return false; + } + *options = nullptr; + return true; +} + +static bool CheckLoadMallocDebug(char** options) { + // If kDebugMallocEnvOptions is set then it overrides the system properties. + char* env = getenv(kDebugEnvOptions); + if (env == nullptr || env[0] == '\0') { + if (__system_property_get(kDebugPropertyOptions, *options) == 0 || *options[0] == '\0') { + return false; + } + + // Check to see if only a specific program should have debug malloc enabled. + char program[PROP_VALUE_MAX]; + if (__system_property_get(kDebugPropertyProgram, program) != 0 && + strstr(getprogname(), program) == nullptr) { + return false; + } + } else { + *options = env; + } + return true; +} + +void SetGlobalFunctions(void* functions[]) { + for (size_t i = 0; i < FUNC_LAST; i++) { + gFunctions[i] = functions[i]; + } +} + +static void ClearGlobalFunctions() { + for (size_t i = 0; i < FUNC_LAST; i++) { + gFunctions[i] = nullptr; + } +} + +bool InitSharedLibrary(void* impl_handle, const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) { + static constexpr const char* names[] = { + "initialize", + "finalize", + "get_malloc_leak_info", + "free_malloc_leak_info", + "malloc_backtrace", + "write_malloc_leak_info", + }; + for (size_t i = 0; i < FUNC_LAST; i++) { + char symbol[128]; + snprintf(symbol, sizeof(symbol), "%s_%s", prefix, names[i]); + gFunctions[i] = dlsym(impl_handle, symbol); + if (gFunctions[i] == nullptr) { + error_log("%s: %s routine not found in %s", getprogname(), symbol, shared_lib); + ClearGlobalFunctions(); + return false; + } + } + + if (!InitMallocFunctions(impl_handle, dispatch_table, prefix)) { + ClearGlobalFunctions(); + return false; + } + return true; +} + +extern "C" struct android_namespace_t* android_get_exported_namespace(const char* name); + +void* LoadSharedLibrary(const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) { + void* impl_handle = nullptr; + // Try to load the libc_malloc_* libs from the "runtime" namespace and then + // fall back to dlopen() to load them from the default namespace. + // + // The libraries are packaged in the runtime APEX together with libc.so. + // However, since the libc.so is searched via the symlink in the system + // partition (/system/lib/libc.so -> /apex/com.android.runtime/bionic/libc.so) + // libc.so is loaded into the default namespace. If we just dlopen() here, the + // linker will load the libs found in /system/lib which might be incompatible + // with libc.so in the runtime APEX. Use android_dlopen_ext to explicitly load + // the ones in the runtime APEX. + struct android_namespace_t* runtime_ns = android_get_exported_namespace("com_android_runtime"); + if (runtime_ns != nullptr) { + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, + .library_namespace = runtime_ns, + }; + impl_handle = android_dlopen_ext(shared_lib, RTLD_NOW | RTLD_LOCAL, &dlextinfo); + } + + if (impl_handle == nullptr) { + impl_handle = dlopen(shared_lib, RTLD_NOW | RTLD_LOCAL); + } + + if (impl_handle == nullptr) { + error_log("%s: Unable to open shared library %s: %s", getprogname(), shared_lib, dlerror()); + return nullptr; + } + + if (!InitSharedLibrary(impl_handle, shared_lib, prefix, dispatch_table)) { + dlclose(impl_handle); + impl_handle = nullptr; + } + + return impl_handle; +} + +bool FinishInstallHooks(libc_globals* globals, const char* options, const char* prefix) { + init_func_t init_func = reinterpret_cast(gFunctions[FUNC_INITIALIZE]); + + // If GWP-ASan was initialised, we should use it as the dispatch table for + // heapprofd/malloc_debug/malloc_debug. + const MallocDispatch* prev_dispatch = GetDefaultDispatchTable(); + if (prev_dispatch == nullptr) { + prev_dispatch = NativeAllocatorDispatch(); + } + + if (!init_func(prev_dispatch, &gZygoteChild, options)) { + error_log("%s: failed to enable malloc %s", getprogname(), prefix); + ClearGlobalFunctions(); + return false; + } + + // Do a pointer swap so that all of the functions become valid at once to + // avoid any initialization order problems. + atomic_store(&globals->default_dispatch_table, &globals->malloc_dispatch_table); + if (!MallocLimitInstalled()) { + atomic_store(&globals->current_dispatch_table, &globals->malloc_dispatch_table); + } + + // Use atexit to trigger the cleanup function. This avoids a problem + // where another atexit function is used to cleanup allocated memory, + // but the finalize function was already called. This particular error + // seems to be triggered by a zygote spawned process calling exit. + int ret_value = __cxa_atexit(MallocFiniImpl, nullptr, nullptr); + if (ret_value != 0) { + // We don't consider this a fatal error. + warning_log("failed to set atexit cleanup function: %d", ret_value); + } + return true; +} + +static bool InstallHooks(libc_globals* globals, const char* options, const char* prefix, + const char* shared_lib) { + void* impl_handle = LoadSharedLibrary(shared_lib, prefix, &globals->malloc_dispatch_table); + if (impl_handle == nullptr) { + return false; + } + + if (!FinishInstallHooks(globals, options, prefix)) { + dlclose(impl_handle); + return false; + } + return true; +} + +// Initializes memory allocation framework once per process. +static void MallocInitImpl(libc_globals* globals) { + char prop[PROP_VALUE_MAX]; + char* options = prop; + + MaybeInitGwpAsanFromLibc(globals); + + // Prefer malloc debug since it existed first and is a more complete + // malloc interceptor than the hooks. + bool hook_installed = false; + if (CheckLoadMallocDebug(&options)) { + hook_installed = InstallHooks(globals, options, kDebugPrefix, kDebugSharedLib); + } else if (CheckLoadMallocHooks(&options)) { + hook_installed = InstallHooks(globals, options, kHooksPrefix, kHooksSharedLib); + } + + if (!hook_installed) { + if (HeapprofdShouldLoad()) { + HeapprofdInstallHooksAtInit(globals); + } + } else { + // Record the fact that incompatible hooks are active, to skip any later + // heapprofd signal handler invocations. + HeapprofdRememberHookConflict(); + } +} + +// Initializes memory allocation framework. +// This routine is called from __libc_init routines in libc_init_dynamic.cpp. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) { + MallocInitImpl(globals); +} + +// ============================================================================= +// Functions to support dumping of native heap allocations using malloc debug. +// ============================================================================= +bool GetMallocLeakInfo(android_mallopt_leak_info_t* leak_info) { + void* func = gFunctions[FUNC_GET_MALLOC_LEAK_INFO]; + if (func == nullptr) { + errno = ENOTSUP; + return false; + } + reinterpret_cast(func)( + &leak_info->buffer, &leak_info->overall_size, &leak_info->info_size, + &leak_info->total_memory, &leak_info->backtrace_size); + return true; +} + +bool FreeMallocLeakInfo(android_mallopt_leak_info_t* leak_info) { + void* func = gFunctions[FUNC_FREE_MALLOC_LEAK_INFO]; + if (func == nullptr) { + errno = ENOTSUP; + return false; + } + reinterpret_cast(func)(leak_info->buffer); + return true; +} + +bool WriteMallocLeakInfo(FILE* fp) { + void* func = gFunctions[FUNC_WRITE_LEAK_INFO]; + bool written = false; + if (func != nullptr) { + written = reinterpret_cast(func)(fp); + } + + if (!written) { + fprintf(fp, "Native heap dump not available. To enable, run these commands (requires root):\n"); + fprintf(fp, "# adb shell stop\n"); + fprintf(fp, "# adb shell setprop libc.debug.malloc.options backtrace\n"); + fprintf(fp, "# adb shell start\n"); + errno = ENOTSUP; + } + return written; +} +// ============================================================================= + +// ============================================================================= +// Exported for use by libmemunreachable. +// ============================================================================= +extern "C" ssize_t malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) { + void* func = gFunctions[FUNC_MALLOC_BACKTRACE]; + if (func == nullptr) { + return 0; + } + return reinterpret_cast(func)(pointer, frames, frame_count); +} +// ============================================================================= + +// ============================================================================= +// Platform-internal mallopt variant. +// ============================================================================= +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { + if (opcode == M_SET_ZYGOTE_CHILD) { + if (arg != nullptr || arg_size != 0) { + errno = EINVAL; + return false; + } + gZygoteChild = true; + return true; + } + if (opcode == M_INIT_ZYGOTE_CHILD_PROFILING) { + if (arg != nullptr || arg_size != 0) { + errno = EINVAL; + return false; + } + atomic_store_explicit(&gZygoteChildProfileable, true, memory_order_release); + // Also check if heapprofd should start profiling from app startup. + HeapprofdInitZygoteChildProfiling(); + return true; + } + if (opcode == M_GET_PROCESS_PROFILEABLE) { + if (arg == nullptr || arg_size != sizeof(bool)) { + errno = EINVAL; + return false; + } + // Native processes are considered profileable. Zygote children are considered + // profileable only when appropriately tagged. + *reinterpret_cast(arg) = + !gZygoteChild || atomic_load_explicit(&gZygoteChildProfileable, memory_order_acquire); + return true; + } + if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) { + return LimitEnable(arg, arg_size); + } + if (opcode == M_WRITE_MALLOC_LEAK_INFO_TO_FILE) { + if (arg == nullptr || arg_size != sizeof(FILE*)) { + errno = EINVAL; + return false; + } + return WriteMallocLeakInfo(reinterpret_cast(arg)); + } + if (opcode == M_GET_MALLOC_LEAK_INFO) { + if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) { + errno = EINVAL; + return false; + } + return GetMallocLeakInfo(reinterpret_cast(arg)); + } + if (opcode == M_FREE_MALLOC_LEAK_INFO) { + if (arg == nullptr || arg_size != sizeof(android_mallopt_leak_info_t)) { + errno = EINVAL; + return false; + } + return FreeMallocLeakInfo(reinterpret_cast(arg)); + } + if (opcode == M_SET_HEAP_TAGGING_LEVEL) { + return SetHeapTaggingLevel(arg, arg_size); + } + if (opcode == M_INITIALIZE_GWP_ASAN) { + if (arg == nullptr || arg_size != sizeof(bool)) { + errno = EINVAL; + return false; + } + __libc_globals.mutate([&](libc_globals* globals) { + return MaybeInitGwpAsan(globals, *reinterpret_cast(arg)); + }); + } + // Try heapprofd's mallopt, as it handles options not covered here. + return HeapprofdMallopt(opcode, arg, arg_size); +} +// ============================================================================= + +#if !defined(__LP64__) && defined(__arm__) +// ============================================================================= +// Old platform only functions that some old 32 bit apps are still using. +// See b/132175052. +// Only compile the functions for 32 bit arm, so that new apps do not use +// these functions. +// ============================================================================= +extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, + size_t* total_memory, size_t* backtrace_size) { + if (info == nullptr || overall_size == nullptr || info_size == nullptr || + total_memory == nullptr || backtrace_size == nullptr) { + return; + } + + *info = nullptr; + *overall_size = 0; + *info_size = 0; + *total_memory = 0; + *backtrace_size = 0; + + android_mallopt_leak_info_t leak_info = {}; + if (android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info))) { + *info = leak_info.buffer; + *overall_size = leak_info.overall_size; + *info_size = leak_info.info_size; + *total_memory = leak_info.total_memory; + *backtrace_size = leak_info.backtrace_size; + } +} + +extern "C" void free_malloc_leak_info(uint8_t* info) { + android_mallopt_leak_info_t leak_info = { .buffer = info }; + android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)); +} +// ============================================================================= +#endif diff --git a/aosp/bionic/libc/bionic/malloc_common_dynamic.h b/aosp/bionic/libc/bionic/malloc_common_dynamic.h new file mode 100644 index 000000000..048d42a26 --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_common_dynamic.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include +#include + +#include +#include + +// Function prototypes. +bool InitSharedLibrary(void* impl_handle, const char* shared_lib, const char* prefix, + MallocDispatch* dispatch_table); + +void* LoadSharedLibrary(const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table); + +bool FinishInstallHooks(libc_globals* globals, const char* options, const char* prefix); + +// Lock for globals, to guarantee that only one thread is doing a mutate. +extern pthread_mutex_t gGlobalsMutateLock; +extern _Atomic bool gGlobalsMutating; + +// Function hooks instantiations, used by dispatch-table allocators to install themselves. +void SetGlobalFunctions(void* functions[]); diff --git a/aosp/bionic/libc/bionic/malloc_heapprofd.cpp b/aosp/bionic/libc/bionic/malloc_heapprofd.cpp new file mode 100644 index 000000000..51becf067 --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_heapprofd.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2019 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. + */ + +#if defined(LIBC_STATIC) +#error This file should not be compiled for static targets. +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gwp_asan_wrappers.h" +#include "malloc_common.h" +#include "malloc_common_dynamic.h" +#include "malloc_heapprofd.h" +#include "malloc_limit.h" + +// Installing heapprofd hooks is a multi step process, as outlined below. +// +// The incremental hooking and a dedicated task thread are used since we cannot +// do heavy work within a signal handler, or when blocking a malloc invocation. +// +// +--->+-------------+------------------+ +// | +->+kInitialState+----------------+ | malloc functions are not intercepted in any way. +// | | +-------+-----+ | | +// | | | | | +// | | v | | +// | | +-------+----------------+ | | currently installing the ephemeral hooks. +// | | |kInstallingEphemeralHook|<--+ | | +// | | +-------+----------------+ | | | +// | | | | | | +// | | v | | | +// | | +-------+---------------+ | | | ephemeral hooks are installed. on the first call to +// | | |kEphemeralHookInstalled| | | | malloc these hooks spawn a thread that installs the +// | | +-------+---------------+ | | | heapprofd hooks. +// | | | | | | +// | | v | | | +// | | +-------+--------------+ | | | first call to malloc happened. the hooks are reset to +// | +--|kRemovingEphemeralHook| | | | kInitialState. +// | +----------------------+ | | | +// | | | | +// | | | | +// | +---------------+ | | | currently installing the heapprofd hook +// | |kInstallingHook|<-----------|-+ | +// | +-------+-------+ | | +// | | | | +// | v | | +// | +-------+------+ | | heapprofd hooks are installed. these forward calls to +// | |kHookInstalled|-------------+ | malloc / free / etc. to heapprofd_client.so. +// | +-------+------+ | +// | | | +// | v | +// | +-------+---------+ | currently resetting the hooks to default. +// |----+kUninstallingHook| | +// +-----------------+ | +// | +// | +// +------------------+ | malloc debug / malloc hooks are active. these take +// |kIncompatibleHooks+<------------+ precendence over heapprofd, so heapprofd will not get +// +------------------+ enabled. this is a terminal state. +// +enum MallocHeapprofdState : uint8_t { + kInitialState, + kInstallingEphemeralHook, + kEphemeralHookInstalled, + kRemovingEphemeralHook, + kInstallingHook, + kHookInstalled, + kUninstallingHook, + kIncompatibleHooks +}; + +enum ModifyGlobalsMode { + kWithLock, // all calls to MaybeModifyGlobals with kWithLock will serialise. they can fail + // due to a concurrent call with kWithoutLock. + kWithoutLock // calls to MaybeModifyGlobals with kWithoutLock do not serialise. they can fail + // due to concurrent calls with kWithoutLock or kWithLock. +}; + +// Provide mutual exclusion so no two threads try to modify the globals at the same time. +template +bool MaybeModifyGlobals(ModifyGlobalsMode mode, Fn f) { + bool success = false; + if (mode == kWithLock) { + pthread_mutex_lock(&gGlobalsMutateLock); + } + // As we have grabbed the mutex, the following condition should always hold, except + // if we are currently running HandleHeapprofdSignal. + if (!atomic_exchange(&gGlobalsMutating, true)) { + f(); + success = true; + atomic_store(&gGlobalsMutating, false); + } else { + error_log("%s: heapprofd client: concurrent modification.", getprogname()); + } + if (mode == kWithLock) { + pthread_mutex_unlock(&gGlobalsMutateLock); + } + return success; +} + +extern "C" void* MallocInitHeapprofdHook(size_t); + +static constexpr char kHeapprofdSharedLib[] = "heapprofd_client.so"; +static constexpr char kHeapprofdPrefix[] = "heapprofd"; +static constexpr char kHeapprofdPropertyEnable[] = "heapprofd.enable"; + +constexpr char kHeapprofdProgramPropertyPrefix[] = "heapprofd.enable."; +constexpr size_t kHeapprofdProgramPropertyPrefixSize = sizeof(kHeapprofdProgramPropertyPrefix) - 1; +constexpr size_t kMaxCmdlineSize = 512; + +// The handle returned by dlopen when previously loading the heapprofd +// hooks. nullptr if shared library has not been already been loaded. +static _Atomic (void*) gHeapprofdHandle = nullptr; +static _Atomic MallocHeapprofdState gHeapprofdState = kInitialState; + +static bool GetHeapprofdProgramProperty(char* data, size_t size) { + if (size < kHeapprofdProgramPropertyPrefixSize) { + error_log("%s: Overflow constructing heapprofd property", getprogname()); + return false; + } + memcpy(data, kHeapprofdProgramPropertyPrefix, kHeapprofdProgramPropertyPrefixSize); + + int fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + error_log("%s: Failed to open /proc/self/cmdline", getprogname()); + return false; + } + char cmdline[kMaxCmdlineSize]; + ssize_t rd = read(fd, cmdline, sizeof(cmdline) - 1); + close(fd); + if (rd == -1) { + error_log("%s: Failed to read /proc/self/cmdline", getprogname()); + return false; + } + cmdline[rd] = '\0'; + char* first_arg = static_cast(memchr(cmdline, '\0', rd)); + if (first_arg == nullptr) { + error_log("%s: Overflow reading cmdline", getprogname()); + return false; + } + // For consistency with what we do with Java app cmdlines, trim everything + // after the @ sign of the first arg. + char* first_at = static_cast(memchr(cmdline, '@', rd)); + if (first_at != nullptr && first_at < first_arg) { + *first_at = '\0'; + first_arg = first_at; + } + + char* start = static_cast(memrchr(cmdline, '/', first_arg - cmdline)); + if (start == first_arg) { + // The first argument ended in a slash. + error_log("%s: cmdline ends in /", getprogname()); + return false; + } else if (start == nullptr) { + start = cmdline; + } else { + // Skip the /. + start++; + } + + size_t name_size = static_cast(first_arg - start); + if (name_size >= size - kHeapprofdProgramPropertyPrefixSize) { + error_log("%s: overflow constructing heapprofd property.", getprogname()); + return false; + } + // + 1 to also copy the trailing null byte. + memcpy(data + kHeapprofdProgramPropertyPrefixSize, start, name_size + 1); + return true; +} + +// Runtime triggering entry-point. Two possible call sites: +// * when receiving a profiling signal with a si_value indicating heapprofd. +// * when a Zygote child is marking itself as profileable, and there's a +// matching profiling request for this process (in which case heapprofd client +// is loaded synchronously). +// In both cases, the caller is responsible for verifying that the process is +// considered profileable. + +// Previously installed default dispatch table, if it exists. This is used to +// load heapprofd properly when GWP-ASan was already installed. If GWP-ASan was +// already installed, heapprofd will take over the dispatch table, but will use +// GWP-ASan as the backing dispatch. Writes to this variable is atomically +// protected by MaybeModifyGlobals. +// Reads are not protected, so this is atomic. We cannot fail the call in +// MallocInitHeapprofdHook. +static _Atomic (const MallocDispatch*) gPreviousDefaultDispatchTable = nullptr; +static MallocDispatch gEphemeralDispatch; + +void HandleHeapprofdSignal() { + if (atomic_load(&gHeapprofdState) == kIncompatibleHooks) { + error_log("%s: not enabling heapprofd, malloc_debug/malloc_hooks are enabled.", getprogname()); + return; + } + + // We cannot grab the mutex here, as this is used in a signal handler. + MaybeModifyGlobals(kWithoutLock, [] { + MallocHeapprofdState expected = kInitialState; + // If hooks are already installed, we still want to install ephemeral hooks to retrigger + // heapprofd client initialization. + MallocHeapprofdState expected2 = kHookInstalled; + if (atomic_compare_exchange_strong(&gHeapprofdState, &expected, + kInstallingEphemeralHook) || + atomic_compare_exchange_strong(&gHeapprofdState, &expected2, + kInstallingEphemeralHook)) { + const MallocDispatch* default_dispatch = GetDefaultDispatchTable(); + + // Below, we initialize heapprofd lazily by redirecting libc's malloc() to + // call MallocInitHeapprofdHook, which spawns off a thread and initializes + // heapprofd. During the short period between now and when heapprofd is + // initialized, allocations may need to be serviced. There are three + // possible configurations: + + if (default_dispatch == nullptr) { + // 1. No malloc hooking has been done (heapprofd, GWP-ASan, etc.). In + // this case, everything but malloc() should come from the system + // allocator. + atomic_store(&gPreviousDefaultDispatchTable, nullptr); + gEphemeralDispatch = *NativeAllocatorDispatch(); + } else if (DispatchIsGwpAsan(default_dispatch)) { + // 2. GWP-ASan was installed. We should use GWP-ASan for everything but + // malloc() in the interim period before heapprofd is properly + // installed. After heapprofd is finished installing, we will use + // GWP-ASan as heapprofd's backing allocator to allow heapprofd and + // GWP-ASan to coexist. + atomic_store(&gPreviousDefaultDispatchTable, default_dispatch); + gEphemeralDispatch = *default_dispatch; + } else { + // 3. It may be possible at this point in time that heapprofd is + // *already* the default dispatch, and as such we don't want to use + // heapprofd as the backing store for itself (otherwise infinite + // recursion occurs). We will use the system allocator functions. Note: + // We've checked that no other malloc interceptors are being used by + // validating `gHeapprofdIncompatibleHooks` above, so we don't need to + // worry about that case here. + atomic_store(&gPreviousDefaultDispatchTable, nullptr); + gEphemeralDispatch = *NativeAllocatorDispatch(); + } + + // Now, replace the malloc function so that the next call to malloc() will + // initialize heapprofd. + gEphemeralDispatch.malloc = MallocInitHeapprofdHook; + + // And finally, install these new malloc-family interceptors. + __libc_globals.mutate([](libc_globals* globals) { + atomic_store(&globals->default_dispatch_table, &gEphemeralDispatch); + if (!MallocLimitInstalled()) { + atomic_store(&globals->current_dispatch_table, &gEphemeralDispatch); + } + }); + atomic_store(&gHeapprofdState, kEphemeralHookInstalled); + } else { + error_log("%s: heapprofd: failed to transition kInitialState -> kInstallingEphemeralHook. " + "current state (possible race): %d", getprogname(), expected2); + } + }); + // Otherwise, we're racing against malloc_limit's enable logic (at most once + // per process, and a niche feature). This is highly unlikely, so simply give + // up if it does happen. +} + +bool HeapprofdShouldLoad() { + // First check for heapprofd.enable. If it is set to "all", enable + // heapprofd for all processes. Otherwise, check heapprofd.enable.${prog}, + // if it is set and not 0, enable heap profiling for this process. + char property_value[PROP_VALUE_MAX]; + if (__system_property_get(kHeapprofdPropertyEnable, property_value) == 0) { + return false; + } + if (strcmp(property_value, "all") == 0) { + return true; + } + + char program_property[kHeapprofdProgramPropertyPrefixSize + kMaxCmdlineSize]; + if (!GetHeapprofdProgramProperty(program_property, + sizeof(program_property))) { + return false; + } + if (__system_property_get(program_property, property_value) == 0) { + return false; + } + return property_value[0] != '\0'; +} + +void HeapprofdRememberHookConflict() { + atomic_store(&gHeapprofdState, kIncompatibleHooks); +} + +static void CommonInstallHooks(libc_globals* globals) { + void* impl_handle = atomic_load(&gHeapprofdHandle); + bool reusing_handle = impl_handle != nullptr; + if (!reusing_handle) { + impl_handle = LoadSharedLibrary(kHeapprofdSharedLib, kHeapprofdPrefix, &globals->malloc_dispatch_table); + if (impl_handle == nullptr) { + return; + } + } else if (!InitSharedLibrary(impl_handle, kHeapprofdSharedLib, kHeapprofdPrefix, &globals->malloc_dispatch_table)) { + return; + } + + // Before we set the new default_dispatch_table in FinishInstallHooks, save + // the previous dispatch table. If DispatchReset() gets called later, we want + // to be able to restore the dispatch. We're still under + // MaybeModifyGlobals locks at this point. + atomic_store(&gPreviousDefaultDispatchTable, GetDefaultDispatchTable()); + + if (FinishInstallHooks(globals, nullptr, kHeapprofdPrefix)) { + atomic_store(&gHeapprofdHandle, impl_handle); + } else if (!reusing_handle) { + dlclose(impl_handle); + } +} + +void HeapprofdInstallHooksAtInit(libc_globals* globals) { + MaybeModifyGlobals(kWithoutLock, [globals] { + MallocHeapprofdState expected = kInitialState; + if (atomic_compare_exchange_strong(&gHeapprofdState, &expected, kInstallingHook)) { + CommonInstallHooks(globals); + atomic_store(&gHeapprofdState, kHookInstalled); + } else { + error_log("%s: heapprofd: failed to transition kInitialState -> kInstallingHook. " + "current state (possible race): %d", getprogname(), expected); + } + }); +} + +static void* InitHeapprofd(void*) { + MaybeModifyGlobals(kWithLock, [] { + MallocHeapprofdState expected = kInitialState; + if (atomic_compare_exchange_strong(&gHeapprofdState, &expected, kInstallingHook)) { + __libc_globals.mutate([](libc_globals* globals) { + CommonInstallHooks(globals); + }); + atomic_store(&gHeapprofdState, kHookInstalled); + } else { + error_log("%s: heapprofd: failed to transition kInitialState -> kInstallingHook. " + "current state (possible race): %d", getprogname(), expected); + } + }); + return nullptr; +} + +extern "C" void* MallocInitHeapprofdHook(size_t bytes) { + MaybeModifyGlobals(kWithLock, [] { + MallocHeapprofdState expected = kEphemeralHookInstalled; + if (atomic_compare_exchange_strong(&gHeapprofdState, &expected, kRemovingEphemeralHook)) { + __libc_globals.mutate([](libc_globals* globals) { + const MallocDispatch* previous_dispatch = atomic_load(&gPreviousDefaultDispatchTable); + atomic_store(&globals->default_dispatch_table, previous_dispatch); + if (!MallocLimitInstalled()) { + atomic_store(&globals->current_dispatch_table, previous_dispatch); + } + }); + atomic_store(&gHeapprofdState, kInitialState); + + pthread_t thread_id; + if (pthread_create(&thread_id, nullptr, InitHeapprofd, nullptr) != 0) { + error_log("%s: heapprofd: failed to pthread_create.", getprogname()); + } else if (pthread_setname_np(thread_id, "heapprofdinit") != 0) { + error_log("%s: heapprod: failed to pthread_setname_np", getprogname()); + } else if (pthread_detach(thread_id) != 0) { + error_log("%s: heapprofd: failed to pthread_detach", getprogname()); + } + } else { + warning_log("%s: heapprofd: could not transition kEphemeralHookInstalled -> " + "kRemovingEphemeralHook. current state (possible race): %d. this can be benign " + "if two threads try this transition at the same time", getprogname(), + expected); + } + }); + // If we had a previous dispatch table, use that to service the allocation, + // otherwise fall back to the native allocator. + // This could be modified by a concurrent HandleHeapprofdSignal, but that is + // benign as we will dispatch to the ephemeral handler, which will then dispatch + // to the underlying one. + const MallocDispatch* previous_dispatch = atomic_load(&gPreviousDefaultDispatchTable); + if (previous_dispatch) { + return previous_dispatch->malloc(bytes); + } + return NativeAllocatorDispatch()->malloc(bytes); +} + +bool HeapprofdInitZygoteChildProfiling() { + // Conditionally start "from startup" profiling. + if (HeapprofdShouldLoad()) { + // Directly call the signal handler codepath (properly protects against + // concurrent invocations). + HandleHeapprofdSignal(); + } + return true; +} + +static bool DispatchReset() { + if (atomic_load(&gHeapprofdState) == kInitialState) { + return true; + } + + bool success = false; + MaybeModifyGlobals(kWithLock, [&success] { + MallocHeapprofdState expected = kHookInstalled; + + if(atomic_compare_exchange_strong(&gHeapprofdState, &expected, kUninstallingHook)){ + __libc_globals.mutate([](libc_globals* globals) { + const MallocDispatch* previous_dispatch = atomic_load(&gPreviousDefaultDispatchTable); + atomic_store(&globals->default_dispatch_table, previous_dispatch); + if (!MallocLimitInstalled()) { + atomic_store(&globals->current_dispatch_table, previous_dispatch); + } + }); + atomic_store(&gHeapprofdState, kInitialState); + success = true; + } else { + error_log("%s: heapprofd: failed to transition kHookInstalled -> kUninstallingHook. " + "current state (possible race): %d", getprogname(), + expected); + } + }); + if (!success) { + errno = EAGAIN; + } + return success; +} + +bool HeapprofdMallopt(int opcode, void* arg, size_t arg_size) { + if (opcode == M_RESET_HOOKS) { + if (arg != nullptr || arg_size != 0) { + errno = EINVAL; + return false; + } + return DispatchReset(); + } + errno = ENOTSUP; + return false; +} diff --git a/aosp/bionic/libc/bionic/malloc_heapprofd.h b/aosp/bionic/libc/bionic/malloc_heapprofd.h new file mode 100644 index 000000000..d67a78887 --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_heapprofd.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +#include + +bool HeapprofdShouldLoad(); + +void HeapprofdInstallHooksAtInit(libc_globals* globals); + +void HeapprofdRememberHookConflict(); + +void HandleHeapprofdSignal(); + +bool HeapprofdInitZygoteChildProfiling(); + +bool HeapprofdMallopt(int optcode, void* arg, size_t arg_size); + diff --git a/aosp/bionic/libc/bionic/malloc_limit.cpp b/aosp/bionic/libc/bionic/malloc_limit.cpp new file mode 100644 index 000000000..1405a39f2 --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_limit.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include +#include + +#include + +#if __has_feature(hwaddress_sanitizer) +#include +#endif + +#include "malloc_common.h" +#include "malloc_common_dynamic.h" +#include "malloc_heapprofd.h" +#include "malloc_limit.h" + +__BEGIN_DECLS +static void* LimitCalloc(size_t n_elements, size_t elem_size); +static void LimitFree(void* mem); +static void* LimitMalloc(size_t bytes); +static void* LimitMemalign(size_t alignment, size_t bytes); +static int LimitPosixMemalign(void** memptr, size_t alignment, size_t size); +static void* LimitRealloc(void* old_mem, size_t bytes); +static void* LimitAlignedAlloc(size_t alignment, size_t size); +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +static void* LimitPvalloc(size_t bytes); +static void* LimitValloc(size_t bytes); +#endif + +// Pass through functions. +static size_t LimitUsableSize(const void* mem); +static struct mallinfo LimitMallinfo(); +static int LimitIterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), void* arg); +static void LimitMallocDisable(); +static void LimitMallocEnable(); +static int LimitMallocInfo(int options, FILE* fp); +static int LimitMallopt(int param, int value); +__END_DECLS + +static constexpr MallocDispatch __limit_dispatch + __attribute__((unused)) = { + LimitCalloc, + LimitFree, + LimitMallinfo, + LimitMalloc, + LimitUsableSize, + LimitMemalign, + LimitPosixMemalign, +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + LimitPvalloc, +#endif + LimitRealloc, +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + LimitValloc, +#endif + LimitIterate, + LimitMallocDisable, + LimitMallocEnable, + LimitMallopt, + LimitAlignedAlloc, + LimitMallocInfo, + }; + +static _Atomic uint64_t gAllocated; +static uint64_t gAllocLimit; + +static inline bool CheckLimit(size_t bytes) { + uint64_t total; + if (__predict_false(__builtin_add_overflow( + atomic_load_explicit(&gAllocated, memory_order_relaxed), bytes, &total) || + total > gAllocLimit)) { + return false; + } + return true; +} + +static inline void* IncrementLimit(void* mem) { + if (__predict_false(mem == nullptr)) { + return nullptr; + } + atomic_fetch_add(&gAllocated, LimitUsableSize(mem)); + return mem; +} + +void* LimitCalloc(size_t n_elements, size_t elem_size) { + size_t total; + if (__builtin_mul_overflow(n_elements, elem_size, &total) || !CheckLimit(total)) { + warning_log("malloc_limit: calloc(%zu, %zu) exceeds limit %" PRId64, n_elements, elem_size, + gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->calloc(n_elements, elem_size)); + } + return IncrementLimit(Malloc(calloc)(n_elements, elem_size)); +} + +void LimitFree(void* mem) { + atomic_fetch_sub(&gAllocated, LimitUsableSize(mem)); + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->free(mem); + } + return Malloc(free)(mem); +} + +void* LimitMalloc(size_t bytes) { + if (!CheckLimit(bytes)) { + warning_log("malloc_limit: malloc(%zu) exceeds limit %" PRId64, bytes, gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->malloc(bytes)); + } + return IncrementLimit(Malloc(malloc)(bytes)); +} + +static void* LimitMemalign(size_t alignment, size_t bytes) { + if (!CheckLimit(bytes)) { + warning_log("malloc_limit: memalign(%zu, %zu) exceeds limit %" PRId64, alignment, bytes, + gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->memalign(alignment, bytes)); + } + return IncrementLimit(Malloc(memalign)(alignment, bytes)); +} + +static int LimitPosixMemalign(void** memptr, size_t alignment, size_t size) { + if (!CheckLimit(size)) { + warning_log("malloc_limit: posix_memalign(%zu, %zu) exceeds limit %" PRId64, alignment, size, + gAllocLimit); + return ENOMEM; + } + int retval; + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + retval = dispatch_table->posix_memalign(memptr, alignment, size); + } else { + retval = Malloc(posix_memalign)(memptr, alignment, size); + } + if (__predict_false(retval != 0)) { + return retval; + } + IncrementLimit(*memptr); + return 0; +} + +static void* LimitAlignedAlloc(size_t alignment, size_t size) { + if (!CheckLimit(size)) { + warning_log("malloc_limit: aligned_alloc(%zu, %zu) exceeds limit %" PRId64, alignment, size, + gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->aligned_alloc(alignment, size)); + } + return IncrementLimit(Malloc(aligned_alloc)(alignment, size)); +} + +static void* LimitRealloc(void* old_mem, size_t bytes) { + size_t old_usable_size = LimitUsableSize(old_mem); + void* new_ptr; + // Need to check the size only if the allocation will increase in size. + if (bytes > old_usable_size && !CheckLimit(bytes - old_usable_size)) { + warning_log("malloc_limit: realloc(%p, %zu) exceeds limit %" PRId64, old_mem, bytes, + gAllocLimit); + // Free the old pointer. + LimitFree(old_mem); + return nullptr; + } + + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + new_ptr = dispatch_table->realloc(old_mem, bytes); + } else { + new_ptr = Malloc(realloc)(old_mem, bytes); + } + + if (__predict_false(new_ptr == nullptr)) { + // This acts as if the pointer was freed. + atomic_fetch_sub(&gAllocated, old_usable_size); + return nullptr; + } + + size_t new_usable_size = LimitUsableSize(new_ptr); + // Assumes that most allocations increase in size, rather than shrink. + if (__predict_false(old_usable_size > new_usable_size)) { + atomic_fetch_sub(&gAllocated, old_usable_size - new_usable_size); + } else { + atomic_fetch_add(&gAllocated, new_usable_size - old_usable_size); + } + return new_ptr; +} + +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +static void* LimitPvalloc(size_t bytes) { + if (!CheckLimit(bytes)) { + warning_log("malloc_limit: pvalloc(%zu) exceeds limit %" PRId64, bytes, gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->pvalloc(bytes)); + } + return IncrementLimit(Malloc(pvalloc)(bytes)); +} + +static void* LimitValloc(size_t bytes) { + if (!CheckLimit(bytes)) { + warning_log("malloc_limit: valloc(%zu) exceeds limit %" PRId64, bytes, gAllocLimit); + return nullptr; + } + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return IncrementLimit(dispatch_table->valloc(bytes)); + } + return IncrementLimit(Malloc(valloc)(bytes)); +} +#endif + +bool MallocLimitInstalled() { + return GetDispatchTable() == &__limit_dispatch; +} + +#if defined(LIBC_STATIC) +static bool EnableLimitDispatchTable() { + // This is the only valid way to modify the dispatch tables for a + // static executable so no locks are necessary. + __libc_globals.mutate([](libc_globals* globals) { + atomic_store(&globals->current_dispatch_table, &__limit_dispatch); + }); + return true; +} +#else +static bool EnableLimitDispatchTable() { + pthread_mutex_lock(&gGlobalsMutateLock); + // All other code that calls mutate will grab the gGlobalsMutateLock. + // However, there is one case where the lock cannot be acquired, in the + // signal handler that enables heapprofd. In order to avoid having two + // threads calling mutate at the same time, use an atomic variable to + // verify that only this function or the signal handler are calling mutate. + // If this function is called at the same time as the signal handler is + // being called, allow a short period for the signal handler to complete + // before failing. + bool enabled = false; + size_t num_tries = 20; + while (true) { + if (!atomic_exchange(&gGlobalsMutating, true)) { + __libc_globals.mutate([](libc_globals* globals) { + atomic_store(&globals->current_dispatch_table, &__limit_dispatch); + }); + atomic_store(&gGlobalsMutating, false); + enabled = true; + break; + } + if (--num_tries == 0) { + break; + } + usleep(1000); + } + pthread_mutex_unlock(&gGlobalsMutateLock); + if (enabled) { + info_log("malloc_limit: Allocation limit enabled, max size %" PRId64 " bytes\n", gAllocLimit); + } else { + error_log("malloc_limit: Failed to enable allocation limit."); + } + return enabled; +} +#endif + +bool LimitEnable(void* arg, size_t arg_size) { + if (arg == nullptr || arg_size != sizeof(size_t)) { + errno = EINVAL; + return false; + } + + static _Atomic bool limit_enabled; + if (atomic_exchange(&limit_enabled, true)) { + // The limit can only be enabled once. + error_log("malloc_limit: The allocation limit has already been set, it can only be set once."); + return false; + } + + gAllocLimit = *reinterpret_cast(arg); +#if __has_feature(hwaddress_sanitizer) + size_t current_allocated = __sanitizer_get_current_allocated_bytes(); +#else + size_t current_allocated; + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + current_allocated = dispatch_table->mallinfo().uordblks; + } else { + current_allocated = Malloc(mallinfo)().uordblks; + } +#endif + atomic_store(&gAllocated, current_allocated); + + return EnableLimitDispatchTable(); +} + +static size_t LimitUsableSize(const void* mem) { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_usable_size(mem); + } + return Malloc(malloc_usable_size)(mem); +} + +static struct mallinfo LimitMallinfo() { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->mallinfo(); + } + return Malloc(mallinfo)(); +} + +static int LimitIterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), void* arg) { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_iterate(base, size, callback, arg); + } + return Malloc(malloc_iterate)(base, size, callback, arg); +} + +static void LimitMallocDisable() { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + dispatch_table->malloc_disable(); + } else { + Malloc(malloc_disable)(); + } +} + +static void LimitMallocEnable() { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + dispatch_table->malloc_enable(); + } else { + Malloc(malloc_enable)(); + } +} + +static int LimitMallocInfo(int options, FILE* fp) { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->malloc_info(options, fp); + } + return Malloc(malloc_info)(options, fp); +} + +static int LimitMallopt(int param, int value) { + auto dispatch_table = GetDefaultDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + return dispatch_table->mallopt(param, value); + } + return Malloc(mallopt)(param, value); +} diff --git a/aosp/bionic/libc/bionic/malloc_limit.h b/aosp/bionic/libc/bionic/malloc_limit.h new file mode 100644 index 000000000..b638e83ec --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_limit.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +// Function prototypes. +bool LimitEnable(void* arg, size_t arg_size); + +// Returns true if malloc_limit is installed (by checking the current dispatch +// table). +bool MallocLimitInstalled(); diff --git a/aosp/bionic/libc/bionic/malloc_tagged_pointers.h b/aosp/bionic/libc/bionic/malloc_tagged_pointers.h new file mode 100644 index 000000000..de3cc2ed9 --- /dev/null +++ b/aosp/bionic/libc/bionic/malloc_tagged_pointers.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +// We choose a static pointer tag here for performance reasons. Dynamic tagging +// doesn't improve our detection, and simply hurts performance. This tag is +// deliberately chosen to always point to inaccessible memory on a standard +// 64-bit userspace process, and be easily identifiable by developers. This tag +// is also deliberately different from the standard pattern-init tag (0xAA), as +// to be distinguishable from an uninitialized-pointer access. The first and +// second nibbles are also deliberately designed to be the bitset-mirror of each +// other (0b1011, 0b0100) in order to reduce incidental matches. We also ensure +// that the top bit is set, as this catches incorrect code that assumes that a +// "negative" pointer indicates error. Users must not rely on the +// implementation-defined value of this pointer tag, as it may change. +static constexpr uintptr_t POINTER_TAG = 0xB4; +static constexpr unsigned UNTAG_SHIFT = 40; +static constexpr unsigned CHECK_SHIFT = 48; +static constexpr unsigned TAG_SHIFT = 56; +#if defined(__aarch64__) +static constexpr uintptr_t ADDRESS_MASK = (static_cast(1) << TAG_SHIFT) - 1; +static constexpr uintptr_t TAG_MASK = static_cast(0xFF) << TAG_SHIFT; + +static inline uintptr_t FixedPointerTag() { + return __libc_globals->heap_pointer_tag & TAG_MASK; +} + +static inline uintptr_t PointerCheckMask() { + return (__libc_globals->heap_pointer_tag << (TAG_SHIFT - CHECK_SHIFT)) & TAG_MASK; +} + +static inline uintptr_t PointerUntagMask() { + return ~(__libc_globals->heap_pointer_tag << (TAG_SHIFT - UNTAG_SHIFT)); +} +#endif // defined(__aarch64__) + +// Return a forcibly-tagged pointer. +static inline void* TagPointer(void* ptr) { +#if defined(__aarch64__) + return reinterpret_cast(reinterpret_cast(ptr) | FixedPointerTag()); +#else + async_safe_fatal("Attempting to tag a pointer (%p) on non-aarch64.", ptr); +#endif +} + +#if defined(__aarch64__) +// Return a forcibly-untagged pointer. The pointer tag is not checked for +// validity. +static inline void* UntagPointer(const volatile void* ptr) { + return reinterpret_cast(reinterpret_cast(ptr) & ADDRESS_MASK); +} + +// Untag the pointer, and check the pointer tag iff the kernel supports tagged pointers and the +// pointer tag isn't being used by HWASAN or MTE. If the tag is incorrect, trap. +static inline void* MaybeUntagAndCheckPointer(const volatile void* ptr) { + if (__predict_false(ptr == nullptr)) { + return nullptr; + } + + uintptr_t ptr_int = reinterpret_cast(ptr); + + // Applications may disable pointer tagging, which will be propagated to + // libc in the zygote. This means that there may already be tagged heap + // allocations that will fail when checked against the zero-ed heap tag. The + // check below allows us to turn *off* pointer tagging (by setting PointerCheckMask() and + // FixedPointerTag() to zero) and still allow tagged heap allocations to be freed. + if ((ptr_int & PointerCheckMask()) != FixedPointerTag()) { + // TODO(b/145604058) - Upstream tagged pointers documentation and provide + // a link to it in the abort message here. + async_safe_fatal("Pointer tag for %p was truncated.", ptr); + } + return reinterpret_cast(ptr_int & PointerUntagMask()); +} + +// Return a tagged pointer iff the kernel supports tagged pointers, and `ptr` is +// non-null. +static inline void* MaybeTagPointer(void* ptr) { + if (__predict_true(ptr != nullptr)) { + return TagPointer(ptr); + } + return ptr; +} + +#else // defined(__aarch64__) +static inline void* UntagPointer(const volatile void* ptr) { + return const_cast(ptr); +} + +static inline void* MaybeTagPointer(void* ptr) { + return ptr; +} + +static inline void* MaybeUntagAndCheckPointer(const volatile void* ptr) { + return const_cast(ptr); +} + +#endif // defined(__aarch64__) diff --git a/aosp/bionic/libc/bionic/mblen.cpp b/aosp/bionic/libc/bionic/mblen.cpp new file mode 100644 index 000000000..7def6f138 --- /dev/null +++ b/aosp/bionic/libc/bionic/mblen.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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 +#include + +int mblen(const char* s, size_t n) { + mbstate_t state = {}; + return mbrlen(s, n, &state); +} diff --git a/aosp/bionic/libc/bionic/mbrtoc16.cpp b/aosp/bionic/libc/bionic/mbrtoc16.cpp new file mode 100644 index 000000000..acea426f6 --- /dev/null +++ b/aosp/bionic/libc/bionic/mbrtoc16.cpp @@ -0,0 +1,89 @@ +/* + * 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 +#include +#include +#include + +#include "private/bionic_mbstate.h" + +static inline bool mbspartialc16(const mbstate_t* state) { + return mbstate_get_byte(state, 3) != 0; +} + +static size_t begin_surrogate(char32_t c32, char16_t* pc16, + size_t nconv, mbstate_t* state) { + c32 -= 0x10000; + char16_t trail = (c32 & 0x3ff) | 0xdc00; + + mbstate_set_byte(state, 0, trail & 0x00ff); + mbstate_set_byte(state, 1, (trail & 0xff00) >> 8); + mbstate_set_byte(state, 3, nconv & 0xff); + + *pc16 = ((c32 & 0xffc00) >> 10) | 0xd800; + // Defined by POSIX as return value for first surrogate character. + return static_cast(-3); +} + +static size_t finish_surrogate(char16_t* pc16, mbstate_t* state) { + char16_t trail = mbstate_get_byte(state, 1) << 8 | + mbstate_get_byte(state, 0); + *pc16 = trail; + return mbstate_reset_and_return(mbstate_get_byte(state, 3), state); +} + +size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + char16_t __private_pc16; + if (pc16 == nullptr) { + pc16 = &__private_pc16; + } + + if (mbspartialc16(state)) { + return finish_surrogate(pc16, state); + } + + char32_t c32; + size_t nconv = mbrtoc32(&c32, s, n, state); + if (__MB_IS_ERR(nconv)) { + return nconv; + } else if (nconv == 0) { + return mbstate_reset_and_return(nconv, state); + } else if (c32 > 0x10ffff) { + // Input cannot be encoded as UTF-16. + return mbstate_reset_and_return_illegal(EILSEQ, state); + } else if (c32 < 0x10000) { + *pc16 = static_cast(c32); + return mbstate_reset_and_return(nconv, state); + } else { + return begin_surrogate(c32, pc16, nconv, state); + } +} diff --git a/aosp/bionic/libc/bionic/mbrtoc32.cpp b/aosp/bionic/libc/bionic/mbrtoc32.cpp new file mode 100644 index 000000000..644e54275 --- /dev/null +++ b/aosp/bionic/libc/bionic/mbrtoc32.cpp @@ -0,0 +1,138 @@ +/* + * 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 +#include +#include +#include + +#include "private/bionic_mbstate.h" + +size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + // We should never get to a state which has all 4 bytes of the sequence set. + // Full state verification is done when decoding the sequence (after we have + // all the bytes). + if (mbstate_get_byte(state, 3) != 0) { + return mbstate_reset_and_return_illegal(EINVAL, state); + } + + if (s == nullptr) { + s = ""; + n = 1; + pc32 = nullptr; + } + + if (n == 0) { + return 0; + } + + uint8_t ch; + if (mbsinit(state) && (((ch = static_cast(*s)) & ~0x7f) == 0)) { + // Fast path for plain ASCII characters. + if (pc32 != nullptr) { + *pc32 = ch; + } + return (ch != '\0' ? 1 : 0); + } + + // Determine the number of octets that make up this character + // from the first octet, and a mask that extracts the + // interesting bits of the first octet. We already know + // the character is at least two bytes long. + size_t length; + int mask; + + // We also specify a lower bound for the character code to + // detect redundant, non-"shortest form" encodings. For + // example, the sequence C0 80 is _not_ a legal representation + // of the null character. This enforces a 1-to-1 mapping + // between character codes and their multibyte representations. + char32_t lower_bound; + + // The first byte in the state (if any) tells the length. + size_t bytes_so_far = mbstate_bytes_so_far(state); + ch = bytes_so_far > 0 ? mbstate_get_byte(state, 0) : static_cast(*s); + if ((ch & 0x80) == 0) { + mask = 0x7f; + length = 1; + lower_bound = 0; + } else if ((ch & 0xe0) == 0xc0) { + mask = 0x1f; + length = 2; + lower_bound = 0x80; + } else if ((ch & 0xf0) == 0xe0) { + mask = 0x0f; + length = 3; + lower_bound = 0x800; + } else if ((ch & 0xf8) == 0xf0) { + mask = 0x07; + length = 4; + lower_bound = 0x10000; + } else { + // Malformed input; input is not UTF-8. See RFC 3629. + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + + // Fill in the state. + size_t bytes_wanted = length - bytes_so_far; + size_t i; + for (i = 0; i < MIN(bytes_wanted, n); i++) { + if (!mbsinit(state) && ((*s & 0xc0) != 0x80)) { + // Malformed input; bad characters in the middle of a character. + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + mbstate_set_byte(state, bytes_so_far + i, *s++); + } + if (i < bytes_wanted) { + return __MB_ERR_INCOMPLETE_SEQUENCE; + } + + // Decode the octet sequence representing the character in chunks + // of 6 bits, most significant first. + char32_t c32 = mbstate_get_byte(state, 0) & mask; + for (i = 1; i < length; i++) { + c32 <<= 6; + c32 |= mbstate_get_byte(state, i) & 0x3f; + } + + if (c32 < lower_bound) { + // Malformed input; redundant encoding. + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if ((c32 >= 0xd800 && c32 <= 0xdfff) || (c32 > 0x10ffff)) { + // Malformed input; invalid code points. + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if (pc32 != nullptr) { + *pc32 = c32; + } + return mbstate_reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state); +} diff --git a/aosp/bionic/libc/bionic/memmem.cpp b/aosp/bionic/libc/bionic/memmem.cpp new file mode 100644 index 000000000..019e7720f --- /dev/null +++ b/aosp/bionic/libc/bionic/memmem.cpp @@ -0,0 +1,60 @@ +/* + * 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 + +void* memmem(const void* void_haystack, size_t n, const void* void_needle, size_t m) { + const unsigned char* haystack = reinterpret_cast(void_haystack); + const unsigned char* needle = reinterpret_cast(void_needle); + + if (n < m) return nullptr; + + if (m == 0) return const_cast(void_haystack); + if (m == 1) return const_cast(memchr(haystack, needle[0], n)); + + // This uses the "Not So Naive" algorithm, a very simple but usually effective algorithm. + // http://www-igm.univ-mlv.fr/~lecroq/string/ + const unsigned char* y = haystack; + const unsigned char* x = needle; + size_t j = 0; + size_t k = 1, l = 2; + + if (x[0] == x[1]) { + k = 2; + l = 1; + } + while (j <= n-m) { + if (x[1] != y[j+1]) { + j += k; + } else { + if (!memcmp(x+2, y+j+2, m-2) && x[0] == y[j]) return const_cast(&y[j]); + j += l; + } + } + return nullptr; +} diff --git a/aosp/bionic/libc/bionic/mempcpy.cpp b/aosp/bionic/libc/bionic/mempcpy.cpp new file mode 100644 index 000000000..b7b72f737 --- /dev/null +++ b/aosp/bionic/libc/bionic/mempcpy.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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 + +void* mempcpy(void* dst, const void* src, size_t n) { + return reinterpret_cast(memcpy(dst, src, n)) + n; +} diff --git a/aosp/bionic/libc/bionic/mkdir.cpp b/aosp/bionic/libc/bionic/mkdir.cpp new file mode 100644 index 000000000..90dc76159 --- /dev/null +++ b/aosp/bionic/libc/bionic/mkdir.cpp @@ -0,0 +1,35 @@ +/* + * 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 +#include +#include + +int mkdir(const char* path, mode_t mode) { + return mkdirat(AT_FDCWD, path, mode); +} diff --git a/aosp/bionic/libc/bionic/mkfifo.cpp b/aosp/bionic/libc/bionic/mkfifo.cpp new file mode 100644 index 000000000..a98b35008 --- /dev/null +++ b/aosp/bionic/libc/bionic/mkfifo.cpp @@ -0,0 +1,39 @@ +/* + * 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 + +#include + +int mkfifo(const char* path, mode_t mode) { + return mkfifoat(AT_FDCWD, path, mode); +} + +int mkfifoat(int fd, const char* path, mode_t mode) { + return mknodat(fd, path, (mode & ~S_IFMT) | S_IFIFO, 0); +} diff --git a/aosp/bionic/libc/bionic/mknod.cpp b/aosp/bionic/libc/bionic/mknod.cpp new file mode 100644 index 000000000..68d4309db --- /dev/null +++ b/aosp/bionic/libc/bionic/mknod.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include + +int mknod(const char* path, mode_t mode, dev_t dev) { + return mknodat(AT_FDCWD, path, mode, dev); +} diff --git a/aosp/bionic/libc/bionic/mmap.cpp b/aosp/bionic/libc/bionic/mmap.cpp new file mode 100644 index 000000000..9aad0b315 --- /dev/null +++ b/aosp/bionic/libc/bionic/mmap.cpp @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include +#include + +#include "platform/bionic/macros.h" +#include "private/ErrnoRestorer.h" + +// mmap2(2) is like mmap(2), but the offset is in 4096-byte blocks, not bytes. +extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); + +#define MMAP2_SHIFT 12 // 2**12 == 4096 + +static bool kernel_has_MADV_MERGEABLE = true; + +void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) { + if (offset < 0 || (offset & ((1UL << MMAP2_SHIFT)-1)) != 0) { + errno = EINVAL; + return MAP_FAILED; + } + + // prevent allocations large enough for `end - start` to overflow + size_t rounded = __BIONIC_ALIGN(size, PAGE_SIZE); + if (rounded < size || rounded > PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + + bool is_private_anonymous = + (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS); + bool is_stack_or_grows_down = (flags & (MAP_STACK | MAP_GROWSDOWN)) != 0; + + void* result = __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT); + + if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE && + is_private_anonymous && !is_stack_or_grows_down) { + ErrnoRestorer errno_restorer; + int rc = madvise(result, size, MADV_MERGEABLE); + if (rc == -1 && errno == EINVAL) { + kernel_has_MADV_MERGEABLE = false; + } + } + + return result; +} + +void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) { + return mmap64(addr, size, prot, flags, fd, static_cast(offset)); +} diff --git a/aosp/bionic/libc/bionic/mntent.cpp b/aosp/bionic/libc/bionic/mntent.cpp new file mode 100644 index 000000000..6a12e7838 --- /dev/null +++ b/aosp/bionic/libc/bionic/mntent.cpp @@ -0,0 +1,96 @@ +/* + * 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 +#include + +#include "bionic/pthread_internal.h" + +mntent* getmntent(FILE* fp) { + auto& tls = __get_bionic_tls(); + return getmntent_r(fp, &tls.mntent_buf, tls.mntent_strings, sizeof(tls.mntent_strings)); +} + +mntent* getmntent_r(FILE* fp, struct mntent* e, char* buf, int buf_len) { + memset(e, 0, sizeof(*e)); + while (fgets(buf, buf_len, fp) != nullptr) { + // Entries look like "proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0". + // That is: mnt_fsname mnt_dir mnt_type mnt_opts 0 0. + int fsname0, fsname1, dir0, dir1, type0, type1, opts0, opts1; + if (sscanf(buf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + &fsname0, &fsname1, &dir0, &dir1, &type0, &type1, &opts0, &opts1, + &e->mnt_freq, &e->mnt_passno) == 2) { + e->mnt_fsname = &buf[fsname0]; + buf[fsname1] = '\0'; + + e->mnt_dir = &buf[dir0]; + buf[dir1] = '\0'; + + e->mnt_type = &buf[type0]; + buf[type1] = '\0'; + + e->mnt_opts = &buf[opts0]; + buf[opts1] = '\0'; + + return e; + } + } + return nullptr; +} + +FILE* setmntent(const char* path, const char* mode) { + return fopen(path, mode); +} + +int endmntent(FILE* fp) { + if (fp != nullptr) { + fclose(fp); + } + return 1; +} + +char* hasmntopt(const struct mntent* mnt, const char* opt) { + char* token = mnt->mnt_opts; + char* const end = mnt->mnt_opts + strlen(mnt->mnt_opts); + const size_t optLen = strlen(opt); + + while (token) { + char* const tokenEnd = token + optLen; + if (tokenEnd > end) break; + + if (memcmp(token, opt, optLen) == 0 && + (*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) { + return token; + } + + token = strchr(token, ','); + if (token) token++; + } + + return nullptr; +} diff --git a/aosp/bionic/libc/bionic/mremap.cpp b/aosp/bionic/libc/bionic/mremap.cpp new file mode 100644 index 000000000..d7c9353e0 --- /dev/null +++ b/aosp/bionic/libc/bionic/mremap.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include + +#include "platform/bionic/macros.h" + +extern "C" void* __mremap(void*, size_t, size_t, int, void*); + +void* mremap(void* old_address, size_t old_size, size_t new_size, int flags, ...) { + // prevent allocations large enough for `end - start` to overflow + size_t rounded = __BIONIC_ALIGN(new_size, PAGE_SIZE); + if (rounded < new_size || rounded > PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + + void* new_address = nullptr; + // The optional argument is only valid if the MREMAP_FIXED flag is set, + // so we assume it's not present otherwise. + if ((flags & MREMAP_FIXED) != 0) { + va_list ap; + va_start(ap, flags); + new_address = va_arg(ap, void*); + va_end(ap); + } + return __mremap(old_address, old_size, new_size, flags, new_address); +} diff --git a/aosp/bionic/libc/bionic/ndk_cruft.cpp b/aosp/bionic/libc/bionic/ndk_cruft.cpp new file mode 100644 index 000000000..e9a5b5b79 --- /dev/null +++ b/aosp/bionic/libc/bionic/ndk_cruft.cpp @@ -0,0 +1,392 @@ +/* + * 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. + */ + +// This file perpetuates the mistakes of the past. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platform/bionic/macros.h" + +extern "C" { + +// LP64 doesn't need to support any legacy cruft. +#if !defined(__LP64__) + +// By the time any NDK-built code is running, there are plenty of threads. +int __isthreaded = 1; + +// These were accidentally declared in because we stupidly used to inline +// getpagesize() and __getpageshift(). Needed for backwards compatibility with old NDK apps. +unsigned int __page_size = PAGE_SIZE; +unsigned int __page_shift = 12; + +// TODO: remove this backward compatibility hack (for jb-mr1 strace binaries). +pid_t __wait4(pid_t pid, int* status, int options, struct rusage* rusage) { + return wait4(pid, status, options, rusage); +} + +// TODO: does anything still need this? +int __open() { + abort(); +} + +// TODO: does anything still need this? +void** __get_tls() { +#include "platform/bionic/tls.h" + return __get_tls(); +} + +// This non-standard function was in our for some reason. +void memswap(void* m1, void* m2, size_t n) { + char* p = reinterpret_cast(m1); + char* p_end = p + n; + char* q = reinterpret_cast(m2); + while (p < p_end) { + char tmp = *p; + *p = *q; + *q = tmp; + p++; + q++; + } +} + +int pthread_attr_setstackaddr(pthread_attr_t*, void*) { + // This was removed from POSIX.1-2008, and is not implemented on bionic. + // Needed for ABI compatibility with the NDK. + return ENOSYS; +} + +int pthread_attr_getstackaddr(const pthread_attr_t* attr, void** stack_addr) { + // This was removed from POSIX.1-2008. + // Needed for ABI compatibility with the NDK. + *stack_addr = (char*)attr->stack_base + attr->stack_size; + return 0; +} + +// Non-standard cruft that should only ever have been in system/core/toolbox. +char* strtotimeval(const char* str, struct timeval* ts) { + char* s; + ts->tv_sec = strtoumax(str, &s, 10); + + long fractional_seconds = 0; + if (*s == '.') { + s++; + int count = 0; + + // Read up to 6 digits (microseconds). + while (*s && isdigit(*s)) { + if (++count < 7) { + fractional_seconds = fractional_seconds*10 + (*s - '0'); + } + s++; + } + + for (; count < 6; count++) { + fractional_seconds *= 10; + } + } + + ts->tv_usec = fractional_seconds; + return s; +} + +static inline int digitval(int ch) { + unsigned d; + + d = (unsigned)(ch - '0'); + if (d < 10) return (int)d; + + d = (unsigned)(ch - 'a'); + if (d < 6) return (int)(d+10); + + d = (unsigned)(ch - 'A'); + if (d < 6) return (int)(d+10); + + return -1; +} + +// This non-standard function was in our for some reason. +uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) { + const unsigned char* p = (const unsigned char *)nptr; + const unsigned char* end = p + n; + int minus = 0; + uintmax_t v = 0; + int d; + + while (p < end && isspace(*p)) { + p++; + } + + if (p < end) { + char c = p[0]; + if (c == '-' || c == '+') { + minus = (c == '-'); + p++; + } + } + + if (base == 0) { + if (p+2 < end && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + base = 16; + } else if (p+1 < end && p[0] == '0') { + p += 1; + base = 8; + } else { + base = 10; + } + } else if (base == 16) { + if (p+2 < end && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + } + } + + while (p < end && (d = digitval(*p)) >= 0 && d < base) { + v = v*base + d; + p += 1; + } + + if (endptr) { + *endptr = (char*) p; + } + + return minus ? -v : v; +} + +// This non-standard function was in our for some reason. +intmax_t strntoimax(const char* nptr, char** endptr, int base, size_t n) { + return (intmax_t) strntoumax(nptr, endptr, base, n); +} + +// POSIX calls this dprintf, but LP32 Android had fdprintf instead. +int fdprintf(int fd, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + int rc = vdprintf(fd, fmt, ap); + va_end(ap); + return rc; +} + +// POSIX calls this vdprintf, but LP32 Android had fdprintf instead. +int vfdprintf(int fd, const char* fmt, va_list ap) { + return vdprintf(fd, fmt, ap); +} + +#define __futex_wake __real_futex_wake +#define __futex_wait __real_futex_wait +#include "private/bionic_futex.h" +#undef __futex_wake +#undef __futex_wait + +// This used to be in . +int __futex_wake(volatile void* ftx, int count) { + return __real_futex_wake(ftx, count); +} + +// This used to be in . +int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) { + return __real_futex_wait(ftx, value, timeout); +} + +// Unity's libmono uses this. +int tkill(pid_t tid, int sig) { + return syscall(__NR_tkill, tid, sig); +} + +// This was removed from POSIX 2008. +wchar_t* wcswcs(wchar_t* haystack, wchar_t* needle) { + return wcsstr(haystack, needle); +} + +// This was removed from POSIX 2008. +sighandler_t bsd_signal(int signum, sighandler_t handler) { + return signal(signum, handler); +} + +// This was removed from POSIX 2008. +#undef bcopy +void bcopy(const void* src, void* dst, size_t n) { + memmove(dst, src, n); +} + +// This was removed from POSIX 2008. +#undef bzero +void bzero(void* dst, size_t n) { + memset(dst, 0, n); +} + +// sysv_signal() was never in POSIX. +extern "C++" sighandler_t _signal(int signum, sighandler_t handler, int flags); +sighandler_t sysv_signal(int signum, sighandler_t handler) { + return _signal(signum, handler, SA_RESETHAND); +} + +// This is a system call that was never in POSIX. Use readdir(3) instead. +int __getdents64(unsigned int, dirent*, unsigned int); +int getdents(unsigned int fd, dirent* dirp, unsigned int count) { + return __getdents64(fd, dirp, count); +} + +// This is a BSDism that we never implemented correctly. Used by Firefox. +int issetugid() { + return 0; +} + +// This was removed from POSIX 2004. +pid_t wait3(int* status, int options, struct rusage* rusage) { + return wait4(-1, status, options, rusage); +} + +// This was removed from POSIX 2004. +int getdtablesize() { + struct rlimit r; + + if (getrlimit(RLIMIT_NOFILE, &r) < 0) { + return sysconf(_SC_OPEN_MAX); + } + + return r.rlim_cur; +} + +// A leaked BSD stdio implementation detail that's now a no-op. +void __sinit() {} +int __sdidinit = 1; + +// Only used by ftime, which was removed from POSIX 2008. +struct timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + +// This was removed from POSIX 2008. +int ftime(struct timeb* tb) { + struct timeval tv; + struct timezone tz; + + if (gettimeofday(&tv, &tz) < 0) + return -1; + + tb->time = tv.tv_sec; + tb->millitm = (tv.tv_usec + 500) / 1000; + + if (tb->millitm == 1000) { + ++tb->time; + tb->millitm = 0; + } + + tb->timezone = tz.tz_minuteswest; + tb->dstflag = tz.tz_dsttime; + + return 0; +} + +// This was removed from POSIX 2008. +char* index(const char* str, int ch) { + return const_cast(strchr(str, ch)); +} + +// This was removed from BSD. +void arc4random_stir(void) { + // The current implementation stirs itself as needed. +} + +// This was removed from BSD. +void arc4random_addrandom(unsigned char*, int) { + // The current implementation adds randomness as needed. +} + +// Old versions of the NDK did not export malloc_usable_size, but did +// export dlmalloc_usable_size. We are moving away from dlmalloc in L +// so make this call malloc_usable_size. +size_t dlmalloc_usable_size(void* ptr) { + return malloc_usable_size(ptr); +} + +// In L we added a public pthread_gettid_np, but some apps were using the private API. +pid_t __pthread_gettid(pthread_t t) { + return pthread_gettid_np(t); +} + +// Older versions of apportable used dlmalloc directly instead of malloc, +// so export this compatibility shim that simply calls malloc. +void* dlmalloc(size_t size) { + return malloc(size); +} + +} // extern "C" + +#define __get_thread __real_get_thread +#include "pthread_internal.h" +#undef __get_thread + +extern "C" { + +// Various third-party apps contain a backport of our pthread_rwlock implementation that uses this. +pthread_internal_t* __get_thread() { + return __real_get_thread(); +} + +// This one exists only for the LP32 NDK and is not present anywhere else. +extern long __set_errno_internal(int); +long __set_errno(int n) { + return __set_errno_internal(n); +} + +// Since dlmalloc_inspect_all and dlmalloc_trim are exported for systems +// that use dlmalloc, be consistent and export them everywhere. +void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) { +} +int dlmalloc_trim(size_t) { + return 0; +} + +// LP32's had putw (but not getw). +int putw(int value, FILE* fp) { + return fwrite(&value, sizeof(value), 1, fp) == 1 ? 0 : EOF; +} + +#endif // !defined (__LP64__) + +} // extern "C" diff --git a/aosp/bionic/libc/bionic/ndk_cruft_data.cpp b/aosp/bionic/libc/bionic/ndk_cruft_data.cpp new file mode 100644 index 000000000..e512b4a57 --- /dev/null +++ b/aosp/bionic/libc/bionic/ndk_cruft_data.cpp @@ -0,0 +1,94 @@ + +// Ancient NDKs' contained inline references to these tables. + +#if !defined(__LP64__) + +/* $OpenBSD: tolower_.c,v 1.11 2015/09/19 04:02:21 guenther Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +static const short _C_tolower_[] = { + -1, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_tolower_tab_ = _C_tolower_; + +/* $OpenBSD: toupper_.c,v 1.12 2015/09/19 04:02:21 guenther Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +static const short _C_toupper_[] = { + -1, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_toupper_tab_ = _C_toupper_; + +#endif diff --git a/aosp/bionic/libc/bionic/net_if.cpp b/aosp/bionic/libc/bionic/net_if.cpp new file mode 100644 index 000000000..ad53364c9 --- /dev/null +++ b/aosp/bionic/libc/bionic/net_if.cpp @@ -0,0 +1,153 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private/ScopedFd.h" + +#include "bionic_netlink.h" + +char* if_indextoname(unsigned ifindex, char* ifname) { + ScopedFd s(socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0)); + if (s.get() == -1) return nullptr; + + ifreq ifr = {.ifr_ifindex = static_cast(ifindex)}; + return (ioctl(s.get(), SIOCGIFNAME, &ifr) == -1) ? nullptr + : strncpy(ifname, ifr.ifr_name, IFNAMSIZ); +} + +unsigned if_nametoindex(const char* ifname) { + ScopedFd s(socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0)); + if (s.get() == -1) return 0; + + ifreq ifr = {}; + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_name[IFNAMSIZ - 1] = 0; + return (ioctl(s.get(), SIOCGIFINDEX, &ifr) == -1) ? 0 : ifr.ifr_ifindex; +} + +struct if_list { + if_list* next; + struct if_nameindex data; + + explicit if_list(if_list** list) { + // push_front onto `list`. + next = *list; + *list = this; + } + + static void Free(if_list* list, bool names_too) { + while (list) { + if_list* it = list; + list = it->next; + if (names_too) free(it->data.if_name); + free(it); + } + } +}; + +static void __if_nameindex_callback(void* context, nlmsghdr* hdr) { + if_list** list = reinterpret_cast(context); + if (hdr->nlmsg_type == RTM_NEWLINK) { + ifinfomsg* ifi = reinterpret_cast(NLMSG_DATA(hdr)); + + // Create a new entry and set the interface index. + if_list* new_link = new if_list(list); + new_link->data.if_index = ifi->ifi_index; + + // Go through the various bits of information and find the name. + rtattr* rta = IFLA_RTA(ifi); + size_t rta_len = IFLA_PAYLOAD(hdr); + while (RTA_OK(rta, rta_len)) { + if (rta->rta_type == IFLA_IFNAME) { + new_link->data.if_name = strndup(reinterpret_cast(RTA_DATA(rta)), RTA_PAYLOAD(rta)); + } + rta = RTA_NEXT(rta, rta_len); + } + } +} + +struct if_nameindex* if_nameindex() { + if_list* list = nullptr; + + // Open the netlink socket and ask for all the links; + NetlinkConnection nc; + bool okay = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__if_nameindex_callback, &list); + if (!okay) { + if_list::Free(list, true); + return nullptr; + } + + // Count the interfaces. + size_t interface_count = 0; + for (if_list* it = list; it != nullptr; it = it->next) { + ++interface_count; + } + + // Build the array POSIX requires us to return. + struct if_nameindex* result = new struct if_nameindex[interface_count + 1]; + if (result) { + struct if_nameindex* out = result; + for (if_list* it = list; it != nullptr; it = it->next) { + out->if_index = it->data.if_index; + out->if_name = it->data.if_name; + ++out; + } + out->if_index = 0; + out->if_name = nullptr; + } + + // Free temporary storage. + if_list::Free(list, false); + + return result; +} + +void if_freenameindex(struct if_nameindex* array) { + if (array == nullptr) return; + + struct if_nameindex* ptr = array; + while (ptr->if_index != 0 || ptr->if_name != nullptr) { + free(ptr->if_name); + ++ptr; + } + + delete[] array; +} diff --git a/aosp/bionic/libc/bionic/netdb.cpp b/aosp/bionic/libc/bionic/netdb.cpp new file mode 100644 index 000000000..dc2a037fa --- /dev/null +++ b/aosp/bionic/libc/bionic/netdb.cpp @@ -0,0 +1,67 @@ +/* + * 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 + +// We don't have an /etc/networks or /etc/protocols, so these are just dummies. + +void endnetent() { +} + +void endprotoent() { +} + +netent* getnetbyaddr(uint32_t /*net*/, int /*type*/) { + return nullptr; +} + +netent* getnetbyname(const char* /*name*/) { + return nullptr; +} + +netent* getnetent() { + return nullptr; +} + +protoent* getprotobyname(const char* /*name*/) { + return nullptr; +} + +protoent* getprotobynumber(int /*proto*/) { + return nullptr; +} + +protoent* getprotoent() { + return nullptr; +} + +void setnetent(int /*stayopen*/) { +} + +void setprotoent(int /*stayopen*/) { +} diff --git a/aosp/bionic/libc/bionic/netinet_in.cpp b/aosp/bionic/libc/bionic/netinet_in.cpp new file mode 100644 index 000000000..2a7090aeb --- /dev/null +++ b/aosp/bionic/libc/bionic/netinet_in.cpp @@ -0,0 +1,71 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include + +constexpr int START_PORT = 600; +constexpr int END_PORT = IPPORT_RESERVED; +constexpr int NUM_PORTS = (END_PORT - START_PORT); + +int bindresvport(int sd, struct sockaddr_in* sin) { + sockaddr_in sin0; + if (sin == nullptr) { + memset(&sin0, 0, sizeof(sin0)); + sin = &sin0; + sin->sin_family = AF_INET; + } + + if (sin->sin_family != AF_INET) { + errno = EPFNOSUPPORT; + return -1; + } + + // TODO: thread safety! + static short port; + if (port == 0) { + port = START_PORT + (getpid() % NUM_PORTS); + } + + for (size_t i = NUM_PORTS; i > 0; i--, port++) { + if (port == END_PORT) port = START_PORT; + sin->sin_port = htons(port); + int rc = TEMP_FAILURE_RETRY(bind(sd, reinterpret_cast(sin), sizeof(*sin))); + if (rc >= 0) return rc; + } + return -1; +} + +const in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; diff --git a/aosp/bionic/libc/bionic/new.cpp b/aosp/bionic/libc/bionic/new.cpp new file mode 100644 index 000000000..a0da2fb18 --- /dev/null +++ b/aosp/bionic/libc/bionic/new.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 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 + +#include +#include + +#include + +const std::nothrow_t std::nothrow = {}; + +void* operator new(std::size_t size) { + void* p = malloc(size); + if (p == nullptr) { + async_safe_fatal("new failed to allocate %zu bytes", size); + } + return p; +} + +void* operator new[](std::size_t size) { + void* p = malloc(size); + if (p == nullptr) { + async_safe_fatal("new[] failed to allocate %zu bytes", size); + } + return p; +} + +void operator delete(void* ptr) throw() { + free(ptr); +} + +void operator delete[](void* ptr) throw() { + free(ptr); +} + +void* operator new(std::size_t size, const std::nothrow_t&) { + return malloc(size); +} + +void* operator new[](std::size_t size, const std::nothrow_t&) { + return malloc(size); +} + +void operator delete(void* ptr, const std::nothrow_t&) throw() { + free(ptr); +} + +void operator delete[](void* ptr, const std::nothrow_t&) throw() { + free(ptr); +} diff --git a/aosp/bionic/libc/bionic/nl_types.cpp b/aosp/bionic/libc/bionic/nl_types.cpp new file mode 100644 index 000000000..2cde59188 --- /dev/null +++ b/aosp/bionic/libc/bionic/nl_types.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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 + +#include + +nl_catd catopen(const char*, int) { + return reinterpret_cast(-1); +} + +char* catgets(nl_catd, int, int, const char* message) { + return const_cast(message); +} + +int catclose(nl_catd) { + // Since we didn't hand out a valid nl_catd, you can't be returning one to us. + errno = EBADF; + return -1; +} diff --git a/aosp/bionic/libc/bionic/open.cpp b/aosp/bionic/libc/bionic/open.cpp new file mode 100644 index 000000000..bd8685a3a --- /dev/null +++ b/aosp/bionic/libc/bionic/open.cpp @@ -0,0 +1,92 @@ +/* + * 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 +#include +#include +#include + +#include "private/bionic_fdtrack.h" +#include "private/bionic_fortify.h" + +extern "C" int __openat(int, const char*, int, int); + +static inline int force_O_LARGEFILE(int flags) { +#if defined(__LP64__) + return flags; // No need, and aarch64's strace gets confused. +#else + return flags | O_LARGEFILE; +#endif +} + +static inline bool needs_mode(int flags) { + return ((flags & O_CREAT) == O_CREAT) || ((flags & O_TMPFILE) == O_TMPFILE); +} + +int creat(const char* pathname, mode_t mode) { + return open(pathname, O_CREAT | O_TRUNC | O_WRONLY, mode); +} +__strong_alias(creat64, creat); + +int open(const char* pathname, int flags, ...) { + mode_t mode = 0; + + if (needs_mode(flags)) { + va_list args; + va_start(args, flags); + mode = static_cast(va_arg(args, int)); + va_end(args); + } + + return FDTRACK_CREATE(__openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode)); +} +__strong_alias(open64, open); + +int __open_2(const char* pathname, int flags) { + if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode"); + return FDTRACK_CREATE_NAME("open", __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0)); +} + +int openat(int fd, const char *pathname, int flags, ...) { + mode_t mode = 0; + + if (needs_mode(flags)) { + va_list args; + va_start(args, flags); + mode = static_cast(va_arg(args, int)); + va_end(args); + } + + return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), mode)); +} +__strong_alias(openat64, openat); + +int __openat_2(int fd, const char* pathname, int flags) { + if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode"); + return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), 0)); +} diff --git a/aosp/bionic/libc/bionic/pathconf.cpp b/aosp/bionic/libc/bionic/pathconf.cpp new file mode 100644 index 000000000..9724f4436 --- /dev/null +++ b/aosp/bionic/libc/bionic/pathconf.cpp @@ -0,0 +1,156 @@ +/* + * 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 + +#include +#include +#include + +static long __filesizebits(const struct statfs& s) { + switch (s.f_type) { + case JFFS2_SUPER_MAGIC: + case MSDOS_SUPER_MAGIC: + case NCP_SUPER_MAGIC: + return 32; + } + // There won't be any new 32-bit file systems. + return 64; +} + +static long __link_max(const struct statfs& s) { + // These constant values were taken from kernel headers. + // They're not available in uapi headers. + switch (s.f_type) { + case EXT2_SUPER_MAGIC: + return 32000; + case MINIX_SUPER_MAGIC: + return 250; + case MINIX2_SUPER_MAGIC: + return 65530; + case REISERFS_SUPER_MAGIC: + return 0xffff - 1000; + case UFS_MAGIC: + return 32000; + } + return LINK_MAX; +} + +static long __2_symlinks(const struct statfs& s) { + switch (s.f_type) { + case ADFS_SUPER_MAGIC: + case BFS_MAGIC: + case CRAMFS_MAGIC: + case EFS_SUPER_MAGIC: + case MSDOS_SUPER_MAGIC: + case QNX4_SUPER_MAGIC: + return 0; + } + return 1; +} + +static long __pathconf(const struct statfs& s, int name) { + switch (name) { + case _PC_FILESIZEBITS: + return __filesizebits(s); + + case _PC_LINK_MAX: + return __link_max(s); + + case _PC_MAX_CANON: + return MAX_CANON; + + case _PC_MAX_INPUT: + return MAX_INPUT; + + case _PC_NAME_MAX: + return s.f_namelen; + + case _PC_PATH_MAX: + return PATH_MAX; + + case _PC_PIPE_BUF: + return PIPE_BUF; + + case _PC_2_SYMLINKS: + return __2_symlinks(s); + + case _PC_ALLOC_SIZE_MIN: /* fall through */ + case _PC_REC_XFER_ALIGN: + return s.f_frsize; + + case _PC_REC_MIN_XFER_SIZE: + return s.f_bsize; + +#if 0 + case _PC_REC_INCR_XFER_SIZE: + case _PC_REC_MAX_XFER_SIZE: +#endif + + case _PC_SYMLINK_MAX: + return -1; /* no limit */ + + case _PC_CHOWN_RESTRICTED: + return _POSIX_CHOWN_RESTRICTED; + + case _PC_NO_TRUNC: + return _POSIX_NO_TRUNC; + + case _PC_VDISABLE: + return _POSIX_VDISABLE; + + case _PC_ASYNC_IO: + return -1; + + case _PC_PRIO_IO: + return -1; + + case _PC_SYNC_IO: + return -1; + + default: + errno = EINVAL; + return -1; + } +} + +long pathconf(const char* path, int name) { + struct statfs sb; + if (statfs(path, &sb) == -1) { + return -1; + } + return __pathconf(sb, name); +} + +long fpathconf(int fd, int name) { + struct statfs sb; + if (fstatfs(fd, &sb) == -1) { + return -1; + } + return __pathconf(sb, name); +} diff --git a/aosp/bionic/libc/bionic/pause.cpp b/aosp/bionic/libc/bionic/pause.cpp new file mode 100644 index 000000000..534a80430 --- /dev/null +++ b/aosp/bionic/libc/bionic/pause.cpp @@ -0,0 +1,35 @@ +/* + * 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 +#include + +int pause() { + sigset64_t mask = {}; + return sigsuspend64(&mask); +} diff --git a/aosp/bionic/libc/bionic/pipe.cpp b/aosp/bionic/libc/bionic/pipe.cpp new file mode 100644 index 000000000..f1976568f --- /dev/null +++ b/aosp/bionic/libc/bionic/pipe.cpp @@ -0,0 +1,51 @@ +/* + * 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 + +#include "private/bionic_fdtrack.h" + +extern "C" int __pipe2(int pipefd[2], int flags); + +int pipe(int pipefd[2]) { + int rc = __pipe2(pipefd, 0); + if (rc == 0) { + FDTRACK_CREATE(pipefd[0]); + FDTRACK_CREATE(pipefd[1]); + } + return rc; +} + +int pipe2(int pipefd[2], int flags) { + int rc = __pipe2(pipefd, flags); + if (rc == 0) { + FDTRACK_CREATE(pipefd[0]); + FDTRACK_CREATE(pipefd[1]); + } + return rc; +} diff --git a/aosp/bionic/libc/bionic/poll.cpp b/aosp/bionic/libc/bionic/poll.cpp new file mode 100644 index 000000000..329031530 --- /dev/null +++ b/aosp/bionic/libc/bionic/poll.cpp @@ -0,0 +1,140 @@ +/* + * 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 +#include +#include + +#include + +#include "private/bionic_time_conversions.h" +#include "private/SigSetConverter.h" + +extern "C" int __ppoll(pollfd*, unsigned int, timespec*, const sigset64_t*, size_t); +extern "C" int __pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*); + +int poll(pollfd* fds, nfds_t fd_count, int ms) { + timespec ts; + timespec* ts_ptr = nullptr; + if (ms >= 0) { + timespec_from_ms(ts, ms); + ts_ptr = &ts; + } + return __ppoll(fds, fd_count, ts_ptr, nullptr, 0); +} + +int ppoll(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset_t* ss) { + // The underlying `__ppoll` system call only takes `sigset64_t`. + SigSetConverter set; + sigset64_t* ss_ptr = nullptr; + if (ss != nullptr) { + set = {}; + set.sigset = *ss; + ss_ptr = &set.sigset64; + } + return ppoll64(fds, fd_count, ts, ss_ptr); +} + +int ppoll64(pollfd* fds, nfds_t fd_count, const timespec* ts, const sigset64_t* ss) { + // The underlying __ppoll system call modifies its `struct timespec` argument. + timespec mutable_ts; + timespec* mutable_ts_ptr = nullptr; + if (ts != nullptr) { + mutable_ts = *ts; + mutable_ts_ptr = &mutable_ts; + } + + sigset64_t mutable_ss; + sigset64_t* mutable_ss_ptr = nullptr; + if (ss != nullptr) { + mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK); + mutable_ss_ptr = &mutable_ss; + } + + return __ppoll(fds, fd_count, mutable_ts_ptr, mutable_ss_ptr, sizeof(*mutable_ss_ptr)); +} + +int select(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, timeval* tv) { + timespec ts; + timespec* ts_ptr = nullptr; + if (tv != nullptr) { + if (!timespec_from_timeval(ts, *tv)) { + errno = EINVAL; + return -1; + } + ts_ptr = &ts; + } + int result = __pselect6(fd_count, read_fds, write_fds, error_fds, ts_ptr, nullptr); + if (tv != nullptr) { + timeval_from_timespec(*tv, ts); + } + return result; +} + +int pselect(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, + const timespec* ts, const sigset_t* ss) { + // The underlying `__pselect6` system call only takes `sigset64_t`. + SigSetConverter set; + sigset64_t* ss_ptr = nullptr; + if (ss != nullptr) { + set = {}; + set.sigset = *ss; + ss_ptr = &set.sigset64; + } + return pselect64(fd_count, read_fds, write_fds, error_fds, ts, ss_ptr); +} + +int pselect64(int fd_count, fd_set* read_fds, fd_set* write_fds, fd_set* error_fds, + const timespec* ts, const sigset64_t* ss) { + // The underlying __pselect6 system call modifies its `struct timespec` argument. + timespec mutable_ts; + timespec* mutable_ts_ptr = nullptr; + if (ts != nullptr) { + mutable_ts = *ts; + mutable_ts_ptr = &mutable_ts; + } + + sigset64_t mutable_ss; + sigset64_t* mutable_ss_ptr = nullptr; + if (ss != nullptr) { + mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK); + mutable_ss_ptr = &mutable_ss; + } + + // The Linux kernel only handles 6 arguments and this system call really needs 7, + // so the last argument is a void* pointing to: + struct pselect6_extra_data_t { + uintptr_t ss_addr; + size_t ss_len; + }; + pselect6_extra_data_t extra_data; + extra_data.ss_addr = reinterpret_cast(mutable_ss_ptr); + extra_data.ss_len = sizeof(*mutable_ss_ptr); + + return __pselect6(fd_count, read_fds, write_fds, error_fds, mutable_ts_ptr, &extra_data); +} diff --git a/aosp/bionic/libc/bionic/posix_fadvise.cpp b/aosp/bionic/libc/bionic/posix_fadvise.cpp new file mode 100644 index 000000000..3a74af363 --- /dev/null +++ b/aosp/bionic/libc/bionic/posix_fadvise.cpp @@ -0,0 +1,51 @@ +/* + * 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 + +#include "private/ErrnoRestorer.h" + +extern "C" int __arm_fadvise64_64(int, int, off64_t, off64_t); +extern "C" int __fadvise64(int, off64_t, off64_t, int); + +// No architecture actually has the 32-bit off_t system call. +int posix_fadvise(int fd, off_t offset, off_t length, int advice) { + return posix_fadvise64(fd, offset, length, advice); +} + +#if defined(__arm__) +int posix_fadvise64(int fd, off64_t offset, off64_t length, int advice) { + ErrnoRestorer errno_restorer; + return (__arm_fadvise64_64(fd, advice, offset, length) == 0) ? 0 : errno; +} +#else +int posix_fadvise64(int fd, off64_t offset, off64_t length, int advice) { + ErrnoRestorer errno_restorer; + return (__fadvise64(fd, offset, length, advice) == 0) ? 0 : errno; +} +#endif diff --git a/aosp/bionic/libc/bionic/posix_fallocate.cpp b/aosp/bionic/libc/bionic/posix_fallocate.cpp new file mode 100644 index 000000000..bdc1636b9 --- /dev/null +++ b/aosp/bionic/libc/bionic/posix_fallocate.cpp @@ -0,0 +1,41 @@ +/* + * 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 + +#include "private/ErrnoRestorer.h" + +int posix_fallocate(int fd, off_t offset, off_t length) { + ErrnoRestorer errno_restorer; + return (fallocate(fd, 0, offset, length) == 0) ? 0 : errno; +} + +int posix_fallocate64(int fd, off64_t offset, off64_t length) { + ErrnoRestorer errno_restorer; + return (fallocate64(fd, 0, offset, length) == 0) ? 0 : errno; +} diff --git a/aosp/bionic/libc/bionic/posix_madvise.cpp b/aosp/bionic/libc/bionic/posix_madvise.cpp new file mode 100644 index 000000000..d77be0178 --- /dev/null +++ b/aosp/bionic/libc/bionic/posix_madvise.cpp @@ -0,0 +1,42 @@ +/* + * 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 +#include + +#include "private/ErrnoRestorer.h" + +int posix_madvise(void* addr, size_t len, int advice) { + ErrnoRestorer errno_restorer; + + // Don't call madvise() on POSIX_MADV_DONTNEED, it will make the space not available. + if (advice == POSIX_MADV_DONTNEED) { + return 0; + } + return (madvise(addr, len, advice) == 0 ? 0 : errno); +} diff --git a/aosp/bionic/libc/bionic/posix_timers.cpp b/aosp/bionic/libc/bionic/posix_timers.cpp new file mode 100644 index 000000000..f522516af --- /dev/null +++ b/aosp/bionic/libc/bionic/posix_timers.cpp @@ -0,0 +1,221 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +// System calls. +extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t); +extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t); +extern "C" int __timer_create(clockid_t, sigevent*, __kernel_timer_t*); +extern "C" int __timer_delete(__kernel_timer_t); +extern "C" int __timer_getoverrun(__kernel_timer_t); +extern "C" int __timer_gettime(__kernel_timer_t, itimerspec*); +extern "C" int __timer_settime(__kernel_timer_t, int, const itimerspec*, itimerspec*); + +// Most POSIX timers are handled directly by the kernel. We translate SIGEV_THREAD timers +// into SIGEV_THREAD_ID timers so the kernel handles all the time-related stuff and we just +// need to worry about running user code on a thread. + +// We can't use SIGALRM because too many other C library functions throw that around, and since +// they don't send to a specific thread, all threads are eligible to handle the signal and we can +// end up with one of our POSIX timer threads handling it (meaning that the intended recipient +// doesn't). glibc uses SIGRTMIN for its POSIX timer implementation, so in the absence of any +// reason to use anything else, we use that too. +static const int TIMER_SIGNAL = (__SIGRTMIN + 0); + +struct PosixTimer { + __kernel_timer_t kernel_timer_id; + + int sigev_notify; + + // The fields below are only needed for a SIGEV_THREAD timer. + pthread_t callback_thread; + void (*callback)(sigval_t); + sigval_t callback_argument; + atomic_bool deleted; // Set when the timer is deleted, to prevent further calling of callback. +}; + +static __kernel_timer_t to_kernel_timer_id(timer_t timer) { + return reinterpret_cast(timer)->kernel_timer_id; +} + +static void* __timer_thread_start(void* arg) { + PosixTimer* timer = reinterpret_cast(arg); + + sigset64_t sigset = {}; + sigaddset64(&sigset, TIMER_SIGNAL); + + while (true) { + // Wait for a signal... + siginfo_t si = {}; + if (__rt_sigtimedwait(&sigset, &si, nullptr, sizeof(sigset)) == -1) continue; + + if (si.si_code == SI_TIMER) { + // This signal was sent because a timer fired, so call the callback. + + // All events to the callback will be ignored when the timer is deleted. + if (atomic_load(&timer->deleted) == true) { + continue; + } + timer->callback(timer->callback_argument); + } else if (si.si_code == SI_TKILL) { + // This signal was sent because someone wants us to exit. + free(timer); + return nullptr; + } + } +} + +static void __timer_thread_stop(PosixTimer* timer) { + atomic_store(&timer->deleted, true); + pthread_kill(timer->callback_thread, TIMER_SIGNAL); +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html +int timer_create(clockid_t clock_id, sigevent* evp, timer_t* timer_id) { + PosixTimer* timer = reinterpret_cast(malloc(sizeof(PosixTimer))); + if (timer == nullptr) { + return -1; + } + + timer->sigev_notify = (evp == nullptr) ? SIGEV_SIGNAL : evp->sigev_notify; + + // If not a SIGEV_THREAD timer, the kernel can handle it without our help. + if (timer->sigev_notify != SIGEV_THREAD) { + if (__timer_create(clock_id, evp, &timer->kernel_timer_id) == -1) { + free(timer); + return -1; + } + + *timer_id = timer; + return 0; + } + + // Otherwise, this must be SIGEV_THREAD timer... + timer->callback = evp->sigev_notify_function; + timer->callback_argument = evp->sigev_value; + atomic_init(&timer->deleted, false); + + // Check arguments that the kernel doesn't care about but we do. + if (timer->callback == nullptr) { + free(timer); + errno = EINVAL; + return -1; + } + + // Create this timer's thread. + pthread_attr_t thread_attributes; + if (evp->sigev_notify_attributes == nullptr) { + pthread_attr_init(&thread_attributes); + } else { + thread_attributes = *reinterpret_cast(evp->sigev_notify_attributes); + } + pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED); + + // We start the thread with TIMER_SIGNAL blocked by blocking the signal here and letting it + // inherit. If it tried to block the signal itself, there would be a race. + sigset64_t sigset = {}; + sigaddset64(&sigset, TIMER_SIGNAL); + sigset64_t old_sigset; + + // Use __rt_sigprocmask instead of sigprocmask64 to avoid filtering out TIMER_SIGNAL. + __rt_sigprocmask(SIG_BLOCK, &sigset, &old_sigset, sizeof(sigset)); + + int rc = pthread_create(&timer->callback_thread, &thread_attributes, __timer_thread_start, timer); + + __rt_sigprocmask(SIG_SETMASK, &old_sigset, nullptr, sizeof(old_sigset)); + + if (rc != 0) { + free(timer); + errno = rc; + return -1; + } + + sigevent se = *evp; + se.sigev_signo = TIMER_SIGNAL; + se.sigev_notify = SIGEV_THREAD_ID; + se.sigev_notify_thread_id = pthread_gettid_np(timer->callback_thread); + if (__timer_create(clock_id, &se, &timer->kernel_timer_id) == -1) { + __timer_thread_stop(timer); + return -1; + } + + // Give the thread a specific meaningful name. + // It can't do this itself because the kernel timer isn't created until after it's running. + char name[16]; // 16 is the kernel-imposed limit. + snprintf(name, sizeof(name), "POSIX timer %d", to_kernel_timer_id(timer)); + pthread_setname_np(timer->callback_thread, name); + + *timer_id = timer; + return 0; +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_delete.html +int timer_delete(timer_t id) { + int rc = __timer_delete(to_kernel_timer_id(id)); + if (rc == -1) { + return -1; + } + + PosixTimer* timer = reinterpret_cast(id); + if (timer->sigev_notify == SIGEV_THREAD) { + // Stopping the timer's thread frees the timer data when it's safe. + __timer_thread_stop(timer); + } else { + // For timers without threads, we can just free right away. + free(timer); + } + + return 0; +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_gettime.html +int timer_gettime(timer_t id, itimerspec* ts) { + return __timer_gettime(to_kernel_timer_id(id), ts); +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_settime.html +// When using timer_settime to disarm a repeatable SIGEV_THREAD timer with a very small +// period (like below 1ms), the kernel may continue to send events to the callback thread +// for a few extra times. This behavior is fine because in POSIX standard: The effect of +// disarming or resetting a timer with pending expiration notifications is unspecified. +int timer_settime(timer_t id, int flags, const itimerspec* ts, itimerspec* ots) { + PosixTimer* timer= reinterpret_cast(id); + return __timer_settime(timer->kernel_timer_id, flags, ts, ots); +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html +int timer_getoverrun(timer_t id) { + return __timer_getoverrun(to_kernel_timer_id(id)); +} diff --git a/aosp/bionic/libc/bionic/pthread_atfork.cpp b/aosp/bionic/libc/bionic/pthread_atfork.cpp new file mode 100644 index 000000000..0dcabdfb2 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_atfork.cpp @@ -0,0 +1,182 @@ +/* + * 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 +#include +#include + +#include "platform/bionic/macros.h" + +struct atfork_t { + atfork_t* next; + atfork_t* prev; + + void (*prepare)(void); + void (*child)(void); + void (*parent)(void); + + void* dso_handle; +}; + +class atfork_list_t { + public: + constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {} + + template + void walk_forward(F f) { + for (atfork_t* it = first_; it != nullptr; it = it->next) { + f(it); + } + } + + template + void walk_backwards(F f) { + for (atfork_t* it = last_; it != nullptr; it = it->prev) { + f(it); + } + } + + void push_back(atfork_t* entry) { + entry->next = nullptr; + entry->prev = last_; + if (entry->prev != nullptr) { + entry->prev->next = entry; + } + if (first_ == nullptr) { + first_ = entry; + } + last_ = entry; + } + + template + void remove_if(F predicate) { + atfork_t* it = first_; + while (it != nullptr) { + if (predicate(it)) { + atfork_t* entry = it; + it = it->next; + remove(entry); + } else { + it = it->next; + } + } + } + + private: + void remove(atfork_t* entry) { + if (entry->prev != nullptr) { + entry->prev->next = entry->next; + } else { + first_ = entry->next; + } + + if (entry->next != nullptr) { + entry->next->prev = entry->prev; + } else { + last_ = entry->prev; + } + + free(entry); + } + + atfork_t* first_; + atfork_t* last_; + + BIONIC_DISALLOW_COPY_AND_ASSIGN(atfork_list_t); +}; + +static pthread_mutex_t g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static atfork_list_t g_atfork_list; + +void __bionic_atfork_run_prepare() { + // We lock the atfork list here, unlock it in the parent, and reset it in the child. + // This ensures that nobody can modify the handler array between the calls + // to the prepare and parent/child handlers. + pthread_mutex_lock(&g_atfork_list_mutex); + + // Call pthread_atfork() prepare handlers. POSIX states that the prepare + // handlers should be called in the reverse order of the parent/child + // handlers, so we iterate backwards. + g_atfork_list.walk_backwards([](atfork_t* it) { + if (it->prepare != nullptr) { + it->prepare(); + } + }); +} + +void __bionic_atfork_run_child() { + g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + + pthread_mutex_lock(&g_atfork_list_mutex); + g_atfork_list.walk_forward([](atfork_t* it) { + if (it->child != nullptr) { + it->child(); + } + }); + pthread_mutex_unlock(&g_atfork_list_mutex); +} + +void __bionic_atfork_run_parent() { + g_atfork_list.walk_forward([](atfork_t* it) { + if (it->parent != nullptr) { + it->parent(); + } + }); + + pthread_mutex_unlock(&g_atfork_list_mutex); +} + +// __register_atfork is the name used by glibc +extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), + void(*child)(void), void* dso) { + atfork_t* entry = reinterpret_cast(malloc(sizeof(atfork_t))); + if (entry == nullptr) { + return ENOMEM; + } + + entry->prepare = prepare; + entry->parent = parent; + entry->child = child; + entry->dso_handle = dso; + + pthread_mutex_lock(&g_atfork_list_mutex); + + g_atfork_list.push_back(entry); + + pthread_mutex_unlock(&g_atfork_list_mutex); + + return 0; +} + +extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) { + pthread_mutex_lock(&g_atfork_list_mutex); + g_atfork_list.remove_if([&](const atfork_t* entry) { + return entry->dso_handle == dso; + }); + pthread_mutex_unlock(&g_atfork_list_mutex); +} diff --git a/aosp/bionic/libc/bionic/pthread_attr.cpp b/aosp/bionic/libc/bionic/pthread_attr.cpp new file mode 100644 index 000000000..3c4b169ee --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_attr.cpp @@ -0,0 +1,274 @@ +/* + * 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 + +#include +#include +#include +#include + +#include + +#include "private/bionic_defs.h" +#include "private/bionic_string_utils.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_init(pthread_attr_t* attr) { + attr->flags = 0; + attr->stack_base = nullptr; + attr->stack_size = PTHREAD_STACK_SIZE_DEFAULT; + attr->guard_size = PTHREAD_GUARD_SIZE; + attr->sched_policy = SCHED_NORMAL; + attr->sched_priority = 0; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_destroy(pthread_attr_t* attr) { + memset(attr, 0x42, sizeof(pthread_attr_t)); + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setinheritsched(pthread_attr_t* attr, int flag) { + if (flag == PTHREAD_EXPLICIT_SCHED) { + attr->flags &= ~PTHREAD_ATTR_FLAG_INHERIT; + attr->flags |= PTHREAD_ATTR_FLAG_EXPLICIT; + } else if (flag == PTHREAD_INHERIT_SCHED) { + attr->flags |= PTHREAD_ATTR_FLAG_INHERIT; + attr->flags &= ~PTHREAD_ATTR_FLAG_EXPLICIT; + } else { + return EINVAL; + } + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getinheritsched(const pthread_attr_t* attr, int* flag) { + if ((attr->flags & PTHREAD_ATTR_FLAG_INHERIT) != 0) { + *flag = PTHREAD_INHERIT_SCHED; + } else if ((attr->flags & PTHREAD_ATTR_FLAG_EXPLICIT) != 0) { + *flag = PTHREAD_EXPLICIT_SCHED; + } else { + // Historical behavior before P, when pthread_attr_setinheritsched was added. + *flag = (attr->sched_policy != SCHED_NORMAL) ? PTHREAD_EXPLICIT_SCHED : PTHREAD_INHERIT_SCHED; + } + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setdetachstate(pthread_attr_t* attr, int state) { + if (state == PTHREAD_CREATE_DETACHED) { + attr->flags |= PTHREAD_ATTR_FLAG_DETACHED; + } else if (state == PTHREAD_CREATE_JOINABLE) { + attr->flags &= ~PTHREAD_ATTR_FLAG_DETACHED; + } else { + return EINVAL; + } + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* state) { + *state = (attr->flags & PTHREAD_ATTR_FLAG_DETACHED) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy) { + attr->sched_policy = policy; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getschedpolicy(const pthread_attr_t* attr, int* policy) { + *policy = attr->sched_policy; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setschedparam(pthread_attr_t* attr, const sched_param* param) { + attr->sched_priority = param->sched_priority; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getschedparam(const pthread_attr_t* attr, sched_param* param) { + param->sched_priority = attr->sched_priority; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { + if (stack_size < PTHREAD_STACK_MIN) { + return EINVAL; + } + attr->stack_size = stack_size; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) { + void* unused; + return pthread_attr_getstack(attr, &unused, stack_size); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setstack(pthread_attr_t* attr, void* stack_base, size_t stack_size) { + if ((stack_size & (PAGE_SIZE - 1) || stack_size < PTHREAD_STACK_MIN)) { + return EINVAL; + } + if (reinterpret_cast(stack_base) & (PAGE_SIZE - 1)) { + return EINVAL; + } + attr->stack_base = stack_base; + attr->stack_size = stack_size; + return 0; +} + +static uintptr_t __get_main_stack_startstack() { + FILE* fp = fopen("/proc/self/stat", "re"); + if (fp == nullptr) { + async_safe_fatal("couldn't open /proc/self/stat: %s", strerror(errno)); + } + + char line[BUFSIZ]; + if (fgets(line, sizeof(line), fp) == nullptr) { + async_safe_fatal("couldn't read /proc/self/stat: %s", strerror(errno)); + } + + fclose(fp); + + // See man 5 proc. There's no reason comm can't contain ' ' or ')', + // so we search backwards for the end of it. We're looking for this field: + // + // startstack %lu (28) The address of the start (i.e., bottom) of the stack. + uintptr_t startstack = 0; + const char* end_of_comm = strrchr(line, ')'); + if (sscanf(end_of_comm + 1, " %*c " + "%*d %*d %*d %*d %*d " + "%*u %*u %*u %*u %*u %*u %*u " + "%*d %*d %*d %*d %*d %*d " + "%*u %*u %*d %*u %*u %*u %" SCNuPTR, &startstack) != 1) { + async_safe_fatal("couldn't parse /proc/self/stat"); + } + + return startstack; +} + +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; + } + + // Ask the kernel where our main thread's stack started. + uintptr_t startstack = __get_main_stack_startstack(); + + // Hunt for the region that contains that address. + FILE* fp = fopen("/proc/self/maps", "re"); + if (fp == nullptr) { + async_safe_fatal("couldn't open /proc/self/maps: %s", strerror(errno)); + } + char line[BUFSIZ]; + while (fgets(line, sizeof(line), fp) != nullptr) { + uintptr_t lo, hi; + if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) { + if (lo <= startstack && startstack <= hi) { + *stack_size = stack_limit.rlim_cur; + *stack_base = reinterpret_cast(hi - *stack_size); + fclose(fp); + return 0; + } + } + } + async_safe_fatal("Stack not found in /proc/self/maps"); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getstack(const pthread_attr_t* attr, void** stack_base, size_t* stack_size) { + *stack_base = attr->stack_base; + *stack_size = attr->stack_size; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guard_size) { + attr->guard_size = guard_size; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getguardsize(const pthread_attr_t* attr, size_t* guard_size) { + *guard_size = attr->guard_size; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_getattr_np(pthread_t t, pthread_attr_t* attr) { + pthread_internal_t* thread = reinterpret_cast(t); + *attr = thread->attr; + // We prefer reading join_state here to setting thread->attr.flags in pthread_detach. + // Because data race exists in the latter case. + if (atomic_load(&thread->join_state) == THREAD_DETACHED) { + attr->flags |= PTHREAD_ATTR_FLAG_DETACHED; + } + // The main thread's stack information is not stored in thread->attr, and we need to + // collect that at runtime. + if (thread->tid == getpid()) { + return __pthread_attr_getstack_main_thread(&attr->stack_base, &attr->stack_size); + } + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_setscope(pthread_attr_t*, int scope) { + if (scope == PTHREAD_SCOPE_SYSTEM) { + return 0; + } + if (scope == PTHREAD_SCOPE_PROCESS) { + return ENOTSUP; + } + return EINVAL; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_attr_getscope(const pthread_attr_t*, int* scope) { + *scope = PTHREAD_SCOPE_SYSTEM; + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_barrier.cpp b/aosp/bionic/libc/bionic/pthread_barrier.cpp new file mode 100644 index 000000000..1618222a1 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_barrier.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015 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 +#include +#include + +#include "private/bionic_futex.h" + +int pthread_barrierattr_init(pthread_barrierattr_t* attr) { + *attr = 0; + return 0; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t* attr) { + *attr = 0; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t* attr, int* pshared) { + *pshared = (*attr & 1) ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t* attr, int pshared) { + if (pshared == PTHREAD_PROCESS_SHARED) { + *attr |= 1; + } else { + *attr &= ~1; + } + return 0; +} + +enum BarrierState { + WAIT, + RELEASE, +}; + +struct pthread_barrier_internal_t { + // One barrier can be used for unlimited number of cycles. In each cycle, [init_count] + // threads must call pthread_barrier_wait() before any of them successfully return from + // the call. It is undefined behavior if there are more than [init_count] threads call + // pthread_barrier_wait() in one cycle. + uint32_t init_count; + // Barrier state. It is WAIT if waiting for more threads to enter the barrier in this cycle, + // otherwise threads are leaving the barrier. + _Atomic(BarrierState) state; + // Number of threads having entered but not left the barrier in this cycle. + atomic_uint wait_count; + // Whether the barrier is shared across processes. + bool pshared; + uint32_t __reserved[4]; +}; + +static_assert(sizeof(pthread_barrier_t) == sizeof(pthread_barrier_internal_t), + "pthread_barrier_t should actually be pthread_barrier_internal_t in implementation." + ); + +static_assert(alignof(pthread_barrier_t) >= 4, + "pthread_barrier_t should fulfill the alignment of pthread_barrier_internal_t."); + +static inline pthread_barrier_internal_t* __get_internal_barrier(pthread_barrier_t* barrier) { + return reinterpret_cast(barrier); +} + +int pthread_barrier_init(pthread_barrier_t* barrier_interface, const pthread_barrierattr_t* attr, + unsigned count) { + pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface); + if (count == 0) { + return EINVAL; + } + barrier->init_count = count; + atomic_init(&barrier->state, WAIT); + atomic_init(&barrier->wait_count, 0); + barrier->pshared = false; + if (attr != nullptr && (*attr & 1)) { + barrier->pshared = true; + } + return 0; +} + +// According to POSIX standard, pthread_barrier_wait() synchronizes memory between participating +// threads. It means all memory operations made by participating threads before calling +// pthread_barrier_wait() can be seen by all participating threads after the function call. +// We establish this by making a happens-before relation between all threads entering the barrier +// with the last thread entering the barrier, and a happens-before relation between the last +// thread entering the barrier with all threads leaving the barrier. +int pthread_barrier_wait(pthread_barrier_t* barrier_interface) { + pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface); + + // Wait until all threads for the previous cycle have left the barrier. This is needed + // as a participating thread can call pthread_barrier_wait() again before other + // threads have left the barrier. Use acquire operation here to synchronize with + // the last thread leaving the previous cycle, so we can read correct wait_count below. + while(atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) { + __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr); + } + + uint32_t prev_wait_count = atomic_load_explicit(&barrier->wait_count, memory_order_relaxed); + while (true) { + // It happens when there are more than [init_count] threads trying to enter the barrier + // at one cycle. We read the POSIX standard as disallowing this, since additional arriving + // threads are not synchronized with respect to the barrier reset. We also don't know of + // any reasonable cases in which this would be intentional. + if (prev_wait_count >= barrier->init_count) { + return EINVAL; + } + // Use memory_order_acq_rel operation here to synchronize between all threads entering + // the barrier with the last thread entering the barrier. + if (atomic_compare_exchange_weak_explicit(&barrier->wait_count, &prev_wait_count, + prev_wait_count + 1u, memory_order_acq_rel, + memory_order_relaxed)) { + break; + } + } + + int result = 0; + if (prev_wait_count + 1 == barrier->init_count) { + result = PTHREAD_BARRIER_SERIAL_THREAD; + if (prev_wait_count != 0) { + // Use release operation here to synchronize between the last thread entering the + // barrier with all threads leaving the barrier. + atomic_store_explicit(&barrier->state, RELEASE, memory_order_release); + __futex_wake_ex(&barrier->state, barrier->pshared, prev_wait_count); + } + } else { + // Use acquire operation here to synchronize between the last thread entering the + // barrier with all threads leaving the barrier. + while (atomic_load_explicit(&barrier->state, memory_order_acquire) == WAIT) { + __futex_wait_ex(&barrier->state, barrier->pshared, WAIT, false, nullptr); + } + } + // Use release operation here to make it not reordered with previous operations. + if (atomic_fetch_sub_explicit(&barrier->wait_count, 1, memory_order_release) == 1) { + // Use release operation here to synchronize with threads entering the barrier for + // the next cycle, or the thread calling pthread_barrier_destroy(). + atomic_store_explicit(&barrier->state, WAIT, memory_order_release); + __futex_wake_ex(&barrier->state, barrier->pshared, barrier->init_count); + } + return result; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier_interface) { + pthread_barrier_internal_t* barrier = __get_internal_barrier(barrier_interface); + if (barrier->init_count == 0) { + return EINVAL; + } + // Use acquire operation here to synchronize with the last thread leaving the barrier. + // So we can read correct wait_count below. + while (atomic_load_explicit(&barrier->state, memory_order_acquire) == RELEASE) { + __futex_wait_ex(&barrier->state, barrier->pshared, RELEASE, false, nullptr); + } + if (atomic_load_explicit(&barrier->wait_count, memory_order_relaxed) != 0) { + return EBUSY; + } + barrier->init_count = 0; + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_cond.cpp b/aosp/bionic/libc/bionic/pthread_cond.cpp new file mode 100644 index 000000000..e85706902 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_cond.cpp @@ -0,0 +1,258 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include + +#include "pthread_internal.h" + +#include "private/bionic_futex.h" +#include "private/bionic_time_conversions.h" +#include "private/bionic_tls.h" + +// XXX *technically* there is a race condition that could allow +// XXX a signal to be missed. If thread A is preempted in _wait() +// XXX after unlocking the mutex and before waiting, and if other +// XXX threads call signal or broadcast UINT_MAX/2 times (exactly), +// XXX before thread A is scheduled again and calls futex_wait(), +// XXX then the signal will be lost. + +// We use one bit in pthread_condattr_t (long) values as the 'shared' flag +// and one bit for the clock type (CLOCK_REALTIME is 0 and +// CLOCK_MONOTONIC is 1). The rest of the bits are a counter. +// +// The 'value' field in pthread_cond_t has the same layout. + +#define COND_SHARED_MASK 0x0001 +#define COND_CLOCK_MASK 0x0002 +#define COND_COUNTER_STEP 0x0004 +#define COND_FLAGS_MASK (COND_SHARED_MASK | COND_CLOCK_MASK) +#define COND_COUNTER_MASK (~COND_FLAGS_MASK) + +#define COND_IS_SHARED(c) (((c) & COND_SHARED_MASK) != 0) +#define COND_GET_CLOCK(c) (((c) & COND_CLOCK_MASK) >> 1) +#define COND_SET_CLOCK(attr, c) ((attr) | (c << 1)) + +int pthread_condattr_init(pthread_condattr_t* attr) { + *attr = 0; + *attr |= PTHREAD_PROCESS_PRIVATE; + *attr |= (CLOCK_REALTIME << 1); + return 0; +} + +int pthread_condattr_getpshared(const pthread_condattr_t* attr, int* pshared) { + *pshared = static_cast(COND_IS_SHARED(*attr)); + return 0; +} + +int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared) { + if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) { + return EINVAL; + } + + *attr |= pshared; + return 0; +} + +int pthread_condattr_getclock(const pthread_condattr_t* attr, clockid_t* clock) { + *clock = COND_GET_CLOCK(*attr); + return 0; +} + +int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock) { + if (clock != CLOCK_MONOTONIC && clock != CLOCK_REALTIME) { + return EINVAL; + } + + *attr = COND_SET_CLOCK(*attr, clock); + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t* attr) { + *attr = 0xdeada11d; + return 0; +} + +struct pthread_cond_internal_t { + atomic_uint state; + + bool process_shared() { + return COND_IS_SHARED(atomic_load_explicit(&state, memory_order_relaxed)); + } + + bool use_realtime_clock() { + return COND_GET_CLOCK(atomic_load_explicit(&state, memory_order_relaxed)) == CLOCK_REALTIME; + } + +#if defined(__LP64__) + char __reserved[44]; +#endif +}; + +static_assert(sizeof(pthread_cond_t) == sizeof(pthread_cond_internal_t), + "pthread_cond_t should actually be pthread_cond_internal_t in implementation."); + +// For binary compatibility with old version of pthread_cond_t, we can't use more strict alignment +// than 4-byte alignment. +static_assert(alignof(pthread_cond_t) == 4, + "pthread_cond_t should fulfill the alignment requirement of pthread_cond_internal_t."); + +static pthread_cond_internal_t* __get_internal_cond(pthread_cond_t* cond_interface) { + return reinterpret_cast(cond_interface); +} + +int pthread_cond_init(pthread_cond_t* cond_interface, const pthread_condattr_t* attr) { + pthread_cond_internal_t* cond = __get_internal_cond(cond_interface); + + unsigned int init_state = 0; + if (attr != nullptr) { + init_state = (*attr & COND_FLAGS_MASK); + } + atomic_init(&cond->state, init_state); + + return 0; +} + +int pthread_cond_destroy(pthread_cond_t* cond_interface) { + pthread_cond_internal_t* cond = __get_internal_cond(cond_interface); + atomic_store_explicit(&cond->state, 0xdeadc04d, memory_order_relaxed); + return 0; +} + +// This function is used by pthread_cond_broadcast and +// pthread_cond_signal to atomically decrement the counter +// then wake up thread_count threads. +static int __pthread_cond_pulse(pthread_cond_internal_t* cond, int thread_count) { + // We don't use a release/seq_cst fence here. Because pthread_cond_wait/signal can't be + // used as a method for memory synchronization by itself. It should always be used with + // pthread mutexes. Note that Spurious wakeups from pthread_cond_wait/timedwait may occur, + // so when using condition variables there is always a boolean predicate involving shared + // variables associated with each condition wait that is true if the thread should proceed. + // If the predicate is seen true before a condition wait, pthread_cond_wait/timedwait will + // not be called. That's why pthread_wait/signal pair can't be used as a method for memory + // synchronization. And it doesn't help even if we use any fence here. + + // The increase of value should leave flags alone, even if the value can overflows. + atomic_fetch_add_explicit(&cond->state, COND_COUNTER_STEP, memory_order_relaxed); + + __futex_wake_ex(&cond->state, cond->process_shared(), thread_count); + return 0; +} + +static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex_t* mutex, + bool use_realtime_clock, const timespec* abs_timeout_or_null) { + int result = check_timespec(abs_timeout_or_null, true); + if (result != 0) { + return result; + } + + unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed); + pthread_mutex_unlock(mutex); + int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state, + use_realtime_clock, abs_timeout_or_null); + pthread_mutex_lock(mutex); + + if (status == -ETIMEDOUT) { + return ETIMEDOUT; + } + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t* cond_interface) { + return __pthread_cond_pulse(__get_internal_cond(cond_interface), INT_MAX); +} + +int pthread_cond_signal(pthread_cond_t* cond_interface) { + return __pthread_cond_pulse(__get_internal_cond(cond_interface), 1); +} + +int pthread_cond_wait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex) { + pthread_cond_internal_t* cond = __get_internal_cond(cond_interface); + return __pthread_cond_timedwait(cond, mutex, false, nullptr); +} + +int pthread_cond_timedwait(pthread_cond_t *cond_interface, pthread_mutex_t * mutex, + const timespec *abstime) { + + pthread_cond_internal_t* cond = __get_internal_cond(cond_interface); + return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime); +} + +extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface, + pthread_mutex_t* mutex, + const timespec* abs_timeout) { + return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout); +} + +int pthread_cond_clockwait(pthread_cond_t* cond_interface, pthread_mutex_t* mutex, clockid_t clock, + const struct timespec* abs_timeout) { + switch (clock) { + case CLOCK_MONOTONIC: + return pthread_cond_timedwait_monotonic_np(cond_interface, mutex, abs_timeout); + case CLOCK_REALTIME: + return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout); + default: + return EINVAL; + } +} + +#if !defined(__LP64__) +// TODO: this exists only for backward binary compatibility on 32 bit platforms. +extern "C" int pthread_cond_timedwait_monotonic(pthread_cond_t* cond_interface, + pthread_mutex_t* mutex, + const timespec* abs_timeout) { + return pthread_cond_timedwait_monotonic_np(cond_interface, mutex, abs_timeout); +} + +// Force this function using CLOCK_MONOTONIC because it was always using +// CLOCK_MONOTONIC in history. +extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface, + pthread_mutex_t* mutex, + const timespec* rel_timeout) { + timespec ts; + timespec* abs_timeout = nullptr; + if (rel_timeout != nullptr) { + absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_MONOTONIC); + abs_timeout = &ts; + } + return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout); +} + +extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface, + pthread_mutex_t* mutex, unsigned ms) { + timespec ts; + timespec_from_ms(ts, ms); + return pthread_cond_timedwait_relative_np(cond_interface, mutex, &ts); +} +#endif // !defined(__LP64__) diff --git a/aosp/bionic/libc/bionic/pthread_create.cpp b/aosp/bionic/libc/bionic/pthread_create.cpp new file mode 100644 index 000000000..d4a8bef26 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_create.cpp @@ -0,0 +1,444 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include + +#include "pthread_internal.h" + +#include + +#include "private/bionic_constants.h" +#include "private/bionic_defs.h" +#include "private/bionic_globals.h" +#include "platform/bionic/macros.h" +#include "private/bionic_ssp.h" +#include "private/bionic_systrace.h" +#include "private/bionic_tls.h" +#include "private/ErrnoRestorer.h" + +// x86 uses segment descriptors rather than a direct pointer to TLS. +#if defined(__i386__) +#include +void __init_user_desc(struct user_desc*, bool, void*); +#endif + +__attribute__((no_stack_protector)) +void __init_tcb_stack_guard(bionic_tcb* tcb) { + // GCC looks in the TLS for the stack guard on x86, so copy it there from our global. + tcb->tls_slot(TLS_SLOT_STACK_GUARD) = reinterpret_cast(__stack_chk_guard); +} + +void __init_bionic_tls_ptrs(bionic_tcb* tcb, bionic_tls* tls) { + tcb->thread()->bionic_tls = tls; + tcb->tls_slot(TLS_SLOT_BIONIC_TLS) = tls; +} + +// Allocate a temporary bionic_tls that the dynamic linker's main thread can +// use while it's loading the initial set of ELF modules. +bionic_tls* __allocate_temp_bionic_tls() { + size_t allocation_size = __BIONIC_ALIGN(sizeof(bionic_tls), PAGE_SIZE); + void* allocation = mmap(nullptr, allocation_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (allocation == MAP_FAILED) { + // Avoid strerror because it might need bionic_tls. + async_safe_fatal("failed to allocate bionic_tls: error %d", errno); + } + return static_cast(allocation); +} + +void __free_temp_bionic_tls(bionic_tls* tls) { + munmap(tls, __BIONIC_ALIGN(sizeof(bionic_tls), PAGE_SIZE)); +} + +static void __init_alternate_signal_stack(pthread_internal_t* thread) { + // Create and set an alternate signal stack. + void* stack_base = mmap(nullptr, SIGNAL_STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (stack_base != MAP_FAILED) { + // Create a guard to catch stack overflows in signal handlers. + if (mprotect(stack_base, PTHREAD_GUARD_SIZE, PROT_NONE) == -1) { + munmap(stack_base, SIGNAL_STACK_SIZE); + return; + } + stack_t ss; + ss.ss_sp = reinterpret_cast(stack_base) + PTHREAD_GUARD_SIZE; + ss.ss_size = SIGNAL_STACK_SIZE - PTHREAD_GUARD_SIZE; + ss.ss_flags = 0; + sigaltstack(&ss, nullptr); + thread->alternate_signal_stack = stack_base; + + // We can only use const static allocated string for mapped region name, as Android kernel + // uses the string pointer directly when dumping /proc/pid/maps. + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack"); + } +} + +static void __init_shadow_call_stack(pthread_internal_t* thread __unused) { +#ifdef __aarch64__ + // Allocate the stack and the guard region. + char* scs_guard_region = reinterpret_cast( + mmap(nullptr, SCS_GUARD_REGION_SIZE, 0, MAP_PRIVATE | MAP_ANON, -1, 0)); + thread->shadow_call_stack_guard_region = scs_guard_region; + + // The address is aligned to SCS_SIZE so that we only need to store the lower log2(SCS_SIZE) bits + // in jmp_buf. + char* scs_aligned_guard_region = + reinterpret_cast(align_up(reinterpret_cast(scs_guard_region), SCS_SIZE)); + + // We need to ensure that [scs_offset,scs_offset+SCS_SIZE) is in the guard region and that there + // is at least one unmapped page after the shadow call stack (to catch stack overflows). We can't + // use arc4random_uniform in init because /dev/urandom might not have been created yet. + size_t scs_offset = + (getpid() == 1) ? 0 : (arc4random_uniform(SCS_GUARD_REGION_SIZE / SCS_SIZE - 1) * SCS_SIZE); + + // Make the stack readable and writable and store its address in register x18. This is + // deliberately the only place where the address is stored. + char *scs = scs_aligned_guard_region + scs_offset; + mprotect(scs, SCS_SIZE, PROT_READ | PROT_WRITE); + __asm__ __volatile__("mov x18, %0" ::"r"(scs)); +#endif +} + +void __init_additional_stacks(pthread_internal_t* thread) { + __init_alternate_signal_stack(thread); + __init_shadow_call_stack(thread); +} + +int __init_thread(pthread_internal_t* thread) { + thread->cleanup_stack = nullptr; + + if (__predict_true((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) == 0)) { + atomic_init(&thread->join_state, THREAD_NOT_JOINED); + } else { + atomic_init(&thread->join_state, THREAD_DETACHED); + } + + // Set the scheduling policy/priority of the thread if necessary. + bool need_set = true; + int policy; + sched_param param; + if ((thread->attr.flags & PTHREAD_ATTR_FLAG_INHERIT) != 0) { + // Unless the parent has SCHED_RESET_ON_FORK set, we've already inherited from the parent. + policy = sched_getscheduler(0); + need_set = ((policy & SCHED_RESET_ON_FORK) != 0); + if (need_set) { + if (policy == -1) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create sched_getscheduler failed: %s", strerror(errno)); + return errno; + } + if (sched_getparam(0, ¶m) == -1) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create sched_getparam failed: %s", strerror(errno)); + return errno; + } + } + } else { + policy = thread->attr.sched_policy; + param.sched_priority = thread->attr.sched_priority; + } + // Backwards compatibility: before P, Android didn't have pthread_attr_setinheritsched, + // and our behavior was neither of the POSIX behaviors. + if ((thread->attr.flags & (PTHREAD_ATTR_FLAG_INHERIT|PTHREAD_ATTR_FLAG_EXPLICIT)) == 0) { + need_set = (thread->attr.sched_policy != SCHED_NORMAL); + } + if (need_set) { + if (sched_setscheduler(thread->tid, policy, ¶m) == -1) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create sched_setscheduler(%d, {%d}) call failed: %s", policy, + param.sched_priority, strerror(errno)); +#if defined(__LP64__) + // For backwards compatibility reasons, we only report failures on 64-bit devices. + return errno; +#endif + } + } + + return 0; +} + + +// Allocate a thread's primary mapping. This mapping includes static TLS and +// optionally a stack. Static TLS includes ELF TLS segments and the bionic_tls +// struct. +// +// The stack_guard_size must be a multiple of the PAGE_SIZE. +ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) { + const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + + // Allocate in order: stack guard, stack, static TLS, guard page. + size_t mmap_size; + if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {}; + + // Align the result to a page size. + const size_t unaligned_size = mmap_size; + mmap_size = __BIONIC_ALIGN(mmap_size, PAGE_SIZE); + if (mmap_size < unaligned_size) return {}; + + // Create a new private anonymous map. Make the entire mapping PROT_NONE, then carve out a + // read+write area in the middle. + const int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; + char* const space = static_cast(mmap(nullptr, mmap_size, PROT_NONE, flags, -1, 0)); + if (space == MAP_FAILED) { + async_safe_format_log(ANDROID_LOG_WARN, + "libc", + "pthread_create failed: couldn't allocate %zu-bytes mapped space: %s", + mmap_size, strerror(errno)); + return {}; + } + const size_t writable_size = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE; + if (mprotect(space + stack_guard_size, + writable_size, + PROT_READ | PROT_WRITE) != 0) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "pthread_create failed: couldn't mprotect R+W %zu-byte thread mapping region: %s", + writable_size, strerror(errno)); + munmap(space, mmap_size); + return {}; + } + + ThreadMapping result = {}; + result.mmap_base = space; + result.mmap_size = mmap_size; + result.mmap_base_unguarded = space + stack_guard_size; + result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE; + result.static_tls = space + mmap_size - PTHREAD_GUARD_SIZE - layout.size(); + result.stack_base = space; + result.stack_top = result.static_tls; + return result; +} + +static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** child_stack) { + ThreadMapping mapping; + char* stack_top; + bool stack_clean = false; + + if (attr->stack_base == nullptr) { + // The caller didn't provide a stack, so allocate one. + + // Make sure the guard size is a multiple of PAGE_SIZE. + const size_t unaligned_guard_size = attr->guard_size; + attr->guard_size = __BIONIC_ALIGN(attr->guard_size, PAGE_SIZE); + if (attr->guard_size < unaligned_guard_size) return EAGAIN; + + mapping = __allocate_thread_mapping(attr->stack_size, attr->guard_size); + if (mapping.mmap_base == nullptr) return EAGAIN; + + stack_top = mapping.stack_top; + attr->stack_base = mapping.stack_base; + stack_clean = true; + } else { + mapping = __allocate_thread_mapping(0, PTHREAD_GUARD_SIZE); + if (mapping.mmap_base == nullptr) return EAGAIN; + + stack_top = static_cast(attr->stack_base) + attr->stack_size; + } + + // Carve out space from the stack for the thread's pthread_internal_t. This + // memory isn't counted in pthread_attr_getstacksize. + + // To safely access the pthread_internal_t and thread stack, we need to find a 16-byte aligned boundary. + stack_top = align_down(stack_top - sizeof(pthread_internal_t), 16); + + pthread_internal_t* thread = reinterpret_cast(stack_top); + if (!stack_clean) { + // If thread was not allocated by mmap(), it may not have been cleared to zero. + // So assume the worst and zero it. + memset(thread, 0, sizeof(pthread_internal_t)); + } + + // Locate static TLS structures within the mapped region. + const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; + auto tcb = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tcb()); + auto tls = reinterpret_cast(mapping.static_tls + layout.offset_bionic_tls()); + + // Initialize TLS memory. + __init_static_tls(mapping.static_tls); + __init_tcb(tcb, thread); + __init_tcb_dtv(tcb); + __init_tcb_stack_guard(tcb); + __init_bionic_tls_ptrs(tcb, tls); + + attr->stack_size = stack_top - static_cast(attr->stack_base); + thread->attr = *attr; + thread->mmap_base = mapping.mmap_base; + thread->mmap_size = mapping.mmap_size; + thread->mmap_base_unguarded = mapping.mmap_base_unguarded; + thread->mmap_size_unguarded = mapping.mmap_size_unguarded; + thread->stack_top = reinterpret_cast(stack_top); + + *tcbp = tcb; + *child_stack = stack_top; + return 0; +} + +void __set_stack_and_tls_vma_name(bool is_main_thread) { + // Name the thread's stack-and-tls area to help with debugging. This mapped area also includes + // static TLS data, which is typically a few pages (e.g. bionic_tls). + pthread_internal_t* thread = __get_thread(); + const char* name; + if (is_main_thread) { + name = "stack_and_tls:main"; + } else { + // The kernel doesn't copy the name string, but this variable will last at least as long as the + // mapped area. The mapped area's VMAs are unmapped with a single call to munmap. + auto& name_buffer = thread->vma_name_buffer; + static_assert(arraysize(name_buffer) >= arraysize("stack_and_tls:") + 11 + 1); + async_safe_format_buffer(name_buffer, arraysize(name_buffer), "stack_and_tls:%d", thread->tid); + name = name_buffer; + } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, thread->mmap_base_unguarded, thread->mmap_size_unguarded, + name); +} + +extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t); + +__attribute__((no_sanitize("hwaddress"))) +static int __pthread_start(void* arg) { + pthread_internal_t* thread = reinterpret_cast(arg); + + __hwasan_thread_enter(); + + // Wait for our creating thread to release us. This lets it have time to + // notify gdb about this thread before we start doing anything. + // This also provides the memory barrier needed to ensure that all memory + // accesses previously made by the creating thread are visible to us. + thread->startup_handshake_lock.lock(); + + __set_stack_and_tls_vma_name(false); + __init_additional_stacks(thread); + __rt_sigprocmask(SIG_SETMASK, &thread->start_mask, nullptr, sizeof(thread->start_mask)); + + void* result = thread->start_routine(thread->start_routine_arg); + pthread_exit(result); + + return 0; +} + +// A dummy start routine for pthread_create failures where we've created a thread but aren't +// going to run user code on it. We swap out the user's start routine for this and take advantage +// of the regular thread teardown to free up resources. +static void* __do_nothing(void*) { + return nullptr; +} + + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr, + void* (*start_routine)(void*), void* arg) { + ErrnoRestorer errno_restorer; + + pthread_attr_t thread_attr; + ScopedTrace trace("pthread_create"); + if (attr == nullptr) { + pthread_attr_init(&thread_attr); + } else { + thread_attr = *attr; + attr = nullptr; // Prevent misuse below. + } + + bionic_tcb* tcb = nullptr; + void* child_stack = nullptr; + int result = __allocate_thread(&thread_attr, &tcb, &child_stack); + if (result != 0) { + return result; + } + + pthread_internal_t* thread = tcb->thread(); + + // Create a lock for the thread to wait on once it starts so we can keep + // it from doing anything until after we notify the debugger about it + // + // This also provides the memory barrier we need to ensure that all + // memory accesses previously performed by this thread are visible to + // the new thread. + thread->startup_handshake_lock.init(false); + thread->startup_handshake_lock.lock(); + + thread->start_routine = start_routine; + thread->start_routine_arg = arg; + + thread->set_cached_pid(getpid()); + + int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | + CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; + void* tls = &tcb->tls_slot(0); +#if defined(__i386__) + // On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than + // a pointer to the TLS itself. + user_desc tls_descriptor; + __init_user_desc(&tls_descriptor, false, tls); + tls = &tls_descriptor; +#endif + + sigset64_t block_all_mask; + sigfillset64(&block_all_mask); + __rt_sigprocmask(SIG_SETMASK, &block_all_mask, &thread->start_mask, sizeof(thread->start_mask)); + int rc = clone(__pthread_start, child_stack, flags, thread, &(thread->tid), tls, &(thread->tid)); + __rt_sigprocmask(SIG_SETMASK, &thread->start_mask, nullptr, sizeof(thread->start_mask)); + if (rc == -1) { + int clone_errno = errno; + // We don't have to unlock the mutex at all because clone(2) failed so there's no child waiting to + // be unblocked, but we're about to unmap the memory the mutex is stored in, so this serves as a + // reminder that you can't rewrite this function to use a ScopedPthreadMutexLocker. + thread->startup_handshake_lock.unlock(); + if (thread->mmap_size != 0) { + munmap(thread->mmap_base, thread->mmap_size); + } + async_safe_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", + strerror(clone_errno)); + return clone_errno; + } + + int init_errno = __init_thread(thread); + if (init_errno != 0) { + // Mark the thread detached and replace its start_routine with a no-op. + // Letting the thread run is the easiest way to clean up its resources. + atomic_store(&thread->join_state, THREAD_DETACHED); + __pthread_internal_add(thread); + thread->start_routine = __do_nothing; + thread->startup_handshake_lock.unlock(); + return init_errno; + } + + // Publish the pthread_t and unlock the mutex to let the new thread start running. + *thread_out = __pthread_internal_add(thread); + thread->startup_handshake_lock.unlock(); + + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_detach.cpp b/aosp/bionic/libc/bionic/pthread_detach.cpp new file mode 100644 index 000000000..6b2203979 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_detach.cpp @@ -0,0 +1,54 @@ +/* + * 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 +#include + +#include "private/bionic_defs.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_detach(pthread_t t) { + pthread_internal_t* thread = __pthread_internal_find(t, "pthread_detach"); + if (thread == nullptr) { + return ESRCH; + } + + ThreadJoinState old_state = THREAD_NOT_JOINED; + while (old_state == THREAD_NOT_JOINED && + !atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_DETACHED)) { + } + + if (old_state == THREAD_NOT_JOINED) { + return 0; + } else if (old_state == THREAD_EXITED_NOT_JOINED) { + // Use pthread_join to clean it up. + return pthread_join(t, nullptr); + } + return EINVAL; +} diff --git a/aosp/bionic/libc/bionic/pthread_equal.cpp b/aosp/bionic/libc/bionic/pthread_equal.cpp new file mode 100644 index 000000000..493b2c25c --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_equal.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int pthread_equal(pthread_t lhs, pthread_t rhs) { + return (lhs == rhs ? 1 : 0); +} diff --git a/aosp/bionic/libc/bionic/pthread_exit.cpp b/aosp/bionic/libc/bionic/pthread_exit.cpp new file mode 100644 index 000000000..3b873b314 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_exit.cpp @@ -0,0 +1,140 @@ +/* + * 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 + +#include +#include +#include +#include + +#include "private/bionic_constants.h" +#include "private/bionic_defs.h" +#include "private/ScopedSignalBlocker.h" +#include "pthread_internal.h" + +extern "C" __noreturn void _exit_with_stack_teardown(void*, size_t); +extern "C" __noreturn void __exit(int); +extern "C" int __set_tid_address(int*); +extern "C" void __cxa_thread_finalize(); + +/* CAVEAT: our implementation of pthread_cleanup_push/pop doesn't support C++ exceptions + * and thread cancelation + */ + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void __pthread_cleanup_push(__pthread_cleanup_t* c, __pthread_cleanup_func_t routine, void* arg) { + pthread_internal_t* thread = __get_thread(); + c->__cleanup_routine = routine; + c->__cleanup_arg = arg; + c->__cleanup_prev = thread->cleanup_stack; + thread->cleanup_stack = c; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void __pthread_cleanup_pop(__pthread_cleanup_t* c, int execute) { + pthread_internal_t* thread = __get_thread(); + thread->cleanup_stack = c->__cleanup_prev; + if (execute) { + c->__cleanup_routine(c->__cleanup_arg); + } +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void pthread_exit(void* return_value) { + // Call dtors for thread_local objects first. + __cxa_thread_finalize(); + + pthread_internal_t* thread = __get_thread(); + thread->return_value = return_value; + + // Call the cleanup handlers. + while (thread->cleanup_stack) { + __pthread_cleanup_t* c = thread->cleanup_stack; + thread->cleanup_stack = c->__cleanup_prev; + c->__cleanup_routine(c->__cleanup_arg); + } + + // Call the TLS destructors. It is important to do that before removing this + // thread from the global list. This will ensure that if someone else deletes + // a TLS key, the corresponding value will be set to NULL in this thread's TLS + // space (see pthread_key_delete). + pthread_key_clean_all(); + + if (thread->alternate_signal_stack != nullptr) { + // Tell the kernel to stop using the alternate signal stack. + stack_t ss; + memset(&ss, 0, sizeof(ss)); + ss.ss_flags = SS_DISABLE; + sigaltstack(&ss, nullptr); + + // Free it. + munmap(thread->alternate_signal_stack, SIGNAL_STACK_SIZE); + thread->alternate_signal_stack = nullptr; + } + + ThreadJoinState old_state = THREAD_NOT_JOINED; + while (old_state == THREAD_NOT_JOINED && + !atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_EXITED_NOT_JOINED)) { + } + + // We don't want to take a signal after unmapping the stack, the shadow call + // stack, or dynamic TLS memory. + ScopedSignalBlocker ssb; + +#ifdef __aarch64__ + // Free the shadow call stack and guard pages. + munmap(thread->shadow_call_stack_guard_region, SCS_GUARD_REGION_SIZE); +#endif + + // Free the ELF TLS DTV and all dynamically-allocated ELF TLS memory. + __free_dynamic_tls(__get_bionic_tcb()); + + if (old_state == THREAD_DETACHED) { + // The thread is detached, no one will use pthread_internal_t after pthread_exit. + // So we can free mapped space, which includes pthread_internal_t and thread stack. + // First make sure that the kernel does not try to clear the tid field + // because we'll have freed the memory before the thread actually exits. + __set_tid_address(nullptr); + + // pthread_internal_t is freed below with stack, not here. + __pthread_internal_remove(thread); + + if (thread->mmap_size != 0) { + // We need to free mapped space for detached threads when they exit. + // That's not something we can do in C. + __hwasan_thread_exit(); + _exit_with_stack_teardown(thread->mmap_base, thread->mmap_size); + } + } + + // No need to free mapped space. Either there was no space mapped, or it is left for + // the pthread_join caller to clean up. + __hwasan_thread_exit(); + __exit(0); +} diff --git a/aosp/bionic/libc/bionic/pthread_getcpuclockid.cpp b/aosp/bionic/libc/bionic/pthread_getcpuclockid.cpp new file mode 100644 index 000000000..6d1884ef7 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_getcpuclockid.cpp @@ -0,0 +1,48 @@ +/* + * 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 + +#include "private/bionic_defs.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_getcpuclockid(pthread_t t, clockid_t* clockid) { + pid_t tid = __pthread_internal_gettid(t, "pthread_getcpuclockid"); + if (tid == -1) return ESRCH; + + // The tid is stored in the top bits, but negated. + clockid_t result = ~static_cast(tid) << 3; + // Bits 0 and 1: clock type (0 = CPUCLOCK_PROF, 1 = CPUCLOCK_VIRT, 2 = CPUCLOCK_SCHED). + result |= 2; + // Bit 2: thread (set) or process (clear)? + result |= (1 << 2); + + *clockid = result; + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_getschedparam.cpp b/aosp/bionic/libc/bionic/pthread_getschedparam.cpp new file mode 100644 index 000000000..765287fa4 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_getschedparam.cpp @@ -0,0 +1,45 @@ +/* + * 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 + +#include "private/bionic_defs.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_getschedparam(pthread_t t, int* policy, sched_param* param) { + ErrnoRestorer errno_restorer; + + pid_t tid = __pthread_internal_gettid(t, "pthread_getschedparam"); + if (tid == -1) return ESRCH; + + if (sched_getparam(tid, param) == -1) return errno; + *policy = sched_getscheduler(tid); + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_gettid_np.cpp b/aosp/bionic/libc/bionic/pthread_gettid_np.cpp new file mode 100644 index 000000000..d14900bbb --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_gettid_np.cpp @@ -0,0 +1,35 @@ +/* + * 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 "private/bionic_defs.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +pid_t pthread_gettid_np(pthread_t t) { + return __pthread_internal_gettid(t, "pthread_gettid_np"); +} diff --git a/aosp/bionic/libc/bionic/pthread_internal.cpp b/aosp/bionic/libc/bionic/pthread_internal.cpp new file mode 100644 index 000000000..e0911581b --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_internal.cpp @@ -0,0 +1,117 @@ +/* + * 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 "pthread_internal.h" + +#include +#include +#include +#include + +#include + +#include "private/ScopedRWLock.h" +#include "private/bionic_futex.h" +#include "private/bionic_tls.h" + +static pthread_internal_t* g_thread_list = nullptr; +static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER; + +pthread_t __pthread_internal_add(pthread_internal_t* thread) { + ScopedWriteLock locker(&g_thread_list_lock); + + // We insert at the head. + thread->next = g_thread_list; + thread->prev = nullptr; + if (thread->next != nullptr) { + thread->next->prev = thread; + } + g_thread_list = thread; + return reinterpret_cast(thread); +} + +void __pthread_internal_remove(pthread_internal_t* thread) { + ScopedWriteLock locker(&g_thread_list_lock); + + if (thread->next != nullptr) { + thread->next->prev = thread->prev; + } + if (thread->prev != nullptr) { + thread->prev->next = thread->next; + } else { + g_thread_list = thread->next; + } +} + +static void __pthread_internal_free(pthread_internal_t* thread) { + if (thread->mmap_size != 0) { + // Free mapped space, including thread stack and pthread_internal_t. + munmap(thread->mmap_base, thread->mmap_size); + } +} + +void __pthread_internal_remove_and_free(pthread_internal_t* thread) { + __pthread_internal_remove(thread); + __pthread_internal_free(thread); +} + +pid_t __pthread_internal_gettid(pthread_t thread_id, const char* caller) { + pthread_internal_t* thread = __pthread_internal_find(thread_id, caller); + return thread ? thread->tid : -1; +} + +pthread_internal_t* __pthread_internal_find(pthread_t thread_id, const char* caller) { + pthread_internal_t* thread = reinterpret_cast(thread_id); + + // Check if we're looking for ourselves before acquiring the lock. + if (thread == __get_thread()) return thread; + + { + // Make sure to release the lock before the abort below. Otherwise, + // some apps might deadlock in their own crash handlers (see b/6565627). + ScopedReadLock locker(&g_thread_list_lock); + for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { + if (t == thread) return thread; + } + } + + // Historically we'd return null, but from API level 26 we catch this error. + if (android_get_application_target_sdk_version() >= 26) { + if (thread == nullptr) { + // This seems to be a common mistake, and it's relatively harmless because + // there will never be a valid thread at address 0, whereas other invalid + // addresses might sometimes contain threads or things that look enough like + // threads for us to do some real damage by continuing. + // TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level. + async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to %s", caller); + } else { + async_safe_fatal("invalid pthread_t %p passed to %s", thread, caller); + } + } + return nullptr; +} diff --git a/aosp/bionic/libc/bionic/pthread_internal.h b/aosp/bionic/libc/bionic/pthread_internal.h new file mode 100644 index 000000000..1f055f59e --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_internal.h @@ -0,0 +1,244 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#if __has_feature(hwaddress_sanitizer) +#include +#else +#define __hwasan_thread_enter() +#define __hwasan_thread_exit() +#endif + +#include "private/bionic_elf_tls.h" +#include "private/bionic_lock.h" +#include "private/bionic_tls.h" + +// Has the thread been detached by a pthread_join or pthread_detach call? +#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 + +// Has the thread been joined by another thread? +#define PTHREAD_ATTR_FLAG_JOINED 0x00000002 + +// Used for pthread_attr_setinheritsched. We need two flags for this apparent +// boolean because our historical behavior matches neither of the POSIX choices. +#define PTHREAD_ATTR_FLAG_INHERIT 0x00000004 +#define PTHREAD_ATTR_FLAG_EXPLICIT 0x00000008 + +enum ThreadJoinState { + THREAD_NOT_JOINED, + THREAD_EXITED_NOT_JOINED, + THREAD_JOINED, + THREAD_DETACHED +}; + +class thread_local_dtor; + +class pthread_internal_t { + public: + class pthread_internal_t* next; + class pthread_internal_t* prev; + + pid_t tid; + + private: + uint32_t cached_pid_ : 31; + uint32_t vforked_ : 1; + + public: + bool is_vforked() { return vforked_; } + + pid_t invalidate_cached_pid() { + pid_t old_value; + get_cached_pid(&old_value); + set_cached_pid(0); + return old_value; + } + + void set_cached_pid(pid_t value) { + cached_pid_ = value; + } + + bool get_cached_pid(pid_t* cached_pid) { + *cached_pid = cached_pid_; + return (*cached_pid != 0); + } + + pthread_attr_t attr; + + _Atomic(ThreadJoinState) join_state; + + __pthread_cleanup_t* cleanup_stack; + + void* (*start_routine)(void*); + void* start_routine_arg; + void* return_value; + sigset64_t start_mask; + + void* alternate_signal_stack; + + // The start address of the shadow call stack's guard region (arm64 only). + // This address is only used to deallocate the shadow call stack on thread + // exit; the address of the stack itself is stored only in the x18 register. + // Because the protection offered by SCS relies on the secrecy of the stack + // address, storing the address here weakens the protection, but only + // slightly, because it is relatively easy for an attacker to discover the + // address of the guard region anyway (e.g. it can be discovered by reference + // to other allocations), but not the stack itself, which is <0.1% of the size + // of the guard region. + // + // There are at least two other options for discovering the start address of + // the guard region on thread exit, but they are not as simple as storing in + // TLS. + // 1) Derive it from the value of the x18 register. This is only possible in + // processes that do not contain legacy code that might clobber x18, + // therefore each process must declare early during process startup whether + // it might load legacy code. + // 2) Mark the guard region as such using prctl(PR_SET_VMA_ANON_NAME) and + // discover its address by reading /proc/self/maps. One issue with this is + // that reading /proc/self/maps can race with allocations, so we may need + // code to handle retries. + void* shadow_call_stack_guard_region; + + // A pointer to the top of the stack. This lets android_unsafe_frame_pointer_chase determine the + // top of the stack quickly, which would otherwise require special logic for the main thread. + uintptr_t stack_top; + + Lock startup_handshake_lock; + + void* mmap_base; + size_t mmap_size; + + // The location of the VMA to label as the thread's stack_and_tls. + void* mmap_base_unguarded; + size_t mmap_size_unguarded; + char vma_name_buffer[32]; + + thread_local_dtor* thread_local_dtors; + + /* + * The dynamic linker implements dlerror(3), which makes it hard for us to implement this + * per-thread buffer by simply using malloc(3) and free(3). + */ + char* current_dlerror; +#define __BIONIC_DLERROR_BUFFER_SIZE 512 + char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE]; + + bionic_tls* bionic_tls; + + int errno_value; +}; + +struct ThreadMapping { + char* mmap_base; + size_t mmap_size; + char* mmap_base_unguarded; + size_t mmap_size_unguarded; + + char* static_tls; + char* stack_base; + char* stack_top; +}; + +__LIBC_HIDDEN__ void __init_tcb(bionic_tcb* tcb, pthread_internal_t* thread); +__LIBC_HIDDEN__ void __init_tcb_stack_guard(bionic_tcb* tcb); +__LIBC_HIDDEN__ void __init_tcb_dtv(bionic_tcb* tcb); +__LIBC_HIDDEN__ void __init_bionic_tls_ptrs(bionic_tcb* tcb, bionic_tls* tls); +__LIBC_HIDDEN__ bionic_tls* __allocate_temp_bionic_tls(); +__LIBC_HIDDEN__ void __free_temp_bionic_tls(bionic_tls* tls); +__LIBC_HIDDEN__ void __init_additional_stacks(pthread_internal_t*); +__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread); +__LIBC_HIDDEN__ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size); +__LIBC_HIDDEN__ void __set_stack_and_tls_vma_name(bool is_main_thread); + +__LIBC_HIDDEN__ pthread_t __pthread_internal_add(pthread_internal_t* thread); +__LIBC_HIDDEN__ pthread_internal_t* __pthread_internal_find(pthread_t pthread_id, const char* caller); +__LIBC_HIDDEN__ pid_t __pthread_internal_gettid(pthread_t pthread_id, const char* caller); +__LIBC_HIDDEN__ void __pthread_internal_remove(pthread_internal_t* thread); +__LIBC_HIDDEN__ void __pthread_internal_remove_and_free(pthread_internal_t* thread); + +static inline __always_inline bionic_tcb* __get_bionic_tcb() { + return reinterpret_cast(&__get_tls()[MIN_TLS_SLOT]); +} + +// Make __get_thread() inlined for performance reason. See http://b/19825434. +static inline __always_inline pthread_internal_t* __get_thread() { + return static_cast(__get_tls()[TLS_SLOT_THREAD_ID]); +} + +static inline __always_inline bionic_tls& __get_bionic_tls() { + return *static_cast(__get_tls()[TLS_SLOT_BIONIC_TLS]); +} + +static inline __always_inline TlsDtv* __get_tcb_dtv(bionic_tcb* tcb) { + uintptr_t dtv_slot = reinterpret_cast(tcb->tls_slot(TLS_SLOT_DTV)); + return reinterpret_cast(dtv_slot - offsetof(TlsDtv, generation)); +} + +static inline void __set_tcb_dtv(bionic_tcb* tcb, TlsDtv* val) { + tcb->tls_slot(TLS_SLOT_DTV) = &val->generation; +} + +extern "C" __LIBC_HIDDEN__ int __set_tls(void* ptr); + +__LIBC_HIDDEN__ void pthread_key_clean_all(void); + +// Address space is precious on LP32, so use the minimum unit: one page. +// On LP64, we could use more but there's no obvious advantage to doing +// so, and the various media processes use RLIMIT_AS as a way to limit +// the amount of allocation they'll do. +#define PTHREAD_GUARD_SIZE PAGE_SIZE + +// SIGSTKSZ (8KiB) is not big enough. +// An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack. +// On 64-bit, logging uses more than 8KiB by itself, ucontext is comically +// large on aarch64, and we have effectively infinite address space, so double +// the signal stack size. +#if defined(__LP64__) +#define SIGNAL_STACK_SIZE_WITHOUT_GUARD (32 * 1024) +#else +#define SIGNAL_STACK_SIZE_WITHOUT_GUARD (16 * 1024) +#endif + +// Traditionally we gave threads a 1MiB stack. When we started +// allocating per-thread alternate signal stacks to ease debugging of +// stack overflows, we subtracted the same amount we were using there +// from the default thread stack size. This should keep memory usage +// roughly constant. +#define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD) + +// Leave room for a guard page in the internally created signal stacks. +#define SIGNAL_STACK_SIZE (SIGNAL_STACK_SIZE_WITHOUT_GUARD + PTHREAD_GUARD_SIZE) + +// Needed by fork. +__LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare(); +__LIBC_HIDDEN__ extern void __bionic_atfork_run_child(); +__LIBC_HIDDEN__ extern void __bionic_atfork_run_parent(); diff --git a/aosp/bionic/libc/bionic/pthread_join.cpp b/aosp/bionic/libc/bionic/pthread_join.cpp new file mode 100644 index 000000000..e230faba9 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_join.cpp @@ -0,0 +1,74 @@ +/* + * 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 + +#include "private/bionic_defs.h" +#include "private/bionic_futex.h" +#include "private/bionic_systrace.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_join(pthread_t t, void** return_value) { + ScopedTrace trace("pthread_join"); + if (t == pthread_self()) { + return EDEADLK; + } + + pthread_internal_t* thread = __pthread_internal_find(t, "pthread_join"); + if (thread == nullptr) { + return ESRCH; + } + + ThreadJoinState old_state = THREAD_NOT_JOINED; + while ((old_state == THREAD_NOT_JOINED || old_state == THREAD_EXITED_NOT_JOINED) && + !atomic_compare_exchange_weak(&thread->join_state, &old_state, THREAD_JOINED)) { + } + + if (old_state == THREAD_DETACHED || old_state == THREAD_JOINED) { + return EINVAL; + } + + pid_t tid = thread->tid; + volatile int* tid_ptr = &thread->tid; + + // We set thread->join_state to THREAD_JOINED with atomic operation, + // so no one is going to remove this thread except us. + + // Wait for the thread to actually exit, if it hasn't already. + while (*tid_ptr != 0) { + __futex_wait(tid_ptr, tid, nullptr); + } + + if (return_value) { + *return_value = thread->return_value; + } + + __pthread_internal_remove_and_free(thread); + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_key.cpp b/aosp/bionic/libc/bionic/pthread_key.cpp new file mode 100644 index 000000000..53f0f1179 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_key.cpp @@ -0,0 +1,191 @@ +/* + * 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 +#include +#include + +#include "private/bionic_defs.h" +#include "private/bionic_tls.h" +#include "pthread_internal.h" + +typedef void (*key_destructor_t)(void*); + +#define SEQ_KEY_IN_USE_BIT 0 + +#define SEQ_INCREMENT_STEP (1 << SEQ_KEY_IN_USE_BIT) + +// pthread_key_internal_t records the use of each pthread key slot: +// seq records the state of the slot. +// bit 0 is 1 when the key is in use, 0 when it is unused. Each time we create or delete the +// pthread key in the slot, we increse the seq by 1 (which inverts bit 0). The reason to use +// a sequence number instead of a boolean value here is that when the key slot is deleted and +// reused for a new key, pthread_getspecific will not return stale data. +// key_destructor records the destructor called at thread exit. +struct pthread_key_internal_t { + atomic_uintptr_t seq; + atomic_uintptr_t key_destructor; +}; + +static pthread_key_internal_t key_map[BIONIC_PTHREAD_KEY_COUNT]; + +static inline bool SeqOfKeyInUse(uintptr_t seq) { + return seq & (1 << SEQ_KEY_IN_USE_BIT); +} + +#define KEY_VALID_FLAG (1 << 31) + +static_assert(sizeof(pthread_key_t) == sizeof(int) && static_cast(-1) < 0, + "pthread_key_t should be typedef to int"); + +static inline bool KeyInValidRange(pthread_key_t key) { + // key < 0 means bit 31 is set. + // Then key < (2^31 | BIONIC_PTHREAD_KEY_COUNT) means the index part of key < BIONIC_PTHREAD_KEY_COUNT. + return (key < (KEY_VALID_FLAG | BIONIC_PTHREAD_KEY_COUNT)); +} + +static inline pthread_key_data_t* get_thread_key_data() { + return __get_bionic_tls().key_data; +} + +// Called from pthread_exit() to remove all pthread keys. This must call the destructor of +// all keys that have a non-NULL data value and a non-NULL destructor. +__LIBC_HIDDEN__ void pthread_key_clean_all() { + // Because destructors can do funky things like deleting/creating other keys, + // we need to implement this in a loop. + pthread_key_data_t* key_data = get_thread_key_data(); + for (size_t rounds = PTHREAD_DESTRUCTOR_ITERATIONS; rounds > 0; --rounds) { + size_t called_destructor_count = 0; + for (size_t i = 0; i < BIONIC_PTHREAD_KEY_COUNT; ++i) { + uintptr_t seq = atomic_load_explicit(&key_map[i].seq, memory_order_relaxed); + if (SeqOfKeyInUse(seq) && seq == key_data[i].seq && key_data[i].data != nullptr) { + // Other threads may be calling pthread_key_delete/pthread_key_create while current thread + // is exiting. So we need to ensure we read the right key_destructor. + // We can rely on a user-established happens-before relationship between the creation and + // use of pthread key to ensure that we're not getting an earlier key_destructor. + // To avoid using the key_destructor of the newly created key in the same slot, we need to + // recheck the sequence number after reading key_destructor. As a result, we either see the + // right key_destructor, or the sequence number must have changed when we reread it below. + key_destructor_t key_destructor = reinterpret_cast( + atomic_load_explicit(&key_map[i].key_destructor, memory_order_relaxed)); + if (key_destructor == nullptr) { + continue; + } + atomic_thread_fence(memory_order_acquire); + if (atomic_load_explicit(&key_map[i].seq, memory_order_relaxed) != seq) { + continue; + } + + // We need to clear the key data now, this will prevent the destructor (or a later one) + // from seeing the old value if it calls pthread_getspecific(). + // We don't do this if 'key_destructor == NULL' just in case another destructor + // function is responsible for manually releasing the corresponding data. + void* data = key_data[i].data; + key_data[i].data = nullptr; + + (*key_destructor)(data); + ++called_destructor_count; + } + } + + // If we didn't call any destructors, there is no need to check the pthread keys again. + if (called_destructor_count == 0) { + break; + } + } +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_key_create(pthread_key_t* key, void (*key_destructor)(void*)) { + for (size_t i = 0; i < BIONIC_PTHREAD_KEY_COUNT; ++i) { + uintptr_t seq = atomic_load_explicit(&key_map[i].seq, memory_order_relaxed); + while (!SeqOfKeyInUse(seq)) { + if (atomic_compare_exchange_weak(&key_map[i].seq, &seq, seq + SEQ_INCREMENT_STEP)) { + atomic_store(&key_map[i].key_destructor, reinterpret_cast(key_destructor)); + *key = i | KEY_VALID_FLAG; + return 0; + } + } + } + return EAGAIN; +} + +// Deletes a pthread_key_t. note that the standard mandates that this does +// not call the destructors for non-NULL key values. Instead, it is the +// responsibility of the caller to properly dispose of the corresponding data +// and resources, using any means it finds suitable. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_key_delete(pthread_key_t key) { + if (__predict_false(!KeyInValidRange(key))) { + return EINVAL; + } + key &= ~KEY_VALID_FLAG; + // Increase seq to invalidate values in all threads. + uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed); + if (SeqOfKeyInUse(seq)) { + if (atomic_compare_exchange_strong(&key_map[key].seq, &seq, seq + SEQ_INCREMENT_STEP)) { + return 0; + } + } + return EINVAL; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void* pthread_getspecific(pthread_key_t key) { + if (__predict_false(!KeyInValidRange(key))) { + return nullptr; + } + key &= ~KEY_VALID_FLAG; + uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed); + pthread_key_data_t* data = &get_thread_key_data()[key]; + // It is user's responsibility to synchornize between the creation and use of pthread keys, + // so we use memory_order_relaxed when checking the sequence number. + if (__predict_true(SeqOfKeyInUse(seq) && data->seq == seq)) { + return data->data; + } + // We arrive here when current thread holds the seq of an deleted pthread key. So the + // data is for the deleted pthread key, and should be cleared. + data->data = nullptr; + return nullptr; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_setspecific(pthread_key_t key, const void* ptr) { + if (__predict_false(!KeyInValidRange(key))) { + return EINVAL; + } + key &= ~KEY_VALID_FLAG; + uintptr_t seq = atomic_load_explicit(&key_map[key].seq, memory_order_relaxed); + if (__predict_true(SeqOfKeyInUse(seq))) { + pthread_key_data_t* data = &get_thread_key_data()[key]; + data->seq = seq; + data->data = const_cast(ptr); + return 0; + } + return EINVAL; +} diff --git a/aosp/bionic/libc/bionic/pthread_kill.cpp b/aosp/bionic/libc/bionic/pthread_kill.cpp new file mode 100644 index 000000000..cada9c2a8 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_kill.cpp @@ -0,0 +1,46 @@ +/* + * 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 +#include + +#include "private/bionic_defs.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_kill(pthread_t t, int sig) { + ErrnoRestorer errno_restorer; + + pid_t tid = __pthread_internal_gettid(t, "pthread_kill"); + + // tid gets reset to 0 on thread exit by CLONE_CHILD_CLEARTID. + if (tid == 0 || tid == -1) return ESRCH; + + return (tgkill(getpid(), tid, sig) == -1) ? errno : 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_mutex.cpp b/aosp/bionic/libc/bionic/pthread_mutex.cpp new file mode 100644 index 000000000..a15e98149 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_mutex.cpp @@ -0,0 +1,1032 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pthread_internal.h" + +#include "private/bionic_constants.h" +#include "private/bionic_fortify.h" +#include "private/bionic_futex.h" +#include "private/bionic_systrace.h" +#include "private/bionic_time_conversions.h" +#include "private/bionic_tls.h" + +/* a mutex attribute holds the following fields + * + * bits: name description + * 0-3 type type of mutex + * 4 shared process-shared flag + * 5 protocol whether it is a priority inherit mutex. + */ +#define MUTEXATTR_TYPE_MASK 0x000f +#define MUTEXATTR_SHARED_MASK 0x0010 +#define MUTEXATTR_PROTOCOL_MASK 0x0020 + +#define MUTEXATTR_PROTOCOL_SHIFT 5 + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + *attr = PTHREAD_MUTEX_DEFAULT; + return 0; +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + *attr = -1; + return 0; +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type_p) +{ + int type = (*attr & MUTEXATTR_TYPE_MASK); + + if (type < PTHREAD_MUTEX_NORMAL || type > PTHREAD_MUTEX_ERRORCHECK) { + return EINVAL; + } + + *type_p = type; + return 0; +} + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + if (type < PTHREAD_MUTEX_NORMAL || type > PTHREAD_MUTEX_ERRORCHECK ) { + return EINVAL; + } + + *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; + return 0; +} + +/* process-shared mutexes are not supported at the moment */ + +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + switch (pshared) { + case PTHREAD_PROCESS_PRIVATE: + *attr &= ~MUTEXATTR_SHARED_MASK; + return 0; + + case PTHREAD_PROCESS_SHARED: + /* our current implementation of pthread actually supports shared + * mutexes but won't cleanup if a process dies with the mutex held. + * Nevertheless, it's better than nothing. Shared mutexes are used + * by surfaceflinger and audioflinger. + */ + *attr |= MUTEXATTR_SHARED_MASK; + return 0; + } + return EINVAL; +} + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t* attr, int* pshared) { + *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t* attr, int protocol) { + if (protocol != PTHREAD_PRIO_NONE && protocol != PTHREAD_PRIO_INHERIT) { + return EINVAL; + } + *attr = (*attr & ~MUTEXATTR_PROTOCOL_MASK) | (protocol << MUTEXATTR_PROTOCOL_SHIFT); + return 0; +} + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t* attr, int* protocol) { + *protocol = (*attr & MUTEXATTR_PROTOCOL_MASK) >> MUTEXATTR_PROTOCOL_SHIFT; + return 0; +} + +// Priority Inheritance mutex implementation +struct PIMutex { + // mutex type, can be 0 (normal), 1 (recursive), 2 (errorcheck), constant during lifetime + uint8_t type; + // process-shared flag, constant during lifetime + bool shared; + // - 1 + uint16_t counter; + // owner_tid is read/written by both userspace code and kernel code. It includes three fields: + // FUTEX_WAITERS, FUTEX_OWNER_DIED and FUTEX_TID_MASK. + atomic_int owner_tid; +}; + +static inline __always_inline int PIMutexTryLock(PIMutex& mutex) { + pid_t tid = __get_thread()->tid; + // Handle common case first. + int old_owner = 0; + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex.owner_tid, + &old_owner, tid, + memory_order_acquire, + memory_order_relaxed))) { + return 0; + } + if (tid == (old_owner & FUTEX_TID_MASK)) { + // We already own this mutex. + if (mutex.type == PTHREAD_MUTEX_NORMAL) { + return EBUSY; + } + if (mutex.type == PTHREAD_MUTEX_ERRORCHECK) { + return EDEADLK; + } + if (mutex.counter == 0xffff) { + return EAGAIN; + } + mutex.counter++; + return 0; + } + return EBUSY; +} + +// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on +// ARM/ARM64, which increases at most 20 percent overhead. So make it noinline. +static int __attribute__((noinline)) PIMutexTimedLock(PIMutex& mutex, + bool use_realtime_clock, + const timespec* abs_timeout) { + int ret = PIMutexTryLock(mutex); + if (__predict_true(ret == 0)) { + return 0; + } + if (ret == EBUSY) { + ScopedTrace trace("Contending for pthread mutex"); + ret = -__futex_pi_lock_ex(&mutex.owner_tid, mutex.shared, use_realtime_clock, abs_timeout); + } + return ret; +} + +static int PIMutexUnlock(PIMutex& mutex) { + pid_t tid = __get_thread()->tid; + int old_owner = tid; + // Handle common case first. + if (__predict_true(mutex.type == PTHREAD_MUTEX_NORMAL)) { + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex.owner_tid, + &old_owner, 0, + memory_order_release, + memory_order_relaxed))) { + return 0; + } + } else { + old_owner = atomic_load_explicit(&mutex.owner_tid, memory_order_relaxed); + } + + if (tid != (old_owner & FUTEX_TID_MASK)) { + // The mutex can only be unlocked by the thread who owns it. + return EPERM; + } + if (mutex.type == PTHREAD_MUTEX_RECURSIVE) { + if (mutex.counter != 0u) { + --mutex.counter; + return 0; + } + } + if (old_owner == tid) { + // No thread is waiting. + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex.owner_tid, + &old_owner, 0, + memory_order_release, + memory_order_relaxed))) { + return 0; + } + } + return -__futex_pi_unlock(&mutex.owner_tid, mutex.shared); +} + +static int PIMutexDestroy(PIMutex& mutex) { + // The mutex should be in unlocked state (owner_tid == 0) when destroyed. + // Store 0xffffffff to make the mutex unusable. + int old_owner = 0; + if (atomic_compare_exchange_strong_explicit(&mutex.owner_tid, &old_owner, 0xffffffff, + memory_order_relaxed, memory_order_relaxed)) { + return 0; + } + return EBUSY; +} + +#if !defined(__LP64__) + +namespace PIMutexAllocator { +// pthread_mutex_t has only 4 bytes in 32-bit programs, which are not enough to hold PIMutex. +// So we use malloc to allocate PIMutexes and use 16-bit of pthread_mutex_t as indexes to find +// the allocated PIMutexes. This allows at most 65536 PI mutexes. +// When calling operations like pthread_mutex_lock/unlock, the 16-bit index is mapped to the +// corresponding PIMutex. To make the map operation fast, we use a lockless mapping method: +// Once a PIMutex is allocated, all the data used to map index to the PIMutex isn't changed until +// it is destroyed. +// Below are the data structures: +// // struct Node contains a PIMutex. +// typedef Node NodeArray[256]; +// typedef NodeArray* NodeArrayP; +// NodeArrayP nodes[256]; +// +// A 16-bit index is mapped to Node as below: +// (*nodes[index >> 8])[index & 0xff] +// +// Also use a free list to allow O(1) finding recycled PIMutexes. + +union Node { + PIMutex mutex; + int next_free_id; // If not -1, refer to the next node in the free PIMutex list. +}; +typedef Node NodeArray[256]; +typedef NodeArray* NodeArrayP; + +// lock_ protects below items. +static Lock lock; +static NodeArrayP* nodes; +static int next_to_alloc_id; +static int first_free_id = -1; // If not -1, refer to the first node in the free PIMutex list. + +static inline __always_inline Node& IdToNode(int id) { + return (*nodes[id >> 8])[id & 0xff]; +} + +static inline __always_inline PIMutex& IdToPIMutex(int id) { + return IdToNode(id).mutex; +} + +static int AllocIdLocked() { + if (first_free_id != -1) { + int result = first_free_id; + first_free_id = IdToNode(result).next_free_id; + return result; + } + if (next_to_alloc_id >= 0x10000) { + return -1; + } + int array_pos = next_to_alloc_id >> 8; + int node_pos = next_to_alloc_id & 0xff; + if (node_pos == 0) { + if (array_pos == 0) { + nodes = static_cast(calloc(256, sizeof(NodeArray*))); + if (nodes == nullptr) { + return -1; + } + } + nodes[array_pos] = static_cast(malloc(sizeof(NodeArray))); + if (nodes[array_pos] == nullptr) { + return -1; + } + } + return next_to_alloc_id++; +} + +// If succeed, return an id referring to a PIMutex, otherwise return -1. +// A valid id is in range [0, 0xffff]. +static int AllocId() { + lock.lock(); + int result = AllocIdLocked(); + lock.unlock(); + if (result != -1) { + memset(&IdToPIMutex(result), 0, sizeof(PIMutex)); + } + return result; +} + +static void FreeId(int id) { + lock.lock(); + IdToNode(id).next_free_id = first_free_id; + first_free_id = id; + lock.unlock(); +} + +} // namespace PIMutexAllocator + +#endif // !defined(__LP64__) + + +/* Convenience macro, creates a mask of 'bits' bits that starts from + * the 'shift'-th least significant bit in a 32-bit word. + * + * Examples: FIELD_MASK(0,4) -> 0xf + * FIELD_MASK(16,9) -> 0x1ff0000 + */ +#define FIELD_MASK(shift,bits) (((1 << (bits))-1) << (shift)) + +/* This one is used to create a bit pattern from a given field value */ +#define FIELD_TO_BITS(val,shift,bits) (((val) & ((1 << (bits))-1)) << (shift)) + +/* And this one does the opposite, i.e. extract a field's value from a bit pattern */ +#define FIELD_FROM_BITS(val,shift,bits) (((val) >> (shift)) & ((1 << (bits))-1)) + +/* Convenience macros. + * + * These are used to form or modify the bit pattern of a given mutex value + */ + +/* Mutex state: + * + * 0 for unlocked + * 1 for locked, no waiters + * 2 for locked, maybe waiters + */ +#define MUTEX_STATE_SHIFT 0 +#define MUTEX_STATE_LEN 2 + +#define MUTEX_STATE_MASK FIELD_MASK(MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) +#define MUTEX_STATE_FROM_BITS(v) FIELD_FROM_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) +#define MUTEX_STATE_TO_BITS(v) FIELD_TO_BITS(v, MUTEX_STATE_SHIFT, MUTEX_STATE_LEN) + +#define MUTEX_STATE_UNLOCKED 0 /* must be 0 to match PTHREAD_MUTEX_INITIALIZER */ +#define MUTEX_STATE_LOCKED_UNCONTENDED 1 /* must be 1 due to atomic dec in unlock operation */ +#define MUTEX_STATE_LOCKED_CONTENDED 2 /* must be 1 + LOCKED_UNCONTENDED due to atomic dec */ + +#define MUTEX_STATE_BITS_UNLOCKED MUTEX_STATE_TO_BITS(MUTEX_STATE_UNLOCKED) +#define MUTEX_STATE_BITS_LOCKED_UNCONTENDED MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_UNCONTENDED) +#define MUTEX_STATE_BITS_LOCKED_CONTENDED MUTEX_STATE_TO_BITS(MUTEX_STATE_LOCKED_CONTENDED) + +// Return true iff the mutex is unlocked. +#define MUTEX_STATE_BITS_IS_UNLOCKED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_UNLOCKED) + +// Return true iff the mutex is locked with no waiters. +#define MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_UNCONTENDED) + +// return true iff the mutex is locked with maybe waiters. +#define MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(v) (((v) & MUTEX_STATE_MASK) == MUTEX_STATE_BITS_LOCKED_CONTENDED) + +/* used to flip from LOCKED_UNCONTENDED to LOCKED_CONTENDED */ +#define MUTEX_STATE_BITS_FLIP_CONTENTION(v) ((v) ^ (MUTEX_STATE_BITS_LOCKED_CONTENDED ^ MUTEX_STATE_BITS_LOCKED_UNCONTENDED)) + +/* Mutex counter: + * + * We need to check for overflow before incrementing, and we also need to + * detect when the counter is 0 + */ +#define MUTEX_COUNTER_SHIFT 2 +#define MUTEX_COUNTER_LEN 11 +#define MUTEX_COUNTER_MASK FIELD_MASK(MUTEX_COUNTER_SHIFT, MUTEX_COUNTER_LEN) + +#define MUTEX_COUNTER_BITS_WILL_OVERFLOW(v) (((v) & MUTEX_COUNTER_MASK) == MUTEX_COUNTER_MASK) +#define MUTEX_COUNTER_BITS_IS_ZERO(v) (((v) & MUTEX_COUNTER_MASK) == 0) + +/* Used to increment the counter directly after overflow has been checked */ +#define MUTEX_COUNTER_BITS_ONE FIELD_TO_BITS(1, MUTEX_COUNTER_SHIFT,MUTEX_COUNTER_LEN) + +/* Mutex shared bit flag + * + * This flag is set to indicate that the mutex is shared among processes. + * This changes the futex opcode we use for futex wait/wake operations + * (non-shared operations are much faster). + */ +#define MUTEX_SHARED_SHIFT 13 +#define MUTEX_SHARED_MASK FIELD_MASK(MUTEX_SHARED_SHIFT,1) + +/* Mutex type: + * We support normal, recursive and errorcheck mutexes. + */ +#define MUTEX_TYPE_SHIFT 14 +#define MUTEX_TYPE_LEN 2 +#define MUTEX_TYPE_MASK FIELD_MASK(MUTEX_TYPE_SHIFT,MUTEX_TYPE_LEN) + +#define MUTEX_TYPE_TO_BITS(t) FIELD_TO_BITS(t, MUTEX_TYPE_SHIFT, MUTEX_TYPE_LEN) + +#define MUTEX_TYPE_BITS_NORMAL MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_NORMAL) +#define MUTEX_TYPE_BITS_RECURSIVE MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_RECURSIVE) +#define MUTEX_TYPE_BITS_ERRORCHECK MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_ERRORCHECK) +// Use a special mutex type to mark priority inheritance mutexes. +#define PI_MUTEX_STATE MUTEX_TYPE_TO_BITS(3) + +// For a PI mutex, it includes below fields: +// Atomic(uint16_t) state; +// PIMutex pi_mutex; // uint16_t pi_mutex_id in 32-bit programs +// +// state holds the following fields: +// +// bits: name description +// 15-14 type mutex type, should be 3 +// 13-0 padding should be 0 +// +// pi_mutex holds the state of a PI mutex. +// pi_mutex_id holds an integer to find the state of a PI mutex. +// +// For a Non-PI mutex, it includes below fields: +// Atomic(uint16_t) state; +// atomic_int owner_tid; // Atomic(uint16_t) in 32-bit programs +// +// state holds the following fields: +// +// bits: name description +// 15-14 type mutex type, can be 0 (normal), 1 (recursive), 2 (errorcheck) +// 13 shared process-shared flag +// 12-2 counter - 1 +// 1-0 state lock state (0, 1 or 2) +// +// bits 15-13 are constant during the lifetime of the mutex. +// +// owner_tid is used only in recursive and errorcheck Non-PI mutexes to hold the mutex owner +// thread id. +// +// PI mutexes and Non-PI mutexes are distinguished by checking type field in state. +#if defined(__LP64__) +struct pthread_mutex_internal_t { + _Atomic(uint16_t) state; + uint16_t __pad; + union { + atomic_int owner_tid; + PIMutex pi_mutex; + }; + char __reserved[28]; + + PIMutex& ToPIMutex() { + return pi_mutex; + } + + void FreePIMutex() { + } +} __attribute__((aligned(4))); + +#else +struct pthread_mutex_internal_t { + _Atomic(uint16_t) state; + union { + _Atomic(uint16_t) owner_tid; + uint16_t pi_mutex_id; + }; + + PIMutex& ToPIMutex() { + return PIMutexAllocator::IdToPIMutex(pi_mutex_id); + } + + void FreePIMutex() { + PIMutexAllocator::FreeId(pi_mutex_id); + } +} __attribute__((aligned(4))); +#endif + +static_assert(sizeof(pthread_mutex_t) == sizeof(pthread_mutex_internal_t), + "pthread_mutex_t should actually be pthread_mutex_internal_t in implementation."); + +// For binary compatibility with old version of pthread_mutex_t, we can't use more strict alignment +// than 4-byte alignment. +static_assert(alignof(pthread_mutex_t) == 4, + "pthread_mutex_t should fulfill the alignment of pthread_mutex_internal_t."); + +static inline pthread_mutex_internal_t* __get_internal_mutex(pthread_mutex_t* mutex_interface) { + return reinterpret_cast(mutex_interface); +} + +int pthread_mutex_init(pthread_mutex_t* mutex_interface, const pthread_mutexattr_t* attr) { + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + + memset(mutex, 0, sizeof(pthread_mutex_internal_t)); + + if (__predict_true(attr == nullptr)) { + atomic_init(&mutex->state, MUTEX_TYPE_BITS_NORMAL); + return 0; + } + + uint16_t state = 0; + if ((*attr & MUTEXATTR_SHARED_MASK) != 0) { + state |= MUTEX_SHARED_MASK; + } + + switch (*attr & MUTEXATTR_TYPE_MASK) { + case PTHREAD_MUTEX_NORMAL: + state |= MUTEX_TYPE_BITS_NORMAL; + break; + case PTHREAD_MUTEX_RECURSIVE: + state |= MUTEX_TYPE_BITS_RECURSIVE; + break; + case PTHREAD_MUTEX_ERRORCHECK: + state |= MUTEX_TYPE_BITS_ERRORCHECK; + break; + default: + return EINVAL; + } + + if (((*attr & MUTEXATTR_PROTOCOL_MASK) >> MUTEXATTR_PROTOCOL_SHIFT) == PTHREAD_PRIO_INHERIT) { +#if !defined(__LP64__) + if (state & MUTEX_SHARED_MASK) { + return EINVAL; + } + int id = PIMutexAllocator::AllocId(); + if (id == -1) { + return ENOMEM; + } + mutex->pi_mutex_id = id; +#endif + atomic_init(&mutex->state, PI_MUTEX_STATE); + PIMutex& pi_mutex = mutex->ToPIMutex(); + pi_mutex.type = *attr & MUTEXATTR_TYPE_MASK; + pi_mutex.shared = (*attr & MUTEXATTR_SHARED_MASK) != 0; + } else { + atomic_init(&mutex->state, state); + atomic_init(&mutex->owner_tid, 0); + } + return 0; +} + +// namespace for Non-PI mutex routines. +namespace NonPI { + +static inline __always_inline int NormalMutexTryLock(pthread_mutex_internal_t* mutex, + uint16_t shared) { + const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; + const uint16_t locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; + + uint16_t old_state = unlocked; + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, + locked_uncontended, memory_order_acquire, memory_order_relaxed))) { + return 0; + } + return EBUSY; +} + +/* + * Lock a normal Non-PI mutex. + * + * As noted above, there are three states: + * 0 (unlocked, no contention) + * 1 (locked, no contention) + * 2 (locked, contention) + * + * Non-recursive mutexes don't use the thread-id or counter fields, and the + * "type" value is zero, so the only bits that will be set are the ones in + * the lock state field. + */ +static inline __always_inline int NormalMutexLock(pthread_mutex_internal_t* mutex, + uint16_t shared, + bool use_realtime_clock, + const timespec* abs_timeout_or_null) { + if (__predict_true(NormalMutexTryLock(mutex, shared) == 0)) { + return 0; + } + int result = check_timespec(abs_timeout_or_null, true); + if (result != 0) { + return result; + } + + ScopedTrace trace("Contending for pthread mutex"); + + const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; + const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED; + + // We want to go to sleep until the mutex is available, which requires + // promoting it to locked_contended. We need to swap in the new state + // and then wait until somebody wakes us up. + // An atomic_exchange is used to compete with other threads for the lock. + // If it returns unlocked, we have acquired the lock, otherwise another + // thread still holds the lock and we should wait again. + // If lock is acquired, an acquire fence is needed to make all memory accesses + // made by other threads visible to the current CPU. + while (atomic_exchange_explicit(&mutex->state, locked_contended, + memory_order_acquire) != unlocked) { + if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock, + abs_timeout_or_null) == -ETIMEDOUT) { + return ETIMEDOUT; + } + } + return 0; +} + +/* + * Release a normal Non-PI mutex. The caller is responsible for determining + * that we are in fact the owner of this lock. + */ +static inline __always_inline void NormalMutexUnlock(pthread_mutex_internal_t* mutex, + uint16_t shared) { + const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; + const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED; + + // We use an atomic_exchange to release the lock. If locked_contended state + // is returned, some threads is waiting for the lock and we need to wake up + // one of them. + // A release fence is required to make previous stores visible to next + // lock owner threads. + if (atomic_exchange_explicit(&mutex->state, unlocked, + memory_order_release) == locked_contended) { + // Wake up one waiting thread. We don't know which thread will be + // woken or when it'll start executing -- futexes make no guarantees + // here. There may not even be a thread waiting. + // + // The newly-woken thread will replace the unlocked state we just set above + // with locked_contended state, which means that when it eventually releases + // the mutex it will also call FUTEX_WAKE. This results in one extra wake + // call whenever a lock is contended, but let us avoid forgetting anyone + // without requiring us to track the number of sleepers. + // + // It's possible for another thread to sneak in and grab the lock between + // the exchange above and the wake call below. If the new thread is "slow" + // and holds the lock for a while, we'll wake up a sleeper, which will swap + // in locked_uncontended state and then go back to sleep since the lock is + // still held. If the new thread is "fast", running to completion before + // we call wake, the thread we eventually wake will find an unlocked mutex + // and will execute. Either way we have correct behavior and nobody is + // orphaned on the wait queue. + // + // The pthread_mutex_internal_t object may have been deallocated between the + // atomic exchange and the wake call. In that case, this wake call could + // target unmapped memory or memory used by an otherwise unrelated futex + // operation. Even if the kernel avoids spurious futex wakeups from its + // point of view, this wake call could trigger a spurious wakeup in any + // futex accessible from this process. References: + // - https://lkml.org/lkml/2014/11/27/472 + // - http://austingroupbugs.net/view.php?id=811#c2267 + __futex_wake_ex(&mutex->state, shared, 1); + } +} + +/* This common inlined function is used to increment the counter of a recursive Non-PI mutex. + * + * If the counter overflows, it will return EAGAIN. + * Otherwise, it atomically increments the counter and returns 0. + * + */ +static inline __always_inline int RecursiveIncrement(pthread_mutex_internal_t* mutex, + uint16_t old_state) { + // Detect recursive lock overflow and return EAGAIN. + // This is safe because only the owner thread can modify the + // counter bits in the mutex value. + if (MUTEX_COUNTER_BITS_WILL_OVERFLOW(old_state)) { + return EAGAIN; + } + + // Other threads are able to change the lower bits (e.g. promoting it to "contended"), + // but the mutex counter will not overflow. So we use atomic_fetch_add operation here. + // The mutex is already locked by current thread, so we don't need an acquire fence. + atomic_fetch_add_explicit(&mutex->state, MUTEX_COUNTER_BITS_ONE, memory_order_relaxed); + return 0; +} + +// Wait on a recursive or errorcheck Non-PI mutex. +static inline __always_inline int RecursiveOrErrorcheckMutexWait(pthread_mutex_internal_t* mutex, + uint16_t shared, + uint16_t old_state, + bool use_realtime_clock, + const timespec* abs_timeout) { +// __futex_wait always waits on a 32-bit value. But state is 16-bit. For a normal mutex, the owner_tid +// field in mutex is not used. On 64-bit devices, the __pad field in mutex is not used. +// But when a recursive or errorcheck mutex is used on 32-bit devices, we need to add the +// owner_tid value in the value argument for __futex_wait, otherwise we may always get EAGAIN error. + +#if defined(__LP64__) + return __futex_wait_ex(&mutex->state, shared, old_state, use_realtime_clock, abs_timeout); + +#else + // This implementation works only when the layout of pthread_mutex_internal_t matches below expectation. + // And it is based on the assumption that Android is always in little-endian devices. + static_assert(offsetof(pthread_mutex_internal_t, state) == 0, ""); + static_assert(offsetof(pthread_mutex_internal_t, owner_tid) == 2, ""); + + uint32_t owner_tid = atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed); + return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state, + use_realtime_clock, abs_timeout); +#endif +} + +// Lock a Non-PI mutex. +static int MutexLockWithTimeout(pthread_mutex_internal_t* mutex, bool use_realtime_clock, + const timespec* abs_timeout_or_null) { + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + uint16_t mtype = (old_state & MUTEX_TYPE_MASK); + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + + // Handle common case first. + if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) { + return NormalMutexLock(mutex, shared, use_realtime_clock, abs_timeout_or_null); + } + + // Do we already own this recursive or error-check mutex? + pid_t tid = __get_thread()->tid; + if (tid == atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed)) { + if (mtype == MUTEX_TYPE_BITS_ERRORCHECK) { + return EDEADLK; + } + return RecursiveIncrement(mutex, old_state); + } + + const uint16_t unlocked = mtype | shared | MUTEX_STATE_BITS_UNLOCKED; + const uint16_t locked_uncontended = mtype | shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; + const uint16_t locked_contended = mtype | shared | MUTEX_STATE_BITS_LOCKED_CONTENDED; + + // First, if the mutex is unlocked, try to quickly acquire it. + // In the optimistic case where this works, set the state to locked_uncontended. + if (old_state == unlocked) { + // If exchanged successfully, an acquire fence is required to make + // all memory accesses made by other threads visible to the current CPU. + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, + locked_uncontended, memory_order_acquire, memory_order_relaxed))) { + atomic_store_explicit(&mutex->owner_tid, tid, memory_order_relaxed); + return 0; + } + } + + ScopedTrace trace("Contending for pthread mutex"); + + while (true) { + if (old_state == unlocked) { + // NOTE: We put the state to locked_contended since we _know_ there + // is contention when we are in this loop. This ensures all waiters + // will be unlocked. + + // If exchanged successfully, an acquire fence is required to make + // all memory accesses made by other threads visible to the current CPU. + if (__predict_true(atomic_compare_exchange_weak_explicit(&mutex->state, + &old_state, locked_contended, + memory_order_acquire, + memory_order_relaxed))) { + atomic_store_explicit(&mutex->owner_tid, tid, memory_order_relaxed); + return 0; + } + continue; + } else if (MUTEX_STATE_BITS_IS_LOCKED_UNCONTENDED(old_state)) { + // We should set it to locked_contended beforing going to sleep. This can make + // sure waiters will be woken up eventually. + + int new_state = MUTEX_STATE_BITS_FLIP_CONTENTION(old_state); + if (__predict_false(!atomic_compare_exchange_weak_explicit(&mutex->state, + &old_state, new_state, + memory_order_relaxed, + memory_order_relaxed))) { + continue; + } + old_state = new_state; + } + + int result = check_timespec(abs_timeout_or_null, true); + if (result != 0) { + return result; + } + // We are in locked_contended state, sleep until someone wakes us up. + if (RecursiveOrErrorcheckMutexWait(mutex, shared, old_state, use_realtime_clock, + abs_timeout_or_null) == -ETIMEDOUT) { + return ETIMEDOUT; + } + old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + } +} + +} // namespace NonPI + +static inline __always_inline bool IsMutexDestroyed(uint16_t mutex_state) { + return mutex_state == 0xffff; +} + +// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on +// ARM64. So make it noinline. +static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex, + const char* function_name) { + if (android_get_application_target_sdk_version() >= 28) { + __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex); + } + return EBUSY; +} + +int pthread_mutex_lock(pthread_mutex_t* mutex_interface) { +#if !defined(__LP64__) + // Some apps depend on being able to pass NULL as a mutex and get EINVAL + // back. Don't need to worry about it for LP64 since the ABI is brand new, + // but keep compatibility for LP32. http://b/19995172. + if (mutex_interface == nullptr) { + return EINVAL; + } +#endif + + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + uint16_t mtype = (old_state & MUTEX_TYPE_MASK); + // Avoid slowing down fast path of normal mutex lock operation. + if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + if (__predict_true(NonPI::NormalMutexTryLock(mutex, shared) == 0)) { + return 0; + } + } + if (old_state == PI_MUTEX_STATE) { + PIMutex& m = mutex->ToPIMutex(); + // Handle common case first. + if (__predict_true(PIMutexTryLock(m) == 0)) { + return 0; + } + return PIMutexTimedLock(mutex->ToPIMutex(), false, nullptr); + } + if (__predict_false(IsMutexDestroyed(old_state))) { + return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__); + } + return NonPI::MutexLockWithTimeout(mutex, false, nullptr); +} + +int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) { +#if !defined(__LP64__) + // Some apps depend on being able to pass NULL as a mutex and get EINVAL + // back. Don't need to worry about it for LP64 since the ABI is brand new, + // but keep compatibility for LP32. http://b/19995172. + if (mutex_interface == nullptr) { + return EINVAL; + } +#endif + + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + uint16_t mtype = (old_state & MUTEX_TYPE_MASK); + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + + // Handle common case first. + if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { + NonPI::NormalMutexUnlock(mutex, shared); + return 0; + } + if (old_state == PI_MUTEX_STATE) { + return PIMutexUnlock(mutex->ToPIMutex()); + } + if (__predict_false(IsMutexDestroyed(old_state))) { + return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__); + } + + // Do we already own this recursive or error-check mutex? + pid_t tid = __get_thread()->tid; + if ( tid != atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed) ) { + return EPERM; + } + + // If the counter is > 0, we can simply decrement it atomically. + // Since other threads can mutate the lower state bits (and only the + // lower state bits), use a compare_exchange loop to do it. + if (!MUTEX_COUNTER_BITS_IS_ZERO(old_state)) { + // We still own the mutex, so a release fence is not needed. + atomic_fetch_sub_explicit(&mutex->state, MUTEX_COUNTER_BITS_ONE, memory_order_relaxed); + return 0; + } + + // The counter is 0, so we'are going to unlock the mutex by resetting its + // state to unlocked, we need to perform a atomic_exchange inorder to read + // the current state, which will be locked_contended if there may have waiters + // to awake. + // A release fence is required to make previous stores visible to next + // lock owner threads. + atomic_store_explicit(&mutex->owner_tid, 0, memory_order_relaxed); + const uint16_t unlocked = mtype | shared | MUTEX_STATE_BITS_UNLOCKED; + old_state = atomic_exchange_explicit(&mutex->state, unlocked, memory_order_release); + if (MUTEX_STATE_BITS_IS_LOCKED_CONTENDED(old_state)) { + __futex_wake_ex(&mutex->state, shared, 1); + } + + return 0; +} + +int pthread_mutex_trylock(pthread_mutex_t* mutex_interface) { + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + uint16_t mtype = (old_state & MUTEX_TYPE_MASK); + + // Handle common case first. + if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + return NonPI::NormalMutexTryLock(mutex, shared); + } + if (old_state == PI_MUTEX_STATE) { + return PIMutexTryLock(mutex->ToPIMutex()); + } + if (__predict_false(IsMutexDestroyed(old_state))) { + return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__); + } + + // Do we already own this recursive or error-check mutex? + pid_t tid = __get_thread()->tid; + if (tid == atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed)) { + if (mtype == MUTEX_TYPE_BITS_ERRORCHECK) { + return EBUSY; + } + return NonPI::RecursiveIncrement(mutex, old_state); + } + + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + const uint16_t unlocked = mtype | shared | MUTEX_STATE_BITS_UNLOCKED; + const uint16_t locked_uncontended = mtype | shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; + + // Same as pthread_mutex_lock, except that we don't want to wait, and + // the only operation that can succeed is a single compare_exchange to acquire the + // lock if it is released / not owned by anyone. No need for a complex loop. + // If exchanged successfully, an acquire fence is required to make + // all memory accesses made by other threads visible to the current CPU. + old_state = unlocked; + if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, + locked_uncontended, + memory_order_acquire, + memory_order_relaxed))) { + atomic_store_explicit(&mutex->owner_tid, tid, memory_order_relaxed); + return 0; + } + return EBUSY; +} + +#if !defined(__LP64__) +extern "C" int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex_interface, unsigned ms) { + timespec ts; + timespec_from_ms(ts, ms); + timespec abs_timeout; + absolute_timespec_from_timespec(abs_timeout, ts, CLOCK_MONOTONIC); + int error = NonPI::MutexLockWithTimeout(__get_internal_mutex(mutex_interface), false, + &abs_timeout); + if (error == ETIMEDOUT) { + error = EBUSY; + } + return error; +} +#endif + +static int __pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, bool use_realtime_clock, + const timespec* abs_timeout, const char* function) { + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + uint16_t mtype = (old_state & MUTEX_TYPE_MASK); + // Handle common case first. + if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { + uint16_t shared = (old_state & MUTEX_SHARED_MASK); + if (__predict_true(NonPI::NormalMutexTryLock(mutex, shared) == 0)) { + return 0; + } + } + if (old_state == PI_MUTEX_STATE) { + return PIMutexTimedLock(mutex->ToPIMutex(), use_realtime_clock, abs_timeout); + } + if (__predict_false(IsMutexDestroyed(old_state))) { + return HandleUsingDestroyedMutex(mutex_interface, function); + } + return NonPI::MutexLockWithTimeout(mutex, use_realtime_clock, abs_timeout); +} + +int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const struct timespec* abs_timeout) { + return __pthread_mutex_timedlock(mutex_interface, true, abs_timeout, __FUNCTION__); +} + +int pthread_mutex_timedlock_monotonic_np(pthread_mutex_t* mutex_interface, + const struct timespec* abs_timeout) { + return __pthread_mutex_timedlock(mutex_interface, false, abs_timeout, __FUNCTION__); +} + +int pthread_mutex_clocklock(pthread_mutex_t* mutex_interface, clockid_t clock, + const struct timespec* abs_timeout) { + switch (clock) { + case CLOCK_MONOTONIC: + return __pthread_mutex_timedlock(mutex_interface, false, abs_timeout, __FUNCTION__); + case CLOCK_REALTIME: + return __pthread_mutex_timedlock(mutex_interface, true, abs_timeout, __FUNCTION__); + default: { + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + if (IsMutexDestroyed(old_state)) { + return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__); + } + return EINVAL; + } + } +} + +int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) { + pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface); + uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); + if (__predict_false(IsMutexDestroyed(old_state))) { + return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__); + } + if (old_state == PI_MUTEX_STATE) { + int result = PIMutexDestroy(mutex->ToPIMutex()); + if (result == 0) { + mutex->FreePIMutex(); + atomic_store(&mutex->state, 0xffff); + } + return result; + } + // Store 0xffff to make the mutex unusable. Although POSIX standard says it is undefined + // behavior to destroy a locked mutex, we prefer not to change mutex->state in that situation. + if (MUTEX_STATE_BITS_IS_UNLOCKED(old_state) && + atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, 0xffff, + memory_order_relaxed, memory_order_relaxed)) { + return 0; + } + return EBUSY; +} diff --git a/aosp/bionic/libc/bionic/pthread_once.cpp b/aosp/bionic/libc/bionic/pthread_once.cpp new file mode 100644 index 000000000..f48eadcd3 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_once.cpp @@ -0,0 +1,85 @@ +/* + * 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 +#include + +#include "private/bionic_futex.h" + +#define ONCE_INITIALIZATION_NOT_YET_STARTED 0 +#define ONCE_INITIALIZATION_UNDERWAY 1 +#define ONCE_INITIALIZATION_COMPLETE 2 + +/* NOTE: this implementation doesn't support a init function that throws a C++ exception + * or calls fork() + */ +int pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) { + static_assert(sizeof(atomic_int) == sizeof(pthread_once_t), + "pthread_once_t should actually be atomic_int in implementation."); + + // We prefer casting to atomic_int instead of declaring pthread_once_t to be atomic_int directly. + // Because using the second method pollutes pthread.h, and causes an error when compiling libcxx. + atomic_int* once_control_ptr = reinterpret_cast(once_control); + + // First check if the once is already initialized. This will be the common + // case and we want to make this as fast as possible. Note that this still + // requires a load_acquire operation here to ensure that all the + // stores performed by the initialization function are observable on + // this CPU after we exit. + int old_value = atomic_load_explicit(once_control_ptr, memory_order_acquire); + + while (true) { + if (__predict_true(old_value == ONCE_INITIALIZATION_COMPLETE)) { + return 0; + } + + // Try to atomically set the initialization underway flag. This requires a compare exchange + // in a loop, and we may need to exit prematurely if the initialization is complete. + if (!atomic_compare_exchange_weak_explicit(once_control_ptr, &old_value, + ONCE_INITIALIZATION_UNDERWAY, + memory_order_acquire, memory_order_acquire)) { + continue; + } + + if (old_value == ONCE_INITIALIZATION_NOT_YET_STARTED) { + // We got here first, we can handle the initialization. + (*init_routine)(); + + // Do a store_release indicating that initialization is complete. + atomic_store_explicit(once_control_ptr, ONCE_INITIALIZATION_COMPLETE, memory_order_release); + + // Wake up any waiters, if any. + __futex_wake_ex(once_control_ptr, 0, INT_MAX); + return 0; + } + + // The initialization is underway, wait for its finish. + __futex_wait_ex(once_control_ptr, 0, old_value, false, nullptr); + old_value = atomic_load_explicit(once_control_ptr, memory_order_acquire); + } +} diff --git a/aosp/bionic/libc/bionic/pthread_rwlock.cpp b/aosp/bionic/libc/bionic/pthread_rwlock.cpp new file mode 100644 index 000000000..ebf6697a0 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_rwlock.cpp @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2010 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 +#include +#include + +#include "pthread_internal.h" +#include "private/bionic_futex.h" +#include "private/bionic_lock.h" +#include "private/bionic_time_conversions.h" + +/* Technical note: + * + * Possible states of a read/write lock: + * + * - no readers and no writer (unlocked) + * - one or more readers sharing the lock at the same time (read-locked) + * - one writer holding the lock (write-lock) + * + * Additionally: + * - trying to get the write-lock while there are any readers blocks + * - trying to get the read-lock while there is a writer blocks + * - a single thread can acquire the lock multiple times in read mode + * + * - Posix states that behavior is undefined (may deadlock) if a thread tries + * to acquire the lock + * - in write mode while already holding the lock (whether in read or write mode) + * - in read mode while already holding the lock in write mode. + * - This implementation will return EDEADLK in "write after write" and "read after + * write" cases and will deadlock in write after read case. + * + */ + +// A rwlockattr is implemented as a 32-bit integer which has following fields: +// bits name description +// 1 rwlock_kind have rwlock preference like PTHREAD_RWLOCK_PREFER_READER_NP. +// 0 process_shared set to 1 if the rwlock is shared between processes. + +#define RWLOCKATTR_PSHARED_SHIFT 0 +#define RWLOCKATTR_KIND_SHIFT 1 + +#define RWLOCKATTR_PSHARED_MASK 1 +#define RWLOCKATTR_KIND_MASK 2 +#define RWLOCKATTR_RESERVED_MASK (~3) + +static inline __always_inline __always_inline bool __rwlockattr_getpshared(const pthread_rwlockattr_t* attr) { + return (*attr & RWLOCKATTR_PSHARED_MASK) >> RWLOCKATTR_PSHARED_SHIFT; +} + +static inline __always_inline __always_inline void __rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) { + *attr = (*attr & ~RWLOCKATTR_PSHARED_MASK) | (pshared << RWLOCKATTR_PSHARED_SHIFT); +} + +static inline __always_inline int __rwlockattr_getkind(const pthread_rwlockattr_t* attr) { + return (*attr & RWLOCKATTR_KIND_MASK) >> RWLOCKATTR_KIND_SHIFT; +} + +static inline __always_inline void __rwlockattr_setkind(pthread_rwlockattr_t* attr, int kind) { + *attr = (*attr & ~RWLOCKATTR_KIND_MASK) | (kind << RWLOCKATTR_KIND_SHIFT); +} + + +int pthread_rwlockattr_init(pthread_rwlockattr_t* attr) { + *attr = 0; + return 0; +} + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t* attr) { + *attr = -1; + return 0; +} + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t* attr, int* pshared) { + if (__rwlockattr_getpshared(attr)) { + *pshared = PTHREAD_PROCESS_SHARED; + } else { + *pshared = PTHREAD_PROCESS_PRIVATE; + } + return 0; +} + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) { + switch (pshared) { + case PTHREAD_PROCESS_PRIVATE: + __rwlockattr_setpshared(attr, 0); + return 0; + case PTHREAD_PROCESS_SHARED: + __rwlockattr_setpshared(attr, 1); + return 0; + default: + return EINVAL; + } +} + +int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t* attr, int* pref) { + *pref = __rwlockattr_getkind(attr); + return 0; +} + +int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref) { + switch (pref) { + case PTHREAD_RWLOCK_PREFER_READER_NP: // Fall through. + case PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP: + __rwlockattr_setkind(attr, pref); + return 0; + default: + return EINVAL; + } +} + +// A rwlock state is implemented as a 32-bit integer which has following rules: +// bits name description +// 31 owned_by_writer_flag set to 1 if the lock is owned by a writer now. +// 30-2 reader_count the count of readers holding the lock. +// 1 have_pending_writers set to 1 if having pending writers. +// 0 have_pending_readers set to 1 if having pending readers. + +#define STATE_HAVE_PENDING_READERS_SHIFT 0 +#define STATE_HAVE_PENDING_WRITERS_SHIFT 1 +#define STATE_READER_COUNT_SHIFT 2 +#define STATE_OWNED_BY_WRITER_SHIFT 31 + +#define STATE_HAVE_PENDING_READERS_FLAG (1 << STATE_HAVE_PENDING_READERS_SHIFT) +#define STATE_HAVE_PENDING_WRITERS_FLAG (1 << STATE_HAVE_PENDING_WRITERS_SHIFT) +#define STATE_READER_COUNT_CHANGE_STEP (1 << STATE_READER_COUNT_SHIFT) +#define STATE_OWNED_BY_WRITER_FLAG (1 << STATE_OWNED_BY_WRITER_SHIFT) + +#define STATE_HAVE_PENDING_READERS_OR_WRITERS_FLAG \ + (STATE_HAVE_PENDING_READERS_FLAG | STATE_HAVE_PENDING_WRITERS_FLAG) + +struct pthread_rwlock_internal_t { + atomic_int state; + atomic_int writer_tid; + + bool pshared; + bool writer_nonrecursive_preferred; + uint16_t __pad; + +// When a reader thread plans to suspend on the rwlock, it will add STATE_HAVE_PENDING_READERS_FLAG +// in state, increase pending_reader_count, and wait on pending_reader_wakeup_serial. After woken +// up, the reader thread decreases pending_reader_count, and the last pending reader thread should +// remove STATE_HAVE_PENDING_READERS_FLAG in state. A pending writer thread works in a similar way, +// except that it uses flag and members for writer threads. + + Lock pending_lock; // All pending members below are protected by pending_lock. + uint32_t pending_reader_count; // Count of pending reader threads. + uint32_t pending_writer_count; // Count of pending writer threads. + uint32_t pending_reader_wakeup_serial; // Pending reader threads wait on this address by futex_wait. + uint32_t pending_writer_wakeup_serial; // Pending writer threads wait on this address by futex_wait. + +#if defined(__LP64__) + char __reserved[20]; +#else + char __reserved[4]; +#endif +}; + +static inline __always_inline bool __state_owned_by_writer(int state) { + return state < 0; +} + +static inline __always_inline bool __state_owned_by_readers(int state) { + // If state >= 0, the owned_by_writer_flag is not set. + // And if state >= STATE_READER_COUNT_CHANGE_STEP, the reader_count field is not empty. + return state >= STATE_READER_COUNT_CHANGE_STEP; +} + +static inline __always_inline bool __state_owned_by_readers_or_writer(int state) { + return state < 0 || state >= STATE_READER_COUNT_CHANGE_STEP; +} + +static inline __always_inline int __state_add_writer_flag(int state) { + return state | STATE_OWNED_BY_WRITER_FLAG; +} + +static inline __always_inline bool __state_is_last_reader(int state) { + return (state >> STATE_READER_COUNT_SHIFT) == 1; +} + +static inline __always_inline bool __state_have_pending_writers(int state) { + return state & STATE_HAVE_PENDING_WRITERS_FLAG; +} + +static inline __always_inline bool __state_have_pending_readers_or_writers(int state) { + return state & STATE_HAVE_PENDING_READERS_OR_WRITERS_FLAG; +} + +static_assert(sizeof(pthread_rwlock_t) == sizeof(pthread_rwlock_internal_t), + "pthread_rwlock_t should actually be pthread_rwlock_internal_t in implementation."); + +// For binary compatibility with old version of pthread_rwlock_t, we can't use more strict +// alignment than 4-byte alignment. +static_assert(alignof(pthread_rwlock_t) == 4, + "pthread_rwlock_t should fulfill the alignment requirement of pthread_rwlock_internal_t."); + +static inline __always_inline pthread_rwlock_internal_t* __get_internal_rwlock(pthread_rwlock_t* rwlock_interface) { + return reinterpret_cast(rwlock_interface); +} + +int pthread_rwlock_init(pthread_rwlock_t* rwlock_interface, const pthread_rwlockattr_t* attr) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + memset(rwlock, 0, sizeof(pthread_rwlock_internal_t)); + + if (__predict_false(attr != nullptr)) { + rwlock->pshared = __rwlockattr_getpshared(attr); + int kind = __rwlockattr_getkind(attr); + switch (kind) { + case PTHREAD_RWLOCK_PREFER_READER_NP: + rwlock->writer_nonrecursive_preferred = false; + break; + case PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP: + rwlock->writer_nonrecursive_preferred = true; + break; + default: + return EINVAL; + } + if ((*attr & RWLOCKATTR_RESERVED_MASK) != 0) { + return EINVAL; + } + } + + atomic_init(&rwlock->state, 0); + rwlock->pending_lock.init(rwlock->pshared); + return 0; +} + +int pthread_rwlock_destroy(pthread_rwlock_t* rwlock_interface) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + if (atomic_load_explicit(&rwlock->state, memory_order_relaxed) != 0) { + return EBUSY; + } + return 0; +} + +static inline __always_inline bool __can_acquire_read_lock(int old_state, + bool writer_nonrecursive_preferred) { + // If writer is preferred with nonrecursive reader, we prevent further readers from acquiring + // the lock when there are writers waiting for the lock. + bool cannot_apply = __state_owned_by_writer(old_state) || + (writer_nonrecursive_preferred && __state_have_pending_writers(old_state)); + return !cannot_apply; +} + +static inline __always_inline int __pthread_rwlock_tryrdlock(pthread_rwlock_internal_t* rwlock) { + int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed); + + while (__predict_true(__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred))) { + + int new_state = old_state + STATE_READER_COUNT_CHANGE_STEP; + if (__predict_false(!__state_owned_by_readers(new_state))) { // Happens when reader count overflows. + return EAGAIN; + } + if (__predict_true(atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, new_state, + memory_order_acquire, memory_order_relaxed))) { + return 0; + } + } + return EBUSY; +} + +static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock, + const timespec* abs_timeout_or_null) { + if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) { + return EDEADLK; + } + + while (true) { + int result = __pthread_rwlock_tryrdlock(rwlock); + if (result == 0 || result == EAGAIN) { + return result; + } + result = check_timespec(abs_timeout_or_null, true); + if (result != 0) { + return result; + } + + int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed); + if (__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) { + continue; + } + + rwlock->pending_lock.lock(); + rwlock->pending_reader_count++; + + // We rely on the fact that all atomic exchange operations on the same object (here it is + // rwlock->state) always appear to occur in a single total order. If the pending flag is added + // before unlocking, the unlocking thread will wakeup the waiter. Otherwise, we will see the + // state is unlocked and will not wait anymore. + old_state = atomic_fetch_or_explicit(&rwlock->state, STATE_HAVE_PENDING_READERS_FLAG, + memory_order_relaxed); + + int old_serial = rwlock->pending_reader_wakeup_serial; + rwlock->pending_lock.unlock(); + + int futex_result = 0; + if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) { + futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared, + old_serial, use_realtime_clock, abs_timeout_or_null); + } + + rwlock->pending_lock.lock(); + rwlock->pending_reader_count--; + if (rwlock->pending_reader_count == 0) { + atomic_fetch_and_explicit(&rwlock->state, ~STATE_HAVE_PENDING_READERS_FLAG, + memory_order_relaxed); + } + rwlock->pending_lock.unlock(); + + if (futex_result == -ETIMEDOUT) { + return ETIMEDOUT; + } + } +} + +static inline __always_inline bool __can_acquire_write_lock(int old_state) { + return !__state_owned_by_readers_or_writer(old_state); +} + +static inline __always_inline int __pthread_rwlock_trywrlock(pthread_rwlock_internal_t* rwlock) { + int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed); + + while (__predict_true(__can_acquire_write_lock(old_state))) { + if (__predict_true(atomic_compare_exchange_weak_explicit(&rwlock->state, &old_state, + __state_add_writer_flag(old_state), memory_order_acquire, memory_order_relaxed))) { + + atomic_store_explicit(&rwlock->writer_tid, __get_thread()->tid, memory_order_relaxed); + return 0; + } + } + return EBUSY; +} + +static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock, + const timespec* abs_timeout_or_null) { + if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) { + return EDEADLK; + } + while (true) { + int result = __pthread_rwlock_trywrlock(rwlock); + if (result == 0) { + return result; + } + result = check_timespec(abs_timeout_or_null, true); + if (result != 0) { + return result; + } + + int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed); + if (__can_acquire_write_lock(old_state)) { + continue; + } + + rwlock->pending_lock.lock(); + rwlock->pending_writer_count++; + + old_state = atomic_fetch_or_explicit(&rwlock->state, STATE_HAVE_PENDING_WRITERS_FLAG, + memory_order_relaxed); + + int old_serial = rwlock->pending_writer_wakeup_serial; + rwlock->pending_lock.unlock(); + + int futex_result = 0; + if (!__can_acquire_write_lock(old_state)) { + futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared, + old_serial, use_realtime_clock, abs_timeout_or_null); + } + + rwlock->pending_lock.lock(); + rwlock->pending_writer_count--; + if (rwlock->pending_writer_count == 0) { + atomic_fetch_and_explicit(&rwlock->state, ~STATE_HAVE_PENDING_WRITERS_FLAG, + memory_order_relaxed); + } + rwlock->pending_lock.unlock(); + + if (futex_result == -ETIMEDOUT) { + return ETIMEDOUT; + } + } +} + +int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock_interface) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + // Avoid slowing down fast path of rdlock. + if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) { + return 0; + } + return __pthread_rwlock_timedrdlock(rwlock, false, nullptr); +} + +int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + return __pthread_rwlock_timedrdlock(rwlock, true, abs_timeout); +} + +int pthread_rwlock_timedrdlock_monotonic_np(pthread_rwlock_t* rwlock_interface, + const timespec* abs_timeout) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + return __pthread_rwlock_timedrdlock(rwlock, false, abs_timeout); +} + +int pthread_rwlock_clockrdlock(pthread_rwlock_t* rwlock_interface, clockid_t clock, + const struct timespec* abs_timeout) { + switch (clock) { + case CLOCK_MONOTONIC: + return pthread_rwlock_timedrdlock_monotonic_np(rwlock_interface, abs_timeout); + case CLOCK_REALTIME: + return pthread_rwlock_timedrdlock(rwlock_interface, abs_timeout); + default: + return EINVAL; + } +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock_interface) { + return __pthread_rwlock_tryrdlock(__get_internal_rwlock(rwlock_interface)); +} + +int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock_interface) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + // Avoid slowing down fast path of wrlock. + if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) { + return 0; + } + return __pthread_rwlock_timedwrlock(rwlock, false, nullptr); +} + +int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + return __pthread_rwlock_timedwrlock(rwlock, true, abs_timeout); +} + +int pthread_rwlock_timedwrlock_monotonic_np(pthread_rwlock_t* rwlock_interface, + const timespec* abs_timeout) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + return __pthread_rwlock_timedwrlock(rwlock, false, abs_timeout); +} + +int pthread_rwlock_clockwrlock(pthread_rwlock_t* rwlock_interface, clockid_t clock, + const struct timespec* abs_timeout) { + switch (clock) { + case CLOCK_MONOTONIC: + return pthread_rwlock_timedwrlock_monotonic_np(rwlock_interface, abs_timeout); + case CLOCK_REALTIME: + return pthread_rwlock_timedwrlock(rwlock_interface, abs_timeout); + default: + return EINVAL; + } +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock_interface) { + return __pthread_rwlock_trywrlock(__get_internal_rwlock(rwlock_interface)); +} + +int pthread_rwlock_unlock(pthread_rwlock_t* rwlock_interface) { + pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface); + + int old_state = atomic_load_explicit(&rwlock->state, memory_order_relaxed); + if (__state_owned_by_writer(old_state)) { + if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) != __get_thread()->tid) { + return EPERM; + } + atomic_store_explicit(&rwlock->writer_tid, 0, memory_order_relaxed); + old_state = atomic_fetch_and_explicit(&rwlock->state, ~STATE_OWNED_BY_WRITER_FLAG, + memory_order_release); + if (!__state_have_pending_readers_or_writers(old_state)) { + return 0; + } + + } else if (__state_owned_by_readers(old_state)) { + old_state = atomic_fetch_sub_explicit(&rwlock->state, STATE_READER_COUNT_CHANGE_STEP, + memory_order_release); + if (!__state_is_last_reader(old_state) || !__state_have_pending_readers_or_writers(old_state)) { + return 0; + } + + } else { + return EPERM; + } + + // Wake up pending readers or writers. + rwlock->pending_lock.lock(); + if (rwlock->pending_writer_count != 0) { + rwlock->pending_writer_wakeup_serial++; + rwlock->pending_lock.unlock(); + + __futex_wake_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared, 1); + + } else if (rwlock->pending_reader_count != 0) { + rwlock->pending_reader_wakeup_serial++; + rwlock->pending_lock.unlock(); + + __futex_wake_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared, INT_MAX); + + } else { + // It happens when waiters are woken up by timeout. + rwlock->pending_lock.unlock(); + } + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_self.cpp b/aosp/bionic/libc/bionic/pthread_self.cpp new file mode 100644 index 000000000..0a83f0780 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_self.cpp @@ -0,0 +1,33 @@ +/* + * 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 "pthread_internal.h" + +pthread_t pthread_self() { + return reinterpret_cast(__get_thread()); +} diff --git a/aosp/bionic/libc/bionic/pthread_setname_np.cpp b/aosp/bionic/libc/bionic/pthread_setname_np.cpp new file mode 100644 index 000000000..5236e4dbe --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_setname_np.cpp @@ -0,0 +1,107 @@ +/* + * 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 + +#include +#include // For snprintf. +#include +#include +#include +#include +#include + +#include "private/bionic_defs.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +// This value is not exported by kernel headers. +#define MAX_TASK_COMM_LEN 16 + +static int __open_task_comm_fd(pthread_t t, int flags, const char* caller) { + char comm_name[64]; + snprintf(comm_name, sizeof(comm_name), "/proc/self/task/%d/comm", + __pthread_internal_gettid(t, caller)); + return open(comm_name, O_CLOEXEC | flags); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_getname_np(pthread_t t, char* buf, size_t buf_size) { + ErrnoRestorer errno_restorer; + + if (buf_size < MAX_TASK_COMM_LEN) return ERANGE; + + // Getting our own name is an easy special case. + if (t == pthread_self()) { + return prctl(PR_GET_NAME, buf) ? errno : 0; + } + + // We have to get another thread's name. + int fd = __open_task_comm_fd(t, O_RDONLY, "pthread_getname_np"); + if (fd == -1) return errno; + + ssize_t n = TEMP_FAILURE_RETRY(read(fd, buf, buf_size)); + close(fd); + + if (n == -1) return errno; + + // The kernel adds a trailing '\n' to the /proc file, + // so this is actually the normal case for short names. + if (n > 0 && buf[n - 1] == '\n') { + buf[n - 1] = '\0'; + return 0; + } + + if (n == static_cast(buf_size)) return ERANGE; + buf[n] = '\0'; + return 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_setname_np(pthread_t t, const char* thread_name) { + ErrnoRestorer errno_restorer; + + size_t thread_name_len = strlen(thread_name); + if (thread_name_len >= MAX_TASK_COMM_LEN) return ERANGE; + + // Setting our own name is an easy special case. + if (t == pthread_self()) { + return prctl(PR_SET_NAME, thread_name) ? errno : 0; + } + + // We have to set another thread's name. + int fd = __open_task_comm_fd(t, O_WRONLY, "pthread_setname_np"); + if (fd == -1) return errno; + + ssize_t n = TEMP_FAILURE_RETRY(write(fd, thread_name, thread_name_len)); + close(fd); + + if (n == -1) return errno; + if (n != static_cast(thread_name_len)) return EIO; + return 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_setschedparam.cpp b/aosp/bionic/libc/bionic/pthread_setschedparam.cpp new file mode 100644 index 000000000..656fe3208 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_setschedparam.cpp @@ -0,0 +1,56 @@ +/* + * 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 +#include +#include + +#include "private/bionic_defs.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_setschedparam(pthread_t t, int policy, const sched_param* param) { + ErrnoRestorer errno_restorer; + + pid_t tid = __pthread_internal_gettid(t, "pthread_setschedparam"); + if (tid == -1) return ESRCH; + + return (sched_setscheduler(tid, policy, param) == -1) ? errno : 0; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_setschedprio(pthread_t t, int priority) { + ErrnoRestorer errno_restorer; + + pid_t tid = __pthread_internal_gettid(t, "pthread_setschedprio"); + if (tid == -1) return ESRCH; + + sched_param param = { .sched_priority = priority }; + return (sched_setparam(tid, ¶m) == -1) ? errno : 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_sigqueue.cpp b/aosp/bionic/libc/bionic/pthread_sigqueue.cpp new file mode 100644 index 000000000..93c349e2d --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_sigqueue.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include +#include + +#include "private/bionic_defs.h" +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int pthread_sigqueue(pthread_t t, int sig, const union sigval value) { + ErrnoRestorer errno_restorer; + + pid_t tid = __pthread_internal_gettid(t, "pthread_sigqueue"); + if (tid == -1) return ESRCH; + + siginfo_t siginfo; + siginfo.si_code = SI_QUEUE; + siginfo.si_pid = getpid(); + siginfo.si_uid = getuid(); + siginfo.si_value = value; + + return syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, sig, &siginfo) ? errno : 0; +} diff --git a/aosp/bionic/libc/bionic/pthread_spinlock.cpp b/aosp/bionic/libc/bionic/pthread_spinlock.cpp new file mode 100644 index 000000000..f26f28303 --- /dev/null +++ b/aosp/bionic/libc/bionic/pthread_spinlock.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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 + +#include "private/bionic_lock.h" + +// User-level spinlocks can be hazardous to battery life on Android. +// We implement a simple compromise that behaves mostly like a spinlock, +// but prevents excessively long spinning. + +struct pthread_spinlock_internal_t { + Lock lock; +}; + +static_assert(sizeof(pthread_spinlock_t) == sizeof(pthread_spinlock_internal_t), + "pthread_spinlock_t should actually be pthread_spinlock_internal_t."); + +static_assert(alignof(pthread_spinlock_t) >= 4, + "pthread_spinlock_t should fulfill the alignment of pthread_spinlock_internal_t."); + +static inline pthread_spinlock_internal_t* __get_internal_spinlock(pthread_spinlock_t* lock) { + return reinterpret_cast(lock); +} + +int pthread_spin_init(pthread_spinlock_t* lock_interface, int pshared) { + pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface); + lock->lock.init(pshared); + return 0; +} + +int pthread_spin_destroy(pthread_spinlock_t* lock_interface) { + pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface); + return lock->lock.trylock() ? 0 : EBUSY; +} + +int pthread_spin_trylock(pthread_spinlock_t* lock_interface) { + pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface); + return lock->lock.trylock() ? 0 : EBUSY; +} + +int pthread_spin_lock(pthread_spinlock_t* lock_interface) { + pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface); + for (int i = 0; i < 10000; ++i) { + if (lock->lock.trylock()) { + return 0; + } + } + lock->lock.lock(); + return 0; +} + +int pthread_spin_unlock(pthread_spinlock_t* lock_interface) { + pthread_spinlock_internal_t* lock = __get_internal_spinlock(lock_interface); + lock->lock.unlock(); + return 0; +} diff --git a/aosp/bionic/libc/bionic/ptrace.cpp b/aosp/bionic/libc/bionic/ptrace.cpp new file mode 100644 index 000000000..5156ec24c --- /dev/null +++ b/aosp/bionic/libc/bionic/ptrace.cpp @@ -0,0 +1,55 @@ +/* + * 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 +#include + +extern "C" long __ptrace(int req, pid_t pid, void* addr, void* data); + +long ptrace(int req, ...) { + bool is_peek = (req == PTRACE_PEEKUSR || req == PTRACE_PEEKTEXT || req == PTRACE_PEEKDATA); + long peek_result; + + va_list args; + va_start(args, req); + pid_t pid = va_arg(args, pid_t); + void* addr = va_arg(args, void*); + void* data; + if (is_peek) { + data = &peek_result; + } else { + data = va_arg(args, void*); + } + va_end(args); + + long result = __ptrace(req, pid, addr, data); + if (is_peek && result == 0) { + return peek_result; + } + return result; +} diff --git a/aosp/bionic/libc/bionic/pty.cpp b/aosp/bionic/libc/bionic/pty.cpp new file mode 100644 index 000000000..71e14d9db --- /dev/null +++ b/aosp/bionic/libc/bionic/pty.cpp @@ -0,0 +1,196 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bionic/pthread_internal.h" +#include "private/FdPath.h" + +int getpt() { + return posix_openpt(O_RDWR|O_NOCTTY); +} + +int grantpt(int) { + return 0; +} + +int posix_openpt(int flags) { + return open("/dev/ptmx", flags); +} + +char* ptsname(int fd) { + bionic_tls& tls = __get_bionic_tls(); + char* buf = tls.ptsname_buf; + int error = ptsname_r(fd, buf, sizeof(tls.ptsname_buf)); + return (error == 0) ? buf : nullptr; +} + +int ptsname_r(int fd, char* buf, size_t len) { + if (buf == nullptr) { + errno = EINVAL; + return errno; + } + + unsigned int pty_num; + if (ioctl(fd, TIOCGPTN, &pty_num) != 0) { + errno = ENOTTY; + return errno; + } + + if (snprintf(buf, len, "/dev/pts/%u", pty_num) >= static_cast(len)) { + errno = ERANGE; + return errno; + } + + return 0; +} + +char* ttyname(int fd) { + bionic_tls& tls = __get_bionic_tls(); + char* buf = tls.ttyname_buf; + int error = ttyname_r(fd, buf, sizeof(tls.ttyname_buf)); + return (error == 0) ? buf : nullptr; +} + +int ttyname_r(int fd, char* buf, size_t len) { + if (buf == nullptr) { + errno = EINVAL; + return errno; + } + + if (!isatty(fd)) { + return errno; + } + + ssize_t count = readlink(FdPath(fd).c_str(), buf, len); + if (count == -1) { + return errno; + } + if (static_cast(count) == len) { + errno = ERANGE; + return errno; + } + buf[count] = '\0'; + return 0; +} + +int unlockpt(int fd) { + int unlock = 0; + return ioctl(fd, TIOCSPTLCK, &unlock); +} + +int openpty(int* master, int* slave, char* name, const termios* t, const winsize* ws) { + *master = getpt(); + if (*master == -1) { + return -1; + } + + if (grantpt(*master) == -1 || unlockpt(*master) == -1) { + close(*master); + return -1; + } + + char buf[32]; + if (name == nullptr) { + name = buf; + } + if (ptsname_r(*master, name, sizeof(buf)) != 0) { + close(*master); + return -1; + } + + *slave = open(name, O_RDWR|O_NOCTTY); + if (*slave == -1) { + close(*master); + return -1; + } + + if (t != nullptr) { + tcsetattr(*slave, TCSAFLUSH, t); + } + if (ws != nullptr) { + ioctl(*slave, TIOCSWINSZ, ws); + } + + return 0; +} + +int forkpty(int* amaster, char* name, const termios* t, const winsize* ws) { + int master; + int slave; + if (openpty(&master, &slave, name, t, ws) == -1) { + return -1; + } + + pid_t pid = fork(); + if (pid == -1) { + close(master); + close(slave); + return -1; + } + + if (pid == 0) { + // Child. + *amaster = -1; + close(master); + if (login_tty(slave) == -1) { + _exit(1); + } + return 0; + } + + // Parent. + *amaster = master; + close(slave); + return pid; +} + +int login_tty(int fd) { + setsid(); + + if (ioctl(fd, TIOCSCTTY, nullptr) == -1) { + return -1; + } + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) { + close(fd); + } + + return 0; +} diff --git a/aosp/bionic/libc/bionic/pututline.c b/aosp/bionic/libc/bionic/pututline.c new file mode 100644 index 000000000..8cbf47057 --- /dev/null +++ b/aosp/bionic/libc/bionic/pututline.c @@ -0,0 +1,64 @@ +/* + * 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 +#include +#include + + +void pututline(struct utmp* utmp) +{ + FILE* f; + struct utmp u; + long i; + + if (!(f = fopen(_PATH_UTMP, "w+e"))) + return; + + while (fread(&u, sizeof(struct utmp), 1, f) == 1) + { + if (!strncmp(utmp->ut_line, u.ut_line, sizeof(u.ut_line) -1)) + { + if ((i = ftell(f)) < 0) + goto ret; + if (fseek(f, i - sizeof(struct utmp), SEEK_SET) < 0) + goto ret; + fwrite(utmp, sizeof(struct utmp), 1, f); + goto ret; + } + } + + + fclose(f); + + if (!(f = fopen(_PATH_UTMP, "w+e"))) + return; + fwrite(utmp, sizeof(struct utmp), 1, f); + +ret: + fclose(f); +} diff --git a/aosp/bionic/libc/bionic/raise.cpp b/aosp/bionic/libc/bionic/raise.cpp new file mode 100644 index 000000000..1f204d4a2 --- /dev/null +++ b/aosp/bionic/libc/bionic/raise.cpp @@ -0,0 +1,40 @@ +/* + * 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 +#include +#include +#include + +int raise(int sig) { + // Protect ourselves against stale cached PID/TID values by fetching them via syscall. + // http://b/37769298 + pid_t pid = syscall(__NR_getpid); + pid_t tid = syscall(__NR_gettid); + return tgkill(pid, tid, sig); +} diff --git a/aosp/bionic/libc/bionic/rand.cpp b/aosp/bionic/libc/bionic/rand.cpp new file mode 100644 index 000000000..0074f2d24 --- /dev/null +++ b/aosp/bionic/libc/bionic/rand.cpp @@ -0,0 +1,29 @@ +/* + * 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 + +// The BSD rand/srand is very weak. glibc just uses random/srandom instead. +// Since we're likely to run code intended for glibc, and POSIX doesn't seem +// to disallow this, we go that route too. + +int rand() { + return random(); +} + +void srand(unsigned int seed) { + return srandom(seed); +} diff --git a/aosp/bionic/libc/bionic/readlink.cpp b/aosp/bionic/libc/bionic/readlink.cpp new file mode 100644 index 000000000..3bb7bc18a --- /dev/null +++ b/aosp/bionic/libc/bionic/readlink.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include + +ssize_t readlink(const char* path, char* buf, size_t size) { + return readlinkat(AT_FDCWD, path, buf, size); +} diff --git a/aosp/bionic/libc/bionic/realpath.cpp b/aosp/bionic/libc/bionic/realpath.cpp new file mode 100644 index 000000000..e43d8e2ff --- /dev/null +++ b/aosp/bionic/libc/bionic/realpath.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 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 + +#include +#include +#include +#include + +#include "private/FdPath.h" +#include "private/ScopedFd.h" + +// This function needs a 4KiB (PATH_MAX) buffer. +// The alternative is to heap allocate and then trim, but that's 2x the code. +// (Remember that readlink(2) won't tell you the needed size, so the multi-pass +// algorithm isn't even an option unless you want to just guess, in which case +// you're back needing to trim again.) +#pragma GCC diagnostic ignored "-Wframe-larger-than=" + +char* realpath(const char* path, char* result) { + // Weird special case. + if (!path) { + errno = EINVAL; + return nullptr; + } + + // Get an O_PATH fd, and... + ScopedFd fd(open(path, O_PATH | O_CLOEXEC)); + if (fd.get() == -1) return nullptr; + + // (...remember the device/inode that we're talking about and...) + struct stat sb; + if (fstat(fd.get(), &sb) == -1) return nullptr; + dev_t st_dev = sb.st_dev; + ino_t st_ino = sb.st_ino; + + // ...ask the kernel to do the hard work for us. + FdPath fd_path(fd.get()); + char dst[PATH_MAX]; + ssize_t l = readlink(fd_path.c_str(), dst, sizeof(dst) - 1); + if (l == -1) return nullptr; + dst[l] = '\0'; + + // What if the file was removed in the meantime? readlink(2) will have + // returned "/a/b/c (deleted)", and we want to return ENOENT instead. + if (stat(dst, &sb) == -1 || st_dev != sb.st_dev || st_ino != sb.st_ino) { + errno = ENOENT; + return nullptr; + } + + return result ? strcpy(result, dst) : strdup(dst); +} diff --git a/aosp/bionic/libc/bionic/reboot.cpp b/aosp/bionic/libc/bionic/reboot.cpp new file mode 100644 index 000000000..b0a1f9773 --- /dev/null +++ b/aosp/bionic/libc/bionic/reboot.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include + +extern "C" int __reboot(int, int, int, void*); + +int reboot(int mode) { + return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, nullptr); +} diff --git a/aosp/bionic/libc/bionic/recv.cpp b/aosp/bionic/libc/bionic/recv.cpp new file mode 100644 index 000000000..32a7a72ae --- /dev/null +++ b/aosp/bionic/libc/bionic/recv.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +ssize_t recv(int socket, void *buf, size_t len, int flags) { + return recvfrom(socket, buf, len, flags, nullptr, nullptr); +} diff --git a/aosp/bionic/libc/bionic/recvmsg.cpp b/aosp/bionic/libc/bionic/recvmsg.cpp new file mode 100644 index 000000000..003f43d8a --- /dev/null +++ b/aosp/bionic/libc/bionic/recvmsg.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 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 +#include + +#include + +#include "private/bionic_fdtrack.h" + +extern "C" ssize_t __recvmsg(int __fd, struct msghdr* __msg, int __flags); +extern "C" int __recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags, + const struct timespec* __timeout); + +static inline __attribute__((artificial)) __attribute__((always_inline)) void track_fds( + struct msghdr* msg, const char* function_name) { + if (!__android_fdtrack_hook) { + return; + } + + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_type != SCM_RIGHTS) { + continue; + } + + if (cmsg->cmsg_len <= sizeof(struct cmsghdr)) { + continue; + } + + size_t data_length = cmsg->cmsg_len - sizeof(struct cmsghdr); + if (data_length % sizeof(int) != 0) { + async_safe_fatal("invalid cmsg length: %zu", data_length); + } + + for (size_t offset = 0; offset < data_length; offset += sizeof(int)) { + int fd; + memcpy(&fd, CMSG_DATA(cmsg) + offset, sizeof(int)); + FDTRACK_CREATE_NAME(function_name, fd); + } + } +} + +ssize_t recvmsg(int __fd, struct msghdr* __msg, int __flags) { + ssize_t rc = __recvmsg(__fd, __msg, __flags); + if (rc == -1) { + return -1; + } + track_fds(__msg, "recvmsg"); + return rc; +} + +int recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags, + const struct timespec* __timeout) { + int rc = __recvmmsg(__fd, __msgs, __msg_count, __flags, __timeout); + if (rc == -1) { + return -1; + } + for (int i = 0; i < rc; ++i) { + track_fds(&__msgs[i].msg_hdr, "recvmmsg"); + } + return rc; +} diff --git a/aosp/bionic/libc/bionic/rename.cpp b/aosp/bionic/libc/bionic/rename.cpp new file mode 100644 index 000000000..82955596b --- /dev/null +++ b/aosp/bionic/libc/bionic/rename.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int rename(const char* old_path, const char* new_path) { + return renameat(AT_FDCWD, old_path, AT_FDCWD, new_path); +} diff --git a/aosp/bionic/libc/bionic/rmdir.cpp b/aosp/bionic/libc/bionic/rmdir.cpp new file mode 100644 index 000000000..e7a9808da --- /dev/null +++ b/aosp/bionic/libc/bionic/rmdir.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int rmdir(const char* path) { + return unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} diff --git a/aosp/bionic/libc/bionic/scandir.cpp b/aosp/bionic/libc/bionic/scandir.cpp new file mode 100644 index 000000000..6a7e36874 --- /dev/null +++ b/aosp/bionic/libc/bionic/scandir.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2013 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 + +#include +#include +#include +#include +#include + +#include "platform/bionic/macros.h" +#include "private/ScopedReaddir.h" + +// A smart pointer to the scandir dirent**. +class ScandirResult { + public: + ScandirResult() : names_(nullptr), size_(0), capacity_(0) { + } + + ~ScandirResult() { + while (size_ > 0) { + free(names_[--size_]); + } + free(names_); + } + + size_t size() { + return size_; + } + + dirent** release() { + dirent** result = names_; + names_ = nullptr; + size_ = capacity_ = 0; + return result; + } + + bool Add(dirent* entry) { + if (size_ >= capacity_) { + size_t new_capacity = capacity_ + 32; + dirent** new_names = + reinterpret_cast(realloc(names_, new_capacity * sizeof(dirent*))); + if (new_names == nullptr) { + return false; + } + names_ = new_names; + capacity_ = new_capacity; + } + + dirent* copy = CopyDirent(entry); + if (copy == nullptr) { + return false; + } + names_[size_++] = copy; + return true; + } + + void Sort(int (*comparator)(const dirent**, const dirent**)) { + // If we have entries and a comparator, sort them. + if (size_ > 0 && comparator != nullptr) { + qsort(names_, size_, sizeof(dirent*), + reinterpret_cast(comparator)); + } + } + + private: + dirent** names_; + size_t size_; + size_t capacity_; + + static dirent* CopyDirent(dirent* original) { + // Allocate the minimum number of bytes necessary, rounded up to a 4-byte boundary. + size_t size = ((original->d_reclen + 3) & ~3); + dirent* copy = reinterpret_cast(malloc(size)); + memcpy(copy, original, original->d_reclen); + return copy; + } + + BIONIC_DISALLOW_COPY_AND_ASSIGN(ScandirResult); +}; + +int scandirat(int parent_fd, const char* dir_name, dirent*** name_list, + int (*filter)(const dirent*), + int (*comparator)(const dirent**, const dirent**)) { + DIR* dir = nullptr; + if (parent_fd == AT_FDCWD) { + dir = opendir(dir_name); + } else { + int dir_fd = openat(parent_fd, dir_name, O_CLOEXEC | O_DIRECTORY | O_RDONLY); + if (dir_fd != -1) { + dir = fdopendir(dir_fd); + } + } + + ScopedReaddir reader(dir); + if (reader.IsBad()) { + return -1; + } + + ScandirResult names; + dirent* entry; + while ((entry = reader.ReadEntry()) != nullptr) { + // If we have a filter, skip names that don't match. + if (filter != nullptr && !(*filter)(entry)) { + continue; + } + names.Add(entry); + } + + names.Sort(comparator); + + size_t size = names.size(); + *name_list = names.release(); + return size; +} +__strong_alias(scandirat64, scandirat); + +int scandir(const char* dir_path, dirent*** name_list, + int (*filter)(const dirent*), + int (*comparator)(const dirent**, const dirent**)) { + return scandirat(AT_FDCWD, dir_path, name_list, filter, comparator); +} +__strong_alias(scandir64, scandir); diff --git a/aosp/bionic/libc/bionic/sched_cpualloc.c b/aosp/bionic/libc/bionic/sched_cpualloc.c new file mode 100644 index 000000000..345de9149 --- /dev/null +++ b/aosp/bionic/libc/bionic/sched_cpualloc.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 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. + */ +#define _GNU_SOURCE 1 +#include +#include + +cpu_set_t* __sched_cpualloc(size_t count) +{ + // The static analyzer complains that CPU_ALLOC_SIZE eventually expands to + // N * sizeof(unsigned long), which is incompatible with cpu_set_t. This is + // on purpose. + return (cpu_set_t*) malloc(CPU_ALLOC_SIZE(count)); // NOLINT +} + +void __sched_cpufree(cpu_set_t* set) +{ + free(set); +} diff --git a/aosp/bionic/libc/bionic/sched_cpucount.c b/aosp/bionic/libc/bionic/sched_cpucount.c new file mode 100644 index 000000000..6f665890b --- /dev/null +++ b/aosp/bionic/libc/bionic/sched_cpucount.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 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. + */ +#define _GNU_SOURCE 1 +#include + +int __sched_cpucount(size_t setsize, const cpu_set_t* set) { + int nn = 0; + int nn_max = setsize / sizeof(__CPU_BITTYPE); + int count = 0; + + for ( ; nn < nn_max; nn++ ) { + count += __builtin_popcountl(set->__bits[nn]); + } + + return count; +} diff --git a/aosp/bionic/libc/bionic/sched_getaffinity.cpp b/aosp/bionic/libc/bionic/sched_getaffinity.cpp new file mode 100644 index 000000000..0c869e4a5 --- /dev/null +++ b/aosp/bionic/libc/bionic/sched_getaffinity.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 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. + */ + +#define _GNU_SOURCE 1 +#include +#include + +extern "C" int __sched_getaffinity(pid_t, size_t, cpu_set_t*); + +int sched_getaffinity(pid_t pid, size_t set_size, cpu_set_t* set) { + int rc = __sched_getaffinity(pid, set_size, set); + if (rc == -1) { + return -1; + } + + // Clear any bytes the kernel didn't touch. + // (The kernel returns the number of bytes written on success.) + memset(reinterpret_cast(set) + rc, 0, set_size - rc); + return 0; +} diff --git a/aosp/bionic/libc/bionic/sched_getcpu.cpp b/aosp/bionic/libc/bionic/sched_getcpu.cpp new file mode 100644 index 000000000..f245fba2f --- /dev/null +++ b/aosp/bionic/libc/bionic/sched_getcpu.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 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. + */ + +#define _GNU_SOURCE 1 +#include + +extern "C" int __getcpu(unsigned*, unsigned*, void*); + +int sched_getcpu() { + unsigned cpu; + int rc = __getcpu(&cpu, nullptr, nullptr); + if (rc == -1) { + return -1; // errno is already set. + } + return cpu; +} diff --git a/aosp/bionic/libc/bionic/scudo.h b/aosp/bionic/libc/bionic/scudo.h new file mode 100644 index 000000000..946a497bf --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include +#include +#include + +#include + +__BEGIN_DECLS + +void* scudo_aligned_alloc(size_t, size_t); +void* scudo_calloc(size_t, size_t); +void scudo_free(void*); +struct mallinfo scudo_mallinfo(); +void* scudo_malloc(size_t); +int scudo_malloc_info(int, FILE*); +size_t scudo_malloc_usable_size(const void*); +int scudo_mallopt(int, int); +void* scudo_memalign(size_t, size_t); +void* scudo_realloc(void*, size_t); +int scudo_posix_memalign(void**, size_t, size_t); +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +void* scudo_pvalloc(size_t); +void* scudo_valloc(size_t); +#endif + +int scudo_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); +void scudo_malloc_disable(); +void scudo_malloc_enable(); + +void* scudo_svelte_aligned_alloc(size_t, size_t); +void* scudo_svelte_calloc(size_t, size_t); +void scudo_svelte_free(void*); +struct mallinfo scudo_svelte_mallinfo(); +void* scudo_svelte_malloc(size_t); +int scudo_svelte_malloc_info(int, FILE*); +size_t scudo_svelte_malloc_usable_size(const void*); +int scudo_svelte_mallopt(int, int); +void* scudo_svelte_memalign(size_t, size_t); +void* scudo_svelte_realloc(void*, size_t); +int scudo_svelte_posix_memalign(void**, size_t, size_t); +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +void* scudo_svelte_pvalloc(size_t); +void* scudo_svelte_valloc(size_t); +#endif + +int scudo_svelte_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); +void scudo_svelte_malloc_disable(); +void scudo_svelte_malloc_enable(); + +__END_DECLS diff --git a/aosp/bionic/libc/bionic/scudo/Android.bp b/aosp/bionic/libc/bionic/scudo/Android.bp new file mode 100644 index 000000000..9b77c0699 --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo/Android.bp @@ -0,0 +1,63 @@ +// +// Copyright (C) 2019 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. +// + +cc_library_shared { + name: "libscudo_wrapper", + vendor_available: true, + srcs: ["scudo.cpp"], + + stl: "none", + system_shared_libs: [], + host_supported: false, + + header_libs: ["libc_headers"], + include_dirs: [ + "bionic/libc", + "bionic/libc/bionic", + ], + + whole_static_libs: ["libasync_safe"], + + arch: { + arm: { + whole_static_libs: ["libclang_rt.scudo_minimal-arm-android.static"], + }, + arm64: { + whole_static_libs: ["libclang_rt.scudo_minimal-aarch64-android.static"], + }, + x86: { + whole_static_libs: ["libclang_rt.scudo_minimal-i686-android.static"], + }, + x86_64: { + whole_static_libs: ["libclang_rt.scudo_minimal-x86_64-android.static"], + }, + }, + + // Will be referencing other libc code that won't be defined here. + allow_undefined_symbols: true, + + multilib: { + lib32: { + version_script: "exported32.map", + }, + lib64: { + version_script: "exported64.map", + }, + }, + + // Like libc, disable native coverage for libscudo_wrapper. + native_coverage: false, +} diff --git a/aosp/bionic/libc/bionic/scudo/exported32.map b/aosp/bionic/libc/bionic/scudo/exported32.map new file mode 100644 index 000000000..4b6791d26 --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo/exported32.map @@ -0,0 +1,16 @@ +LIBC_SCUDO { + global: + scudo_aligned_alloc; + scudo_calloc; + scudo_free; + scudo_mallinfo; + scudo_malloc; + scudo_malloc_usable_size; + scudo_memalign; + scudo_posix_memalign; + scudo_pvalloc; + scudo_realloc; + scudo_valloc; + local: + *; +}; diff --git a/aosp/bionic/libc/bionic/scudo/exported64.map b/aosp/bionic/libc/bionic/scudo/exported64.map new file mode 100644 index 000000000..1346b4b59 --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo/exported64.map @@ -0,0 +1,14 @@ +LIBC_SCUDO { + global: + scudo_aligned_alloc; + scudo_calloc; + scudo_free; + scudo_mallinfo; + scudo_malloc; + scudo_malloc_usable_size; + scudo_memalign; + scudo_posix_memalign; + scudo_realloc; + local: + *; +}; diff --git a/aosp/bionic/libc/bionic/scudo/scudo.cpp b/aosp/bionic/libc/bionic/scudo/scudo.cpp new file mode 100644 index 000000000..2cd36b1b0 --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo/scudo.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include +#include +#include + +#include "platform/bionic/macros.h" + +#include "scudo.h" + +// Disable Scudo's mismatch allocation check, as it is being triggered +// by some third party code. +extern "C" const char *__scudo_default_options() { + return "DeallocationTypeMismatch=false"; +} + +static inline bool AllocTooBig(size_t bytes) { +#if defined(__LP64__) + if (__predict_false(bytes > 0x10000000000ULL)) { +#else + if (__predict_false(bytes > 0x80000000ULL)) { +#endif + return true; + } + return false; +} + +void* scudo_aligned_alloc(size_t alignment, size_t size) { + if (alignment == 0 || !powerof2(alignment) || (size % alignment) != 0) { + errno = EINVAL; + return nullptr; + } + if (AllocTooBig(size)) { + errno = ENOMEM; + return nullptr; + } + + return aligned_alloc(alignment, size); +} + +void* scudo_calloc(size_t item_count, size_t item_size) { + size_t total; + if (__builtin_mul_overflow(item_count, item_size, &total) || AllocTooBig(total)) { + errno = ENOMEM; + return nullptr; + } + return calloc(item_count, item_size); +} + +void scudo_free(void* ptr) { + free(ptr); +} + +extern "C" size_t __sanitizer_get_current_allocated_bytes(); +extern "C" size_t __sanitizer_get_heap_size(); + +struct mallinfo scudo_mallinfo() { + struct mallinfo info {}; + info.uordblks = __sanitizer_get_current_allocated_bytes(); + info.hblkhd = __sanitizer_get_heap_size(); + info.usmblks = info.hblkhd; + return info; +} + +void* scudo_malloc(size_t byte_count) { + if (AllocTooBig(byte_count)) { + errno = ENOMEM; + return nullptr; + } + return malloc(byte_count); +} + +size_t scudo_malloc_usable_size(const void* ptr) { + return malloc_usable_size(ptr); +} + +void* scudo_memalign(size_t alignment, size_t byte_count) { + if (AllocTooBig(byte_count)) { + errno = ENOMEM; + return nullptr; + } + if (alignment != 0) { + if (!powerof2(alignment)) { + alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment); + } + } else { + alignment = 1; + } + return memalign(alignment, byte_count); +} + +void* scudo_realloc(void* ptr, size_t byte_count) { + if (AllocTooBig(byte_count)) { + errno = ENOMEM; + return nullptr; + } + return realloc(ptr, byte_count); +} + +int scudo_posix_memalign(void** memptr, size_t alignment, size_t size) { + if (alignment < sizeof(void*) || !powerof2(alignment)) { + return EINVAL; + } + if (AllocTooBig(size)) { + return ENOMEM; + } + return posix_memalign(memptr, alignment, size); +} + +#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) +extern "C" void* pvalloc(size_t); + +void* scudo_pvalloc(size_t size) { + if (AllocTooBig(size)) { + errno = ENOMEM; + return nullptr; + } + return pvalloc(size); +} + +extern "C" void* valloc(size_t); + +void* scudo_valloc(size_t size) { + if (AllocTooBig(size)) { + errno = ENOMEM; + return nullptr; + } + return valloc(size); +} +#endif + +// Do not try and name the scudo maps by overriding __sanitizer::internal_mmap. +// There is already a function called MmapNamed that names the maps. +// Unfortunately, there is no easy way to override MmapNamed because +// too much of the code is not compiled into functions available in the +// library, and the code is complicated. diff --git a/aosp/bionic/libc/bionic/scudo_wrapper.cpp b/aosp/bionic/libc/bionic/scudo_wrapper.cpp new file mode 100644 index 000000000..162432778 --- /dev/null +++ b/aosp/bionic/libc/bionic/scudo_wrapper.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 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 +#include + +#include "scudo.h" +#include "private/bionic_globals.h" +#include "private/WriteProtected.h" + +__LIBC_HIDDEN__ WriteProtected __libc_globals; + +// Call the libc malloc initialisers. +__attribute__((constructor(1))) static void __scudo_preinit() { + __libc_globals.mutate(__libc_init_malloc); +} + +extern "C" libc_shared_globals* __loader_shared_globals(); + +__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals() { + return __loader_shared_globals(); +} + +#if defined(__i386__) +__LIBC_HIDDEN__ void* __libc_sysinfo = reinterpret_cast(__libc_int0x80); +#endif + +extern "C" void scudo_malloc_disable_memory_tagging() {} + +int scudo_mallopt(int /*param*/, int /*value*/) { + return 0; +} + +int scudo_malloc_info(int /*options*/, FILE* /*fp*/) { + errno = ENOTSUP; + return -1; +} + +int scudo_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) { + return 0; +} + +void scudo_malloc_disable() { +} + +void scudo_malloc_enable() { +} diff --git a/aosp/bionic/libc/bionic/semaphore.cpp b/aosp/bionic/libc/bionic/semaphore.cpp new file mode 100644 index 000000000..33552a90b --- /dev/null +++ b/aosp/bionic/libc/bionic/semaphore.cpp @@ -0,0 +1,329 @@ +/* + * 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. + */ + +// Memory order requirements for POSIX semaphores appear unclear and are +// currently interpreted inconsistently. +// We conservatively prefer sequentially consistent operations for now. +// CAUTION: This is more conservative than some other major implementations, +// and may change if and when the issue is resolved. + +#include +#include +#include +#include +#include +#include + +#include "private/bionic_constants.h" +#include "private/bionic_futex.h" +#include "private/bionic_time_conversions.h" + +// In this implementation, a semaphore contains a +// 31-bit signed value and a 1-bit 'shared' flag +// (for process-sharing purpose). +// +// We use the value -1 to indicate contention on the +// semaphore, 0 or more to indicate uncontended state, +// any value lower than -2 is invalid at runtime. +// +// State diagram: +// +// post(1) ==> 2 +// post(0) ==> 1 +// post(-1) ==> 1, then wake all waiters +// +// wait(2) ==> 1 +// wait(1) ==> 0 +// wait(0) ==> -1 then wait for a wake up + loop +// wait(-1) ==> -1 then wait for a wake up + loop + +// Use the upper 31-bits for the counter, and the lower one +// for the shared flag. +#define SEMCOUNT_SHARED_MASK 0x00000001 +#define SEMCOUNT_VALUE_MASK 0xfffffffe +#define SEMCOUNT_VALUE_SHIFT 1 + +// Convert a value into the corresponding sem->count bit pattern. +#define SEMCOUNT_FROM_VALUE(val) (((val) << SEMCOUNT_VALUE_SHIFT) & SEMCOUNT_VALUE_MASK) + +// Convert a sem->count bit pattern into the corresponding signed value. +static inline int SEMCOUNT_TO_VALUE(unsigned int sval) { + return (static_cast(sval) >> SEMCOUNT_VALUE_SHIFT); +} + +// The value +1 as a sem->count bit-pattern. +#define SEMCOUNT_ONE SEMCOUNT_FROM_VALUE(1) + +// The value -1 as a sem->count bit-pattern. +#define SEMCOUNT_MINUS_ONE SEMCOUNT_FROM_VALUE(~0U) + +#define SEMCOUNT_DECREMENT(sval) (((sval) - (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK) +#define SEMCOUNT_INCREMENT(sval) (((sval) + (1U << SEMCOUNT_VALUE_SHIFT)) & SEMCOUNT_VALUE_MASK) + +static inline atomic_uint* SEM_TO_ATOMIC_POINTER(sem_t* sem) { + static_assert(sizeof(atomic_uint) == sizeof(sem->count), + "sem->count should actually be atomic_uint in implementation."); + + // We prefer casting to atomic_uint instead of declaring sem->count to be atomic_uint directly. + // Because using the second method pollutes semaphore.h. + return reinterpret_cast(&sem->count); +} + +// Return the shared bitflag from a semaphore counter. +static inline unsigned int SEM_GET_SHARED(atomic_uint* sem_count_ptr) { + // memory_order_relaxed is used as SHARED flag will not be changed after init. + return (atomic_load_explicit(sem_count_ptr, memory_order_relaxed) & SEMCOUNT_SHARED_MASK); +} + +int sem_init(sem_t* sem, int pshared, unsigned int value) { + // Ensure that 'value' can be stored in the semaphore. + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + + unsigned int count = SEMCOUNT_FROM_VALUE(value); + if (pshared != 0) { + count |= SEMCOUNT_SHARED_MASK; + } + + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + atomic_init(sem_count_ptr, count); + return 0; +} + +int sem_destroy(sem_t*) { + return 0; +} + +sem_t* sem_open(const char*, int, ...) { + errno = ENOSYS; + return SEM_FAILED; +} + +int sem_close(sem_t*) { + errno = ENOSYS; + return -1; +} + +int sem_unlink(const char*) { + errno = ENOSYS; + return -1; +} + +// Decrement a semaphore's value atomically, +// and return the old one. As a special case, +// this returns immediately if the value is +// negative (i.e. -1) +static int __sem_dec(atomic_uint* sem_count_ptr) { + unsigned int old_value = atomic_load_explicit(sem_count_ptr, memory_order_relaxed); + unsigned int shared = old_value & SEMCOUNT_SHARED_MASK; + + // Use memory_order_seq_cst in atomic_compare_exchange operation to ensure all + // memory access made by other threads can be seen in current thread. + // An acquire fence may be sufficient, but it is still in discussion whether + // POSIX semaphores should provide sequential consistency. + do { + if (SEMCOUNT_TO_VALUE(old_value) < 0) { + break; + } + } while (!atomic_compare_exchange_weak(sem_count_ptr, &old_value, + SEMCOUNT_DECREMENT(old_value) | shared)); + + return SEMCOUNT_TO_VALUE(old_value); +} + +// Same as __sem_dec, but will not touch anything if the +// value is already negative *or* 0. Returns the old value. +static int __sem_trydec(atomic_uint* sem_count_ptr) { + unsigned int old_value = atomic_load_explicit(sem_count_ptr, memory_order_relaxed); + unsigned int shared = old_value & SEMCOUNT_SHARED_MASK; + + // Use memory_order_seq_cst in atomic_compare_exchange operation to ensure all + // memory access made by other threads can be seen in current thread. + // An acquire fence may be sufficient, but it is still in discussion whether + // POSIX semaphores should provide sequential consistency. + do { + if (SEMCOUNT_TO_VALUE(old_value) <= 0) { + break; + } + } while (!atomic_compare_exchange_weak(sem_count_ptr, &old_value, + SEMCOUNT_DECREMENT(old_value) | shared)); + + return SEMCOUNT_TO_VALUE(old_value); +} + +// "Increment" the value of a semaphore atomically and +// return its old value. Note that this implements +// the special case of "incrementing" any negative +// value to +1 directly. +// +// NOTE: The value will _not_ wrap above SEM_VALUE_MAX +static int __sem_inc(atomic_uint* sem_count_ptr) { + unsigned int old_value = atomic_load_explicit(sem_count_ptr, memory_order_relaxed); + unsigned int shared = old_value & SEMCOUNT_SHARED_MASK; + unsigned int new_value; + + // Use memory_order_seq_cst in atomic_compare_exchange operation to ensure all + // memory access made before can be seen in other threads. + // A release fence may be sufficient, but it is still in discussion whether + // POSIX semaphores should provide sequential consistency. + do { + // Can't go higher than SEM_VALUE_MAX. + if (SEMCOUNT_TO_VALUE(old_value) == SEM_VALUE_MAX) { + break; + } + + // If the counter is negative, go directly to one, otherwise just increment. + if (SEMCOUNT_TO_VALUE(old_value) < 0) { + new_value = SEMCOUNT_ONE | shared; + } else { + new_value = SEMCOUNT_INCREMENT(old_value) | shared; + } + } while (!atomic_compare_exchange_weak(sem_count_ptr, &old_value, + new_value)); + + return SEMCOUNT_TO_VALUE(old_value); +} + +int sem_wait(sem_t* sem) { + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + unsigned int shared = SEM_GET_SHARED(sem_count_ptr); + + while (true) { + if (__sem_dec(sem_count_ptr) > 0) { + return 0; + } + + int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, false, nullptr); + if (android_get_application_target_sdk_version() >= 24) { + if (result ==-EINTR) { + errno = EINTR; + return -1; + } + } + } +} + +static int __sem_timedwait(sem_t* sem, const timespec* abs_timeout, bool use_realtime_clock) { + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + + // POSIX says we need to try to decrement the semaphore + // before checking the timeout value. Note that if the + // value is currently 0, __sem_trydec() does nothing. + if (__sem_trydec(sem_count_ptr) > 0) { + return 0; + } + + // Check it as per POSIX. + int result = check_timespec(abs_timeout, false); + if (result != 0) { + errno = result; + return -1; + } + + unsigned int shared = SEM_GET_SHARED(sem_count_ptr); + + while (true) { + // Try to grab the semaphore. If the value was 0, this will also change it to -1. + if (__sem_dec(sem_count_ptr) > 0) { + return 0; + } + + // Contention detected. Wait for a wakeup event. + int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, + use_realtime_clock, abs_timeout); + + // Return in case of timeout or interrupt. + if (result == -ETIMEDOUT || result == -EINTR) { + errno = -result; + return -1; + } + } +} + +int sem_timedwait(sem_t* sem, const timespec* abs_timeout) { + return __sem_timedwait(sem, abs_timeout, true); +} + +int sem_timedwait_monotonic_np(sem_t* sem, const timespec* abs_timeout) { + return __sem_timedwait(sem, abs_timeout, false); +} + +int sem_clockwait(sem_t* sem, clockid_t clock, const timespec* abs_timeout) { + switch (clock) { + case CLOCK_MONOTONIC: + return sem_timedwait_monotonic_np(sem, abs_timeout); + case CLOCK_REALTIME: + return sem_timedwait(sem, abs_timeout); + default: + return EINVAL; + } +} + +int sem_post(sem_t* sem) { + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + unsigned int shared = SEM_GET_SHARED(sem_count_ptr); + + int old_value = __sem_inc(sem_count_ptr); + if (old_value < 0) { + // Contention on the semaphore. Wake up all waiters. + __futex_wake_ex(sem_count_ptr, shared, INT_MAX); + } else if (old_value == SEM_VALUE_MAX) { + // Overflow detected. + errno = EOVERFLOW; + return -1; + } + + return 0; +} + +int sem_trywait(sem_t* sem) { + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + if (__sem_trydec(sem_count_ptr) > 0) { + return 0; + } else { + errno = EAGAIN; + return -1; + } +} + +int sem_getvalue(sem_t* sem, int* sval) { + atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem); + + // Use memory_order_seq_cst in atomic_load operation. + // memory_order_relaxed may be fine here, but it is still in discussion + // whether POSIX semaphores should provide sequential consistency. + int val = SEMCOUNT_TO_VALUE(atomic_load(sem_count_ptr)); + if (val < 0) { + val = 0; + } + + *sval = val; + return 0; +} diff --git a/aosp/bionic/libc/bionic/send.cpp b/aosp/bionic/libc/bionic/send.cpp new file mode 100644 index 000000000..7106c430f --- /dev/null +++ b/aosp/bionic/libc/bionic/send.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +ssize_t send(int socket, const void* buf, size_t len, int flags) { + return sendto(socket, buf, len, flags, nullptr, 0); +} diff --git a/aosp/bionic/libc/bionic/setegid.cpp b/aosp/bionic/libc/bionic/setegid.cpp new file mode 100644 index 000000000..2030ee7a7 --- /dev/null +++ b/aosp/bionic/libc/bionic/setegid.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int setegid(gid_t egid) { + return setresgid(-1, egid, -1); +} diff --git a/aosp/bionic/libc/bionic/seteuid.cpp b/aosp/bionic/libc/bionic/seteuid.cpp new file mode 100644 index 000000000..6d2c89c08 --- /dev/null +++ b/aosp/bionic/libc/bionic/seteuid.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int seteuid(uid_t euid) { + return setresuid(-1, euid,-1); +} diff --git a/aosp/bionic/libc/bionic/setjmp_cookie.cpp b/aosp/bionic/libc/bionic/setjmp_cookie.cpp new file mode 100644 index 000000000..e2a3fc098 --- /dev/null +++ b/aosp/bionic/libc/bionic/setjmp_cookie.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "private/bionic_arc4random.h" +#include "private/bionic_globals.h" + +void __libc_init_setjmp_cookie(libc_globals* globals) { + long value; + __libc_safe_arc4random_buf(&value, sizeof(value)); + + // Mask off the last bit to store the signal flag. + globals->setjmp_cookie = value & ~1; +} + +extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_get(long sigflag) { + if (sigflag & ~1) { + async_safe_fatal("unexpected sigflag value: %ld", sigflag); + } + + return __libc_globals->setjmp_cookie | sigflag; +} + +// Aborts if cookie doesn't match, returns the signal flag otherwise. +extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_cookie_check(long cookie) { + if (__libc_globals->setjmp_cookie != (cookie & ~1)) { + async_safe_fatal("setjmp cookie mismatch"); + } + + return cookie & 1; +} + +extern "C" __LIBC_HIDDEN__ long __bionic_setjmp_checksum_mismatch() { + async_safe_fatal("setjmp checksum mismatch"); +} diff --git a/aosp/bionic/libc/bionic/setpgrp.cpp b/aosp/bionic/libc/bionic/setpgrp.cpp new file mode 100644 index 000000000..4334cd167 --- /dev/null +++ b/aosp/bionic/libc/bionic/setpgrp.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int setpgrp() { + return setpgid(0, 0); +} diff --git a/aosp/bionic/libc/bionic/sigaction.cpp b/aosp/bionic/libc/bionic/sigaction.cpp new file mode 100644 index 000000000..583bf32ce --- /dev/null +++ b/aosp/bionic/libc/bionic/sigaction.cpp @@ -0,0 +1,137 @@ +/* + * 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 +#include + +#include + +extern "C" void __restore_rt(void); +extern "C" void __restore(void); + +#if defined(__LP64__) + +extern "C" int __rt_sigaction(int, const struct __kernel_sigaction*, struct __kernel_sigaction*, size_t); + +int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) { + __kernel_sigaction kernel_new_action; + if (bionic_new_action != nullptr) { + kernel_new_action.sa_flags = bionic_new_action->sa_flags; + kernel_new_action.sa_handler = bionic_new_action->sa_handler; + // Don't filter signals here; if the caller asked for everything to be blocked, we should obey. + kernel_new_action.sa_mask = bionic_new_action->sa_mask; +#if defined(SA_RESTORER) + kernel_new_action.sa_restorer = bionic_new_action->sa_restorer; +#if defined(__aarch64__) + // arm64 has sa_restorer, but unwinding works best if you just let the + // kernel supply the default restorer from [vdso]. gdb doesn't care, but + // libgcc needs the nop that the kernel includes before the actual code. + // (We could add that ourselves, but why bother?) +#else + if (!(kernel_new_action.sa_flags & SA_RESTORER)) { + kernel_new_action.sa_flags |= SA_RESTORER; + kernel_new_action.sa_restorer = &__restore_rt; + } +#endif +#endif + } + + __kernel_sigaction kernel_old_action; + int result = __rt_sigaction(signal, + (bionic_new_action != nullptr) ? &kernel_new_action : nullptr, + (bionic_old_action != nullptr) ? &kernel_old_action : nullptr, + sizeof(sigset_t)); + + if (bionic_old_action != nullptr) { + bionic_old_action->sa_flags = kernel_old_action.sa_flags; + bionic_old_action->sa_handler = kernel_old_action.sa_handler; + bionic_old_action->sa_mask = kernel_old_action.sa_mask; +#if defined(SA_RESTORER) + bionic_old_action->sa_restorer = kernel_old_action.sa_restorer; +#endif + } + + return result; +} + +__strong_alias(sigaction64, sigaction); + +#else + +extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t); + +int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) { + // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t, + // so we have to translate to struct sigaction64 first. + struct sigaction64 kernel_new; + if (bionic_new) { + kernel_new = {}; + kernel_new.sa_flags = bionic_new->sa_flags; + kernel_new.sa_handler = bionic_new->sa_handler; +#if defined(SA_RESTORER) + kernel_new.sa_restorer = bionic_new->sa_restorer; +#endif + // Don't filter signals here; if the caller asked for everything to be blocked, we should obey. + memcpy(&kernel_new.sa_mask, &bionic_new->sa_mask, sizeof(bionic_new->sa_mask)); + } + + struct sigaction64 kernel_old; + int result = sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old); + if (bionic_old) { + *bionic_old = {}; + bionic_old->sa_flags = kernel_old.sa_flags; + bionic_old->sa_handler = kernel_old.sa_handler; +#if defined(SA_RESTORER) + bionic_old->sa_restorer = kernel_old.sa_restorer; +#endif + memcpy(&bionic_old->sa_mask, &kernel_old.sa_mask, sizeof(bionic_old->sa_mask)); + } + return result; +} + +int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigaction64* bionic_old) { + struct sigaction64 kernel_new; + if (bionic_new) { + kernel_new = *bionic_new; +#if defined(SA_RESTORER) + if (!(kernel_new.sa_flags & SA_RESTORER)) { + kernel_new.sa_flags |= SA_RESTORER; + kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore; + } +#endif + // Don't filter signals here; if the caller asked for everything to be blocked, we should obey. + kernel_new.sa_mask = kernel_new.sa_mask; + } + + return __rt_sigaction(signal, + bionic_new ? &kernel_new : nullptr, + bionic_old, + sizeof(kernel_new.sa_mask)); +} + +#endif diff --git a/aosp/bionic/libc/bionic/signal.cpp b/aosp/bionic/libc/bionic/signal.cpp new file mode 100644 index 000000000..b581b5a2e --- /dev/null +++ b/aosp/bionic/libc/bionic/signal.cpp @@ -0,0 +1,314 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "private/ErrnoRestorer.h" +#include "private/SigSetConverter.h" + +extern "C" int __rt_sigpending(const sigset64_t*, size_t); +extern "C" int __rt_sigqueueinfo(pid_t, int, siginfo_t*); +extern "C" int __rt_sigsuspend(const sigset64_t*, size_t); +extern "C" int __rt_sigtimedwait(const sigset64_t*, siginfo_t*, const timespec*, size_t); + +int pthread_sigmask(int how, const sigset_t* new_set, sigset_t* old_set) { + ErrnoRestorer errno_restorer; + return (sigprocmask(how, new_set, old_set) == -1) ? errno : 0; +} + +int pthread_sigmask64(int how, const sigset64_t* new_set, sigset64_t* old_set) { + ErrnoRestorer errno_restorer; + return (sigprocmask64(how, new_set, old_set) == -1) ? errno : 0; +} + +template +int SigAddSet(SigSetT* set, int sig) { + int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long* local_set = reinterpret_cast(set); + if (set == nullptr || bit < 0 || bit >= static_cast(8*sizeof(*set))) { + errno = EINVAL; + return -1; + } + local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); + return 0; +} + +int sigaddset(sigset_t* set, int sig) { + return SigAddSet(set, sig); +} + +int sigaddset64(sigset64_t* set, int sig) { + return SigAddSet(set, sig); +} + +// This isn't in our header files, but is exposed on all architectures. +extern "C" int sigblock(int mask) { + SigSetConverter in, out; + sigemptyset(&in.sigset); + in.bsd = mask; + if (sigprocmask(SIG_BLOCK, &in.sigset, &out.sigset) == -1) return -1; + return out.bsd; +} + +template +int SigDelSet(SigSetT* set, int sig) { + int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long* local_set = reinterpret_cast(set); + if (set == nullptr || bit < 0 || bit >= static_cast(8*sizeof(*set))) { + errno = EINVAL; + return -1; + } + local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT)); + return 0; +} + +int sigdelset(sigset_t* set, int sig) { + return SigDelSet(set, sig); +} + +int sigdelset64(sigset64_t* set, int sig) { + return SigDelSet(set, sig); +} + +template +int SigEmptySet(SigSetT* set) { + if (set == nullptr) { + errno = EINVAL; + return -1; + } + memset(set, 0, sizeof(*set)); + return 0; +} + +int sigemptyset(sigset_t* set) { + return SigEmptySet(set); +} + +int sigemptyset64(sigset64_t* set) { + return SigEmptySet(set); +} + +template +int SigFillSet(SigSetT* set) { + if (set == nullptr) { + errno = EINVAL; + return -1; + } + memset(set, 0xff, sizeof(*set)); + return 0; +} + +int sigfillset(sigset_t* set) { + return SigFillSet(set); +} + +int sigfillset64(sigset64_t* set) { + return SigFillSet(set); +} + +int sighold(int sig) { + sigset64_t set = {}; + if (sigaddset64(&set, sig) == -1) return -1; + return sigprocmask64(SIG_BLOCK, &set, nullptr); +} + +int sigignore(int sig) { + struct sigaction64 sa = { .sa_handler = SIG_IGN }; + return sigaction64(sig, &sa, nullptr); +} + +int siginterrupt(int sig, int flag) { + struct sigaction64 act; + sigaction64(sig, nullptr, &act); + if (flag) { + act.sa_flags &= ~SA_RESTART; + } else { + act.sa_flags |= SA_RESTART; + } + return sigaction64(sig, &act, nullptr); +} + +template +int SigIsMember(const SigSetT* set, int sig) { + int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0. + const unsigned long* local_set = reinterpret_cast(set); + if (set == nullptr || bit < 0 || bit >= static_cast(8*sizeof(*set))) { + errno = EINVAL; + return -1; + } + return static_cast((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1); +} + +int sigismember(const sigset_t* set, int sig) { + return SigIsMember(set, sig); +} + +int sigismember64(const sigset64_t* set, int sig) { + return SigIsMember(set, sig); +} + +__LIBC_HIDDEN__ sighandler_t _signal(int sig, sighandler_t handler, int flags) { + struct sigaction64 sa = { .sa_handler = handler, .sa_flags = flags }; + return (sigaction64(sig, &sa, &sa) == -1) ? SIG_ERR : sa.sa_handler; +} + +sighandler_t signal(int sig, sighandler_t handler) { + return _signal(sig, handler, SA_RESTART); +} + +int sigpause(int sig) { + sigset64_t set = {}; + if (sigprocmask64(SIG_SETMASK, nullptr, &set) == -1 || sigdelset64(&set, sig) == -1) return -1; + return sigsuspend64(&set); +} + +int sigpending(sigset_t* bionic_set) { + SigSetConverter set = {}; + set.sigset = *bionic_set; + if (__rt_sigpending(&set.sigset64, sizeof(set.sigset64)) == -1) return -1; + *bionic_set = set.sigset; + return 0; +} + +int sigpending64(sigset64_t* set) { + return __rt_sigpending(set, sizeof(*set)); +} + +int sigqueue(pid_t pid, int sig, const sigval value) { + siginfo_t info; + memset(&info, 0, sizeof(siginfo_t)); + info.si_signo = sig; + info.si_code = SI_QUEUE; + info.si_pid = getpid(); + info.si_uid = getuid(); + info.si_value = value; + return __rt_sigqueueinfo(pid, sig, &info); +} + +int sigrelse(int sig) { + sigset64_t set = {}; + if (sigaddset64(&set, sig) == -1) return -1; + return sigprocmask64(SIG_UNBLOCK, &set, nullptr); +} + +sighandler_t sigset(int sig, sighandler_t disp) { + struct sigaction64 new_sa; + if (disp != SIG_HOLD) new_sa = { .sa_handler = disp }; + + struct sigaction64 old_sa; + if (sigaction64(sig, (disp == SIG_HOLD) ? nullptr : &new_sa, &old_sa) == -1) { + return SIG_ERR; + } + + sigset64_t new_mask = {}; + sigaddset64(&new_mask, sig); + sigset64_t old_mask; + if (sigprocmask64(disp == SIG_HOLD ? SIG_BLOCK : SIG_UNBLOCK, &new_mask, &old_mask) == -1) { + return SIG_ERR; + } + + return sigismember64(&old_mask, sig) ? SIG_HOLD : old_sa.sa_handler; +} + +// This isn't in our header files, but is exposed on all architectures. +extern "C" int sigsetmask(int mask) { + SigSetConverter in, out; + sigemptyset(&in.sigset); + in.bsd = mask; + if (sigprocmask(SIG_SETMASK, &in.sigset, &out.sigset) == -1) return -1; + return out.bsd; +} + +int sigsuspend(const sigset_t* bionic_set) { + SigSetConverter set = {}; + set.sigset = *bionic_set; + return sigsuspend64(&set.sigset64); +} + +int sigsuspend64(const sigset64_t* set) { + sigset64_t mutable_set; + sigset64_t* mutable_set_ptr = nullptr; + if (set) { + mutable_set = filter_reserved_signals(*set, SIG_SETMASK); + mutable_set_ptr = &mutable_set; + } + return __rt_sigsuspend(mutable_set_ptr, sizeof(*set)); +} + +int sigtimedwait(const sigset_t* bionic_set, siginfo_t* info, const timespec* timeout) { + SigSetConverter set = {}; + set.sigset = *bionic_set; + return sigtimedwait64(&set.sigset64, info, timeout); +} + +int sigtimedwait64(const sigset64_t* set, siginfo_t* info, const timespec* timeout) { + sigset64_t mutable_set; + sigset64_t* mutable_set_ptr = nullptr; + if (set) { + mutable_set = filter_reserved_signals(*set, SIG_SETMASK); + mutable_set_ptr = &mutable_set; + } + return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set)); +} + +int sigwait(const sigset_t* bionic_set, int* sig) { + SigSetConverter set = {}; + set.sigset = *bionic_set; + return sigwait64(&set.sigset64, sig); +} + +int sigwait64(const sigset64_t* set, int* sig) { + while (true) { + // __rt_sigtimedwait can return EAGAIN or EINTR, we need to loop + // around them since sigwait is only allowed to return EINVAL. + int result = sigtimedwait64(set, nullptr, nullptr); + if (result >= 0) { + *sig = result; + return 0; + } + if (errno != EAGAIN && errno != EINTR) return errno; + } +} + +int sigwaitinfo(const sigset_t* set, siginfo_t* info) { + return sigtimedwait(set, info, nullptr); +} + +int sigwaitinfo64(const sigset64_t* set, siginfo_t* info) { + return sigtimedwait64(set, info, nullptr); +} diff --git a/aosp/bionic/libc/bionic/sigprocmask.cpp b/aosp/bionic/libc/bionic/sigprocmask.cpp new file mode 100644 index 000000000..8781c9b4d --- /dev/null +++ b/aosp/bionic/libc/bionic/sigprocmask.cpp @@ -0,0 +1,83 @@ +/* + * 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 +#include + +#include + +#include "private/SigSetConverter.h" + +extern "C" int __rt_sigprocmask(int, const sigset64_t*, sigset64_t*, size_t); + +// +// These need to be kept separate from pthread_sigmask, sigblock, sigsetmask, +// sighold, and sigset because libsigchain only intercepts sigprocmask so we +// can't allow clang to decide to inline sigprocmask. +// + +int sigprocmask(int how, + const sigset_t* bionic_new_set, + sigset_t* bionic_old_set) __attribute__((__noinline__)) { + SigSetConverter new_set; + sigset64_t* new_set_ptr = nullptr; + if (bionic_new_set != nullptr) { + sigemptyset64(&new_set.sigset64); + new_set.sigset = *bionic_new_set; + new_set_ptr = &new_set.sigset64; + } + + SigSetConverter old_set; + if (sigprocmask64(how, new_set_ptr, &old_set.sigset64) == -1) { + return -1; + } + + if (bionic_old_set != nullptr) { + *bionic_old_set = old_set.sigset; + } + + return 0; +} + +int sigprocmask64(int how, + const sigset64_t* new_set, + sigset64_t* old_set) __attribute__((__noinline__)) { + // how is only checked for validity if new_set is provided. + if (new_set && how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) { + errno = EINVAL; + return -1; + } + + sigset64_t mutable_new_set; + sigset64_t* mutable_new_set_ptr = nullptr; + if (new_set) { + mutable_new_set = filter_reserved_signals(*new_set, how); + mutable_new_set_ptr = &mutable_new_set; + } + return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set)); +} diff --git a/aosp/bionic/libc/bionic/sleep.cpp b/aosp/bionic/libc/bionic/sleep.cpp new file mode 100644 index 000000000..fcfd9b2a0 --- /dev/null +++ b/aosp/bionic/libc/bionic/sleep.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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 + +#include + +unsigned sleep(unsigned s) { +#if !defined(__LP64__) + // `s` is `unsigned`, but tv_sec is `int` on LP32. + if (s > INT_MAX) return s - INT_MAX + sleep(INT_MAX); +#endif + + timespec ts = {.tv_sec = static_cast(s)}; + return (nanosleep(&ts, &ts) == -1) ? ts.tv_sec : 0; +} diff --git a/aosp/bionic/libc/bionic/socketpair.cpp b/aosp/bionic/libc/bionic/socketpair.cpp new file mode 100644 index 000000000..d2b4c1907 --- /dev/null +++ b/aosp/bionic/libc/bionic/socketpair.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 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 +#include + +#include "private/bionic_fdtrack.h" + +extern "C" int __socketpair(int domain, int type, int protocol, int sv[2]); + +int socketpair(int domain, int type, int protocol, int sv[2]) { + int rc = __socketpair(domain, type, protocol, sv); + if (rc == 0) { + FDTRACK_CREATE(sv[0]); + FDTRACK_CREATE(sv[1]); + } + return rc; +} diff --git a/aosp/bionic/libc/bionic/spawn.cpp b/aosp/bionic/libc/bionic/spawn.cpp new file mode 100644 index 000000000..e73828f32 --- /dev/null +++ b/aosp/bionic/libc/bionic/spawn.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2017 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 + +#include +#include +#include +#include +#include +#include + +#include + +#include "private/ScopedSignalBlocker.h" +#include "private/SigSetConverter.h" + +enum Action { + kOpen, + kClose, + kDup2 +}; + +struct __posix_spawn_file_action { + __posix_spawn_file_action* next; + + Action what; + int fd; + int new_fd; + char* path; + int flags; + mode_t mode; + + void Do() { + if (what == kOpen) { + fd = open(path, flags, mode); + if (fd == -1) _exit(127); + // If it didn't land where we wanted it, move it. + if (fd != new_fd) { + if (dup2(fd, new_fd) == -1) _exit(127); + close(fd); + } + } else if (what == kClose) { + // Failure to close is ignored. + close(fd); + } else { + if (dup2(fd, new_fd) == -1) _exit(127); + } + } +}; + +struct __posix_spawn_file_actions { + __posix_spawn_file_action* head; + __posix_spawn_file_action* last; + + void Do() { + for (__posix_spawn_file_action* action = head; action != nullptr; action = action->next) { + action->Do(); + } + } +}; + +struct __posix_spawnattr { + short flags; + pid_t pgroup; + sched_param schedparam; + int schedpolicy; + SigSetConverter sigmask; + SigSetConverter sigdefault; +}; + +static void ApplyAttrs(short flags, const posix_spawnattr_t* attr) { + // POSIX: "If POSIX_SPAWN_SETSIGDEF is set ... signals in sigdefault ... + // shall be set to their default actions in the child process." + // POSIX: "Signals set to be caught by the calling process shall be + // set to the default action in the child process." + bool use_sigdefault = ((flags & POSIX_SPAWN_SETSIGDEF) != 0); + const struct sigaction64 default_sa = { .sa_handler = SIG_DFL }; + for (int s = 1; s < _NSIG; ++s) { + bool reset = false; + if (use_sigdefault && sigismember64(&(*attr)->sigdefault.sigset64, s)) { + reset = true; + } else { + struct sigaction64 current; + if (sigaction64(s, nullptr, ¤t) == -1) _exit(127); + reset = (current.sa_handler != SIG_IGN && current.sa_handler != SIG_DFL); + } + if (reset && sigaction64(s, &default_sa, nullptr) == -1) _exit(127); + } + + if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid(0, (*attr)->pgroup) == -1) _exit(127); + if ((flags & POSIX_SPAWN_SETSID) != 0 && setsid() == -1) _exit(127); + + // POSIX_SPAWN_SETSCHEDULER overrides POSIX_SPAWN_SETSCHEDPARAM, but it is not an error + // to set both. + if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) { + if (sched_setscheduler(0, (*attr)->schedpolicy, &(*attr)->schedparam) == -1) _exit(127); + } else if ((flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) { + if (sched_setparam(0, &(*attr)->schedparam) == -1) _exit(127); + } + + if ((flags & POSIX_SPAWN_RESETIDS) != 0) { + if (seteuid(getuid()) == -1 || setegid(getgid()) == -1) _exit(127); + } + + if ((flags & POSIX_SPAWN_SETSIGMASK) != 0) { + if (sigprocmask64(SIG_SETMASK, &(*attr)->sigmask.sigset64, nullptr)) _exit(127); + } +} + +static int posix_spawn(pid_t* pid_ptr, + const char* path, + const posix_spawn_file_actions_t* actions, + const posix_spawnattr_t* attr, + char* const argv[], + char* const env[], + int exec_fn(const char* path, char* const argv[], char* const env[])) { + // See http://man7.org/linux/man-pages/man3/posix_spawn.3.html + // and http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html + + ScopedSignalBlocker ssb; + + short flags = attr ? (*attr)->flags : 0; + bool use_vfork = ((flags & POSIX_SPAWN_USEVFORK) != 0) || (actions == nullptr && flags == 0); + + pid_t pid = use_vfork ? vfork() : fork(); + if (pid == -1) return errno; + + if (pid == 0) { + // Child. + ApplyAttrs(flags, attr); + if (actions) (*actions)->Do(); + if ((flags & POSIX_SPAWN_SETSIGMASK) == 0) ssb.reset(); + exec_fn(path, argv, env ? env : environ); + _exit(127); + } + + // Parent. + if (pid_ptr) *pid_ptr = pid; + return 0; +} + +int posix_spawn(pid_t* pid, const char* path, const posix_spawn_file_actions_t* actions, + const posix_spawnattr_t* attr, char* const argv[], char* const env[]) { + return posix_spawn(pid, path, actions, attr, argv, env, execve); +} + +int posix_spawnp(pid_t* pid, const char* file, const posix_spawn_file_actions_t* actions, + const posix_spawnattr_t* attr, char* const argv[], char* const env[]) { + return posix_spawn(pid, file, actions, attr, argv, env, execvpe); +} + +int posix_spawnattr_init(posix_spawnattr_t* attr) { + *attr = reinterpret_cast<__posix_spawnattr*>(calloc(1, sizeof(__posix_spawnattr))); + return (*attr == nullptr) ? errno : 0; +} + +int posix_spawnattr_destroy(posix_spawnattr_t* attr) { + free(*attr); + *attr = nullptr; + return 0; +} + +int posix_spawnattr_setflags(posix_spawnattr_t* attr, short flags) { + if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | + POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID)) != 0) { + return EINVAL; + } + (*attr)->flags = flags; + return 0; +} + +int posix_spawnattr_getflags(const posix_spawnattr_t* attr, short* flags) { + *flags = (*attr)->flags; + return 0; +} + +int posix_spawnattr_setpgroup(posix_spawnattr_t* attr, pid_t pgroup) { + (*attr)->pgroup = pgroup; + return 0; +} + +int posix_spawnattr_getpgroup(const posix_spawnattr_t* attr, pid_t* pgroup) { + *pgroup = (*attr)->pgroup; + return 0; +} + +int posix_spawnattr_setsigmask(posix_spawnattr_t* attr, const sigset_t* mask) { + (*attr)->sigmask.sigset = *mask; + return 0; +} + +int posix_spawnattr_setsigmask64(posix_spawnattr_t* attr, const sigset64_t* mask) { + (*attr)->sigmask.sigset64 = *mask; + return 0; +} + +int posix_spawnattr_getsigmask(const posix_spawnattr_t* attr, sigset_t* mask) { + *mask = (*attr)->sigmask.sigset; + return 0; +} + +int posix_spawnattr_getsigmask64(const posix_spawnattr_t* attr, sigset64_t* mask) { + *mask = (*attr)->sigmask.sigset64; + return 0; +} + +int posix_spawnattr_setsigdefault(posix_spawnattr_t* attr, const sigset_t* mask) { + (*attr)->sigdefault.sigset = *mask; + return 0; +} + +int posix_spawnattr_setsigdefault64(posix_spawnattr_t* attr, const sigset64_t* mask) { + (*attr)->sigdefault.sigset64 = *mask; + return 0; +} + +int posix_spawnattr_getsigdefault(const posix_spawnattr_t* attr, sigset_t* mask) { + *mask = (*attr)->sigdefault.sigset; + return 0; +} + +int posix_spawnattr_getsigdefault64(const posix_spawnattr_t* attr, sigset64_t* mask) { + *mask = (*attr)->sigdefault.sigset64; + return 0; +} + +int posix_spawnattr_setschedparam(posix_spawnattr_t* attr, const struct sched_param* param) { + (*attr)->schedparam = *param; + return 0; +} + +int posix_spawnattr_getschedparam(const posix_spawnattr_t* attr, struct sched_param* param) { + *param = (*attr)->schedparam; + return 0; +} + +int posix_spawnattr_setschedpolicy(posix_spawnattr_t* attr, int policy) { + (*attr)->schedpolicy = policy; + return 0; +} + +int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* attr, int* policy) { + *policy = (*attr)->schedpolicy; + return 0; +} + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t* actions) { + *actions = reinterpret_cast<__posix_spawn_file_actions*>(calloc(1, sizeof(**actions))); + return (*actions == nullptr) ? errno : 0; +} + +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* actions) { + __posix_spawn_file_action* a = (*actions)->head; + while (a) { + __posix_spawn_file_action* last = a; + a = a->next; + free(last->path); + free(last); + } + free(*actions); + *actions = nullptr; + return 0; +} + +static int posix_spawn_add_file_action(posix_spawn_file_actions_t* actions, + Action what, + int fd, + int new_fd, + const char* path, + int flags, + mode_t mode) { + __posix_spawn_file_action* action = + reinterpret_cast<__posix_spawn_file_action*>(malloc(sizeof(*action))); + if (action == nullptr) return errno; + + action->next = nullptr; + if (path != nullptr) { + action->path = strdup(path); + if (action->path == nullptr) { + free(action); + return errno; + } + } else { + action->path = nullptr; + } + action->what = what; + action->fd = fd; + action->new_fd = new_fd; + action->flags = flags; + action->mode = mode; + + if ((*actions)->head == nullptr) { + (*actions)->head = (*actions)->last = action; + } else { + (*actions)->last->next = action; + (*actions)->last = action; + } + + return 0; +} + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* actions, + int fd, const char* path, int flags, mode_t mode) { + if (fd < 0) return EBADF; + return posix_spawn_add_file_action(actions, kOpen, -1, fd, path, flags, mode); +} + +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* actions, int fd) { + if (fd < 0) return EBADF; + return posix_spawn_add_file_action(actions, kClose, fd, -1, nullptr, 0, 0); +} + +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* actions, int fd, int new_fd) { + if (fd < 0 || new_fd < 0) return EBADF; + return posix_spawn_add_file_action(actions, kDup2, fd, new_fd, nullptr, 0, 0); +} diff --git a/aosp/bionic/libc/bionic/stat.cpp b/aosp/bionic/libc/bionic/stat.cpp new file mode 100644 index 000000000..e71d9d408 --- /dev/null +++ b/aosp/bionic/libc/bionic/stat.cpp @@ -0,0 +1,37 @@ +/* + * 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 +#include +#include +#include + +int stat(const char* path, struct stat* sb) { + return fstatat(AT_FDCWD, path, sb, 0); +} +__strong_alias(stat64, stat); diff --git a/aosp/bionic/libc/bionic/stdlib_l.cpp b/aosp/bionic/libc/bionic/stdlib_l.cpp new file mode 100644 index 000000000..18e9f86fa --- /dev/null +++ b/aosp/bionic/libc/bionic/stdlib_l.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 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 +#include + +double strtod_l(const char* s, char** end_ptr, locale_t) { + return strtod(s, end_ptr); +} + +float strtof_l(const char* s, char** end_ptr, locale_t) { + return strtof(s, end_ptr); +} + +long strtol_l(const char* s, char** end_ptr, int base, locale_t) { + return strtol(s, end_ptr, base); +} + +long double strtold_l(const char* s, char** end_ptr, locale_t) { + return strtold(s, end_ptr); +} + +long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) { + return strtoll(s, end_ptr, base); +} + +unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) { + return strtoul(s, end_ptr, base); +} + +unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) { + return strtoull(s, end_ptr, base); +} + diff --git a/aosp/bionic/libc/bionic/strchr.cpp b/aosp/bionic/libc/bionic/strchr.cpp new file mode 100644 index 000000000..fd8a924a9 --- /dev/null +++ b/aosp/bionic/libc/bionic/strchr.cpp @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 1990 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 + +char* strchr(const char* p, int ch) { + return __strchr_chk(p, ch, __BIONIC_FORTIFY_UNKNOWN_SIZE); +} diff --git a/aosp/bionic/libc/bionic/strchrnul.cpp b/aosp/bionic/libc/bionic/strchrnul.cpp new file mode 100644 index 000000000..55422e06d --- /dev/null +++ b/aosp/bionic/libc/bionic/strchrnul.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2015 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. + */ + +extern "C" const char* strchrnul(const char* s, int ch) { + while (*s && *s != ch) { + ++s; + } + return s; +} diff --git a/aosp/bionic/libc/bionic/strerror.cpp b/aosp/bionic/libc/bionic/strerror.cpp new file mode 100644 index 000000000..57335674b --- /dev/null +++ b/aosp/bionic/libc/bionic/strerror.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2012 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. + */ + +// G++ automatically defines _GNU_SOURCE, which then means that +// gives us the GNU variant. +#undef _GNU_SOURCE + +#include + +#include +#include + +#include + +#include "private/ErrnoRestorer.h" + +#include + +#include "bionic/pthread_internal.h" + +static const char* __sys_error_strings[] = { + [0] = "Success", + [EPERM] = "Operation not permitted", + [ENOENT] = "No such file or directory", + [ESRCH] = "No such process", + [EINTR] = "Interrupted system call", + [EIO] = "I/O error", + [ENXIO] = "No such device or address", + [E2BIG] = "Argument list too long", + [ENOEXEC] = "Exec format error", + [EBADF] = "Bad file descriptor", + [ECHILD] = "No child processes", + [EAGAIN] = "Try again", + [ENOMEM] = "Out of memory", + [EACCES] = "Permission denied", + [EFAULT] = "Bad address", + [ENOTBLK] = "Block device required", + [EBUSY] = "Device or resource busy", + [EEXIST] = "File exists", + [EXDEV] = "Cross-device link", + [ENODEV] = "No such device", + [ENOTDIR] = "Not a directory", + [EISDIR] = "Is a directory", + [EINVAL] = "Invalid argument", + [ENFILE] = "File table overflow", + [EMFILE] = "Too many open files", + [ENOTTY] = "Inappropriate ioctl for device", + [ETXTBSY] = "Text file busy", + [EFBIG] = "File too large", + [ENOSPC] = "No space left on device", + [ESPIPE] = "Illegal seek", + [EROFS] = "Read-only file system", + [EMLINK] = "Too many links", + [EPIPE] = "Broken pipe", + [EDOM] = "Math argument out of domain of func", + [ERANGE] = "Math result not representable", + [EDEADLK] = "Resource deadlock would occur", + [ENAMETOOLONG] = "File name too long", + [ENOLCK] = "No record locks available", + [ENOSYS] = "Function not implemented", + [ENOTEMPTY] = "Directory not empty", + [ELOOP] = "Too many symbolic links encountered", + [ENOMSG] = "No message of desired type", + [EIDRM] = "Identifier removed", + [ECHRNG] = "Channel number out of range", + [EL2NSYNC] = "Level 2 not synchronized", + [EL3HLT] = "Level 3 halted", + [EL3RST] = "Level 3 reset", + [ELNRNG] = "Link number out of range", + [EUNATCH] = "Protocol driver not attached", + [ENOCSI] = "No CSI structure available", + [EL2HLT] = "Level 2 halted", + [EBADE] = "Invalid exchange", + [EBADR] = "Invalid request descriptor", + [EXFULL] = "Exchange full", + [ENOANO] = "No anode", + [EBADRQC] = "Invalid request code", + [EBADSLT] = "Invalid slot", + [EBFONT] = "Bad font file format", + [ENOSTR] = "Device not a stream", + [ENODATA] = "No data available", + [ETIME] = "Timer expired", + [ENOSR] = "Out of streams resources", + [ENONET] = "Machine is not on the network", + [ENOPKG] = "Package not installed", + [EREMOTE] = "Object is remote", + [ENOLINK] = "Link has been severed", + [EADV] = "Advertise error", + [ESRMNT] = "Srmount error", + [ECOMM] = "Communication error on send", + [EPROTO] = "Protocol error", + [EMULTIHOP] = "Multihop attempted", + [EDOTDOT] = "RFS specific error", + [EBADMSG] = "Not a data message", + [EOVERFLOW] = "Value too large for defined data type", + [ENOTUNIQ] = "Name not unique on network", + [EBADFD] = "File descriptor in bad state", + [EREMCHG] = "Remote address changed", + [ELIBACC] = "Can not access a needed shared library", + [ELIBBAD] = "Accessing a corrupted shared library", + [ELIBSCN] = ".lib section in a.out corrupted", + [ELIBMAX] = "Attempting to link in too many shared libraries", + [ELIBEXEC] = "Cannot exec a shared library directly", + [EILSEQ] = "Illegal byte sequence", + [ERESTART] = "Interrupted system call should be restarted", + [ESTRPIPE] = "Streams pipe error", + [EUSERS] = "Too many users", + [ENOTSOCK] = "Socket operation on non-socket", + [EDESTADDRREQ] = "Destination address required", + [EMSGSIZE] = "Message too long", + [EPROTOTYPE] = "Protocol wrong type for socket", + [ENOPROTOOPT] = "Protocol not available", + [EPROTONOSUPPORT] = "Protocol not supported", + [ESOCKTNOSUPPORT] = "Socket type not supported", + [EOPNOTSUPP] = "Operation not supported on transport endpoint", + [EPFNOSUPPORT] = "Protocol family not supported", + [EAFNOSUPPORT] = "Address family not supported by protocol", + [EADDRINUSE] = "Address already in use", + [EADDRNOTAVAIL] = "Cannot assign requested address", + [ENETDOWN] = "Network is down", + [ENETUNREACH] = "Network is unreachable", + [ENETRESET] = "Network dropped connection because of reset", + [ECONNABORTED] = "Software caused connection abort", + [ECONNRESET] = "Connection reset by peer", + [ENOBUFS] = "No buffer space available", + [EISCONN] = "Transport endpoint is already connected", + [ENOTCONN] = "Transport endpoint is not connected", + [ESHUTDOWN] = "Cannot send after transport endpoint shutdown", + [ETOOMANYREFS] = "Too many references: cannot splice", + [ETIMEDOUT] = "Connection timed out", + [ECONNREFUSED] = "Connection refused", + [EHOSTDOWN] = "Host is down", + [EHOSTUNREACH] = "No route to host", + [EALREADY] = "Operation already in progress", + [EINPROGRESS] = "Operation now in progress", + [ESTALE] = "Stale NFS file handle", + [EUCLEAN] = "Structure needs cleaning", + [ENOTNAM] = "Not a XENIX named type file", + [ENAVAIL] = "No XENIX semaphores available", + [EISNAM] = "Is a named type file", + [EREMOTEIO] = "Remote I/O error", + [EDQUOT] = "Quota exceeded", + [ENOMEDIUM] = "No medium found", + [EMEDIUMTYPE] = "Wrong medium type", + [ECANCELED] = "Operation Canceled", + [ENOKEY] = "Required key not available", + [EKEYEXPIRED] = "Key has expired", + [EKEYREVOKED] = "Key has been revoked", + [EKEYREJECTED] = "Key was rejected by service", + [EOWNERDEAD] = "Owner died", + [ENOTRECOVERABLE] = "State not recoverable", + [ERFKILL] = "Operation not possible due to RF-kill", + [EHWPOISON] = "Memory page has hardware error", +}; + +static inline const char* __strerror_lookup(int error_number) { + if (error_number < 0 || error_number >= static_cast(arraysize(__sys_error_strings))) { + return nullptr; + } + return __sys_error_strings[error_number]; +} + +int strerror_r(int error_number, char* buf, size_t buf_len) { + ErrnoRestorer errno_restorer; + size_t length; + + const char* error_name = __strerror_lookup(error_number); + if (error_name != nullptr) { + length = strlcpy(buf, error_name, buf_len); + } else { + length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number); + } + if (length >= buf_len) { + errno_restorer.override(ERANGE); + return -1; + } + + 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. +} + +char* strerror(int error_number) { + // Just return the original constant in the easy cases. + char* result = const_cast(__strerror_lookup(error_number)); + if (result != nullptr) { + return result; + } + + bionic_tls& tls = __get_bionic_tls(); + result = tls.strerror_buf; + strerror_r(error_number, result, sizeof(tls.strerror_buf)); + return result; +} diff --git a/aosp/bionic/libc/bionic/string_l.cpp b/aosp/bionic/libc/bionic/string_l.cpp new file mode 100644 index 000000000..66bfb0e62 --- /dev/null +++ b/aosp/bionic/libc/bionic/string_l.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 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 +#include + +int strcoll_l(const char* s1, const char* s2, locale_t) { + return strcoll(s1, s2); +} + +char* strerror_l(int error, locale_t) { + return strerror(error); +} + +size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) { + return strxfrm(dst, src, n); +} diff --git a/aosp/bionic/libc/bionic/strings_l.cpp b/aosp/bionic/libc/bionic/strings_l.cpp new file mode 100644 index 000000000..0983ab1de --- /dev/null +++ b/aosp/bionic/libc/bionic/strings_l.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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 +#include + +int strcasecmp_l(const char* s1, const char* s2, locale_t) { + return strcasecmp(s1, s2); +} + +int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) { + return strncasecmp(s1, s2, n); +} diff --git a/aosp/bionic/libc/bionic/strnlen.c b/aosp/bionic/libc/bionic/strnlen.c new file mode 100644 index 000000000..2c6f60ae0 --- /dev/null +++ b/aosp/bionic/libc/bionic/strnlen.c @@ -0,0 +1,38 @@ +/* + * 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 + +size_t strnlen(const char* str, size_t maxlen) +{ + char* p = memchr(str, 0, maxlen); + + if (p == NULL) + return maxlen; + else + return (p - str); +} diff --git a/aosp/bionic/libc/bionic/strrchr.cpp b/aosp/bionic/libc/bionic/strrchr.cpp new file mode 100644 index 000000000..b6c40f442 --- /dev/null +++ b/aosp/bionic/libc/bionic/strrchr.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1988 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 + +char* strrchr(const char* p, int ch) { + return __strrchr_chk(p, ch, __BIONIC_FORTIFY_UNKNOWN_SIZE); +} diff --git a/aosp/bionic/libc/bionic/strsignal.cpp b/aosp/bionic/libc/bionic/strsignal.cpp new file mode 100644 index 000000000..05d349861 --- /dev/null +++ b/aosp/bionic/libc/bionic/strsignal.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 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 +#include + +#include "bionic/pthread_internal.h" + +const char* const sys_siglist[NSIG] = { +#define __BIONIC_SIGDEF(signal_number, signal_description) [ signal_number ] = signal_description, +#include "private/bionic_sigdefs.h" +}; + +const char* const sys_signame[NSIG] = { +#define __BIONIC_SIGDEF(signal_number, unused) [ signal_number ] = &(#signal_number)[3], +#include "private/bionic_sigdefs.h" +}; + +extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) { + const char* signal_name = nullptr; + if (signal_number >= 0 && signal_number < NSIG) { + signal_name = sys_siglist[signal_number]; + } + if (signal_name != nullptr) { + return signal_name; + } + + const char* prefix = "Unknown"; + if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) { + prefix = "Real-time"; + signal_number -= SIGRTMIN; + } + size_t length = snprintf(buf, buf_len, "%s signal %d", prefix, signal_number); + if (length >= buf_len) { + return nullptr; + } + return buf; +} + +char* strsignal(int signal_number) { + bionic_tls& tls = __get_bionic_tls(); + return const_cast(__strsignal(signal_number, tls.strsignal_buf, sizeof(tls.strsignal_buf))); +} diff --git a/aosp/bionic/libc/bionic/strtol.cpp b/aosp/bionic/libc/bionic/strtol.cpp new file mode 100644 index 000000000..63ac102b5 --- /dev/null +++ b/aosp/bionic/libc/bionic/strtol.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1992 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 +#include +#include +#include +#include + +template T StrToI(const char* nptr, char** endptr, int base) { + // Ensure that base is between 2 and 36 inclusive, or the special value of 0. + if (base < 0 || base == 1 || base > 36) { + if (endptr != nullptr) *endptr = const_cast(nptr); + errno = EINVAL; + return 0; + } + + // Skip white space and pick up leading +/- sign if any. + // If base is 0, allow 0x for hex and 0 for octal, else + // assume decimal; if base is already 16, allow 0x. + const char* s = nptr; + int c; + do { + c = *s++; + } while (isspace(c)); + int neg; + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') c = *s++; + } + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) base = (c == '0') ? 8 : 10; + + // We always work in the negative space because the most negative value has a + // larger magnitude than the most positive value. + T cutoff = Min / base; + int cutlim = -(Min % base); + // Non-zero if any digits consumed; negative to indicate overflow/underflow. + int any = 0; + T acc = 0; + for (; ; c = *s++) { + if (isdigit(c)) { + c -= '0'; + } else if (isalpha(c)) { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } else { + break; + } + if (c >= base) break; + if (any < 0) continue; + if (acc < cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = Min; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc -= c; + } + } + if (endptr != nullptr) *endptr = const_cast(any ? s - 1 : nptr); + if (!neg) { + if (acc == Min) { + errno = ERANGE; + acc = Max; + } else { + acc = -acc; + } + } + return acc; +} + +template T StrToU(const char* nptr, char** endptr, int base) { + if (base < 0 || base == 1 || base > 36) { + if (endptr != nullptr) *endptr = const_cast(nptr); + errno = EINVAL; + return 0; + } + + const char* s = nptr; + int c; + do { + c = *s++; + } while (isspace(c)); + int neg; + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') c = *s++; + } + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) base = (c == '0') ? 8 : 10; + + T cutoff = Max / static_cast(base); + int cutlim = Max % static_cast(base); + T acc = 0; + int any = 0; + for (; ; c = *s++) { + if (isdigit(c)) { + c -= '0'; + } else if (isalpha(c)) { + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + } else { + break; + } + if (c >= base) break; + if (any < 0) continue; + if (acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + acc = Max; + errno = ERANGE; + } else { + any = 1; + acc *= base; + acc += c; + } + } + if (neg && any > 0) acc = -acc; + if (endptr != nullptr) *endptr = const_cast(any ? s - 1 : nptr); + return acc; +} + +int atoi(const char* s) { + return strtol(s, nullptr, 10); +} + +long atol(const char* s) { + return strtol(s, nullptr, 10); +} + +long long atoll(const char* s) { + return strtoll(s, nullptr, 10); +} + +intmax_t strtoimax(const char* s, char** end, int base) { + return StrToI(s, end, base); +} + +long strtol(const char* s, char** end, int base) { + return StrToI(s, end, base); +} + +long long strtoll(const char* s, char** end, int base) { + return StrToI(s, end, base); +} + +// Public API since L, but not in any header. +extern "C" long long strtoq(const char* s, char** end, int base) { + return strtoll(s, end, base); +} + +unsigned long strtoul(const char* s, char** end, int base) { + return StrToU(s, end, base); +} + +unsigned long long strtoull(const char* s, char** end, int base) { + return StrToU(s, end, base); +} + +uintmax_t strtoumax(const char* s, char** end, int base) { + return StrToU(s, end, base); +} + +// Public API since L, but not in any header. +extern "C" unsigned long long strtouq(const char* s, char** end, int base) { + return strtoull(s, end, base); +} diff --git a/aosp/bionic/libc/bionic/strtold.cpp b/aosp/bionic/libc/bionic/strtold.cpp new file mode 100644 index 000000000..6b673e6e0 --- /dev/null +++ b/aosp/bionic/libc/bionic/strtold.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#define __BIONIC_LP32_USE_LONG_DOUBLE + +#include +#include + +extern "C" int __strtorQ(const char*, char**, int, void*); + +long double strtold(const char* s, char** end_ptr) { +#if defined(__LP64__) + long double result; + __strtorQ(s, end_ptr, FLT_ROUNDS, &result); + return result; +#else + // This is fine for LP32 where long double is just double. + return strtod(s, end_ptr); +#endif +} diff --git a/aosp/bionic/libc/bionic/swab.cpp b/aosp/bionic/libc/bionic/swab.cpp new file mode 100644 index 000000000..bc53ba446 --- /dev/null +++ b/aosp/bionic/libc/bionic/swab.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 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 + +void swab(const void* void_src, void* void_dst, ssize_t byte_count) { + const uint8_t* src = static_cast(void_src); + uint8_t* dst = static_cast(void_dst); + while (byte_count > 1) { + uint8_t x = *src++; + uint8_t y = *src++; + *dst++ = y; + *dst++ = x; + byte_count -= 2; + } +} diff --git a/aosp/bionic/libc/bionic/symlink.cpp b/aosp/bionic/libc/bionic/symlink.cpp new file mode 100644 index 000000000..83cda47f4 --- /dev/null +++ b/aosp/bionic/libc/bionic/symlink.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int symlink(const char* old_path, const char* new_path) { + return symlinkat(old_path, AT_FDCWD, new_path); +} diff --git a/aosp/bionic/libc/bionic/sync_file_range.cpp b/aosp/bionic/libc/bionic/sync_file_range.cpp new file mode 100644 index 000000000..7f60882e6 --- /dev/null +++ b/aosp/bionic/libc/bionic/sync_file_range.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 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 + +extern "C" int __sync_file_range(int, off64_t, off64_t, unsigned int); +extern "C" int __sync_file_range2(int, unsigned int, off64_t, off64_t); + +int sync_file_range(int fd, off64_t offset, off64_t length, unsigned int flags) { +#if __arm__ + return __sync_file_range2(fd, flags, offset, length); +#else + return __sync_file_range(fd, offset, length, flags); +#endif +} diff --git a/aosp/bionic/libc/bionic/sys_epoll.cpp b/aosp/bionic/libc/bionic/sys_epoll.cpp new file mode 100644 index 000000000..22d0a98d7 --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_epoll.cpp @@ -0,0 +1,67 @@ +/* + * 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 +#include + +#include "private/SigSetConverter.h" +#include "private/bionic_fdtrack.h" + +extern "C" int __epoll_create1(int flags); +extern "C" int __epoll_pwait(int, epoll_event*, int, int, const sigset64_t*, size_t); + +int epoll_create(int size) { + if (size <= 0) { + errno = EINVAL; + return -1; + } + return FDTRACK_CREATE(__epoll_create1(0)); +} + +int epoll_create1(int flags) { + return FDTRACK_CREATE(__epoll_create1(flags)); +} + +int epoll_pwait(int fd, epoll_event* events, int max_events, int timeout, const sigset_t* ss) { + SigSetConverter set; + sigset64_t* ss_ptr = nullptr; + if (ss != nullptr) { + set = {}; + set.sigset = *ss; + ss_ptr = &set.sigset64; + } + return epoll_pwait64(fd, events, max_events, timeout, ss_ptr); +} + +int epoll_pwait64(int fd, epoll_event* events, int max_events, int timeout, const sigset64_t* ss) { + return __epoll_pwait(fd, events, max_events, timeout, ss, sizeof(*ss)); +} + +int epoll_wait(int fd, struct epoll_event* events, int max_events, int timeout) { + return epoll_pwait64(fd, events, max_events, timeout, nullptr); +} diff --git a/aosp/bionic/libc/bionic/sys_msg.cpp b/aosp/bionic/libc/bionic/sys_msg.cpp new file mode 100644 index 000000000..462c83b2f --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_msg.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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 + +#include +#include + +int msgctl(int id, int cmd, msqid_ds* buf) { +#if !defined(__LP64__) + // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit. + cmd |= IPC_64; +#endif +#if defined(SYS_msgctl) + return syscall(SYS_msgctl, id, cmd, buf); +#else + return syscall(SYS_ipc, MSGCTL, id, cmd, 0, buf, 0); +#endif +} + +int msgget(key_t key, int flags) { +#if defined(SYS_msgget) + return syscall(SYS_msgget, key, flags); +#else + return syscall(SYS_ipc, MSGGET, key, flags, 0, 0, 0); +#endif +} + +ssize_t msgrcv(int id, void* msg, size_t n, long type, int flags) { +#if defined(SYS_msgrcv) + return syscall(SYS_msgrcv, id, msg, n, type, flags); +#else + return syscall(SYS_ipc, IPCCALL(1, MSGRCV), id, n, flags, msg, type); +#endif +} + +int msgsnd(int id, const void* msg, size_t n, int flags) { +#if defined(SYS_msgsnd) + return syscall(SYS_msgsnd, id, msg, n, flags); +#else + return syscall(SYS_ipc, MSGSND, id, n, flags, msg, 0); +#endif +} diff --git a/aosp/bionic/libc/bionic/sys_sem.cpp b/aosp/bionic/libc/bionic/sys_sem.cpp new file mode 100644 index 000000000..058cfefc8 --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_sem.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 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 + +#include +#include +#include + +int semctl(int id, int num, int cmd, ...) { +#if !defined(__LP64__) + // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit. + cmd |= IPC_64; +#endif + va_list ap; + va_start(ap, cmd); + semun arg = va_arg(ap, semun); + va_end(ap); +#if defined(SYS_semctl) + return syscall(SYS_semctl, id, num, cmd, arg); +#else + return syscall(SYS_ipc, SEMCTL, id, num, cmd, &arg, 0); +#endif +} + +int semget(key_t key, int n, int flags) { +#if defined(SYS_semget) + return syscall(SYS_semget, key, n, flags); +#else + return syscall(SYS_ipc, SEMGET, key, n, flags, 0, 0); +#endif +} + +int semop(int id, sembuf* ops, size_t op_count) { + return semtimedop(id, ops, op_count, nullptr); +} + +int semtimedop(int id, sembuf* ops, size_t op_count, const timespec* ts) { +#if defined(SYS_semtimedop) + return syscall(SYS_semtimedop, id, ops, op_count, ts); +#else + return syscall(SYS_ipc, SEMTIMEDOP, id, op_count, 0, ops, ts); +#endif +} diff --git a/aosp/bionic/libc/bionic/sys_shm.cpp b/aosp/bionic/libc/bionic/sys_shm.cpp new file mode 100644 index 000000000..f780e04d4 --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_shm.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 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 + +#include +#include + +void* shmat(int id, const void* address, int flags) { +#if defined(SYS_shmat) + return reinterpret_cast(syscall(SYS_shmat, id, address, flags)); +#else + // See the kernel's ipc/syscall.c for the other side of this dance. + void* result = nullptr; + if (syscall(SYS_ipc, SHMAT, id, flags, &result, address, 0) == -1) { + return reinterpret_cast(-1); + } + return result; +#endif +} + +int shmctl(int id, int cmd, struct shmid_ds* buf) { +#if !defined(__LP64__) + // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit. + cmd |= IPC_64; +#endif +#if defined(SYS_shmctl) + return syscall(SYS_shmctl, id, cmd, buf); +#else + return syscall(SYS_ipc, SHMCTL, id, cmd, 0, buf, 0); +#endif +} + +int shmdt(const void* address) { +#if defined(SYS_shmdt) + return syscall(SYS_shmdt, address); +#else + return syscall(SYS_ipc, SHMDT, 0, 0, 0, address, 0); +#endif +} + +int shmget(key_t key, size_t size, int flags) { +#if defined(SYS_shmget) + return syscall(SYS_shmget, key, size, flags); +#else + return syscall(SYS_ipc, SHMGET, key, size, flags, 0, 0); +#endif +} diff --git a/aosp/bionic/libc/bionic/sys_signalfd.cpp b/aosp/bionic/libc/bionic/sys_signalfd.cpp new file mode 100644 index 000000000..53d1f25c9 --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_signalfd.cpp @@ -0,0 +1,43 @@ +/* + * 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 + +#include "private/SigSetConverter.h" + +extern "C" int __signalfd4(int, const sigset64_t*, size_t, int); + +int signalfd(int fd, const sigset_t* mask, int flags) { + SigSetConverter set = {}; + set.sigset = *mask; + return signalfd64(fd, &set.sigset64, flags); +} + +int signalfd64(int fd, const sigset64_t* mask, int flags) { + return __signalfd4(fd, mask, sizeof(*mask), flags); +} diff --git a/aosp/bionic/libc/bionic/sys_statfs.cpp b/aosp/bionic/libc/bionic/sys_statfs.cpp new file mode 100644 index 000000000..d78de2ddc --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_statfs.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 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 + +// Paper over the fact that 32-bit kernels use fstatfs64/statfs64 with +// an extra argument, but 64-bit kernels don't have the "64" bit suffix or +// the extra size_t argument. +#if defined(__LP64__) +extern "C" int __fstatfs(int, struct statfs*); +extern "C" int __statfs(const char*, struct statfs*); +# define __fstatfs64(fd,size,buf) __fstatfs(fd,buf) +# define __statfs64(path,size,buf) __statfs(path,buf) +#else +extern "C" int __fstatfs64(int, size_t, struct statfs*); +extern "C" int __statfs64(const char*, size_t, struct statfs*); +#endif + +// The kernel sets a private ST_VALID flag to signal to the C library +// whether the f_flags field is valid. This flag should not be exposed to +// users of the C library. +#define ST_VALID 0x0020 + +int fstatfs(int fd, struct statfs* result) { + int rc = __fstatfs64(fd, sizeof(*result), result); + if (rc != 0) { + return rc; + } + result->f_flags &= ~ST_VALID; + return 0; +} +__strong_alias(fstatfs64, fstatfs); + +int statfs(const char* path, struct statfs* result) { + int rc = __statfs64(path, sizeof(*result), result); + if (rc != 0) { + return rc; + } + result->f_flags &= ~ST_VALID; + return 0; +} +__strong_alias(statfs64, statfs); diff --git a/aosp/bionic/libc/bionic/sys_statvfs.cpp b/aosp/bionic/libc/bionic/sys_statvfs.cpp new file mode 100644 index 000000000..ef5dc57da --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_statvfs.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 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 + +// libc++ uses statvfs (for Darwin compatibility), but on Linux statvfs is +// just another name for statfs, so it didn't arrive until API level 19. We +// make the implementation available as inlines to support std::filesystem +// for NDK users (see https://github.com/android-ndk/ndk/issues/609). + +#define __BIONIC_SYS_STATVFS_INLINE /* Out of line. */ +#define __BIONIC_NEED_STATVFS_INLINES +#undef __BIONIC_NEED_STATVFS64_INLINES +#include + +// Historically we provided actual symbols for statvfs64 and fstatvfs64. +// They're not particularly useful, but we can't take them away. +__strong_alias(statvfs64, statvfs); +__strong_alias(fstatvfs64, fstatvfs); diff --git a/aosp/bionic/libc/bionic/sys_time.cpp b/aosp/bionic/libc/bionic/sys_time.cpp new file mode 100644 index 000000000..3d0cd876d --- /dev/null +++ b/aosp/bionic/libc/bionic/sys_time.cpp @@ -0,0 +1,65 @@ +/* + * 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 + +#include +#include +#include + +#include "private/bionic_time_conversions.h" + +static int futimesat(int fd, const char* path, const timeval tv[2], int flags) { + timespec ts[2]; + if (tv && (!timespec_from_timeval(ts[0], tv[0]) || !timespec_from_timeval(ts[1], tv[1]))) { + errno = EINVAL; + return -1; + } + return utimensat(fd, path, tv ? ts : nullptr, flags); +} + +int utimes(const char* path, const timeval tv[2]) { + return futimesat(AT_FDCWD, path, tv, 0); +} + +int lutimes(const char* path, const timeval tv[2]) { + return futimesat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW); +} + +int futimesat(int fd, const char* path, const timeval tv[2]) { + return futimesat(fd, path, tv, 0); +} + +int futimes(int fd, const timeval tv[2]) { + timespec ts[2]; + if (tv && (!timespec_from_timeval(ts[0], tv[0]) || !timespec_from_timeval(ts[1], tv[1]))) { + errno = EINVAL; + return -1; + } + return futimens(fd, tv ? ts : nullptr); +} diff --git a/aosp/bionic/libc/bionic/sysconf.cpp b/aosp/bionic/libc/bionic/sysconf.cpp new file mode 100644 index 000000000..dd6b129ab --- /dev/null +++ b/aosp/bionic/libc/bionic/sysconf.cpp @@ -0,0 +1,242 @@ +/* + * 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 +#include +#include +#include +#include // For FOPEN_MAX. +#include +#include +#include +#include +#include +#include + +#include "private/bionic_tls.h" + +static long __sysconf_rlimit(int resource) { + rlimit rl; + getrlimit(resource, &rl); + return rl.rlim_cur; +} + +long sysconf(int name) { + switch (name) { + // + // Things we actually have to calculate... + // + case _SC_ARG_MAX: + // You might think that just returning a constant 128KiB (ARG_MAX) would + // make sense, as this guy did: + // + // https://lkml.org/lkml/2017/11/15/813... + // + // I suspect a 128kB sysconf(_SC_ARG_MAX) is the sanest bet, simply + // because of that "conservative is better than aggressive". + // + // Especially since _technically_ we're still limiting things to that + // 128kB due to the single-string limit. + // + // Linus + // + // In practice that caused us trouble with toybox tests for xargs edge + // cases. The tests assume that they can at least reach the kernel's + // "minimum maximum" of 128KiB, but if we report 128KiB for _SC_ARG_MAX + // and xargs starts subtracting the environment space and so on from that, + // then xargs will think it's run out of space when given 128KiB of data, + // which should always work. See this thread for more: + // + // http://lists.landley.net/pipermail/toybox-landley.net/2019-November/011229.html + // + // So let's resign ourselves to tracking what the kernel actually does. + // Right now (2019, Linux 5.3) that amounts to: + return MAX(MIN(__sysconf_rlimit(RLIMIT_STACK) / 4, 3 * _STK_LIM / 4), ARG_MAX); + + case _SC_AVPHYS_PAGES: return get_avphys_pages(); + case _SC_CHILD_MAX: return __sysconf_rlimit(RLIMIT_NPROC); + case _SC_CLK_TCK: return static_cast(getauxval(AT_CLKTCK)); + case _SC_NPROCESSORS_CONF: return get_nprocs_conf(); + case _SC_NPROCESSORS_ONLN: return get_nprocs(); + case _SC_OPEN_MAX: return __sysconf_rlimit(RLIMIT_NOFILE); + + case _SC_PAGESIZE: + case _SC_PAGE_SIZE: + // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value. + return static_cast(getauxval(AT_PAGESZ)); + + case _SC_PHYS_PAGES: return get_phys_pages(); + + // + // Constants... + // + case _SC_BC_BASE_MAX: return _POSIX2_BC_BASE_MAX; // Minimum requirement. + case _SC_BC_DIM_MAX: return _POSIX2_BC_DIM_MAX; // Minimum requirement. + case _SC_BC_SCALE_MAX: return _POSIX2_BC_SCALE_MAX; // Minimum requirement. + case _SC_BC_STRING_MAX: return _POSIX2_BC_STRING_MAX; // Minimum requirement. + case _SC_COLL_WEIGHTS_MAX: return _POSIX2_COLL_WEIGHTS_MAX; // Minimum requirement. + case _SC_EXPR_NEST_MAX: return _POSIX2_EXPR_NEST_MAX; // Minimum requirement. + case _SC_LINE_MAX: return _POSIX2_LINE_MAX; // Minimum requirement. + case _SC_NGROUPS_MAX: return NGROUPS_MAX; + case _SC_PASS_MAX: return PASS_MAX; + case _SC_2_C_BIND: return _POSIX2_C_BIND; + case _SC_2_C_DEV: return _POSIX2_C_DEV; + case _SC_2_CHAR_TERM: return _POSIX2_CHAR_TERM; + case _SC_2_FORT_DEV: return -1; + case _SC_2_FORT_RUN: return -1; + case _SC_2_LOCALEDEF: return _POSIX2_LOCALEDEF; + case _SC_2_SW_DEV: return _POSIX2_SW_DEV; + case _SC_2_UPE: return _POSIX2_UPE; + case _SC_2_VERSION: return _POSIX2_VERSION; + case _SC_JOB_CONTROL: return _POSIX_JOB_CONTROL; + case _SC_SAVED_IDS: return _POSIX_SAVED_IDS; + case _SC_VERSION: return _POSIX_VERSION; + case _SC_RE_DUP_MAX: return _POSIX_RE_DUP_MAX; // Minimum requirement. + case _SC_STREAM_MAX: return FOPEN_MAX; + case _SC_TZNAME_MAX: return _POSIX_TZNAME_MAX; // Minimum requirement. + case _SC_XOPEN_CRYPT: return _XOPEN_CRYPT; + case _SC_XOPEN_ENH_I18N: return _XOPEN_ENH_I18N; + case _SC_XOPEN_SHM: return _XOPEN_SHM; + case _SC_XOPEN_VERSION: return _XOPEN_VERSION; + case _SC_XOPEN_REALTIME: return _XOPEN_REALTIME; + case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS; + case _SC_XOPEN_LEGACY: return _XOPEN_LEGACY; + case _SC_ATEXIT_MAX: return LONG_MAX; // Unlimited. + case _SC_IOV_MAX: return IOV_MAX; + + case _SC_XOPEN_UNIX: return _XOPEN_UNIX; + case _SC_AIO_LISTIO_MAX: return _POSIX_AIO_LISTIO_MAX; // Minimum requirement. + case _SC_AIO_MAX: return _POSIX_AIO_MAX; // Minimum requirement. + case _SC_AIO_PRIO_DELTA_MAX:return 0; // Minimum requirement. + case _SC_DELAYTIMER_MAX: return INT_MAX; + case _SC_MQ_OPEN_MAX: return _POSIX_MQ_OPEN_MAX; // Minimum requirement. + case _SC_MQ_PRIO_MAX: return _POSIX_MQ_PRIO_MAX; // Minimum requirement. + case _SC_RTSIG_MAX: return RTSIG_MAX; + case _SC_SEM_NSEMS_MAX: return _POSIX_SEM_NSEMS_MAX; // Minimum requirement. + case _SC_SEM_VALUE_MAX: return SEM_VALUE_MAX; + case _SC_SIGQUEUE_MAX: return _POSIX_SIGQUEUE_MAX; // Minimum requirement. + case _SC_TIMER_MAX: return _POSIX_TIMER_MAX; // Minimum requirement. + case _SC_ASYNCHRONOUS_IO: return _POSIX_ASYNCHRONOUS_IO; + case _SC_FSYNC: return _POSIX_FSYNC; + case _SC_MAPPED_FILES: return _POSIX_MAPPED_FILES; + case _SC_MEMLOCK: return _POSIX_MEMLOCK; + case _SC_MEMLOCK_RANGE: return _POSIX_MEMLOCK_RANGE; + case _SC_MEMORY_PROTECTION: return _POSIX_MEMORY_PROTECTION; + case _SC_MESSAGE_PASSING: return _POSIX_MESSAGE_PASSING; + case _SC_PRIORITIZED_IO: return _POSIX_PRIORITIZED_IO; + case _SC_PRIORITY_SCHEDULING: return _POSIX_PRIORITY_SCHEDULING; + case _SC_REALTIME_SIGNALS: return _POSIX_REALTIME_SIGNALS; + case _SC_SEMAPHORES: return _POSIX_SEMAPHORES; + case _SC_SHARED_MEMORY_OBJECTS: return _POSIX_SHARED_MEMORY_OBJECTS; + case _SC_SYNCHRONIZED_IO: return _POSIX_SYNCHRONIZED_IO; + case _SC_TIMERS: return _POSIX_TIMERS; + case _SC_GETGR_R_SIZE_MAX: return 1024; + case _SC_GETPW_R_SIZE_MAX: return 1024; + case _SC_LOGIN_NAME_MAX: return LOGIN_NAME_MAX; + case _SC_THREAD_DESTRUCTOR_ITERATIONS: return PTHREAD_DESTRUCTOR_ITERATIONS; + case _SC_THREAD_KEYS_MAX: return PTHREAD_KEYS_MAX; + case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN; + case _SC_THREAD_THREADS_MAX: return -1; // No specific limit. + case _SC_TTY_NAME_MAX: return TTY_NAME_MAX; + case _SC_THREADS: return _POSIX_THREADS; + case _SC_THREAD_ATTR_STACKADDR: return _POSIX_THREAD_ATTR_STACKADDR; + case _SC_THREAD_ATTR_STACKSIZE: return _POSIX_THREAD_ATTR_STACKSIZE; + case _SC_THREAD_PRIORITY_SCHEDULING: return _POSIX_THREAD_PRIORITY_SCHEDULING; + case _SC_THREAD_PRIO_INHERIT: return _POSIX_THREAD_PRIO_INHERIT; + case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT; + case _SC_THREAD_SAFE_FUNCTIONS: return _POSIX_THREAD_SAFE_FUNCTIONS; + case _SC_MONOTONIC_CLOCK: return _POSIX_MONOTONIC_CLOCK; + + case _SC_2_PBS: return -1; // Obsolescent in POSIX.1-2008. + case _SC_2_PBS_ACCOUNTING: return -1; // Obsolescent in POSIX.1-2008. + case _SC_2_PBS_CHECKPOINT: return -1; // Obsolescent in POSIX.1-2008. + case _SC_2_PBS_LOCATE: return -1; // Obsolescent in POSIX.1-2008. + case _SC_2_PBS_MESSAGE: return -1; // Obsolescent in POSIX.1-2008. + case _SC_2_PBS_TRACK: return -1; // Obsolescent in POSIX.1-2008. + case _SC_ADVISORY_INFO: return _POSIX_ADVISORY_INFO; + case _SC_BARRIERS: return _POSIX_BARRIERS; + case _SC_CLOCK_SELECTION: return _POSIX_CLOCK_SELECTION; + case _SC_CPUTIME: return _POSIX_CPUTIME; + + case _SC_HOST_NAME_MAX: return _POSIX_HOST_NAME_MAX; // Minimum requirement. + case _SC_IPV6: return _POSIX_IPV6; + case _SC_RAW_SOCKETS: return _POSIX_RAW_SOCKETS; + case _SC_READER_WRITER_LOCKS: return _POSIX_READER_WRITER_LOCKS; + case _SC_REGEXP: return _POSIX_REGEXP; + case _SC_SHELL: return _POSIX_SHELL; + case _SC_SPAWN: return _POSIX_SPAWN; + case _SC_SPIN_LOCKS: return _POSIX_SPIN_LOCKS; + case _SC_SPORADIC_SERVER: return _POSIX_SPORADIC_SERVER; + case _SC_SS_REPL_MAX: return -1; + case _SC_SYMLOOP_MAX: return _POSIX_SYMLOOP_MAX; // Minimum requirement. + case _SC_THREAD_CPUTIME: return _POSIX_THREAD_CPUTIME; + + case _SC_THREAD_PROCESS_SHARED: return _POSIX_THREAD_PROCESS_SHARED; + case _SC_THREAD_ROBUST_PRIO_INHERIT: return _POSIX_THREAD_ROBUST_PRIO_INHERIT; + case _SC_THREAD_ROBUST_PRIO_PROTECT: return _POSIX_THREAD_ROBUST_PRIO_PROTECT; + case _SC_THREAD_SPORADIC_SERVER: return _POSIX_THREAD_SPORADIC_SERVER; + case _SC_TIMEOUTS: return _POSIX_TIMEOUTS; + case _SC_TRACE: return -1; // Obsolescent in POSIX.1-2008. + case _SC_TRACE_EVENT_FILTER: return -1; // Obsolescent in POSIX.1-2008. + case _SC_TRACE_EVENT_NAME_MAX: return -1; + case _SC_TRACE_INHERIT: return -1; // Obsolescent in POSIX.1-2008. + case _SC_TRACE_LOG: return -1; // Obsolescent in POSIX.1-2008. + case _SC_TRACE_NAME_MAX: return -1; + case _SC_TRACE_SYS_MAX: return -1; + case _SC_TRACE_USER_EVENT_MAX: return -1; + case _SC_TYPED_MEMORY_OBJECTS: return _POSIX_TYPED_MEMORY_OBJECTS; + case _SC_V7_ILP32_OFF32: return _POSIX_V7_ILP32_OFF32; + case _SC_V7_ILP32_OFFBIG: return _POSIX_V7_ILP32_OFFBIG; + case _SC_V7_LP64_OFF64: return _POSIX_V7_LP64_OFF64; + case _SC_V7_LPBIG_OFFBIG: return _POSIX_V7_LPBIG_OFFBIG; + case _SC_XOPEN_STREAMS: return -1; // Obsolescent in POSIX.1-2008. + case _SC_XOPEN_UUCP: return -1; + + // We do not have actual implementations for cache queries. + // It's valid to return 0 as the result is unknown. + case _SC_LEVEL1_ICACHE_SIZE: return 0; + case _SC_LEVEL1_ICACHE_ASSOC: return 0; + case _SC_LEVEL1_ICACHE_LINESIZE: return 0; + case _SC_LEVEL1_DCACHE_SIZE: return 0; + case _SC_LEVEL1_DCACHE_ASSOC: return 0; + case _SC_LEVEL1_DCACHE_LINESIZE: return 0; + case _SC_LEVEL2_CACHE_SIZE: return 0; + case _SC_LEVEL2_CACHE_ASSOC: return 0; + case _SC_LEVEL2_CACHE_LINESIZE: return 0; + case _SC_LEVEL3_CACHE_SIZE: return 0; + case _SC_LEVEL3_CACHE_ASSOC: return 0; + case _SC_LEVEL3_CACHE_LINESIZE: return 0; + case _SC_LEVEL4_CACHE_SIZE: return 0; + case _SC_LEVEL4_CACHE_ASSOC: return 0; + case _SC_LEVEL4_CACHE_LINESIZE: return 0; + + default: + errno = EINVAL; + return -1; + } +} diff --git a/aosp/bionic/libc/bionic/syslog.cpp b/aosp/bionic/libc/bionic/syslog.cpp new file mode 100644 index 000000000..6b17d268a --- /dev/null +++ b/aosp/bionic/libc/bionic/syslog.cpp @@ -0,0 +1,82 @@ +/* + * 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 +#include +#include +#include + +#include + +static const char* syslog_log_tag = nullptr; +static int syslog_priority_mask = 0xff; + +void closelog() { + syslog_log_tag = nullptr; +} + +void openlog(const char* log_tag, int /*options*/, int /*facility*/) { + syslog_log_tag = log_tag; +} + +int setlogmask(int new_mask) { + int old_mask = syslog_priority_mask; + // 0 is used to query the current mask. + if (new_mask != 0) { + syslog_priority_mask = new_mask; + } + return old_mask; +} + +void syslog(int priority, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vsyslog(priority, fmt, args); + va_end(args); +} + +void vsyslog(int priority, const char* fmt, va_list args) { + // Check whether we're supposed to be logging messages of this priority. + if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) { + return; + } + + // What's our log tag? + const char* log_tag = syslog_log_tag; + if (log_tag == nullptr) { + log_tag = getprogname(); + } + + // What's our Android log priority? + priority &= LOG_PRIMASK; + int android_log_priority; + if (priority <= LOG_ERR) { + android_log_priority = ANDROID_LOG_ERROR; + } else if (priority == LOG_WARNING) { + android_log_priority = ANDROID_LOG_WARN; + } else if (priority <= LOG_INFO) { + android_log_priority = ANDROID_LOG_INFO; + } else { + android_log_priority = ANDROID_LOG_DEBUG; + } + + // We can't let async_safe_format_log do the formatting because it doesn't support + // all the printf functionality. + char log_line[1024]; + vsnprintf(log_line, sizeof(log_line), fmt, args); + + async_safe_format_log(android_log_priority, log_tag, "%s", log_line); +} diff --git a/aosp/bionic/libc/bionic/system.cpp b/aosp/bionic/libc/bionic/system.cpp new file mode 100644 index 000000000..950f05c7d --- /dev/null +++ b/aosp/bionic/libc/bionic/system.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include +#include + +#include "private/__bionic_get_shell_path.h" +#include "private/ScopedSignalBlocker.h" +#include "private/ScopedSignalHandler.h" + +int system(const char* command) { + // "The system() function shall always return non-zero when command is NULL." + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html + if (command == nullptr) return 1; + + ScopedSignalBlocker sigchld_blocker(SIGCHLD); + ScopedSignalHandler sigint_ignorer(SIGINT, SIG_IGN); + ScopedSignalHandler sigquit_ignorer(SIGQUIT, SIG_IGN); + + sigset64_t default_mask = {}; + if (sigint_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGINT); + if (sigquit_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGQUIT); + + static constexpr int flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; + posix_spawnattr_t attributes; + if ((errno = posix_spawnattr_init(&attributes))) return -1; + if ((errno = posix_spawnattr_setsigdefault64(&attributes, &default_mask))) return -1; + if ((errno = posix_spawnattr_setsigmask64(&attributes, &sigchld_blocker.old_set_))) return -1; + if ((errno = posix_spawnattr_setflags(&attributes, flags))) return -1; + + const char* argv[] = { "sh", "-c", command, nullptr }; + pid_t child; + if ((errno = posix_spawn(&child, __bionic_get_shell_path(), nullptr, &attributes, + const_cast(argv), environ)) != 0) { + return -1; + } + + posix_spawnattr_destroy(&attributes); + + int status; + pid_t pid = TEMP_FAILURE_RETRY(waitpid(child, &status, 0)); + return (pid == -1 ? -1 : status); +} diff --git a/aosp/bionic/libc/bionic/system_property_api.cpp b/aosp/bionic/libc/bionic/system_property_api.cpp new file mode 100644 index 000000000..a641f12a8 --- /dev/null +++ b/aosp/bionic/libc/bionic/system_property_api.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2017 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. + */ + +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include + +#include +#include + +#include "private/bionic_defs.h" + +static SystemProperties system_properties; +static_assert(__is_trivially_constructible(SystemProperties), + "System Properties must be trivially constructable"); + +// This is public because it was exposed in the NDK. As of 2017-01, ~60 apps reference this symbol. +// It is set to nullptr and never modified. +__BIONIC_WEAK_VARIABLE_FOR_NATIVE_BRIDGE +prop_area* __system_property_area__ = nullptr; + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_properties_init() { + return system_properties.Init(PROP_FILENAME) ? 0 : -1; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_set_filename(const char*) { + return -1; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_area_init() { + bool fsetxattr_failed = false; + return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +uint32_t __system_property_area_serial() { + return system_properties.AreaSerial(); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +const prop_info* __system_property_find(const char* name) { + return system_properties.Find(name); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_read(const prop_info* pi, char* name, char* value) { + return system_properties.Read(pi, name, value); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void __system_property_read_callback(const prop_info* pi, + void (*callback)(void* cookie, const char* name, + const char* value, uint32_t serial), + void* cookie) { + return system_properties.ReadCallback(pi, callback, cookie); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_get(const char* name, char* value) { + return system_properties.Get(name, value); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_update(prop_info* pi, const char* value, unsigned int len) { + return system_properties.Update(pi, value, len); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_add(const char* name, unsigned int namelen, const char* value, + unsigned int valuelen) { + return system_properties.Add(name, namelen, value, valuelen); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +uint32_t __system_property_serial(const prop_info* pi) { + // N.B. a previous version of this function was much heavier-weight + // and enforced acquire semantics, so give our load here acquire + // semantics just in case somebody depends on + // __system_property_serial enforcing memory order, e.g., in case + // someone spins on the result of this function changing before + // loading some value. + return atomic_load_explicit(&pi->serial, memory_order_acquire); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +uint32_t __system_property_wait_any(uint32_t old_serial) { + return system_properties.WaitAny(old_serial); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +bool __system_property_wait(const prop_info* pi, uint32_t old_serial, uint32_t* new_serial_ptr, + const timespec* relative_timeout) { + return system_properties.Wait(pi, old_serial, new_serial_ptr, relative_timeout); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +const prop_info* __system_property_find_nth(unsigned n) { + return system_properties.FindNth(n); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) { + return system_properties.Foreach(propfn, cookie); +} diff --git a/aosp/bionic/libc/bionic/system_property_set.cpp b/aosp/bionic/libc/bionic/system_property_set.cpp new file mode 100644 index 000000000..56822acbd --- /dev/null +++ b/aosp/bionic/libc/bionic/system_property_set.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2017 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include +#include + +#include +#include + +#include "private/bionic_defs.h" +#include "platform/bionic/macros.h" +#include "private/ScopedFd.h" + +static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; +static const char* kServiceVersionPropertyName = "ro.property_service.version"; + +class PropertyServiceConnection { + public: + PropertyServiceConnection() : last_error_(0) { + socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)); + if (socket_.get() == -1) { + last_error_ = errno; + return; + } + + const size_t namelen = strlen(property_service_socket); + sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path)); + addr.sun_family = AF_LOCAL; + socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1; + + if (TEMP_FAILURE_RETRY(connect(socket_.get(), + reinterpret_cast(&addr), alen)) == -1) { + last_error_ = errno; + socket_.reset(); + } + } + + bool IsValid() { + return socket_.get() != -1; + } + + int GetLastError() { + return last_error_; + } + + bool RecvInt32(int32_t* value) { + int result = TEMP_FAILURE_RETRY(recv(socket_.get(), value, sizeof(*value), MSG_WAITALL)); + return CheckSendRecvResult(result, sizeof(*value)); + } + + int socket() { + return socket_.get(); + } + + private: + bool CheckSendRecvResult(int result, int expected_len) { + if (result == -1) { + last_error_ = errno; + } else if (result != expected_len) { + last_error_ = -1; + } else { + last_error_ = 0; + } + + return last_error_ == 0; + } + + ScopedFd socket_; + int last_error_; + + friend class SocketWriter; +}; + +class SocketWriter { + public: + explicit SocketWriter(PropertyServiceConnection* connection) + : connection_(connection), iov_index_(0), uint_buf_index_(0) { + } + + SocketWriter& WriteUint32(uint32_t value) { + CHECK(uint_buf_index_ < kUintBufSize); + CHECK(iov_index_ < kIovSize); + uint32_t* ptr = uint_buf_ + uint_buf_index_; + uint_buf_[uint_buf_index_++] = value; + iov_[iov_index_].iov_base = ptr; + iov_[iov_index_].iov_len = sizeof(*ptr); + ++iov_index_; + return *this; + } + + SocketWriter& WriteString(const char* value) { + uint32_t valuelen = strlen(value); + WriteUint32(valuelen); + if (valuelen == 0) { + return *this; + } + + CHECK(iov_index_ < kIovSize); + iov_[iov_index_].iov_base = const_cast(value); + iov_[iov_index_].iov_len = valuelen; + ++iov_index_; + + return *this; + } + + bool Send() { + if (!connection_->IsValid()) { + return false; + } + + if (writev(connection_->socket(), iov_, iov_index_) == -1) { + connection_->last_error_ = errno; + return false; + } + + iov_index_ = uint_buf_index_ = 0; + return true; + } + + private: + static constexpr size_t kUintBufSize = 8; + static constexpr size_t kIovSize = 8; + + PropertyServiceConnection* connection_; + iovec iov_[kIovSize]; + size_t iov_index_; + uint32_t uint_buf_[kUintBufSize]; + size_t uint_buf_index_; + + BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter); +}; + +struct prop_msg { + unsigned cmd; + char name[PROP_NAME_MAX]; + char value[PROP_VALUE_MAX]; +}; + +static int send_prop_msg(const prop_msg* msg) { + PropertyServiceConnection connection; + if (!connection.IsValid()) { + return connection.GetLastError(); + } + + int result = -1; + int s = connection.socket(); + + const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); + if (num_bytes == sizeof(prop_msg)) { + // We successfully wrote to the property server but now we + // wait for the property server to finish its work. It + // acknowledges its completion by closing the socket so we + // poll here (on nothing), waiting for the socket to close. + // If you 'adb shell setprop foo bar' you'll see the POLLHUP + // once the socket closes. Out of paranoia we cap our poll + // at 250 ms. + pollfd pollfds[1]; + pollfds[0].fd = s; + pollfds[0].events = 0; + const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */)); + if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) { + result = 0; + } else { + // Ignore the timeout and treat it like a success anyway. + // The init process is single-threaded and its property + // service is sometimes slow to respond (perhaps it's off + // starting a child process or something) and thus this + // times out and the caller thinks it failed, even though + // it's still getting around to it. So we fake it here, + // mostly for ctl.* properties, but we do try and wait 250 + // ms so callers who do read-after-write can reliably see + // what they've written. Most of the time. + // TODO: fix the system properties design. + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Property service has timed out while trying to set \"%s\" to \"%s\"", + msg->name, msg->value); + result = 0; + } + } + + return result; +} + +static constexpr uint32_t kProtocolVersion1 = 1; +static constexpr uint32_t kProtocolVersion2 = 2; // current + +static atomic_uint_least32_t g_propservice_protocol_version = 0; + +static void detect_protocol_version() { + char value[PROP_VALUE_MAX]; + if (__system_property_get(kServiceVersionPropertyName, value) == 0) { + g_propservice_protocol_version = kProtocolVersion1; + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Using old property service protocol (\"%s\" is not set)", + kServiceVersionPropertyName); + } else { + uint32_t version = static_cast(atoll(value)); + if (version >= kProtocolVersion2) { + g_propservice_protocol_version = kProtocolVersion2; + } else { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Using old property service protocol (\"%s\"=\"%s\")", + kServiceVersionPropertyName, value); + g_propservice_protocol_version = kProtocolVersion1; + } + } +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_property_set(const char* key, const char* value) { + if (key == nullptr) return -1; + if (value == nullptr) value = ""; + + if (g_propservice_protocol_version == 0) { + detect_protocol_version(); + } + + if (g_propservice_protocol_version == kProtocolVersion1) { + // Old protocol does not support long names or values + if (strlen(key) >= PROP_NAME_MAX) return -1; + if (strlen(value) >= PROP_VALUE_MAX) return -1; + + prop_msg msg; + memset(&msg, 0, sizeof msg); + msg.cmd = PROP_MSG_SETPROP; + strlcpy(msg.name, key, sizeof msg.name); + strlcpy(msg.value, value, sizeof msg.value); + + return send_prop_msg(&msg); + } else { + // New protocol only allows long values for ro. properties only. + if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1; + // Use proper protocol + PropertyServiceConnection connection; + if (!connection.IsValid()) { + errno = connection.GetLastError(); + async_safe_format_log( + ANDROID_LOG_WARN, "libc", + "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value, + errno, strerror(errno)); + return -1; + } + + SocketWriter writer(&connection); + if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) { + errno = connection.GetLastError(); + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)", + key, value, errno, strerror(errno)); + return -1; + } + + int result = -1; + if (!connection.RecvInt32(&result)) { + errno = connection.GetLastError(); + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)", + key, value, errno, strerror(errno)); + return -1; + } + + if (result != PROP_SUCCESS) { + async_safe_format_log(ANDROID_LOG_WARN, "libc", + "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value, + result); + return -1; + } + + return 0; + } +} diff --git a/aosp/bionic/libc/bionic/tdestroy.cpp b/aosp/bionic/libc/bionic/tdestroy.cpp new file mode 100644 index 000000000..6606c5630 --- /dev/null +++ b/aosp/bionic/libc/bionic/tdestroy.cpp @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#include +#include + +struct node_t { + char* key; + struct node* llink; + struct node* rlink; +}; + +// Destroy a tree and free all allocated resources. +// This is a GNU extension, not available from BSD. +void tdestroy(void* root, void (*destroy_func)(void*)) { + node_t* root_node = reinterpret_cast(root); + if (root_node == nullptr) { + return; + } + if (root_node->llink) { + tdestroy(root_node->llink, destroy_func); + } + if (root_node->rlink) { + tdestroy(root_node->rlink, destroy_func); + } + (*destroy_func)(root_node->key); + free(root); +} diff --git a/aosp/bionic/libc/bionic/termios.cpp b/aosp/bionic/libc/bionic/termios.cpp new file mode 100644 index 000000000..5fe8eb0e7 --- /dev/null +++ b/aosp/bionic/libc/bionic/termios.cpp @@ -0,0 +1,46 @@ +/* + * 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 +#include + +// Most of termios was missing in the platform until L, but available as inlines in the NDK. +// We share definitions with the NDK to avoid bugs (https://github.com/android-ndk/ndk/issues/441). +#define __BIONIC_TERMIOS_INLINE /* Out of line. */ +#include + +// Actually declared in , present on all API levels. +pid_t tcgetpgrp(int fd) { + pid_t pid; + return (ioctl(fd, TIOCGPGRP, &pid) == -1) ? -1 : pid; +} + +// Actually declared in , present on all API levels. +int tcsetpgrp(int fd, pid_t pid) { + return ioctl(fd, TIOCSPGRP, &pid); +} diff --git a/aosp/bionic/libc/bionic/thread_private.cpp b/aosp/bionic/libc/bionic/thread_private.cpp new file mode 100644 index 000000000..94fb8bbb9 --- /dev/null +++ b/aosp/bionic/libc/bionic/thread_private.cpp @@ -0,0 +1,42 @@ +/* + * 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 +#include "private/thread_private.h" + +// Some simple glue used to make BSD code thread-safe. + +static pthread_mutex_t g_arc4_lock = PTHREAD_MUTEX_INITIALIZER; + +void _thread_arc4_lock() { + pthread_mutex_lock(&g_arc4_lock); +} + +void _thread_arc4_unlock() { + pthread_mutex_unlock(&g_arc4_lock); +} diff --git a/aosp/bionic/libc/bionic/threads.cpp b/aosp/bionic/libc/bionic/threads.cpp new file mode 100644 index 000000000..f59758013 --- /dev/null +++ b/aosp/bionic/libc/bionic/threads.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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 + +#define __BIONIC_THREADS_INLINE /* Out of line. */ +#include diff --git a/aosp/bionic/libc/bionic/time64.c b/aosp/bionic/libc/bionic/time64.c new file mode 100644 index 000000000..da38bf3b6 --- /dev/null +++ b/aosp/bionic/libc/bionic/time64.c @@ -0,0 +1,802 @@ +/* + +Copyright (c) 2007-2008 Michael G Schwern + +This software originally derived from Paul Sheer's pivotal_gmtime_r.c. + +The MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +/* See http://code.google.com/p/y2038 for this code's origin */ + +#if defined(__LP64__) +#error This cruft should be LP32 only! +#endif + +/* + +Programmers who have available to them 64-bit time values as a 'long +long' type can use localtime64_r() and gmtime64_r() which correctly +converts the time even on 32-bit systems. Whether you have 64-bit time +values will depend on the operating system. + +localtime64_r() is a 64-bit equivalent of localtime_r(). + +gmtime64_r() is a 64-bit equivalent of gmtime_r(). + +*/ + +#include +#include +#include +#include +#include +#include +#include "time64.h" + +/* BIONIC_BEGIN */ +/* the following are here to avoid exposing time64_config.h and + * other types in our public time64.h header + */ +#include "time64_config.h" + +/* Not everyone has gm/localtime_r(), provide a replacement */ +#ifdef HAS_LOCALTIME_R +# define LOCALTIME_R(clock, result) localtime_r(clock, result) +#else +# define LOCALTIME_R(clock, result) fake_localtime_r(clock, result) +#endif +#ifdef HAS_GMTIME_R +# define GMTIME_R(clock, result) gmtime_r(clock, result) +#else +# define GMTIME_R(clock, result) fake_gmtime_r(clock, result) +#endif + +typedef int64_t Int64; +typedef time64_t Time64_T; +typedef int64_t Year; +#define TM tm +/* BIONIC_END */ + +/* Spec says except for stftime() and the _r() functions, these + all return static memory. Stabbings! */ +static struct TM Static_Return_Date; +static char Static_Return_String[35]; + +static const int days_in_month[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, +}; + +static const int julian_days_by_month[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}, +}; + +static char const wday_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char const mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const int length_of_year[2] = { 365, 366 }; + +/* Some numbers relating to the gregorian cycle */ +static const Year years_in_gregorian_cycle = 400; +#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1) +static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL; + +/* Year range we can trust the time funcitons with */ +#define MAX_SAFE_YEAR 2037 +#define MIN_SAFE_YEAR 1971 + +/* 28 year Julian calendar cycle */ +#define SOLAR_CYCLE_LENGTH 28 + +/* Year cycle from MAX_SAFE_YEAR down. */ +static const int safe_years_high[SOLAR_CYCLE_LENGTH] = { + 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, + 2024, 2025, 2026, 2027, + 2028, 2029, 2030, 2031, + 2032, 2033, 2034, 2035, + 2036, 2037, 2010, 2011, + 2012, 2013, 2014, 2015 +}; + +/* Year cycle from MIN_SAFE_YEAR up */ +static const int safe_years_low[SOLAR_CYCLE_LENGTH] = { + 1996, 1997, 1998, 1971, + 1972, 1973, 1974, 1975, + 1976, 1977, 1978, 1979, + 1980, 1981, 1982, 1983, + 1984, 1985, 1986, 1987, + 1988, 1989, 1990, 1991, + 1992, 1993, 1994, 1995, +}; + +/* Let's assume people are going to be looking for dates in the future. + Let's provide some cheats so you can skip ahead. + This has a 4x speed boost when near 2008. +*/ +/* Number of days since epoch on Jan 1st, 2008 GMT */ +#define CHEAT_DAYS (1199145600 / 24 / 60 / 60) +#define CHEAT_YEARS 108 + +#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0) +#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a)) + +#ifdef USE_SYSTEM_LOCALTIME +# define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \ + (a) <= SYSTEM_LOCALTIME_MAX && \ + (a) >= SYSTEM_LOCALTIME_MIN \ +) +#else +# define SHOULD_USE_SYSTEM_LOCALTIME(a) (0) +#endif + +#ifdef USE_SYSTEM_GMTIME +# define SHOULD_USE_SYSTEM_GMTIME(a) ( \ + (a) <= SYSTEM_GMTIME_MAX && \ + (a) >= SYSTEM_GMTIME_MIN \ +) +#else +# define SHOULD_USE_SYSTEM_GMTIME(a) (0) +#endif + +/* Multi varadic macros are a C99 thing, alas */ +#ifdef TIME_64_DEBUG +# define TRACE(format) (fprintf(stderr, format)) +# define TRACE1(format, var1) (fprintf(stderr, format, var1)) +# define TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2)) +# define TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3)) +#else +# define TRACE(format) ((void)0) +# define TRACE1(format, var1) ((void)0) +# define TRACE2(format, var1, var2) ((void)0) +# define TRACE3(format, var1, var2, var3) ((void)0) +#endif + + +static int is_exception_century(Year year) +{ + int is_exception = ((year % 100 == 0) && !(year % 400 == 0)); + TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no"); + + return(is_exception); +} + + +/* timegm() is not in the C or POSIX spec, but it is such a useful + extension I would be remiss in leaving it out. Also I need it + for localtime64() +*/ +Time64_T timegm64(const struct TM *date) { + Time64_T days = 0; + Time64_T seconds = 0; + Year year; + Year orig_year = (Year)date->tm_year; + int cycles = 0; + + if( orig_year > 100 ) { + cycles = (orig_year - 100) / 400; + orig_year -= cycles * 400; + days += (Time64_T)cycles * days_in_gregorian_cycle; + } + else if( orig_year < -300 ) { + cycles = (orig_year - 100) / 400; + orig_year -= cycles * 400; + days += (Time64_T)cycles * days_in_gregorian_cycle; + } + TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year); + + if( orig_year > 70 ) { + year = 70; + while( year < orig_year ) { + days += length_of_year[IS_LEAP(year)]; + year++; + } + } + else if ( orig_year < 70 ) { + year = 69; + do { + days -= length_of_year[IS_LEAP(year)]; + year--; + } while( year >= orig_year ); + } + + + days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon]; + days += date->tm_mday - 1; + + seconds = days * 60 * 60 * 24; + + seconds += date->tm_hour * 60 * 60; + seconds += date->tm_min * 60; + seconds += date->tm_sec; + + return(seconds); +} + + +#if !defined(NDEBUG) +static int check_tm(struct TM *tm) +{ + /* Don't forget leap seconds */ + assert(tm->tm_sec >= 0); + assert(tm->tm_sec <= 61); + + assert(tm->tm_min >= 0); + assert(tm->tm_min <= 59); + + assert(tm->tm_hour >= 0); + assert(tm->tm_hour <= 23); + + assert(tm->tm_mday >= 1); + assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]); + + assert(tm->tm_mon >= 0); + assert(tm->tm_mon <= 11); + + assert(tm->tm_wday >= 0); + assert(tm->tm_wday <= 6); + + assert(tm->tm_yday >= 0); + assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]); + +#ifdef HAS_TM_TM_GMTOFF + assert(tm->tm_gmtoff >= -24 * 60 * 60); + assert(tm->tm_gmtoff <= 24 * 60 * 60); +#endif + + return 1; +} +#endif + + +/* The exceptional centuries without leap years cause the cycle to + shift by 16 +*/ +static Year cycle_offset(Year year) +{ + const Year start_year = 2000; + Year year_diff = year - start_year; + Year exceptions; + + if( year > start_year ) + year_diff--; + + exceptions = year_diff / 100; + exceptions -= year_diff / 400; + + TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n", + year, exceptions, year_diff); + + return exceptions * 16; +} + +/* For a given year after 2038, pick the latest possible matching + year in the 28 year calendar cycle. + + A matching year... + 1) Starts on the same day of the week. + 2) Has the same leap year status. + + This is so the calendars match up. + + Also the previous year must match. When doing Jan 1st you might + wind up on Dec 31st the previous year when doing a -UTC time zone. + + Finally, the next year must have the same start day of week. This + is for Dec 31st with a +UTC time zone. + It doesn't need the same leap year status since we only care about + January 1st. +*/ +static int safe_year(const Year year) +{ + int safe_year = 0; + Year year_cycle; + + if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) { + return (int)year; + } + + year_cycle = year + cycle_offset(year); + + /* safe_years_low is off from safe_years_high by 8 years */ + if( year < MIN_SAFE_YEAR ) + year_cycle -= 8; + + /* Change non-leap xx00 years to an equivalent */ + if( is_exception_century(year) ) + year_cycle += 11; + + /* Also xx01 years, since the previous year will be wrong */ + if( is_exception_century(year - 1) ) + year_cycle += 17; + + year_cycle %= SOLAR_CYCLE_LENGTH; + if( year_cycle < 0 ) + year_cycle = SOLAR_CYCLE_LENGTH + year_cycle; + + assert( year_cycle >= 0 ); + assert( year_cycle < SOLAR_CYCLE_LENGTH ); + if( year < MIN_SAFE_YEAR ) + safe_year = safe_years_low[year_cycle]; + else if( year > MAX_SAFE_YEAR ) + safe_year = safe_years_high[year_cycle]; + else + assert(0); + + TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n", + year, year_cycle, safe_year); + + assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR); + + return safe_year; +} + + +static void copy_tm_to_TM(const struct tm *src, struct TM *dest) { + if( src == NULL ) { + memset(dest, 0, sizeof(*dest)); + } + else { +# ifdef USE_TM64 + dest->tm_sec = src->tm_sec; + dest->tm_min = src->tm_min; + dest->tm_hour = src->tm_hour; + dest->tm_mday = src->tm_mday; + dest->tm_mon = src->tm_mon; + dest->tm_year = (Year)src->tm_year; + dest->tm_wday = src->tm_wday; + dest->tm_yday = src->tm_yday; + dest->tm_isdst = src->tm_isdst; + +# ifdef HAS_TM_TM_GMTOFF + dest->tm_gmtoff = src->tm_gmtoff; +# endif + +# ifdef HAS_TM_TM_ZONE + dest->tm_zone = src->tm_zone; +# endif + +# else + /* They're the same type */ + memcpy(dest, src, sizeof(*dest)); +# endif + } +} + + +static void copy_TM_to_tm(const struct TM *src, struct tm *dest) { + if( src == NULL ) { + memset(dest, 0, sizeof(*dest)); + } + else { +# ifdef USE_TM64 + dest->tm_sec = src->tm_sec; + dest->tm_min = src->tm_min; + dest->tm_hour = src->tm_hour; + dest->tm_mday = src->tm_mday; + dest->tm_mon = src->tm_mon; + dest->tm_year = (int)src->tm_year; + dest->tm_wday = src->tm_wday; + dest->tm_yday = src->tm_yday; + dest->tm_isdst = src->tm_isdst; + +# ifdef HAS_TM_TM_GMTOFF + dest->tm_gmtoff = src->tm_gmtoff; +# endif + +# ifdef HAS_TM_TM_ZONE + dest->tm_zone = src->tm_zone; +# endif + +# else + /* They're the same type */ + memcpy(dest, src, sizeof(*dest)); +# endif + } +} + + +/* Simulate localtime_r() to the best of our ability */ +struct tm * fake_localtime_r(const time_t *clock, struct tm *result) { + const struct tm *static_result = localtime(clock); + + assert(result != NULL); + + if( static_result == NULL ) { + memset(result, 0, sizeof(*result)); + return NULL; + } + else { + memcpy(result, static_result, sizeof(*result)); + return result; + } +} + + + +/* Simulate gmtime_r() to the best of our ability */ +struct tm * fake_gmtime_r(const time_t *clock, struct tm *result) { + const struct tm *static_result = gmtime(clock); + + assert(result != NULL); + + if( static_result == NULL ) { + memset(result, 0, sizeof(*result)); + return NULL; + } + else { + memcpy(result, static_result, sizeof(*result)); + return result; + } +} + + +static Time64_T seconds_between_years(Year left_year, Year right_year) { + int increment = (left_year > right_year) ? 1 : -1; + Time64_T seconds = 0; + int cycles; + + if( left_year > 2400 ) { + cycles = (left_year - 2400) / 400; + left_year -= cycles * 400; + seconds += cycles * seconds_in_gregorian_cycle; + } + else if( left_year < 1600 ) { + cycles = (left_year - 1600) / 400; + left_year += cycles * 400; + seconds += cycles * seconds_in_gregorian_cycle; + } + + while( left_year != right_year ) { + seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24; + right_year += increment; + } + + return seconds * increment; +} + + +Time64_T mktime64(const struct TM *input_date) { + struct tm safe_date; + struct TM date; + Time64_T time; + Year year = input_date->tm_year + 1900; + + if( MIN_SAFE_YEAR <= year && year <= MAX_SAFE_YEAR ) { + copy_TM_to_tm(input_date, &safe_date); + return (Time64_T)mktime(&safe_date); + } + + /* Have to make the year safe in date else it won't fit in safe_date */ + date = *input_date; + date.tm_year = safe_year(year) - 1900; + copy_TM_to_tm(&date, &safe_date); + + time = (Time64_T)mktime(&safe_date); + + time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900)); + + return time; +} + + +/* Because I think mktime() is a crappy name */ +Time64_T timelocal64(const struct TM *date) { + return mktime64(date); +} + + +struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p) +{ + int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday; + Time64_T v_tm_tday; + int leap; + Time64_T m; + Time64_T time = *in_time; + Year year = 70; + int cycles = 0; + + assert(p != NULL); + + /* Use the system gmtime() if time_t is small enough */ + if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) { + time_t safe_time = *in_time; + struct tm safe_date; + GMTIME_R(&safe_time, &safe_date); + + copy_tm_to_TM(&safe_date, p); + assert(check_tm(p)); + + return p; + } + +#ifdef HAS_TM_TM_GMTOFF + p->tm_gmtoff = 0; +#endif + p->tm_isdst = 0; + +#ifdef HAS_TM_TM_ZONE + p->tm_zone = "UTC"; +#endif + + v_tm_sec = (int)(time % 60); + time /= 60; + v_tm_min = (int)(time % 60); + time /= 60; + v_tm_hour = (int)(time % 24); + time /= 24; + v_tm_tday = time; + + WRAP (v_tm_sec, v_tm_min, 60); + WRAP (v_tm_min, v_tm_hour, 60); + WRAP (v_tm_hour, v_tm_tday, 24); + + v_tm_wday = (int)((v_tm_tday + 4) % 7); + if (v_tm_wday < 0) + v_tm_wday += 7; + m = v_tm_tday; + + if (m >= CHEAT_DAYS) { + year = CHEAT_YEARS; + m -= CHEAT_DAYS; + } + + if (m >= 0) { + /* Gregorian cycles, this is huge optimization for distant times */ + cycles = (int)(m / (Time64_T) days_in_gregorian_cycle); + if( cycles ) { + m -= (cycles * (Time64_T) days_in_gregorian_cycle); + year += (cycles * years_in_gregorian_cycle); + } + + /* Years */ + leap = IS_LEAP (year); + while (m >= (Time64_T) length_of_year[leap]) { + m -= (Time64_T) length_of_year[leap]; + year++; + leap = IS_LEAP (year); + } + + /* Months */ + v_tm_mon = 0; + while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) { + m -= (Time64_T) days_in_month[leap][v_tm_mon]; + v_tm_mon++; + } + } else { + year--; + + /* Gregorian cycles */ + cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1); + if( cycles ) { + m -= (cycles * (Time64_T) days_in_gregorian_cycle); + year += (cycles * years_in_gregorian_cycle); + } + + /* Years */ + leap = IS_LEAP (year); + while (m < (Time64_T) -length_of_year[leap]) { + m += (Time64_T) length_of_year[leap]; + year--; + leap = IS_LEAP (year); + } + + /* Months */ + v_tm_mon = 11; + while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) { + m += (Time64_T) days_in_month[leap][v_tm_mon]; + v_tm_mon--; + } + m += (Time64_T) days_in_month[leap][v_tm_mon]; + } + + p->tm_year = year; + if( p->tm_year != year ) { +#ifdef EOVERFLOW + errno = EOVERFLOW; +#endif + return NULL; + } + + /* At this point m is less than a year so casting to an int is safe */ + p->tm_mday = (int) m + 1; + p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m; + p->tm_sec = v_tm_sec; + p->tm_min = v_tm_min; + p->tm_hour = v_tm_hour; + p->tm_mon = v_tm_mon; + p->tm_wday = v_tm_wday; + + assert(check_tm(p)); + + return p; +} + + +struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm) +{ + time_t safe_time; + struct tm safe_date; + struct TM gm_tm; + Year orig_year; + int month_diff; + + assert(local_tm != NULL); + + /* Use the system localtime() if time_t is small enough */ + if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) { + safe_time = *time; + + TRACE1("Using system localtime for %lld\n", *time); + + LOCALTIME_R(&safe_time, &safe_date); + + copy_tm_to_TM(&safe_date, local_tm); + assert(check_tm(local_tm)); + + return local_tm; + } + + if( gmtime64_r(time, &gm_tm) == NULL ) { + TRACE1("gmtime64_r returned null for %lld\n", *time); + return NULL; + } + + orig_year = gm_tm.tm_year; + + if (gm_tm.tm_year > (2037 - 1900) || + gm_tm.tm_year < (1970 - 1900) + ) + { + TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year); + gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900; + } + + safe_time = timegm64(&gm_tm); + if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) { + TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time); + return NULL; + } + + copy_tm_to_TM(&safe_date, local_tm); + + local_tm->tm_year = orig_year; + if( local_tm->tm_year != orig_year ) { + TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n", + (Year)local_tm->tm_year, (Year)orig_year); + +#ifdef EOVERFLOW + errno = EOVERFLOW; +#endif + return NULL; + } + + + month_diff = local_tm->tm_mon - gm_tm.tm_mon; + + /* When localtime is Dec 31st previous year and + gmtime is Jan 1st next year. + */ + if( month_diff == 11 ) { + local_tm->tm_year--; + } + + /* When localtime is Jan 1st, next year and + gmtime is Dec 31st, previous year. + */ + if( month_diff == -11 ) { + local_tm->tm_year++; + } + + /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st + in a non-leap xx00. There is one point in the cycle + we can't account for which the safe xx00 year is a leap + year. So we need to correct for Dec 31st comming out as + the 366th day of the year. + */ + if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 ) + local_tm->tm_yday--; + + assert(check_tm(local_tm)); + + return local_tm; +} + + +static int valid_tm_wday( const struct TM* date ) { + if( 0 <= date->tm_wday && date->tm_wday <= 6 ) + return 1; + else + return 0; +} + +static int valid_tm_mon( const struct TM* date ) { + if( 0 <= date->tm_mon && date->tm_mon <= 11 ) + return 1; + else + return 0; +} + + +char *asctime64_r( const struct TM* date, char *result ) { + /* I figure everything else can be displayed, even hour 25, but if + these are out of range we walk off the name arrays */ + if (!valid_tm_wday(date) || !valid_tm_mon(date)) { + return NULL; + } + + /* Docs state this function does not support years beyond 9999. */ + if (1900 + date->tm_year > 9999) { + return NULL; + } + + /* + * The IBM docs for this function state that the result buffer can be + * assumed to be at least 26 bytes wide. The docs also state that this is + * only valid for years <= 9999, so we know this format string will not + * print more than that many characters. + * + * http://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/asctimer.htm + */ + snprintf(result, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + wday_name[date->tm_wday], + mon_name[date->tm_mon], + date->tm_mday, date->tm_hour, + date->tm_min, date->tm_sec, + 1900 + date->tm_year); + + return result; +} + + +char *ctime64_r( const Time64_T* time, char* result ) { + struct TM date; + + localtime64_r( time, &date ); + return asctime64_r( &date, result ); +} + + +/* Non-thread safe versions of the above */ +struct TM *localtime64(const Time64_T *time) { + return localtime64_r(time, &Static_Return_Date); +} + +struct TM *gmtime64(const Time64_T *time) { + return gmtime64_r(time, &Static_Return_Date); +} + +char *asctime64( const struct TM* date ) { + return asctime64_r( date, Static_Return_String ); +} + +char *ctime64( const Time64_T* time ) { + return asctime64(localtime64(time)); +} diff --git a/aosp/bionic/libc/bionic/time64_config.h b/aosp/bionic/libc/bionic/time64_config.h new file mode 100644 index 000000000..13850451c --- /dev/null +++ b/aosp/bionic/libc/bionic/time64_config.h @@ -0,0 +1,75 @@ +/* Debugging + TIME_64_DEBUG + Define if you want debugging messages +*/ +/* #define TIME_64_DEBUG */ + + +/* INT_64_T + A 64 bit integer type to use to store time and others. + Must be defined. +*/ +#define INT_64_T long long + + +/* USE_TM64 + Should we use a 64 bit safe replacement for tm? This will + let you go past year 2 billion but the struct will be incompatible + with tm. Conversion functions will be provided. +*/ +/* #define USE_TM64 */ + + +/* Availability of system functions. + + HAS_GMTIME_R + Define if your system has gmtime_r() + + HAS_LOCALTIME_R + Define if your system has localtime_r() + + HAS_TIMEGM + Define if your system has timegm(), a GNU extension. +*/ +#define HAS_GMTIME_R +#define HAS_LOCALTIME_R +#define HAS_TIMEGM + + +/* Details of non-standard tm struct elements. + + HAS_TM_TM_GMTOFF + True if your tm struct has a "tm_gmtoff" element. + A BSD extension. + + HAS_TM_TM_ZONE + True if your tm struct has a "tm_zone" element. + A BSD extension. +*/ +#define HAS_TM_TM_GMTOFF +#define HAS_TM_TM_ZONE + + +/* USE_SYSTEM_LOCALTIME + USE_SYSTEM_GMTIME + Should we use the system functions if the time is inside their range? + Your system localtime() is probably more accurate, but our gmtime() is + fast and safe. +*/ +#define USE_SYSTEM_LOCALTIME +/* #define USE_SYSTEM_GMTIME */ + + +/* SYSTEM_LOCALTIME_MAX + SYSTEM_LOCALTIME_MIN + SYSTEM_GMTIME_MAX + SYSTEM_GMTIME_MIN + Maximum and minimum values your system's gmtime() and localtime() + can handle. We will use your system functions if the time falls + inside these ranges. +*/ +#define SYSTEM_LOCALTIME_MAX 2147483647 +#define SYSTEM_LOCALTIME_MIN -2147483647 +#define SYSTEM_GMTIME_MAX 2147483647 +#define SYSTEM_GMTIME_MIN -2147483647 + diff --git a/aosp/bionic/libc/bionic/timespec_get.cpp b/aosp/bionic/libc/bionic/timespec_get.cpp new file mode 100644 index 000000000..7fc21829e --- /dev/null +++ b/aosp/bionic/libc/bionic/timespec_get.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 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 + +int timespec_get(timespec* ts, int base) { + return (base == TIME_UTC && clock_gettime(CLOCK_REALTIME, ts) != -1) ? base : 0; +} diff --git a/aosp/bionic/libc/bionic/tmpfile.cpp b/aosp/bionic/libc/bionic/tmpfile.cpp new file mode 100644 index 000000000..4378e84ab --- /dev/null +++ b/aosp/bionic/libc/bionic/tmpfile.cpp @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "private/ErrnoRestorer.h" +#include "private/ScopedSignalBlocker.h" + +static FILE* __tmpfile_dir(const char* tmp_dir) { + char* path = nullptr; + if (asprintf(&path, "%s/tmp.XXXXXXXXXX", tmp_dir) == -1) { + return nullptr; + } + + int fd; + { + ScopedSignalBlocker ssb; + fd = mkstemp(path); + if (fd == -1) { + free(path); + return nullptr; + } + + // Unlink the file now so that it's removed when closed. + unlink(path); + free(path); + + // Can we still use the file now it's unlinked? + // File systems without hard link support won't have the usual Unix semantics. + struct stat sb; + int rc = fstat(fd, &sb); + if (rc == -1) { + ErrnoRestorer errno_restorer; + close(fd); + return nullptr; + } + } + + // Turn the file descriptor into a FILE*. + FILE* fp = fdopen(fd, "w+"); + if (fp != nullptr) { + return fp; + } + + // Failure. Clean up. We already unlinked, so we just need to close. + ErrnoRestorer errno_restorer; + close(fd); + return nullptr; +} + +FILE* tmpfile() { + // TODO: get this app's temporary directory from the framework ("/data/data/app/cache"). + + // $EXTERNAL_STORAGE turns out not to be very useful because it doesn't support hard links. + // This means we can't do the usual trick of calling unlink before handing the file back. + + FILE* fp = __tmpfile_dir("/data/local/tmp"); + if (fp == nullptr) { + // P_tmpdir is "/tmp/", but POSIX explicitly says that tmpdir(3) should try P_tmpdir before + // giving up. This is potentially useful for bionic on the host anyway. + fp = __tmpfile_dir(P_tmpdir); + } + return fp; +} +__strong_alias(tmpfile64, tmpfile); diff --git a/aosp/bionic/libc/bionic/umount.cpp b/aosp/bionic/libc/bionic/umount.cpp new file mode 100644 index 000000000..fc80baf9b --- /dev/null +++ b/aosp/bionic/libc/bionic/umount.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +int umount(const char* target) { + return umount2(target, 0); +} diff --git a/aosp/bionic/libc/bionic/unlink.cpp b/aosp/bionic/libc/bionic/unlink.cpp new file mode 100644 index 000000000..b1ab15c96 --- /dev/null +++ b/aosp/bionic/libc/bionic/unlink.cpp @@ -0,0 +1,34 @@ +/* + * 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 +#include + +int unlink(const char* path) { + return unlinkat(AT_FDCWD, path, 0); +} diff --git a/aosp/bionic/libc/bionic/usleep.cpp b/aosp/bionic/libc/bionic/usleep.cpp new file mode 100644 index 000000000..22046846e --- /dev/null +++ b/aosp/bionic/libc/bionic/usleep.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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 + +#include + +int usleep(useconds_t us) { + timespec ts; + ts.tv_sec = us / 1000000; + ts.tv_nsec = (us % 1000000) * 1000; + return nanosleep(&ts, nullptr); +} diff --git a/aosp/bionic/libc/bionic/vdso.cpp b/aosp/bionic/libc/bionic/vdso.cpp new file mode 100644 index 000000000..dbca9c013 --- /dev/null +++ b/aosp/bionic/libc/bionic/vdso.cpp @@ -0,0 +1,139 @@ +/* + * 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 "private/bionic_globals.h" +#include "private/bionic_vdso.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline int vdso_return(int result) { + if (__predict_true(result == 0)) return 0; + + errno = -result; + return -1; +} + +int clock_gettime(int clock_id, timespec* tp) { + auto vdso_clock_gettime = reinterpret_cast( + __libc_globals->vdso[VDSO_CLOCK_GETTIME].fn); + if (__predict_true(vdso_clock_gettime)) { + return vdso_return(vdso_clock_gettime(clock_id, tp)); + } + return __clock_gettime(clock_id, tp); +} + +int clock_getres(int clock_id, timespec* tp) { + auto vdso_clock_getres = reinterpret_cast( + __libc_globals->vdso[VDSO_CLOCK_GETRES].fn); + if (__predict_true(vdso_clock_getres)) { + return vdso_return(vdso_clock_getres(clock_id, tp)); + } + return __clock_getres(clock_id, tp); +} + +int gettimeofday(timeval* tv, struct timezone* tz) { + auto vdso_gettimeofday = reinterpret_cast( + __libc_globals->vdso[VDSO_GETTIMEOFDAY].fn); + if (__predict_true(vdso_gettimeofday)) { + return vdso_return(vdso_gettimeofday(tv, tz)); + } + return __gettimeofday(tv, tz); +} + +time_t time(time_t* t) { + auto vdso_time = reinterpret_cast(__libc_globals->vdso[VDSO_TIME].fn); + if (__predict_true(vdso_time)) { + return vdso_time(t); + } + + // We can't fallback to the time(2) system call because it doesn't exist for most architectures. + timeval tv; + if (gettimeofday(&tv, nullptr) == -1) return -1; + if (t) *t = tv.tv_sec; + return tv.tv_sec; +} + +void __libc_init_vdso(libc_globals* globals) { + auto&& vdso = globals->vdso; + vdso[VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, nullptr }; + vdso[VDSO_CLOCK_GETRES] = { VDSO_CLOCK_GETRES_SYMBOL, nullptr }; + vdso[VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, nullptr }; + vdso[VDSO_TIME] = { VDSO_TIME_SYMBOL, nullptr }; + + // Do we have a vdso? + uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR); + ElfW(Ehdr)* vdso_ehdr = reinterpret_cast(vdso_ehdr_addr); + if (vdso_ehdr == nullptr) { + return; + } + + // How many symbols does it have? + size_t symbol_count = 0; + ElfW(Shdr)* vdso_shdr = reinterpret_cast(vdso_ehdr_addr + vdso_ehdr->e_shoff); + for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) { + if (vdso_shdr[i].sh_type == SHT_DYNSYM) { + symbol_count = vdso_shdr[i].sh_size / sizeof(ElfW(Sym)); + } + } + if (symbol_count == 0) { + return; + } + + // Where's the dynamic table? + ElfW(Addr) vdso_addr = 0; + ElfW(Dyn)* vdso_dyn = nullptr; + ElfW(Phdr)* vdso_phdr = reinterpret_cast(vdso_ehdr_addr + vdso_ehdr->e_phoff); + for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) { + if (vdso_phdr[i].p_type == PT_DYNAMIC) { + vdso_dyn = reinterpret_cast(vdso_ehdr_addr + vdso_phdr[i].p_offset); + } else if (vdso_phdr[i].p_type == PT_LOAD) { + vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr; + } + } + if (vdso_addr == 0 || vdso_dyn == nullptr) { + return; + } + + // Where are the string and symbol tables? + const char* strtab = nullptr; + ElfW(Sym)* symtab = nullptr; + for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_STRTAB) { + strtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + } else if (d->d_tag == DT_SYMTAB) { + symtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); + } + } + if (strtab == nullptr || symtab == nullptr) { + return; + } + + // Are there any symbols we want? + for (size_t i = 0; i < symbol_count; ++i) { + for (size_t j = 0; j < VDSO_END; ++j) { + if (strcmp(vdso[j].name, strtab + symtab[i].st_name) == 0) { + vdso[j].fn = reinterpret_cast(vdso_addr + symtab[i].st_value); + } + } + } +} diff --git a/aosp/bionic/libc/bionic/wait.cpp b/aosp/bionic/libc/bionic/wait.cpp new file mode 100644 index 000000000..3e59f5174 --- /dev/null +++ b/aosp/bionic/libc/bionic/wait.cpp @@ -0,0 +1,45 @@ +/* + * 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 +#include + +extern "C" int __waitid(idtype_t which, id_t id, siginfo_t* info, int options, struct rusage* ru); + +pid_t wait(int* status) { + return wait4(-1, status, 0, nullptr); +} + +pid_t waitpid(pid_t pid, int* status, int options) { + return wait4(pid, status, options, nullptr); +} + +int waitid(idtype_t which, id_t id, siginfo_t* info, int options) { + // The system call takes an optional struct rusage that we don't need. + return __waitid(which, id, info, options, nullptr); +} diff --git a/aosp/bionic/libc/bionic/wchar.cpp b/aosp/bionic/libc/bionic/wchar.cpp new file mode 100644 index 000000000..dabe82485 --- /dev/null +++ b/aosp/bionic/libc/bionic/wchar.cpp @@ -0,0 +1,212 @@ +/* $OpenBSD: citrus_utf8.c,v 1.6 2012/12/05 23:19:59 deraadt Exp $ */ + +/*- + * Copyright (c) 2002-2004 Tim J. Robbins + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 +#include +#include +#include +#include + +#include "private/bionic_mbstate.h" + +// +// This file is basically OpenBSD's citrus_utf8.c but rewritten to not require a +// 12-byte mbstate_t so we're backwards-compatible with our LP32 ABI where +// mbstate_t was only 4 bytes. +// +// The state is the UTF-8 sequence. We only support <= 4-bytes sequences so LP32 +// mbstate_t already has enough space (out of the 4 available bytes we only +// need 3 since we should never need to store the entire sequence in the +// intermediary state). +// +// The C standard leaves the conversion state undefined after a bad conversion. +// To avoid unexpected failures due to the possible use of the internal private +// state we always reset the conversion state when encountering illegal +// sequences. +// +// We also implement the POSIX interface directly rather than being accessed via +// function pointers. +// + +int mbsinit(const mbstate_t* ps) { + return (ps == nullptr || (*(reinterpret_cast(ps->__seq)) == 0)); +} + +size_t mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + // Our wchar_t is UTF-32. + return mbrtoc32(reinterpret_cast(pwc), s, n, state); +} + +size_t mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + size_t i, o, r; + + // The fast paths in the loops below are not safe if an ASCII + // character appears as anything but the first byte of a + // multibyte sequence. Check now to avoid doing it in the loops. + if (nmc > 0 && mbstate_bytes_so_far(state) > 0 && static_cast((*src)[0]) < 0x80) { + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + + // Measure only? + if (dst == nullptr) { + for (i = o = 0; i < nmc; i += r, o++) { + if (static_cast((*src)[i]) < 0x80) { + // Fast path for plain ASCII characters. + if ((*src)[i] == '\0') { + return mbstate_reset_and_return(o, state); + } + r = 1; + } else { + r = mbrtowc(nullptr, *src + i, nmc - i, state); + if (r == __MB_ERR_ILLEGAL_SEQUENCE) { + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if (r == __MB_ERR_INCOMPLETE_SEQUENCE) { + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if (r == 0) { + return mbstate_reset_and_return(o, state); + } + } + } + return mbstate_reset_and_return(o, state); + } + + // Actually convert, updating `dst` and `src`. + for (i = o = 0; i < nmc && o < len; i += r, o++) { + if (static_cast((*src)[i]) < 0x80) { + // Fast path for plain ASCII characters. + dst[o] = (*src)[i]; + r = 1; + if ((*src)[i] == '\0') { + *src = nullptr; + return mbstate_reset_and_return(o, state); + } + } else { + r = mbrtowc(dst + o, *src + i, nmc - i, state); + if (r == __MB_ERR_ILLEGAL_SEQUENCE) { + *src += i; + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if (r == __MB_ERR_INCOMPLETE_SEQUENCE) { + *src += nmc; + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + if (r == 0) { + *src = nullptr; + return mbstate_reset_and_return(o, state); + } + } + } + *src += i; + return mbstate_reset_and_return(o, state); +} + +size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) { + return mbsnrtowcs(dst, src, SIZE_MAX, len, ps); +} + +size_t wcrtomb(char* s, wchar_t wc, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + // Our wchar_t is UTF-32. + return c32rtomb(s, static_cast(wc), state); +} + +size_t wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len, mbstate_t* ps) { + static mbstate_t __private_state; + mbstate_t* state = (ps == nullptr) ? &__private_state : ps; + + if (!mbsinit(state)) { + return mbstate_reset_and_return_illegal(EILSEQ, state); + } + + char buf[MB_LEN_MAX]; + size_t i, o, r; + if (dst == nullptr) { + for (i = o = 0; i < nwc; i++, o += r) { + wchar_t wc = (*src)[i]; + if (static_cast(wc) < 0x80) { + // Fast path for plain ASCII characters. + if (wc == 0) { + return o; + } + r = 1; + } else { + r = wcrtomb(buf, wc, state); + if (r == __MB_ERR_ILLEGAL_SEQUENCE) { + return r; + } + } + } + return o; + } + + for (i = o = 0; i < nwc && o < len; i++, o += r) { + wchar_t wc = (*src)[i]; + if (static_cast(wc) < 0x80) { + // Fast path for plain ASCII characters. + dst[o] = wc; + if (wc == 0) { + *src = nullptr; + return o; + } + r = 1; + } else if (len - o >= sizeof(buf)) { + // Enough space to translate in-place. + r = wcrtomb(dst + o, wc, state); + if (r == __MB_ERR_ILLEGAL_SEQUENCE) { + *src += i; + return r; + } + } else { + // May not be enough space; use temp buffer. + r = wcrtomb(buf, wc, state); + if (r == __MB_ERR_ILLEGAL_SEQUENCE) { + *src += i; + return r; + } + if (r > len - o) { + break; + } + memcpy(dst + o, buf, r); + } + } + *src += i; + return o; +} + +size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps) { + return wcsnrtombs(dst, src, SIZE_MAX, len, ps); +} diff --git a/aosp/bionic/libc/bionic/wchar_l.cpp b/aosp/bionic/libc/bionic/wchar_l.cpp new file mode 100644 index 000000000..a86961f20 --- /dev/null +++ b/aosp/bionic/libc/bionic/wchar_l.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 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 +#include + +int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) { + return wcscasecmp(ws1, ws2); +} + +int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) { + return wcsncasecmp(ws1, ws2, n); +} + +int wcscoll_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) { + return wcscoll(ws1, ws2); +} + +size_t wcsftime_l(wchar_t* buf, size_t n, const wchar_t* fmt, const struct tm* tm, locale_t) { + return wcsftime(buf, n, fmt, tm); +} + +size_t wcsxfrm_l(wchar_t* dst, const wchar_t* src, size_t n, locale_t) { + return wcsxfrm(dst, src, n); +} + +double wcstod_l(const wchar_t* s, wchar_t** end_ptr, locale_t) { + return wcstod(s, end_ptr); +} + +float wcstof_l(const wchar_t* s, wchar_t** end_ptr, locale_t) { + return wcstof(s, end_ptr); +} + +long wcstol_l(const wchar_t* s, wchar_t** end_ptr, int base, locale_t) { + return wcstol(s, end_ptr, base); +} + +long long wcstoll_l(const wchar_t* s, wchar_t** end_ptr, int base, locale_t) { + return wcstoll(s, end_ptr, base); +} + +unsigned long wcstoul_l(const wchar_t* s, wchar_t** end_ptr, int base, locale_t) { + return wcstoul(s, end_ptr, base); +} + +unsigned long long wcstoull_l(const wchar_t* s, wchar_t** end_ptr, int base, locale_t) { + return wcstoull(s, end_ptr, base); +} + +long double wcstold_l(const wchar_t* s, wchar_t** end_ptr, locale_t) { + return wcstold(s, end_ptr); +} diff --git a/aosp/bionic/libc/bionic/wcstod.cpp b/aosp/bionic/libc/bionic/wcstod.cpp new file mode 100644 index 000000000..75a59f554 --- /dev/null +++ b/aosp/bionic/libc/bionic/wcstod.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 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. + */ + +#define __BIONIC_LP32_USE_LONG_DOUBLE + +#include + +#include +#include + +#include "local.h" + +/// Performs wide-character string to floating point conversion. +template +float_type wcstod(const wchar_t* str, wchar_t** end, float_type strtod_fn(const char*, char**)) { + const wchar_t* original_str = str; + while (iswspace(*str)) { + str++; + } + + // What's the longest span of the input that might be part of the float? + size_t max_len = wcsspn(str, L"-+0123456789.xXeEpP()nNaAiIfFtTyY"); + + // We know the only valid characters are ASCII, so convert them by brute force. + char* ascii_str = new char[max_len + 1]; + if (!ascii_str) return float_type(); + for (size_t i = 0; i < max_len; ++i) { + ascii_str[i] = str[i] & 0xff; + } + ascii_str[max_len] = 0; + + // Set up a fake FILE that points to those ASCII characters, for `parsefloat`. + FILE f; + __sfileext fext; + _FILEEXT_SETUP(&f, &fext); + f._flags = __SRD; + f._bf._base = f._p = reinterpret_cast(ascii_str); + f._bf._size = f._r = max_len; + f._read = [](void*, char*, int) { return 0; }; // aka `eofread`, aka "no more data". + f._lb._base = nullptr; + + // Ask `parsefloat` to look at the same data more carefully. + + // We can't just do this straight away because we can't construct a suitable FILE* + // in the absence of any `fwmemopen` analogous to `fmemopen`. And we don't want to + // duplicate the `parsefloat` logic. We also don't want to actually have to have wchar_t + // implementations of the ASCII `strtod` logic (though if you were designing a libc + // from scratch, you'd probably want to just make that more generic and lose all the + // cruft on top). + size_t actual_len = parsefloat(&f, ascii_str, ascii_str + max_len); + + // Finally let the ASCII conversion function do the work. + char* ascii_end; + float_type result = strtod_fn(ascii_str, &ascii_end); + if (ascii_end != ascii_str + actual_len) abort(); + + if (end) { + if (actual_len == 0) { + // There was an error. We need to set the end pointer back to the original string, not the + // one we advanced past the leading whitespace. + *end = const_cast(original_str); + } else { + *end = const_cast(str) + actual_len; + } + } + + delete[] ascii_str; + return result; +} + +float wcstof(const wchar_t* s, wchar_t** end) { + return wcstod(s, end, strtof); +} + +double wcstod(const wchar_t* s, wchar_t** end) { + return wcstod(s, end, strtod); +} + +long double wcstold(const wchar_t* s, wchar_t** end) { + return wcstod(s, end, strtold); +} diff --git a/aosp/bionic/libc/bionic/wctype.cpp b/aosp/bionic/libc/bionic/wctype.cpp new file mode 100644 index 000000000..082dadaf4 --- /dev/null +++ b/aosp/bionic/libc/bionic/wctype.cpp @@ -0,0 +1,186 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +#include "private/icu.h" + +enum { + WC_TYPE_INVALID = 0, + WC_TYPE_ALNUM, + WC_TYPE_ALPHA, + WC_TYPE_BLANK, + WC_TYPE_CNTRL, + WC_TYPE_DIGIT, + WC_TYPE_GRAPH, + WC_TYPE_LOWER, + WC_TYPE_PRINT, + WC_TYPE_PUNCT, + WC_TYPE_SPACE, + WC_TYPE_UPPER, + WC_TYPE_XDIGIT, + WC_TYPE_MAX +}; + +int iswalnum(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_ALNUM, isalnum); } +int iswalpha(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_ALPHABETIC, isalpha); } +int iswblank(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_BLANK, isblank); } +int iswgraph(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_GRAPH, isgraph); } +int iswlower(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_LOWERCASE, islower); } +int iswprint(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_PRINT, isprint); } +int iswspace(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_WHITE_SPACE, isspace); } +int iswupper(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_UPPERCASE, isupper); } +int iswxdigit(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_XDIGIT, isxdigit); } + +int iswcntrl(wint_t wc) { + typedef int8_t (*FnT)(UChar32); + static auto u_charType = reinterpret_cast(__find_icu_symbol("u_charType")); + return u_charType ? (u_charType(wc) == U_CONTROL_CHAR) : iscntrl(wc); +} + +int iswdigit(wint_t wc) { + typedef UBool (*FnT)(UChar32); + static auto u_isdigit = reinterpret_cast(__find_icu_symbol("u_isdigit")); + return u_isdigit ? u_isdigit(wc) : isdigit(wc); +} + +int iswpunct(wint_t wc) { + typedef UBool (*FnT)(UChar32); + static auto u_ispunct = reinterpret_cast(__find_icu_symbol("u_ispunct")); + return u_ispunct ? u_ispunct(wc) : ispunct(wc); +} + +int iswalnum_l(wint_t c, locale_t) { return iswalnum(c); } +int iswalpha_l(wint_t c, locale_t) { return iswalpha(c); } +int iswblank_l(wint_t c, locale_t) { return iswblank(c); } +int iswcntrl_l(wint_t c, locale_t) { return iswcntrl(c); } +int iswdigit_l(wint_t c, locale_t) { return iswdigit(c); } +int iswgraph_l(wint_t c, locale_t) { return iswgraph(c); } +int iswlower_l(wint_t c, locale_t) { return iswlower(c); } +int iswprint_l(wint_t c, locale_t) { return iswprint(c); } +int iswpunct_l(wint_t c, locale_t) { return iswpunct(c); } +int iswspace_l(wint_t c, locale_t) { return iswspace(c); } +int iswupper_l(wint_t c, locale_t) { return iswupper(c); } +int iswxdigit_l(wint_t c, locale_t) { return iswxdigit(c); } + +int iswctype(wint_t wc, wctype_t char_class) { + switch (char_class) { + case WC_TYPE_ALNUM: return iswalnum(wc); + case WC_TYPE_ALPHA: return iswalpha(wc); + case WC_TYPE_BLANK: return iswblank(wc); + case WC_TYPE_CNTRL: return iswcntrl(wc); + case WC_TYPE_DIGIT: return iswdigit(wc); + case WC_TYPE_GRAPH: return iswgraph(wc); + case WC_TYPE_LOWER: return iswlower(wc); + case WC_TYPE_PRINT: return iswprint(wc); + case WC_TYPE_PUNCT: return iswpunct(wc); + case WC_TYPE_SPACE: return iswspace(wc); + case WC_TYPE_UPPER: return iswupper(wc); + case WC_TYPE_XDIGIT: return iswxdigit(wc); + default: return 0; + } +} + +int iswctype_l(wint_t wc, wctype_t char_class, locale_t) { + return iswctype(wc, char_class); +} + +wint_t towlower(wint_t wc) { + if (wc < 0x80) { + if (wc >= 'A' && wc <= 'Z') return wc | 0x20; + return wc; + } + + typedef UChar32 (*FnT)(UChar32); + static auto u_tolower = reinterpret_cast(__find_icu_symbol("u_tolower")); + return u_tolower ? u_tolower(wc) : tolower(wc); +} + +wint_t towupper(wint_t wc) { + if (wc < 0x80) { + // Using EOR rather than AND makes no difference on arm, but saves an + // instruction on arm64. + if (wc >= 'a' && wc <= 'z') return wc ^ 0x20; + return wc; + } + + typedef UChar32 (*FnT)(UChar32); + static auto u_toupper = reinterpret_cast(__find_icu_symbol("u_toupper")); + return u_toupper ? u_toupper(wc) : toupper(wc); +} + +wint_t towupper_l(wint_t c, locale_t) { return towupper(c); } +wint_t towlower_l(wint_t c, locale_t) { return towlower(c); } + +wctype_t wctype(const char* property) { + static const char* const properties[WC_TYPE_MAX] = { + "", + "alnum", "alpha", "blank", "cntrl", "digit", "graph", + "lower", "print", "punct", "space", "upper", "xdigit" + }; + for (size_t i = 0; i < WC_TYPE_MAX; ++i) { + if (!strcmp(properties[i], property)) { + return static_cast(i); + } + } + return static_cast(0); +} + +wctype_t wctype_l(const char* property, locale_t) { + return wctype(property); +} + +static wctrans_t wctrans_tolower = wctrans_t(1); +static wctrans_t wctrans_toupper = wctrans_t(2); + +wctrans_t wctrans(const char* name) { + if (strcmp(name, "tolower") == 0) return wctrans_tolower; + if (strcmp(name, "toupper") == 0) return wctrans_toupper; + return nullptr; +} + +wctrans_t wctrans_l(const char* name, locale_t) { + return wctrans(name); +} + +wint_t towctrans(wint_t c, wctrans_t t) { + if (t == wctrans_tolower) return towlower(c); + if (t == wctrans_toupper) return towupper(c); + errno = EINVAL; + return 0; +} + +wint_t towctrans_l(wint_t c, wctrans_t t, locale_t) { + return towctrans(c, t); +} diff --git a/aosp/bionic/libc/bionic/wcwidth.cpp b/aosp/bionic/libc/bionic/wcwidth.cpp new file mode 100644 index 000000000..9676b5a87 --- /dev/null +++ b/aosp/bionic/libc/bionic/wcwidth.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 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 + +#include "private/icu.h" + +int wcwidth(wchar_t wc) { + // Fast-path ASCII. + if (wc >= 0x20 && wc < 0x7f) return 1; + + // ASCII NUL is a special case. + if (wc == 0) return 0; + + // C0. + if (wc < ' ' || (wc >= 0x7f && wc <= 0xa0)) return -1; + + // Now for the i18n part. This isn't defined or standardized, so a lot of the choices are + // pretty arbitrary. See https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c for more details. + + // Fancy unicode control characters? + switch (__icu_charType(wc)) { + case -1: + // No icu4c available; give up. + return -1; + case U_CONTROL_CHAR: + return -1; + case U_NON_SPACING_MARK: + case U_ENCLOSING_MARK: + case U_FORMAT_CHAR: + return 0; + } + if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0; + + // Medial and final jamo render as zero width when used correctly. + switch (__icu_getIntPropertyValue(wc, UCHAR_HANGUL_SYLLABLE_TYPE)) { + case U_HST_VOWEL_JAMO: + case U_HST_TRAILING_JAMO: + return 0; + case U_HST_LEADING_JAMO: + case U_HST_LV_SYLLABLE: + case U_HST_LVT_SYLLABLE: + return 2; + } + + if (wc >= 0x3248 && wc <= 0x4dff) { + // Circled two-digit CJK "speed sign" numbers. EastAsianWidth is ambiguous, + // but wide makes more sense. + if (wc <= 0x324f) return 2; + // Hexagrams. EastAsianWidth is neutral, but wide seems better. + if (wc >= 0x4dc0) return 2; + } + + // The EastAsianWidth property is at least defined by the Unicode standard! + switch (__icu_getIntPropertyValue(wc, UCHAR_EAST_ASIAN_WIDTH)) { + case U_EA_AMBIGUOUS: + case U_EA_HALFWIDTH: + case U_EA_NARROW: + case U_EA_NEUTRAL: + return 1; + case U_EA_FULLWIDTH: + case U_EA_WIDE: + return 2; + } + + return 0; +} diff --git a/aosp/bionic/libc/bionic/wmempcpy.cpp b/aosp/bionic/libc/bionic/wmempcpy.cpp new file mode 100644 index 000000000..54ebf8662 --- /dev/null +++ b/aosp/bionic/libc/bionic/wmempcpy.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 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 + +wchar_t* wmempcpy(wchar_t* dst, const wchar_t* src, size_t n) { + return wmemcpy(dst, src, n) + n; +} diff --git a/aosp/bionic/libc/dns/include/hostent.h b/aosp/bionic/libc/dns/include/hostent.h new file mode 100644 index 000000000..8b9a637cf --- /dev/null +++ b/aosp/bionic/libc/dns/include/hostent.h @@ -0,0 +1,93 @@ +/* $NetBSD: hostent.h,v 1.2 2013/08/27 09:56:12 christos Exp $ */ + +/*- + * Copyright (c) 2013 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _DNS_NET_HOSTENT_H +#define _DNS_NET_HOSTENT_H + +#include +#include +#include + +/* + * These are not being advertised because the interfaces are non-standard. + * There are versions by linux, aix, qnx, sun, etc. Our versions are used + * internally to provide thread safety; they mostly resemble qnx. + */ +void sethostent_r(FILE **); +struct hostent *netbsd_gethostent_r(FILE *, struct hostent *, char *, size_t, int *); +void endhostent_r(FILE **); + +/* + * The following are internal API's and are used only for testing. + */ +struct getnamaddr { + struct hostent *hp; + char *buf; + size_t buflen; + int *he; +}; + +/* /etc/hosts lookup */ +int _hf_gethtbyaddr(void *, void *, va_list); +int _hf_gethtbyname(void *, void *, va_list); + +#ifdef YP +/* NIS lookup */ +int _yp_gethtbyaddr(void *, void *, va_list); +int _yp_gethtbyname(void *, void *, va_list); +#endif + +#define HENT_ARRAY(dst, anum, ptr, len) \ + do { \ + size_t _len = (anum + 1) * sizeof(*dst); \ + if (_len > len) \ + goto nospc; \ + dst = (void *)ptr; \ + ptr += _len; \ + len -= _len; \ + } while (/*CONSTCOND*/0) + +#define HENT_COPY(dst, src, slen, ptr, len) \ + do { \ + if ((size_t)slen > len) \ + goto nospc; \ + memcpy(ptr, src, (size_t)slen); \ + dst = ptr; \ + ptr += slen; \ + len -= slen; \ + } while (/* CONSTCOND */0) + +#define HENT_SCOPY(dst, src, ptr, len) \ + do { \ + size_t _len = strlen(src) + 1; \ + HENT_COPY(dst, src, _len, ptr, len); \ + } while (/* CONSTCOND */0) + +#endif /* _DNS_NET_HOSTENT_H */ diff --git a/aosp/bionic/libc/dns/include/nsswitch.h b/aosp/bionic/libc/dns/include/nsswitch.h new file mode 100644 index 000000000..a0ae83bce --- /dev/null +++ b/aosp/bionic/libc/dns/include/nsswitch.h @@ -0,0 +1,217 @@ +/* $NetBSD: nsswitch.h,v 1.21 2011/07/17 20:54:34 joerg Exp $ */ + +/*- + * Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _NSSWITCH_H +#define _NSSWITCH_H 1 + +#include +#include + +#define NSS_MODULE_INTERFACE_VERSION 0 + +#ifndef _PATH_NS_CONF +#define _PATH_NS_CONF "/etc/nsswitch.conf" +#endif + +#define NS_CONTINUE 0 +#define NS_RETURN 1 + +/* + * Layout of: + * uint32_t ns_src.flags + */ + /* nsswitch.conf status codes and nsdispatch(3) return values */ +#define NS_SUCCESS (1<<0) /* entry was found */ +#define NS_UNAVAIL (1<<1) /* source not responding, or corrupt */ +#define NS_NOTFOUND (1<<2) /* source responded 'no such entry' */ +#define NS_TRYAGAIN (1<<3) /* source busy, may respond to retrys */ +#define NS_STATUSMASK 0x000000ff /* bitmask to get the status flags */ + + /* internal nsdispatch(3) flags; not settable in nsswitch.conf(5) */ +#define NS_FORCEALL (1<<8) /* force all methods to be invoked; */ + +/* + * Currently implemented sources. + */ +#define NSSRC_FILES "files" /* local files */ +#define NSSRC_DNS "dns" /* DNS; IN for hosts, HS for others */ +#define NSSRC_NIS "nis" /* YP/NIS */ +#define NSSRC_COMPAT "compat" /* passwd,group in YP compat mode */ + +/* + * Currently implemented databases. + */ +#define NSDB_HOSTS "hosts" +#define NSDB_GROUP "group" +#define NSDB_GROUP_COMPAT "group_compat" +#define NSDB_NETGROUP "netgroup" +#define NSDB_NETWORKS "networks" +#define NSDB_PASSWD "passwd" +#define NSDB_PASSWD_COMPAT "passwd_compat" +#define NSDB_SHELLS "shells" + +/* + * Suggested databases to implement. + */ +#define NSDB_ALIASES "aliases" +#define NSDB_AUTH "auth" +#define NSDB_AUTOMOUNT "automount" +#define NSDB_BOOTPARAMS "bootparams" +#define NSDB_ETHERS "ethers" +#define NSDB_EXPORTS "exports" +#define NSDB_NETMASKS "netmasks" +#define NSDB_PHONES "phones" +#define NSDB_PRINTCAP "printcap" +#define NSDB_PROTOCOLS "protocols" +#define NSDB_REMOTE "remote" +#define NSDB_RPC "rpc" +#define NSDB_SENDMAILVARS "sendmailvars" +#define NSDB_SERVICES "services" +#define NSDB_TERMCAP "termcap" +#define NSDB_TTYS "ttys" + +/* + * ns_dtab `callback' function signature. + */ +typedef int (*nss_method)(void *, void *, va_list); + +/* + * ns_dtab - `nsswitch dispatch table' + * Contains an entry for each source and the appropriate function to call. + */ +typedef struct { + const char *src; + nss_method callback; + void *cb_data; +} ns_dtab; + +/* + * Macros to help build an ns_dtab[] + */ +#define NS_FILES_CB(F,C) { NSSRC_FILES, F, __UNCONST(C) }, +#define NS_COMPAT_CB(F,C) { NSSRC_COMPAT, F, __UNCONST(C) }, + +#ifdef HESIOD +# define NS_DNS_CB(F,C) { NSSRC_DNS, F, __UNCONST(C) }, +#else +# define NS_DNS_CB(F,C) +#endif + +#ifdef YP +# define NS_NIS_CB(F,C) { NSSRC_NIS, F, __UNCONST(C) }, +#else +# define NS_NIS_CB(F,C) +#endif +#define NS_NULL_CB { .src = NULL }, + +/* + * ns_src - `nsswitch source' + * Used by the nsparser routines to store a mapping between a source + * and its dispatch control flags for a given database. + */ +typedef struct { + const char *name; + uint32_t flags; +} ns_src; + + +/* + * ns_mtab - `nsswitch method table' + * An nsswitch module provides a mapping from (database name, method name) + * tuples to the nss_method and associated callback data. Effectively, + * ns_dtab, but used for dynamically loaded modules. + */ +typedef struct { + const char *database; + const char *name; + nss_method method; + void *mdata; +} ns_mtab; + +/* + * nss_module_register_fn - module registration function + * called at module load + * nss_module_unregister_fn - module un-registration function + * called at module unload + */ +typedef void (*nss_module_unregister_fn)(ns_mtab *, u_int); +typedef ns_mtab *(*nss_module_register_fn)(const char *, u_int *, + nss_module_unregister_fn *); + +#ifdef _NS_PRIVATE + +/* + * Private data structures for back-end nsswitch implementation. + */ + +/* + * ns_dbt - `nsswitch database thang' + * For each database in /etc/nsswitch.conf there is a ns_dbt, with its + * name and a list of ns_src's containing the source information. + */ +typedef struct { + const char *name; /* name of database */ + ns_src *srclist; /* list of sources */ + u_int srclistsize; /* size of srclist */ +} ns_dbt; + +/* + * ns_mod - `nsswitch module' + */ +typedef struct { + const char *name; /* module name */ + void *handle; /* handle from dlopen() */ + ns_mtab *mtab; /* method table */ + u_int mtabsize; /* size of mtab */ + /* called to unload module */ + nss_module_unregister_fn unregister; +} ns_mod; + +#endif /* _NS_PRIVATE */ + + +#include + +__BEGIN_DECLS +int nsdispatch(void *, const ns_dtab [], const char *, + const char *, const ns_src [], ...); + +#ifdef _NS_PRIVATE +int _nsdbtaddsrc(ns_dbt *, const ns_src *); +void _nsdbtdump(const ns_dbt *); +int _nsdbtput(const ns_dbt *); +void _nsyyerror(const char *); +int _nsyylex(void); +#endif /* _NS_PRIVATE */ + +__END_DECLS + +#endif /* !_NSSWITCH_H */ diff --git a/aosp/bionic/libc/dns/include/resolv_cache.h b/aosp/bionic/libc/dns/include/resolv_cache.h new file mode 100644 index 000000000..e049d951f --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_cache.h @@ -0,0 +1,76 @@ +/* + * 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. + */ +#ifndef _RESOLV_CACHE_H_ +#define _RESOLV_CACHE_H_ + +#include +#include + +struct __res_state; + +/* sets the name server addresses to the provided res_state structure. The + * name servers are retrieved from the cache which is associated + * with the network to which the res_state structure is associated */ +__LIBC_HIDDEN__ +extern void _resolv_populate_res_for_net(struct __res_state* statp); + +typedef enum { + RESOLV_CACHE_UNSUPPORTED, /* the cache can't handle that kind of queries */ + /* or the answer buffer is too small */ + RESOLV_CACHE_NOTFOUND, /* the cache doesn't know about this query */ + RESOLV_CACHE_FOUND /* the cache found the answer */ +} ResolvCacheStatus; + +__LIBC_HIDDEN__ +extern ResolvCacheStatus +_resolv_cache_lookup( unsigned netid, + const void* query, + int querylen, + void* answer, + int answersize, + int *answerlen ); + +/* add a (query,answer) to the cache, only call if _resolv_cache_lookup + * did return RESOLV_CACHE_NOTFOUND + */ +__LIBC_HIDDEN__ +extern void +_resolv_cache_add( unsigned netid, + const void* query, + int querylen, + const void* answer, + int answerlen ); + +/* Notify the cache a request failed */ +__LIBC_HIDDEN__ +extern void +_resolv_cache_query_failed( unsigned netid, + const void* query, + int querylen); + +#endif /* _RESOLV_CACHE_H_ */ diff --git a/aosp/bionic/libc/dns/include/resolv_netid.h b/aosp/bionic/libc/dns/include/resolv_netid.h new file mode 100644 index 000000000..aa3159601 --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_netid.h @@ -0,0 +1,113 @@ +/* + * 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. + */ +#ifndef _RESOLV_NETID_H +#define _RESOLV_NETID_H + +/* This header contains declarations related to per-network DNS + * server selection. They are used by system/netd/ and should not be + * exposed by the C library's public NDK headers. + */ +#include +#include +#include "resolv_params.h" +#include + +/* + * Passing NETID_UNSET as the netId causes system/netd/server/DnsProxyListener.cpp to + * fill in the appropriate default netId for the query. + */ +#define NETID_UNSET 0u + +/* + * MARK_UNSET represents the default (i.e. unset) value for a socket mark. + */ +#define MARK_UNSET 0u + +__BEGIN_DECLS + +struct __res_params; +struct addrinfo; + +#define __used_in_netd __attribute__((visibility ("default"))) + +/* + * A struct to capture context relevant to network operations. + * + * Application and DNS netids/marks can differ from one another under certain + * circumstances, notably when a VPN applies to the given uid's traffic but the + * VPN network does not have its own DNS servers explicitly provisioned. + * + * The introduction of per-UID routing means the uid is also an essential part + * of the evaluation context. Its proper uninitialized value is + * NET_CONTEXT_INVALID_UID. + */ +struct android_net_context { + unsigned app_netid; + unsigned app_mark; + unsigned dns_netid; + unsigned dns_mark; + uid_t uid; + unsigned flags; + res_send_qhook qhook; +}; + +#define NET_CONTEXT_INVALID_UID ((uid_t)-1) + +#define NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS 0x00000001 +#define NET_CONTEXT_FLAG_USE_EDNS 0x00000002 + +struct hostent *android_gethostbyaddrfornet(const void *, socklen_t, int, unsigned, unsigned) __used_in_netd; +struct hostent *android_gethostbynamefornet(const char *, int, unsigned, unsigned) __used_in_netd; +int android_getaddrinfofornet(const char *, const char *, const struct addrinfo *, unsigned, + unsigned, struct addrinfo **) __used_in_netd; +/* + * TODO: consider refactoring android_getaddrinfo_proxy() to serve as an + * explore_fqdn() dispatch table method, with the below function only making DNS calls. + */ +struct hostent *android_gethostbyaddrfornetcontext(const void *, socklen_t, int, const struct android_net_context *) __used_in_netd; +struct hostent *android_gethostbynamefornetcontext(const char *, int, const struct android_net_context *) __used_in_netd; +int android_getaddrinfofornetcontext(const char *, const char *, const struct addrinfo *, + const struct android_net_context *, struct addrinfo **) __used_in_netd; + +/* set name servers for a network */ +extern int _resolv_set_nameservers_for_net(unsigned netid, const char** servers, + unsigned numservers, const char *domains, const struct __res_params* params) __used_in_netd; + +/* flush the cache associated with a certain network */ +extern void _resolv_flush_cache_for_net(unsigned netid) __used_in_netd; + +/* delete the cache associated with a certain network */ +extern void _resolv_delete_cache_for_net(unsigned netid) __used_in_netd; + +/* Internal use only. */ +struct hostent *android_gethostbyaddrfornetcontext_proxy(const void *, socklen_t, int , const struct android_net_context *) __LIBC_HIDDEN__; +int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, unsigned, unsigned) __LIBC_HIDDEN__; + +__END_DECLS + +#endif /* _RESOLV_NETID_H */ diff --git a/aosp/bionic/libc/dns/include/resolv_params.h b/aosp/bionic/libc/dns/include/resolv_params.h new file mode 100644 index 000000000..ecc1cc325 --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_params.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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 _RESOLV_PARAMS_H +#define _RESOLV_PARAMS_H + +#include + +/* Hard-coded defines */ +#define MAXNS 4 /* max # name servers we'll track */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define MAXDNSRCHPATH 256 /* max length of domain search paths */ +#define MAXNSSAMPLES 64 /* max # samples to store per server */ + +/* Defaults used for initializing __res_params */ +#define SUCCESS_THRESHOLD 75 /* if successes * 100 / total_samples is less than + * this value, the server is considered failing + */ +#define NSSAMPLE_VALIDITY 1800 /* Sample validity in seconds. + * Set to -1 to disable skipping failing + * servers. + */ + +/* If EDNS0_PADDING is defined, queries will be padded to a multiple of this length +when EDNS0 is active. */ +#define EDNS0_PADDING 128 + +/* per-netid configuration parameters passed from netd to the resolver */ +struct __res_params { + uint16_t sample_validity; // sample lifetime in s + // threshold of success / total samples below which a server is considered broken + uint8_t success_threshold; // 0: disable, value / 100 otherwise + uint8_t min_samples; // min # samples needed for statistics to be considered meaningful + uint8_t max_samples; // max # samples taken into account for statistics + int base_timeout_msec; // base query retry timeout (if 0, use RES_TIMEOUT) +}; + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)(struct sockaddr * const *, + const u_char **, int *, + u_char *, int, int *); + +typedef res_sendhookact (*res_send_rhook)(const struct sockaddr *, + const u_char *, int, u_char *, + int, int *); + +#endif // _RESOLV_PARAMS_H diff --git a/aosp/bionic/libc/dns/include/resolv_private.h b/aosp/bionic/libc/dns/include/resolv_private.h new file mode 100644 index 000000000..77b03bfe0 --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_private.h @@ -0,0 +1,536 @@ +/* $NetBSD: resolv.h,v 1.31 2005/12/26 19:01:47 perry Exp $ */ + +/* + * Copyright (c) 1983, 1987, 1989 + * 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. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * Id: resolv.h,v 1.7.2.11.4.2 2004/06/25 00:41:05 marka Exp + */ + +#ifndef _RESOLV_PRIVATE_H_ +#define _RESOLV_PRIVATE_H_ + +#include + +#include +#include "resolv_static.h" +#include "resolv_params.h" +#include "resolv_stats.h" +#include +#include + +// Linux defines MAXHOSTNAMELEN as 64, while the domain name limit in +// RFC 1034 and RFC 1035 is 255 octets. +#ifdef MAXHOSTNAMELEN +#undef MAXHOSTNAMELEN +#endif +#define MAXHOSTNAMELEN 256 + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 20030124 + +/* + * This used to be defined in res_query.c, now it's in herror.c. + * [XXX no it's not. It's in irs/irs_data.c] + * It was + * never extern'd by any *.h file before it was placed here. For thread + * aware programs, the last h_errno value set is stored in res->h_errno. + * + * XXX: There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO + * (and __h_errno_set) to the public via . + * XXX: __h_errno_set is really part of IRS, not part of the resolver. + * If somebody wants to build and use a resolver that doesn't use IRS, + * what do they do? Perhaps something like + * #ifdef WANT_IRS + * # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) + * #else + * # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) + * #endif + */ + +#define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) +struct __res_state; /* forward */ + +/* + * Resolver configuration file. + * Normally not present, but may contain the address of the + * initial name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#ifdef ANDROID_CHANGES +#define _PATH_RESCONF "/etc/ppp/resolv.conf" +#else +#define _PATH_RESCONF "/etc/resolv.conf" +#endif +#endif + +struct res_sym { + int number; /* Identifying number, like T_MX */ + const char * name; /* Its symbolic name, like "MX" */ + const char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +/* + * Global defines and variables for resolver stub. + */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ +#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */ +#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */ +#define RES_DFLRETRY 2 /* Default #/tries. */ +#define RES_MAXTIME 65535 /* Infinity, in milliseconds. */ + +struct __res_state_ext; + +struct __res_state { + unsigned netid; /* NetId: cache key and socket mark */ + int retrans; /* retransmission time interval */ + int retry; /* number of times to retransmit */ +#ifdef sun + u_int options; /* option flags - see below. */ +#else + u_long options; /* option flags - see below. */ +#endif + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ +#ifdef sun + u_int pfcode; /* RES_PRF_ flags - see below. */ +#else + u_long pfcode; /* RES_PRF_ flags - see below. */ +#endif + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + uint32_t mask; + } sort_list[MAXRESOLVSORT]; +#ifdef __OLD_RES_STATE + char lookups[4]; +#else + res_send_qhook qhook; /* query hook */ + res_send_rhook rhook; /* response hook */ + int res_h_errno; /* last one set for this context */ + unsigned _mark; /* If non-0 SET_MARK to _mark on all request sockets */ + int _vcsock; /* PRIVATE: for res_send VC i/o */ + u_int _flags; /* PRIVATE: see below */ + u_int _pad; /* make _u 64 bit aligned */ + union { + /* On an 32-bit arch this means 512b total. */ + char pad[72 - 4*sizeof (int) - 2*sizeof (void *)]; + struct { + uint16_t nscount; + uint16_t nstimes[MAXNS]; /* ms. */ + int nssocks[MAXNS]; + struct __res_state_ext *ext; /* extention for IPv6 */ + } _ext; + } _u; +#endif + struct res_static rstatic[1]; +}; + +typedef struct __res_state *res_state; + +/* Retrieve a local copy of the stats for the given netid. The buffer must have space for + * MAXNS __resolver_stats. Returns the revision id of the resolvers used. + */ +__LIBC_HIDDEN__ +extern int +_resolv_cache_get_resolver_stats( unsigned netid, struct __res_params* params, + struct __res_stats stats[MAXNS]); + +/* Add a sample to the shared struct for the given netid and server, provided that the + * revision_id of the stored servers has not changed. + */ +__LIBC_HIDDEN__ +extern void +_resolv_cache_add_resolver_stats_sample( unsigned netid, int revision_id, int ns, + const struct __res_sample* sample, int max_samples); + +/* End of stats related definitions */ + +union res_sockaddr_union { + struct sockaddr_in sin; +#ifdef IN6ADDR_ANY_INIT + struct sockaddr_in6 sin6; +#endif +#ifdef ISC_ALIGN64 + int64_t __align64; /* 64bit alignment */ +#else + int32_t __align32; /* 32bit alignment */ +#endif + char __space[128]; /* max size */ +}; + +/* + * Resolver flags (used to be discrete per-module statics ints). + */ +#define RES_F_VC 0x00000001 /* socket is TCP */ +#define RES_F_CONN 0x00000002 /* socket is connected */ +#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors */ +#define RES_F__UNUSED 0x00000008 /* (unused) */ +#define RES_F_LASTMASK 0x000000F0 /* ordinal server of last res_nsend */ +#define RES_F_LASTSHIFT 4 /* bit position of LASTMASK "flag" */ +#define RES_GETLAST(res) (((res)._flags & RES_F_LASTMASK) >> RES_F_LASTSHIFT) + +/* res_findzonecut2() options */ +#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */ +#define RES_IPV4ONLY 0x00000002 /* IPv4 only */ +#define RES_IPV6ONLY 0x00000004 /* IPv6 only */ + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore trucation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +#define RES_ROTATE 0x00004000 /* rotate ns list after each query */ +#define RES_NOCHECKNAME 0x00008000 /* do not check names for sanity. */ +#define RES_KEEPTSIG 0x00010000 /* do not strip TSIG records */ +#define RES_BLAST 0x00020000 /* blast all recursive servers */ +#define RES_NOTLDQUERY 0x00100000 /* don't unqualified name as a tld */ +#define RES_USE_DNSSEC 0x00200000 /* use DNSSEC using OK bit in OPT */ +/* #define RES_DEBUG2 0x00400000 */ /* nslookup internal */ +/* KAME extensions: use higher bit to avoid conflict with ISC use */ +#define RES_USE_DNAME 0x10000000 /* use DNAME */ +#define RES_USE_EDNS0 0x40000000 /* use EDNS0 if configured */ +#define RES_NO_NIBBLE2 0x80000000 /* disable alternate nibble lookup */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | \ + RES_DNSRCH | RES_NO_NIBBLE2) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +#define RES_PRF_TRUNC 0x00008000 +/* 0x00010000 */ + +/* Things involving an internal (static) resolver context. */ +__BEGIN_DECLS + +__LIBC_HIDDEN__ extern struct __res_state *__res_get_state(void); +__LIBC_HIDDEN__ extern void __res_put_state(struct __res_state *); + +#ifndef ANDROID_CHANGES +/* + * Source and Binary compatibility; _res will not work properly + * with multi-threaded programs. + */ +extern struct __res_state *__res_state(void); +#define _res (*__res_state()) +#endif + +__END_DECLS + +#ifndef __BIND_NOSTATIC +#define fp_nquery __fp_nquery +#define fp_query __fp_query +#define hostalias __hostalias +#define p_query __p_query +#define res_close __res_close +#define res_opt __res_opt +#define res_isourserver __res_isourserver +#define res_querydomain __res_querydomain +#define res_send __res_send +#define res_sendsigned __res_sendsigned + +#ifdef BIND_RES_POSIX3 +#define dn_expand __dn_expand +#define res_init __res_init +#define res_query __res_query +#define res_search __res_search +#define res_mkquery __res_mkquery +#endif + +__BEGIN_DECLS +void fp_nquery(const u_char *, int, FILE *); +void fp_query(const u_char *, FILE *); +const char * hostalias(const char *); +void p_query(const u_char *); +void res_close(void); +int res_init(void); +__LIBC_HIDDEN__ int res_opt(int, u_char *, int, int); +int res_isourserver(const struct sockaddr_in *); +int res_mkquery(int, const char *, int, int, const u_char *, int, const u_char *, u_char *, int); +int res_query(const char *, int, int, u_char *, int); +int res_querydomain(const char *, const char *, int, int, u_char *, int); +int res_search(const char *, int, int, u_char *, int); +int res_send(const u_char *, int, u_char *, int); +int res_sendsigned(const u_char *, int, ns_tsig_key *, u_char *, int); +__END_DECLS +#endif + +#if !defined(SHARED_LIBBIND) || defined(LIB) +/* + * If libbind is a shared object (well, DLL anyway) + * these externs break the linker when resolv.h is + * included by a lib client (like named) + * Make them go away if a client is including this + * + */ +__LIBC_HIDDEN__ extern const struct res_sym __p_key_syms[]; +__LIBC_HIDDEN__ extern const struct res_sym __p_cert_syms[]; +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; +__LIBC_HIDDEN__ extern const struct res_sym __p_rcode_syms[]; +#endif /* SHARED_LIBBIND */ + +#ifndef ANDROID_CHANGES +#define dn_comp __dn_comp +#endif +#define dn_count_labels __dn_count_labels +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define loc_aton __loc_aton +#define loc_ntoa __loc_ntoa +#define p_cdname __p_cdname +#define p_cdnname __p_cdnname +#define p_class __p_class +#define p_fqname __p_fqname +#define p_fqnname __p_fqnname +#define p_option __p_option +#define p_secstodate __p_secstodate +#define p_section __p_section +#define p_time __p_time +#define p_type __p_type +#define p_rcode __p_rcode +#define p_sockun __p_sockun +#define putlong __putlong +#define putshort __putshort +#define res_dnok __res_dnok +#define res_findzonecut __res_findzonecut +#define res_findzonecut2 __res_findzonecut2 +#define res_hnok __res_hnok +#define res_hostalias __res_hostalias +#define res_mailok __res_mailok +#define res_nameinquery __res_nameinquery +#define res_nclose __res_nclose +#define res_ninit __res_ninit +#define res_nmkquery __res_nmkquery +#define res_pquery __res_pquery +#define res_nquery __res_nquery +#define res_nquerydomain __res_nquerydomain +#define res_nsearch __res_nsearch +#define res_nsend __res_nsend +#define res_nsendsigned __res_nsendsigned +#define res_nisourserver __res_nisourserver +#define res_ownok __res_ownok +#define res_queriesmatch __res_queriesmatch +#define sym_ntop __sym_ntop +#define sym_ntos __sym_ntos +#define sym_ston __sym_ston +#define res_nopt __res_nopt +#define res_ndestroy __res_ndestroy +#define res_nametoclass __res_nametoclass +#define res_nametotype __res_nametotype +#define res_setservers __res_setservers +#define res_getservers __res_getservers +#define res_buildprotolist __res_buildprotolist +#define res_destroyprotolist __res_destroyprotolist +#define res_destroyservicelist __res_destroyservicelist +#define res_get_nibblesuffix __res_get_nibblesuffix +#define res_get_nibblesuffix2 __res_get_nibblesuffix2 +#define res_ourserver_p __res_ourserver_p +#define res_protocolname __res_protocolname +#define res_protocolnumber __res_protocolnumber +#define res_send_setqhook __res_send_setqhook +#define res_send_setrhook __res_send_setrhook +#define res_servicename __res_servicename +#define res_servicenumber __res_servicenumber +__BEGIN_DECLS +int res_hnok(const char *); +int res_ownok(const char *); +int res_mailok(const char *); +int res_dnok(const char *); +int sym_ston(const struct res_sym *, const char *, int *); +const char * sym_ntos(const struct res_sym *, int, int *); +const char * sym_ntop(const struct res_sym *, int, int *); +#ifndef ANDROID_CHANGES +int b64_ntop(u_char const *, size_t, char *, size_t); +int b64_pton(char const *, u_char *, size_t); +#endif +int loc_aton(const char *, u_char *); +const char * loc_ntoa(const u_char *, char *, size_t); +int dn_skipname(const u_char *, const u_char *); +void putlong(uint32_t, u_char *); +void putshort(uint16_t, u_char *); +#ifndef __ultrix__ +uint16_t _getshort(const u_char *); +uint32_t _getlong(const u_char *); +#endif +const char * p_class(int); +const char * p_time(uint32_t); +const char * p_type(int); +const char * p_rcode(int); +__LIBC_HIDDEN__ const char * p_sockun(union res_sockaddr_union, char *, size_t); +const u_char * p_cdnname(const u_char *, const u_char *, int, FILE *); +const u_char * p_cdname(const u_char *, const u_char *, FILE *); +const u_char * p_fqnname(const u_char *, const u_char *, + int, char *, int); +const u_char * p_fqname(const u_char *, const u_char *, FILE *); +const char * p_option(u_long); +char * p_secstodate(u_long); +int dn_count_labels(const char *); +int res_nameinquery(const char *, int, int, const u_char *, + const u_char *); +int res_queriesmatch(const u_char *, const u_char *, + const u_char *, const u_char *); +__LIBC_HIDDEN__ const char * p_section(int, int); +/* Things involving a resolver context. */ +int res_ninit(res_state); +int res_nisourserver(const res_state, const struct sockaddr_in *); +void fp_resstat(const res_state, FILE *); +__LIBC_HIDDEN__ void res_pquery(const res_state, const u_char *, int, FILE *); +const char * res_hostalias(const res_state, const char *, char *, size_t); +int res_nquery(res_state, const char *, int, int, u_char *, int); +int res_nsearch(res_state, const char *, int, int, u_char *, int); +int res_nquerydomain(res_state, const char *, const char *, + int, int, u_char *, int); +int res_nmkquery(res_state, int, const char *, int, int, + const u_char *, int, const u_char *, + u_char *, int); +int res_nsend(res_state, const u_char *, int, u_char *, int); +int res_nsendsigned(res_state, const u_char *, int, + ns_tsig_key *, u_char *, int); +int res_findzonecut(res_state, const char *, ns_class, int, + char *, size_t, struct in_addr *, int); +int res_findzonecut2(res_state, const char *, ns_class, int, + char *, size_t, + union res_sockaddr_union *, int); +void res_nclose(res_state); +__LIBC_HIDDEN__ int res_nopt(res_state, int, u_char *, int, int); +void res_send_setqhook(res_send_qhook); +void res_send_setrhook(res_send_rhook); +__LIBC_HIDDEN__ int __res_vinit(res_state, int); +void res_destroyservicelist(void); +const char * res_servicename(uint16_t, const char *); +const char * res_protocolname(int); +void res_destroyprotolist(void); +void res_buildprotolist(void); +__LIBC_HIDDEN__ const char * res_get_nibblesuffix(res_state); +__LIBC_HIDDEN__ const char * res_get_nibblesuffix2(res_state); +__LIBC_HIDDEN__ void res_ndestroy(res_state); +__LIBC_HIDDEN__ uint16_t res_nametoclass(const char *, int *); +__LIBC_HIDDEN__ uint16_t res_nametotype(const char *, int *); +__LIBC_HIDDEN__ void res_setservers(res_state, + const union res_sockaddr_union *, int); +__LIBC_HIDDEN__ int res_getservers(res_state, + union res_sockaddr_union *, int); + +struct android_net_context; /* forward */ +__LIBC_HIDDEN__ void res_setnetcontext(res_state, const struct android_net_context *); + +// We use the OpenBSD __res_randomid... +u_int __res_randomid(void); +// ...but NetBSD calls it res_randomid. +#define res_randomid __res_randomid + +#ifdef __i386__ +# define __socketcall extern __attribute__((__cdecl__)) +#else +# define __socketcall extern +#endif + +__socketcall int __connect(int, const struct sockaddr*, socklen_t); + +#undef __socketcall + +// Symbols that are supposed to be in resolv.h, but that we aren't exporting. +int ns_parserr2(ns_msg*, ns_sect, int, ns_rr2*); +int ns_name_pton2(const char*, u_char*, size_t, size_t*); +int ns_name_unpack2(const u_char*, const u_char*, const u_char*, u_char*, size_t, size_t*); +int ns_name_eq(ns_nname_ct, size_t, ns_nname_ct, size_t); +int ns_name_owned(ns_namemap_ct, int, ns_namemap_ct, int); +int ns_name_map(ns_nname_ct, size_t, ns_namemap_t, int); +int ns_name_labels(ns_nname_ct, size_t); + +__END_DECLS + +#endif /* !_RESOLV_PRIVATE_H_ */ diff --git a/aosp/bionic/libc/dns/include/resolv_static.h b/aosp/bionic/libc/dns/include/resolv_static.h new file mode 100644 index 000000000..8f2a095c5 --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_static.h @@ -0,0 +1,32 @@ +#ifndef _RESOLV_STATIC_H +#define _RESOLV_STATIC_H + +#include + +/* this structure contains all the variables that were declared + * 'static' in the original NetBSD resolver code. + * + * this caused vast amounts of crashes and memory corruptions + * when the resolver was being used by multiple threads. + * + * (note: the OpenBSD/FreeBSD resolver has similar 'issues') + */ + +#define MAXALIASES 35 +#define MAXADDRS 35 + +typedef struct res_static { + char* h_addr_ptrs[MAXADDRS + 1]; + char* host_aliases[MAXALIASES]; + char hostbuf[8*1024]; + u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ + FILE* hostf; + int stayopen; + const char* servent_ptr; + struct servent servent; + struct hostent host; +} *res_static; + +extern res_static __res_get_static(void); + +#endif /* _RESOLV_STATIC_H */ diff --git a/aosp/bionic/libc/dns/include/resolv_stats.h b/aosp/bionic/libc/dns/include/resolv_stats.h new file mode 100644 index 000000000..c7901d7c6 --- /dev/null +++ b/aosp/bionic/libc/dns/include/resolv_stats.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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 _RES_STATS_H +#define _RES_STATS_H + +#include +#include +#include +#include + +#include "resolv_params.h" + +#define RCODE_INTERNAL_ERROR 254 +#define RCODE_TIMEOUT 255 + +/* + * Resolver reachability statistics and run-time parameters. + */ + +struct __res_sample { + time_t at; // time in s at which the sample was recorded + uint16_t rtt; // round-trip time in ms + uint8_t rcode; // the DNS rcode or RCODE_XXX defined above +}; + +struct __res_stats { + // Stats of the last queries. + struct __res_sample samples[MAXNSSAMPLES]; + // The number of samples stored. + uint8_t sample_count; + // The next sample to modify. + uint8_t sample_next; +}; + +/* Calculate the round-trip-time from start time t0 and end time t1. */ +extern int +_res_stats_calculate_rtt(const struct timespec* t1, const struct timespec* t0); + +/* Initialize a sample for calculating server reachability statistics. */ +extern void +_res_stats_set_sample(struct __res_sample* sample, time_t now, int rcode, int rtt); + +/* Returns true if the server is considered unusable, i.e. if the success rate is not lower than the + * threshold for the stored stored samples. If not enough samples are stored, the server is + * considered usable. + */ +extern bool +_res_stats_usable_server(const struct __res_params* params, struct __res_stats* stats); + +__BEGIN_DECLS +/* Aggregates the reachability statistics for the given server based on on the stored samples. */ +extern void +android_net_res_stats_aggregate(struct __res_stats* stats, int* successes, int* errors, + int* timeouts, int* internal_errors, int* rtt_avg, time_t* last_sample_time) + __attribute__((visibility ("default"))); + +extern int +android_net_res_stats_get_info_for_net(unsigned netid, int* nscount, + struct sockaddr_storage servers[MAXNS], int* dcount, char domains[MAXDNSRCH][MAXDNSRCHPATH], + struct __res_params* params, struct __res_stats stats[MAXNS]) + __attribute__((visibility ("default"))); + +/* Returns an array of bools indicating which servers are considered good */ +extern void +android_net_res_stats_get_usable_servers(const struct __res_params* params, + struct __res_stats stats[], int nscount, bool valid_servers[]) + __attribute__((visibility ("default"))); +__END_DECLS + +#endif // _RES_STATS_H diff --git a/aosp/bionic/libc/dns/nameser/ns_name.c b/aosp/bionic/libc/dns/nameser/ns_name.c new file mode 100644 index 000000000..c2dc80f59 --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_name.c @@ -0,0 +1,1169 @@ +/* $NetBSD: ns_name.c,v 1.9 2012/03/13 21:13:39 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp"; +#else +__RCSID("$NetBSD: ns_name.c,v 1.9 2012/03/13 21:13:39 christos Exp $"); +#endif +#endif + +#include + +#include +#include + +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include +#include + +#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 + +/* Data. */ + +static const char digits[] = "0123456789"; + +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ +}; + +/* Forward. */ + +static int special(int); +static int printable(int); +static int dn_find(const u_char *, const u_char *, + const u_char * const *, + const u_char * const *); +static int encode_bitsring(const char **, const char *, + unsigned char **, unsigned char **, + unsigned const char *); +static int labellen(const u_char *); +static int decode_bitstring(const unsigned char **, + char *, const char *); + +/* Public. */ + +/* + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { + int m; + + if (n != DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for (; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + _DIAGASSERT(__type_fit(int, dn - dst)); + return (int)(dn - dst); +} + +/* + * Convert a ascii string into an encoded domain name as per RFC1035. + * + * return: + * + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * + * notes: + * Enforces label and domain length limits. + */ +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { + return (ns_name_pton2(src, dst, dstsiz, NULL)); +} + +/* + * ns_name_pton2(src, dst, dstsiz, *dstlen) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * side effects: + * fills in *dstlen (if non-NULL) + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) { + u_char *label, *bp, *eom; + int c, n, escaped, e = 0; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if (c == '[') { /* start a bit string label */ + if ((cp = strchr(src, ']')) == NULL) { + errno = EINVAL; /* ??? */ + return(-1); + } + if ((e = encode_bitsring(&src, cp + 2, + &label, &bp, eom)) + != 0) { + errno = e; + return(-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return(-1); + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) { + n = (int)(cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (int)(cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (int)(cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (int)(bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + if (dstlen != NULL) + *dstlen = (bp - dst); + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (int)(bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + if (dstlen != NULL) + *dstlen = (bp - dst); + return (0); +} + +/* + * Convert a network strings labels into all lowercase. + * + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) +{ + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; + return (-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + for (; l > 0; l--) { + c = *cp++; + if (isascii(c) && isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + _DIAGASSERT(__type_fit(int, dn - dst)); + return (int)(dn - dst); +} + +/* + * Unpack a domain name from a message, source may be compressed. + * + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +int +ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz) +{ + return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL)); +} + +/* + * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + * side effect: + * fills in *dstlen (if non-NULL). + */ +int +ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz, size_t *dstlen) +{ + const u_char *srcp, *dstlim; + u_char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + case NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) { + errno = EMSGSIZE; + return(-1); + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, (size_t)l); + dstp += l; + srcp += l; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) { + _DIAGASSERT(__type_fit(int, srcp - src + 1)); + len = (int)(srcp - src + 1); + } + // BEGIN android-changed: safer pointer overflow check + l = (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (l >= eom - msg) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + srcp = msg + l; + // END android-changed + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp++ = 0; + if (dstlen != NULL) + *dstlen = dstp - dst; + if (len < 0) { + _DIAGASSERT(__type_fit(int, srcp - src)); + len = (int)(srcp - src); + } + return len; +} + +/* + * Pack domain name 'domain' into 'comp_dn'. + * + * return: + * Size of the compressed name, or -1. + * + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +int +ns_name_pack(const u_char *src, u_char *dst, int dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + continue; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + int l0; + + n = *srcp; + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + errno = EMSGSIZE; + return (-1); + } + if ((l0 = labellen(srcp)) < 0) { + errno = EINVAL; + return(-1); + } + l += l0 + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + _DIAGASSERT(__type_fit(int, dstp - dst)); + return (int)(dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, (size_t)(n + 1)); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + _DIAGASSERT(__type_fit(int, dstp - dst)); + return (int)(dstp - dst); +} + +/* + * Expand compressed domain name to presentation format. + * + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * + * note: + * Root domain returns as "." not "". + */ +int +ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, size_t dstsiz) +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * Compress a domain name into wire format, using compression pointers. + * + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. + * The list ends with NULL. 'lastdnptr' is a pointer to the end of the + * array pointed to by 'dnptrs'. Side effect is to update the list of + * pointers for labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); +} + +/* + * Reset dnptrs so that there are no active references to pointers at or + * after src. + */ +void +ns_name_rollback(const u_char *src, const u_char **dnptrs, + const u_char **lastdnptr) +{ + while (dnptrs < lastdnptr && *dnptrs != NULL) { + if (*dnptrs >= src) { + *dnptrs = NULL; + break; + } + dnptrs++; + } +} + +/* + * Advance *ptrptr to skip over the compressed name it points at. + * + * return: + * 0 on success, -1 (with errno set) on failure. + */ +int +ns_name_skip(const u_char **ptrptr, const u_char *eom) +{ + const u_char *cp; + u_int n; + int l=0; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_TYPE_ELT: /* EDNS0 extended label */ + if (cp < eom && (l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + cp += l; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Find the number of octets an nname takes up, including the root label. + * (This is basically ns_name_skip() without compression-pointer support.) + * ((NOTE: can only return zero if passed-in namesiz argument is zero.)) + */ +ssize_t +ns_name_length(ns_nname_ct nname, size_t namesiz) { + ns_nname_ct orig = nname; + u_int n; + + while (namesiz-- > 0 && (n = *nname++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + errno = EISDIR; + return (-1); + } + if (n > namesiz) { + errno = EMSGSIZE; + return (-1); + } + nname += n; + namesiz -= n; + } + return (nname - orig); +} + +/* Compare two nname's for equality. Return -1 on error (setting errno). + */ +int +ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) { + ns_nname_ct ae = a + as, be = b + bs; + int ac, bc; + + while (ac = *a, bc = *b, ac != 0 && bc != 0) { + if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) { + errno = EISDIR; + return (-1); + } + if (a + ac >= ae || b + bc >= be) { + errno = EMSGSIZE; + return (-1); + } + if (ac != bc || strncasecmp((const char *) ++a, + (const char *) ++b, + (size_t)ac) != 0) + return (0); + a += ac, b += bc; + } + return (ac == 0 && bc == 0); +} + +/* Is domain "A" owned by (at or below) domain "B"? + */ +int +ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) { + /* If A is shorter, it cannot be owned by B. */ + if (an < bn) + return (0); + + /* If they are unequal before the length of the shorter, A cannot... */ + while (bn > 0) { + if (a->len != b->len || + strncasecmp((const char *) a->base, + (const char *) b->base, (size_t)a->len) != 0) + return (0); + a++, an--; + b++, bn--; + } + + /* A might be longer or not, but either way, B owns it. */ + return (1); +} + +/* Build an array of tuples from an nname, top-down order. + * Return the number of tuples (labels) thus discovered. + */ +int +ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) { + u_int n; + int l; + + n = *nname++; + namelen--; + + /* Root zone? */ + if (n == 0) { + /* Extra data follows name? */ + if (namelen > 0) { + errno = EMSGSIZE; + return (-1); + } + return (0); + } + + /* Compression pointer? */ + if ((n & NS_CMPRSFLGS) != 0) { + errno = EISDIR; + return (-1); + } + + /* Label too long? */ + if (n > namelen) { + errno = EMSGSIZE; + return (-1); + } + + /* Recurse to get rest of name done first. */ + l = ns_name_map(nname + n, namelen - n, map, mapsize); + if (l < 0) + return (-1); + + /* Too many labels? */ + if (l >= mapsize) { + errno = ENAMETOOLONG; + return (-1); + } + + /* We're on our way back up-stack, store current map data. */ + map[l].base = nname; + map[l].len = n; + return (l + 1); +} + +/* Count the labels in a domain name. Root counts, so COM. has two. This + * is to make the result comparable to the result of ns_name_map(). + */ +int +ns_name_labels(ns_nname_ct nname, size_t namesiz) { + int ret = 0; + u_int n; + + while (namesiz-- > 0 && (n = *nname++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + errno = EISDIR; + return (-1); + } + if (n > namesiz) { + errno = EMSGSIZE; + return (-1); + } + nname += n; + namesiz -= n; + ret++; + } + return (ret + 1); +} +/* Private. */ + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * + * return: + * boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * + * return: + * boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/* + * Search for the counted-label name in an array of compressed names. + * + * return: + * offset from msg if found, or -1. + * + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && + (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for (; n > 0; n--) + if (mklower(*dn++) != + mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') { + _DIAGASSERT(__type_fit(int, + sp - msg)); + return (int)(sp - msg); + } + if (*dn) + continue; + goto next; + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + sp += *sp + 1; + } + } + errno = ENOENT; + return (-1); +} + +static int +decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) +{ + const unsigned char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen, i; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += (int)sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + i = snprintf(dn, eom - dn, "\\[x"); + if (i < 0) + return (-1); + dn += i; + for (b = blen; b > 7; b -= 8, cp++) { + i = snprintf(dn, eom - dn, "%02x", *cp & 0xff); + if (i < 0) + return (-1); + dn += i; + } + if (b > 4) { + tc = *cp++; + i = snprintf(dn, eom - dn, "%02x", tc & (0xff << (8 - b))); + if (i < 0) + return (-1); + dn += i; + } else if (b > 0) { + tc = *cp++; + i = snprintf(dn, eom - dn, "%1x", + (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))); + if (i < 0) + return (-1); + dn += i; + } + i = snprintf(dn, eom - dn, "/%d]", blen); + if (i < 0) + return (-1); + dn += i; + + *cpp = cp; + _DIAGASSERT(__type_fit(int, dn - beg)); + return (int)(dn - beg); +} + +static int +encode_bitsring(const char **bp, const char *end, unsigned char **labelp, + unsigned char ** dst, unsigned const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + unsigned char *tp; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return(EINVAL); + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return(EINVAL); + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return(EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch((c = *cp)) { + case ']': /* end of the bitstring */ + if (afterslash) { + if (beg_blen == NULL) + return(EINVAL); + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return(EINVAL); + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) { + if (!isdigit(c&0xff)) + return(EINVAL); + if (beg_blen == NULL) { + + if (c == '0') { + /* blen never begings with 0 */ + return(EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c&0xff)) + return(EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return(EINVAL); + if (count == 8) { + *tp++ = value; + count = 0; + } + } + break; + } + } + done: + if (cp >= end || tp >= eom) + return(EMSGSIZE); + + /* + * bit length validation: + * If a is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return(EINVAL); + traillen = tbcount - blen; /* between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return(EINVAL); + } + else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = tp; + + return(0); +} + +static int +labellen(const u_char *lp) +{ + int bitlen; + u_char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { + if (l == DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + return(-1); /* unknwon ELT */ + } + return(l); +} diff --git a/aosp/bionic/libc/dns/nameser/ns_netint.c b/aosp/bionic/libc/dns/nameser/ns_netint.c new file mode 100644 index 000000000..8b546f8db --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_netint.c @@ -0,0 +1,59 @@ +/* $NetBSD: ns_netint.c,v 1.7 2012/03/13 21:13:39 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp"; +#else +__RCSID("$NetBSD: ns_netint.c,v 1.7 2012/03/13 21:13:39 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include + +/* Public. */ + +uint16_t +ns_get16(const u_char *src) { + uint16_t dst; + + NS_GET16(dst, src); + return dst; +} + +uint32_t +ns_get32(const u_char *src) { + u_int32_t dst; + + NS_GET32(dst, src); + return dst; +} + +void +ns_put16(uint16_t src, u_char *dst) { + NS_PUT16(src, dst); +} + +void +ns_put32(uint32_t src, u_char *dst) { + NS_PUT32(src, dst); +} diff --git a/aosp/bionic/libc/dns/nameser/ns_parse.c b/aosp/bionic/libc/dns/nameser/ns_parse.c new file mode 100644 index 000000000..3a1901a8d --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_parse.c @@ -0,0 +1,277 @@ +/* $NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp"; +#else +__RCSID("$NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include + +#include +#include + +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include + +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#define RETERR(err) do { errno = (err); return (-1); } while (/*NOTREACHED*//*CONSTCOND*/0) + +/* Public. */ + +struct _ns_flagdata { int mask, shift; }; + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +const struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /* qr. */ + { 0x7800, 11 }, /* opcode. */ + { 0x0400, 10 }, /* aa. */ + { 0x0200, 9 }, /* tc. */ + { 0x0100, 8 }, /* rd. */ + { 0x0080, 7 }, /* ra. */ + { 0x0040, 6 }, /* z. */ + { 0x0020, 5 }, /* ad. */ + { 0x0010, 4 }, /* cd. */ + { 0x000f, 0 }, /* rcode. */ + { 0x0000, 0 }, /* expansion (1/6). */ + { 0x0000, 0 }, /* expansion (2/6). */ + { 0x0000, 0 }, /* expansion (3/6). */ + { 0x0000, 0 }, /* expansion (4/6). */ + { 0x0000, 0 }, /* expansion (5/6). */ + { 0x0000, 0 }, /* expansion (6/6). */ +}; + +int ns_msg_getflag(ns_msg handle, int flag) { + return((u_int32_t)((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift); +} + +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for (; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + _DIAGASSERT(__type_fit(int, ptr - optr)); + return (int)(ptr - optr); +} + +int +ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); + return (0); +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + int tmp; + + /* Make section right. */ + tmp = section; + if (tmp < 0 || section >= ns_s_max) + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* + * This is identical to the above but uses network-format (uncompressed) names. + */ +int +ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) { + int b; + int tmp; + + /* Make section right. */ + tmp = section; + if (tmp < 0 || section >= ns_s_max) + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr, + rr->nname, NS_MAXNNAME, &rr->nnamel); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_msg_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_msg_ptr = msg->_sections[(int)sect]; + } +} diff --git a/aosp/bionic/libc/dns/nameser/ns_print.c b/aosp/bionic/libc/dns/nameser/ns_print.c new file mode 100644 index 000000000..32c87157c --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_print.c @@ -0,0 +1,1259 @@ +/* $NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp"; +#else +__RCSID("$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +/* Forward. */ + +static size_t prune_origin(const char *name, const char *origin); +static int charstr(const u_char *rdata, const u_char *edata, + char **buf, size_t *buflen); +static int addname(const u_char *msg, size_t msglen, + const u_char **p, const char *origin, + char **buf, size_t *buflen); +static void addlen(size_t len, char **buf, size_t *buflen); +static int addstr(const char *src, size_t len, + char **buf, size_t *buflen); +static int addtab(size_t len, size_t target, int spaced, + char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) \ + do { \ + if ((x) < 0) \ + return (-1); \ + } while (/*CONSTCOND*/0) + +static const char base32hex[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv"; +/* Public. */ + +/* + * Convert an RR to presentation format. + * + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrr(const ns_msg *handle, const ns_rr *rr, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + int n; + + n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), + ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), + ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), + name_ctx, origin, buf, buflen); + return (n); +} + +/* + * Convert the fields of an RR into presentation format. + * + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrrf(const u_char *msg, size_t msglen, + const char *name, ns_class class, ns_type type, + u_long ttl, const u_char *rdata, size_t rdlen, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + const char *obuf = buf; + const u_char *edata = rdata + rdlen; + int spaced = 0; + + const char *comment; + char tmp[100]; + int len, x; + + /* + * Owner. + */ + if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { + T(addstr("\t\t\t", (size_t)3, &buf, &buflen)); + } else { + len = (int)prune_origin(name, origin); + if (*name == '\0') { + goto root; + } else if (len == 0) { + T(addstr("@\t\t\t", (size_t)4, &buf, &buflen)); + } else { + T(addstr(name, (size_t)len, &buf, &buflen)); + /* Origin not used or not root, and no trailing dot? */ + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + name[len] == '\0')) && name[len - 1] != '.') { + root: + T(addstr(".", (size_t)1, &buf, &buflen)); + len++; + } + T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen)); + } + } + + /* + * TTL, Class, Type. + */ + T(x = ns_format_ttl(ttl, buf, buflen)); + addlen((size_t)x, &buf, &buflen); + len = snprintf(tmp, sizeof(tmp), " %s %s", p_class(class), p_type(type)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen)); + + /* + * RData. + */ + switch (type) { + case ns_t_a: + if (rdlen != (size_t)NS_INADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ns: + case ns_t_ptr: + case ns_t_dname: + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + + case ns_t_hinfo: + case ns_t_isdn: + /* First word. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + + /* Second word, optional in ISDN records. */ + if (type == ns_t_isdn && rdata == edata) + break; + + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_soa: { + u_long t; + + /* Server name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Administrator name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" (\n", (size_t)3, &buf, &buflen)); + spaced = 0; + + if ((edata - rdata) != 5*NS_INT32SZ) + goto formerr; + + /* Serial number. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + len = snprintf(tmp, sizeof(tmp), "%lu", t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; serial\n", (size_t)9, &buf, &buflen)); + spaced = 0; + + /* Refresh interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; refresh\n", (size_t)10, &buf, &buflen)); + spaced = 0; + + /* Retry interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; retry\n", (size_t)8, &buf, &buflen)); + spaced = 0; + + /* Expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; expiry\n", (size_t)9, &buf, &buflen)); + spaced = 0; + + /* Minimum TTL. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(addstr(" )", (size_t)2, &buf, &buflen)); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; minimum\n", (size_t)10, &buf, &buflen)); + + break; + } + + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: + case ns_t_kx: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u ", t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Target. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_px: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u ", t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_x25: + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_txt: + case ns_t_spf: + while (rdata < edata) { + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + if (rdata < edata) + T(addstr(" ", (size_t)1, &buf, &buflen)); + } + break; + + case ns_t_nsap: { + char t[2+255*3]; + + (void) inet_nsap_ntoa((int)rdlen, rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_aaaa: + if (rdlen != (size_t)NS_IN6ADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_loc: { + char t[255]; + + /* XXX protocol format checking? */ + (void) loc_ntoa(rdata, t, sizeof(t)); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_naptr: { + u_int order, preference; + char t[50]; + + if (rdlen < 2U*NS_INT16SZ) + goto formerr; + + /* Order, Precedence. */ + order = ns_get16(rdata); rdata += NS_INT16SZ; + preference = ns_get16(rdata); rdata += NS_INT16SZ; + len = snprintf(t, sizeof(t), "%u %u ", order, preference); + T(addstr(t, (size_t)len, &buf, &buflen)); + + /* Flags. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Service. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Regexp. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len < 0) + return (-1); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_srv: { + u_int priority, weight, port; + char t[50]; + + if (rdlen < 3U*NS_INT16SZ) + goto formerr; + + /* Priority, Weight, Port. */ + priority = ns_get16(rdata); rdata += NS_INT16SZ; + weight = ns_get16(rdata); rdata += NS_INT16SZ; + port = ns_get16(rdata); rdata += NS_INT16SZ; + len = snprintf(t, sizeof(t), "%u %u %u ", priority, weight, port); + T(addstr(t, (size_t)len, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_minfo: + case ns_t_rp: + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + + case ns_t_wks: { + int n, lcnt; + + if (rdlen < 1U + NS_INT32SZ) + goto formerr; + + /* Address. */ + (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += NS_INADDRSZ; + + /* Protocol. */ + len = snprintf(tmp, sizeof(tmp), " %u ( ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata += NS_INT8SZ; + + /* Bit map. */ + n = 0; + lcnt = 0; + while (rdata < edata) { + u_int c = *rdata++; + do { + if (c & 0200) { + if (lcnt == 0) { + T(addstr("\n\t\t\t\t", (size_t)5, + &buf, &buflen)); + lcnt = 10; + spaced = 0; + } + len = snprintf(tmp, sizeof(tmp), "%d ", n); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + lcnt--; + } + c <<= 1; + } while (++n & 07); + } + T(addstr(")", (size_t)1, &buf, &buflen)); + + break; + } + + case ns_t_key: + case ns_t_dnskey: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int keyflags, protocol, algorithm, key_id; + const char *leader; + int n; + + if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) + goto formerr; + + /* Key flags, Protocol, Algorithm. */ +#ifndef _LIBC + key_id = dst_s_dns_key_id(rdata, edata-rdata); +#else + key_id = 0; +#endif + keyflags = ns_get16(rdata); rdata += NS_INT16SZ; + protocol = *rdata++; + algorithm = *rdata++; + len = snprintf(tmp, sizeof(tmp), "0x%04x %u %u", + keyflags, protocol, algorithm); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Public key data. */ + len = b64_ntop(rdata, (size_t)(edata - rdata), + base64_key, sizeof base64_key); + if (len < 0) + goto formerr; + if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + n = snprintf(tmp, sizeof(tmp), " ; key_tag= %u", key_id); + T(addstr(tmp, (size_t)n, &buf, &buflen)); + + break; + } + + case ns_t_sig: + case ns_t_rrsig: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int typ, algorithm, labels, footprint; + const char *leader; + u_long t; + int n; + + if (rdlen < 22U) + goto formerr; + + /* Type covered, Algorithm, Label count, Original TTL. */ + typ = ns_get16(rdata); rdata += NS_INT16SZ; + algorithm = *rdata++; + labels = *rdata++; + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = snprintf(tmp, sizeof(tmp), "%s %d %d %lu ", + p_type((int)typ), algorithm, labels, t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + if (labels > (u_int)dn_count_labels(name)) + goto formerr; + + /* Signature expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = snprintf(tmp, sizeof(tmp), "%s ", p_secstodate(t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Time signed. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = snprintf(tmp, sizeof(tmp), "%s ", p_secstodate(t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Signature Footprint. */ + footprint = ns_get16(rdata); rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u ", footprint); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Signer's name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Signature. */ + len = b64_ntop(rdata, (size_t)(edata - rdata), + base64_key, sizeof base64_key); + if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + if (len < 0) + goto formerr; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + break; + } + + case ns_t_nxt: { + ptrdiff_t n, c; + + /* Next domain name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Type bit map. */ + n = edata - rdata; + for (c = 0; c < n*8; c++) + if (NS_NXT_BIT_ISSET(c, rdata)) { + len = snprintf(tmp, sizeof(tmp), " %s", p_type((int)c)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + } + break; + } + + case ns_t_cert: { + u_int c_type, key_tag, alg; + int n; + size_t siz; + char base64_cert[8192], tmp1[40]; + const char *leader; + + c_type = ns_get16(rdata); rdata += NS_INT16SZ; + key_tag = ns_get16(rdata); rdata += NS_INT16SZ; + alg = (u_int) *rdata++; + + len = snprintf(tmp1, sizeof(tmp1), "%d %d %d ", c_type, key_tag, alg); + T(addstr(tmp1, (size_t)len, &buf, &buflen)); + siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_cert) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } + else { + len = b64_ntop(rdata, (size_t)(edata-rdata), + base64_cert, siz); + + if (len < 0) + goto formerr; + else if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_cert + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + } + break; + } + + case ns_t_tkey: { + /* KJD - need to complete this */ + u_long t; + int mode, err, keysize; + + /* Algorithm name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Inception. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = snprintf(tmp, sizeof(tmp), "%s ", p_secstodate(t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Experation. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = snprintf(tmp, sizeof(tmp), "%s ", p_secstodate(t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Mode , Error, Key Size. */ + /* Priority, Weight, Port. */ + mode = ns_get16(rdata); rdata += NS_INT16SZ; + err = ns_get16(rdata); rdata += NS_INT16SZ; + keysize = ns_get16(rdata); rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u %u %u ", mode, err, keysize); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* XXX need to dump key, print otherdata length & other data */ + break; + } + + case ns_t_tsig: { + /* BEW - need to complete this */ + int n; + + T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + rdata += 8; /* time */ + n = ns_get16(rdata); rdata += INT16SZ; + rdata += n; /* sig */ + n = ns_get16(rdata); rdata += INT16SZ; /* original id */ + snprintf(buf, buflen, "%d", ns_get16(rdata)); + rdata += INT16SZ; + addlen(strlen(buf), &buf, &buflen); + break; + } + + case ns_t_a6: { + struct in6_addr a; + int pbyte, pbit; + + /* prefix length */ + if (rdlen == 0U) goto formerr; + len = snprintf(tmp, sizeof(tmp), "%d ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + pbit = *rdata; + if (pbit > 128) goto formerr; + pbyte = (pbit & ~7) / 8; + rdata++; + + /* address suffix: provided only when prefix len != 128 */ + if (pbit < 128) { + if (rdata + pbyte >= edata) goto formerr; + memset(&a, 0, sizeof(a)); + memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); + (void) inet_ntop(AF_INET6, &a, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += sizeof(a) - pbyte; + } + + /* prefix name: provided only when prefix len > 0 */ + if (pbit == 0) + break; + if (rdata >= edata) goto formerr; + T(addstr(" ", (size_t)1, &buf, &buflen)); + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_opt: { + len = snprintf(tmp, sizeof(tmp), "%u bytes", class); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + break; + } + + case ns_t_ds: + case ns_t_dlv: + case ns_t_sshfp: { + u_int t; + + if (type == ns_t_ds || type == ns_t_dlv) { + if (rdlen < 4U) goto formerr; + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u ", t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + } else + if (rdlen < 2U) goto formerr; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + while (rdata < edata) { + len = snprintf(tmp, sizeof(tmp), "%02X", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + } + break; + } + + case ns_t_nsec3: + case ns_t_nsec3param: { + u_int t, w, l, j, k, c; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = snprintf(tmp, sizeof(tmp), "%u ", t); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + t = *rdata++; + if (t == 0) { + T(addstr("-", 1, &buf, &buflen)); + } else { + while (t-- > 0) { + len = snprintf(tmp, sizeof(tmp), "%02X", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + } + } + if (type == ns_t_nsec3param) + break; + T(addstr(" ", 1, &buf, &buflen)); + + t = *rdata++; + while (t > 0) { + switch (t) { + case 1: + tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)]; + tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)]; + tmp[2] = tmp[3] = tmp[4] = '='; + tmp[5] = tmp[6] = tmp[7] = '='; + break; + case 2: + tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)]; + tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)| + (((uint32_t)rdata[1]>>6)&0x03)]; + tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)]; + tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)]; + tmp[4] = tmp[5] = tmp[6] = tmp[7] = '='; + break; + case 3: + tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)]; + tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)| + (((uint32_t)rdata[1]>>6)&0x03)]; + tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)]; + tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)| + (((uint32_t)rdata[2]>>4)&0x0f)]; + tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)]; + tmp[5] = tmp[6] = tmp[7] = '='; + break; + case 4: + tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)]; + tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)| + (((uint32_t)rdata[1]>>6)&0x03)]; + tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)]; + tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)| + (((uint32_t)rdata[2]>>4)&0x0f)]; + tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)| + (((uint32_t)rdata[3]>>7)&0x01)]; + tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)]; + tmp[6] = base32hex[((uint32_t)rdata[3]<<3)&0x18]; + tmp[7] = '='; + break; + default: + tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)]; + tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)| + (((uint32_t)rdata[1]>>6)&0x03)]; + tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)]; + tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)| + (((uint32_t)rdata[2]>>4)&0x0f)]; + tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)| + (((uint32_t)rdata[3]>>7)&0x01)]; + tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)]; + tmp[6] = base32hex[(((uint32_t)rdata[3]<<3)&0x18)| + (((uint32_t)rdata[4]>>5)&0x07)]; + tmp[7] = base32hex[(rdata[4]&0x1f)]; + break; + } + T(addstr(tmp, 8, &buf, &buflen)); + if (t >= 5) { + rdata += 5; + t -= 5; + } else { + rdata += t; + t -= t; + } + } + + while (rdata < edata) { + w = *rdata++; + l = *rdata++; + for (j = 0; j < l; j++) { + if (rdata[j] == 0) + continue; + for (k = 0; k < 8; k++) { + if ((rdata[j] & (0x80 >> k)) == 0) + continue; + c = w * 256 + j * 8 + k; + len = snprintf(tmp, sizeof(tmp), " %s", p_type((ns_type)c)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + } + } + rdata += l; + } + break; + } + + case ns_t_nsec: { + u_int w, l, j, k, c; + + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + while (rdata < edata) { + w = *rdata++; + l = *rdata++; + for (j = 0; j < l; j++) { + if (rdata[j] == 0) + continue; + for (k = 0; k < 8; k++) { + if ((rdata[j] & (0x80 >> k)) == 0) + continue; + c = w * 256 + j * 8 + k; + len = snprintf(tmp, sizeof(tmp), " %s", p_type((ns_type)c)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + } + } + rdata += l; + } + break; + } + + case ns_t_dhcid: { + int n; + unsigned int siz; + char base64_dhcid[8192]; + const char *leader; + + siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_dhcid) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } else { + len = b64_ntop(rdata, (size_t)(edata-rdata), + base64_dhcid, siz); + + if (len < 0) + goto formerr; + + else if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_dhcid + n, + (size_t)MIN(len - n, 48), &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + } + break; + } + + case ns_t_ipseckey: { + int n; + unsigned int siz; + char base64_key[8192]; + const char *leader; + + if (rdlen < 2) + goto formerr; + + switch (rdata[1]) { + case 0: + case 3: + if (rdlen < 3) + goto formerr; + break; + case 1: + if (rdlen < 7) + goto formerr; + break; + case 2: + if (rdlen < 19) + goto formerr; + break; + default: + comment = "unknown IPSECKEY gateway type"; + goto hexify; + } + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + len = snprintf(tmp, sizeof(tmp), "%u ", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + + switch (rdata[-2]) { + case 0: + T(addstr(".", 1, &buf, &buflen)); + break; + case 1: + (void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += 4; + break; + case 2: + (void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += 16; + break; + case 3: + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + if (rdata >= edata) + break; + + siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_key) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } else { + len = b64_ntop(rdata, (size_t)(edata-rdata), + base64_key, siz); + + if (len < 0) + goto formerr; + + else if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_key + n, + (size_t)MIN(len - n, 48), &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + } + break; + } + + case ns_t_hip: { + unsigned int i, hip_len, algorithm, key_len; + char base64_key[NS_MD5RSA_MAX_BASE64]; + unsigned int siz; + const char *leader = "\n\t\t\t\t\t"; + + hip_len = *rdata++; + algorithm = *rdata++; + key_len = ns_get16(rdata); + rdata += NS_INT16SZ; + + siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_key) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } else { + len = snprintf(tmp, sizeof(tmp), "( %u ", algorithm); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + for (i = 0; i < hip_len; i++) { + len = snprintf(tmp, sizeof(tmp), "%02X", *rdata); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata++; + } + T(addstr(leader, strlen(leader), &buf, &buflen)); + + len = b64_ntop(rdata, key_len, base64_key, siz); + if (len < 0) + goto formerr; + + T(addstr(base64_key, (size_t)len, &buf, &buflen)); + + rdata += key_len; + while (rdata < edata) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addname(msg, msglen, &rdata, origin, + &buf, &buflen)); + } + T(addstr(" )", 2, &buf, &buflen)); + } + break; + } + + default: + comment = "unknown RR type"; + goto hexify; + } + _DIAGASSERT(__type_fit(int, buf - obuf)); + return (int)(buf - obuf); + formerr: + comment = "RR format error"; + hexify: { + int n, m; + char *p; + + len = snprintf(tmp, sizeof(tmp), "\\# %u%s\t; %s", (unsigned)(edata - rdata), + rdlen != 0U ? " (" : "", comment); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + while (rdata < edata) { + p = tmp; + p += snprintf(p, sizeof(tmp), "\n\t"); + spaced = 0; + n = MIN(16, (int)(edata - rdata)); + for (m = 0; m < n; m++) + p += snprintf(p, sizeof(tmp) - (p - tmp), "%02x ", rdata[m]); + T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); + if (n < 16) { + T(addstr(")", (size_t)1, &buf, &buflen)); + T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen)); + } + p = tmp; + p += snprintf(p, sizeof(tmp), "; "); + for (m = 0; m < n; m++) + *p++ = (isascii(rdata[m]) && isprint(rdata[m])) + ? rdata[m] + : '.'; + T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); + rdata += n; + } + _DIAGASSERT(__type_fit(int, buf - obuf)); + return (int)(buf - obuf); + } +} + +/* Private. */ + +/* + * size_t + * prune_origin(name, origin) + * Find out if the name is at or under the current origin. + * return: + * Number of characters in name before start of origin, + * or length of name if origin does not match. + * notes: + * This function should share code with samedomain(). + */ +static size_t +prune_origin(const char *name, const char *origin) { + const char *oname = name; + + while (*name != '\0') { + if (origin != NULL && ns_samename(name, origin) == 1) + return (name - oname - (name > oname)); + while (*name != '\0') { + if (*name == '\\') { + name++; + /* XXX need to handle \nnn form. */ + if (*name == '\0') + break; + } else if (*name == '.') { + name++; + break; + } + name++; + } + } + return (name - oname); +} + +/* + * int + * charstr(rdata, edata, buf, buflen) + * Format a into the presentation buffer. + * return: + * Number of rdata octets consumed + * 0 for protocol format error + * -1 for output buffer error + * side effects: + * buffer is advanced on success. + */ +static int +charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { + const u_char *odata = rdata; + size_t save_buflen = *buflen; + char *save_buf = *buf; + + if (addstr("\"", (size_t)1, buf, buflen) < 0) + goto enospc; + if (rdata < edata) { + int n = *rdata; + + if (rdata + 1 + n <= edata) { + rdata++; + while (n-- > 0) { + if (strchr("\n\"\\", *rdata) != NULL) + if (addstr("\\", (size_t)1, buf, buflen) < 0) + goto enospc; + if (addstr((const char *)rdata, (size_t)1, + buf, buflen) < 0) + goto enospc; + rdata++; + } + } + } + if (addstr("\"", (size_t)1, buf, buflen) < 0) + goto enospc; + _DIAGASSERT(__type_fit(int, rdata - odata)); + return (int)(rdata - odata); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static int +addname(const u_char *msg, size_t msglen, + const u_char **pp, const char *origin, + char **buf, size_t *buflen) +{ + size_t newlen, save_buflen = *buflen; + char *save_buf = *buf; + int n; + + n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen); + if (n < 0) + goto enospc; /* Guess. */ + newlen = prune_origin(*buf, origin); + if (**buf == '\0') { + goto root; + } else if (newlen == 0U) { + /* Use "@" instead of name. */ + if (newlen + 2 > *buflen) + goto enospc; /* No room for "@\0". */ + (*buf)[newlen++] = '@'; + (*buf)[newlen] = '\0'; + } else { + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { + /* No trailing dot. */ + root: + if (newlen + 2 > *buflen) + goto enospc; /* No room for ".\0". */ + (*buf)[newlen++] = '.'; + (*buf)[newlen] = '\0'; + } + } + *pp += n; + addlen(newlen, buf, buflen); + **buf = '\0'; + _DIAGASSERT(__type_fit(int, newlen)); + return (int)newlen; + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static void +addlen(size_t len, char **buf, size_t *buflen) { + assert(len <= *buflen); + *buf += len; + *buflen -= len; +} + +static int +addstr(const char *src, size_t len, char **buf, size_t *buflen) { + if (len >= *buflen) { + errno = ENOSPC; + return (-1); + } + memcpy(*buf, src, len); + addlen(len, buf, buflen); + **buf = '\0'; + return (0); +} + +static int +addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { + size_t save_buflen = *buflen; + char *save_buf = *buf; + ptrdiff_t t; + + if (spaced || len >= target - 1) { + T(addstr(" ", (size_t)2, buf, buflen)); + spaced = 1; + } else { + for (t = (target - len - 1) / 8; t >= 0; t--) + if (addstr("\t", (size_t)1, buf, buflen) < 0) { + *buflen = save_buflen; + *buf = save_buf; + return (-1); + } + spaced = 0; + } + return (spaced); +} diff --git a/aosp/bionic/libc/dns/nameser/ns_samedomain.c b/aosp/bionic/libc/dns/nameser/ns_samedomain.c new file mode 100644 index 000000000..0be0c2883 --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_samedomain.c @@ -0,0 +1,210 @@ +/* $NetBSD: ns_samedomain.c,v 1.8 2012/11/22 20:22:31 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995,1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp"; +#else +__RCSID("$NetBSD: ns_samedomain.c,v 1.8 2012/11/22 20:22:31 christos Exp $"); +#endif +#endif + +#include +#include +#include +#include + +#ifdef _LIBRESOLV +/* + * Check whether a name belongs to a domain. + * + * Inputs: + * a - the domain whose ancestory is being verified + * b - the potential ancestor we're checking against + * + * Return: + * boolean - is a at or below b? + * + * Notes: + * Trailing dots are first removed from name and domain. + * Always compare complete subdomains, not only whether the + * domain name is the trailing string of the given name. + * + * "host.foobar.top" lies in "foobar.top" and in "top" and in "" + * but NOT in "bar.top" + */ + +int +ns_samedomain(const char *a, const char *b) { + size_t la, lb, i; + int diff, escaped; + const char *cp; + + la = strlen(a); + lb = strlen(b); + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ + if (la != 0U && a[la - 1] == '.') { + escaped = 0; + /* Note this loop doesn't get executed if la==1. */ + for (i = la - 1; i > 0; i--) + if (a[i - 1] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + la--; + } + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ + if (lb != 0U && b[lb - 1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 1; i > 0; i--) + if (b[i - 1] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + lb--; + } + + /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ + if (lb == 0U) + return (1); + + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ + if (lb > la) + return (0); + + /* 'a' and 'b' being equal at this point indicates sameness. */ + if (lb == la) + return (strncasecmp(a, b, lb) == 0); + + /* Ok, we know la > lb. */ + + diff = (int)(la - lb); + + /* + * If 'a' is only 1 character longer than 'b', then it can't be + * a subdomain of 'b' (because of the need for the '.' label + * separator). + */ + if (diff < 2) + return (0); + + /* + * If the character before the last 'lb' characters of 'b' + * isn't '.', then it can't be a match (this lets us avoid + * having "foobar.com" match "bar.com"). + */ + if (a[diff - 1] != '.') + return (0); + + /* + * We're not sure about that '.', however. It could be escaped + * and thus not a really a label separator. + */ + escaped = 0; + for (i = diff - 1; i > 0; i--) + if (a[i - 1] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (escaped) + return (0); + + /* Now compare aligned trailing substring. */ + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); +} + +/* + * is "a" a subdomain of "b"? + */ +int +ns_subdomain(const char *a, const char *b) { + return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); +} +#endif + +#ifdef _LIBC +/* + * make a canonical copy of domain name "src" + * + * notes: + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + */ + +int +ns_makecanon(const char *src, char *dst, size_t dstsize) { + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { /* Note: sizeof == 2 */ + errno = EMSGSIZE; + return (-1); + } + strcpy(dst, src); + while (n >= 1U && dst[n - 1] == '.') /* Ends in "." */ + if (n >= 2U && dst[n - 2] == '\\' && /* Ends in "\." */ + (n < 3U || dst[n - 3] != '\\')) /* But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return (0); +} + +/* + * determine whether domain name "a" is the same as domain name "b" + * + * return: + * -1 on error + * 0 if names differ + * 1 if names are the same + */ + +int +ns_samename(const char *a, const char *b) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(a, ta, sizeof ta) < 0 || + ns_makecanon(b, tb, sizeof tb) < 0) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} +#endif diff --git a/aosp/bionic/libc/dns/nameser/ns_ttl.c b/aosp/bionic/libc/dns/nameser/ns_ttl.c new file mode 100644 index 000000000..de073b8c6 --- /dev/null +++ b/aosp/bionic/libc/dns/nameser/ns_ttl.c @@ -0,0 +1,161 @@ +/* $NetBSD: ns_ttl.c,v 1.8 2012/03/13 21:13:39 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp"; +#else +__RCSID("$NetBSD: ns_ttl.c,v 1.8 2012/03/13 21:13:39 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include + +#include +#include +#include +#include +#include + +/* Forward. */ + +static int fmt1(int t, char s, char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) do { if ((x) < 0) return (-1); } while(0) + +/* Public. */ + +int +ns_format_ttl(u_long src, char *dst, size_t dstlen) { + char *odst = dst; + int secs, mins, hours, days, weeks, x; + char *p; + + secs = (int)(src % 60); src /= 60; + mins = (int)(src % 60); src /= 60; + hours = (int)(src % 24); src /= 24; + days = (int)(src % 7); src /= 7; + weeks = (int)src; src = 0; + + x = 0; + if (weeks) { + T(fmt1(weeks, 'W', &dst, &dstlen)); + x++; + } + if (days) { + T(fmt1(days, 'D', &dst, &dstlen)); + x++; + } + if (hours) { + T(fmt1(hours, 'H', &dst, &dstlen)); + x++; + } + if (mins) { + T(fmt1(mins, 'M', &dst, &dstlen)); + x++; + } + if (secs || !(weeks || days || hours || mins)) { + T(fmt1(secs, 'S', &dst, &dstlen)); + x++; + } + + if (x > 1) { + int ch; + + for (p = odst; (ch = *p) != '\0'; p++) + if (isascii(ch) && isupper(ch)) + *p = tolower(ch); + } + + _DIAGASSERT(__type_fit(int, dst - odst)); + return (int)(dst - odst); +} + +#ifndef _LIBC +int +ns_parse_ttl(const char *src, u_long *dst) { + u_long ttl, tmp; + int ch, digits, dirty; + + ttl = 0; + tmp = 0; + digits = 0; + dirty = 0; + while ((ch = *src++) != '\0') { + if (!isascii(ch) || !isprint(ch)) + goto einval; + if (isdigit(ch)) { + tmp *= 10; + tmp += (ch - '0'); + digits++; + continue; + } + if (digits == 0) + goto einval; + if (islower(ch)) + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; /*FALLTHROUGH*/ + case 'D': tmp *= 24; /*FALLTHROUGH*/ + case 'H': tmp *= 60; /*FALLTHROUGH*/ + case 'M': tmp *= 60; /*FALLTHROUGH*/ + case 'S': break; + default: goto einval; + } + ttl += tmp; + tmp = 0; + digits = 0; + dirty = 1; + } + if (digits > 0) { + if (dirty) + goto einval; + else + ttl += tmp; + } else if (!dirty) + goto einval; + *dst = ttl; + return (0); + + einval: + errno = EINVAL; + return (-1); +} +#endif + +/* Private. */ + +static int +fmt1(int t, char s, char **buf, size_t *buflen) { + char tmp[50]; + size_t len; + + len = (size_t)snprintf(tmp, sizeof(tmp), "%d%c", t, s); + if ((int)len < 0 || len + 1 > *buflen) + return (-1); + strcpy(*buf, tmp); + *buf += len; + *buflen -= len; + return (0); +} diff --git a/aosp/bionic/libc/dns/net/getaddrinfo.c b/aosp/bionic/libc/dns/net/getaddrinfo.c new file mode 100644 index 000000000..d0c11d2b0 --- /dev/null +++ b/aosp/bionic/libc/dns/net/getaddrinfo.c @@ -0,0 +1,2469 @@ +/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ +/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: + * 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 project 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 PROJECT 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 PROJECT 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. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2553 is silent about which error + * code must be returned for which situation. + * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 + * says to use inet_aton() to convert IPv4 numeric to binary (alows + * classful form as a result). + * current code - disallow classful form for IPv4 (due to use of inet_pton). + * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is + * invalid. + * current code - SEGV on freeaddrinfo(NULL) + * Note: + * - We use getipnodebyname() just for thread-safeness. There's no intent + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to + * getipnodebyname(). + * - The code filters out AFs that are not supported by the kernel, + * when globbing NULL hostname (to loopback, or wildcard). Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? + * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. + * (1) what should we do against numeric hostname (2) what should we do + * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? + * non-loopback address configured? global address configured? + * - To avoid search order issue, we have a big amount of code duplicate + * from gethnamaddr.c and some other places. The issues that there's no + * lower layer function to lookup "IPv4 or IPv6" record. Calling + * gethostbyname2 from getaddrinfo will end up in wrong search order, as + * follows: + * - The code makes use of following calls when asked to resolver with + * ai_family = PF_UNSPEC: + * getipnodebyname(host, AF_INET6); + * getipnodebyname(host, AF_INET); + * This will result in the following queries if the node is configure to + * prefer /etc/hosts than DNS: + * lookup /etc/hosts for IPv6 address + * lookup DNS for IPv6 address + * lookup /etc/hosts for IPv4 address + * lookup DNS for IPv4 address + * which may not meet people's requirement. + * The right thing to happen is to have underlying layer which does + * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. + * This would result in a bit of code duplicate with _dns_ghbyname() and + * friends. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "NetdClientDispatch.h" +#include "resolv_cache.h" +#include "resolv_netid.h" +#include "resolv_private.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "nsswitch.h" +#include "private/bionic_defs.h" + +typedef union sockaddr_union { + struct sockaddr generic; + struct sockaddr_in in; + struct sockaddr_in6 in6; +} sockaddr_union; + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in_loopback[] = { 127, 0, 0, 1 }; +#ifdef INET6 +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; +#endif + +#if defined(__ANDROID__) +// This should be synchronized to ResponseCode.h +static const int DnsProxyQueryResult = 222; +#endif + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#if 0 + { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, +#endif +#ifdef INET6 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, +#endif + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#ifdef INET6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + +static const ns_src default_dns_files[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NSSRC_DNS, NS_SUCCESS }, + { 0, 0 } +}; + +#define MAXPACKET (8*1024) + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +struct res_target { + struct res_target *next; + const char *name; /* domain name */ + int qclass, qtype; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer buffer */ + int n; /* result length */ +}; + +static int str2number(const char *); +static int explore_fqdn(const struct addrinfo *, const char *, + const char *, struct addrinfo **, const struct android_net_context *); +static int explore_null(const struct addrinfo *, + const char *, struct addrinfo **); +static int explore_numeric(const struct addrinfo *, const char *, + const char *, struct addrinfo **, const char *); +static int explore_numeric_scope(const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int get_canonname(const struct addrinfo *, + struct addrinfo *, const char *); +static struct addrinfo *get_ai(const struct addrinfo *, + const struct afd *, const char *); +static int get_portmatch(const struct addrinfo *, const char *); +static int get_port(const struct addrinfo *, const char *, int); +static const struct afd *find_afd(int); +#ifdef INET6 +static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); +#endif + +static struct addrinfo *getanswer(const querybuf *, int, const char *, int, + const struct addrinfo *); +static int _dns_getaddrinfo(void *, void *, va_list); +static void _sethtent(FILE **); +static void _endhtent(FILE **); +static struct addrinfo *_gethtent(FILE **, const char *, + const struct addrinfo *); +static int _files_getaddrinfo(void *, void *, va_list); +static int _find_src_addr(const struct sockaddr *, struct sockaddr *, unsigned , uid_t); + +static int res_queryN(const char *, struct res_target *, res_state); +static int res_searchN(const char *, struct res_target *, res_state); +static int res_querydomainN(const char *, const char *, + struct res_target *, res_state); + +static const char * const ai_errlist[] = { + "Success", + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "Memory allocation failure", /* EAI_MEMORY */ + "No address associated with hostname", /* EAI_NODATA */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown", /* EAI_PROTOCOL */ + "Argument buffer overflow", /* EAI_OVERFLOW */ + "Unknown error", /* EAI_MAX */ +}; + +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (/*CONSTCOND*/0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#define GET_CANONNAME(ai, str) \ +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ + /*NOTREACHED*/ \ +} while (/*CONSTCOND*/0) + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ + (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +const char * +gai_strerror(int ecode) +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + +#if defined(__BIONIC__) + if (ai == NULL) return; +#else + _DIAGASSERT(ai != NULL); +#endif + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + ai = next; + } while (ai); +} + +static int +str2number(const char *p) +{ + char *ep; + unsigned long v; + + assert(p != NULL); + + if (*p == '\0') + return -1; + ep = NULL; + errno = 0; + v = strtoul(p, &ep, 10); + if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) + return v; + else + return -1; +} + +/* + * The following functions determine whether IPv4 or IPv6 connectivity is + * available in order to implement AI_ADDRCONFIG. + * + * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is + * available, but whether addresses of the specified family are "configured + * on the local system". However, bionic doesn't currently support getifaddrs, + * so checking for connectivity is the next best thing. + */ +static int +_have_ipv6(unsigned mark, uid_t uid) { + static const struct sockaddr_in6 sin6_test = { + .sin6_family = AF_INET6, + .sin6_addr.s6_addr = { // 2000:: + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + sockaddr_union addr = { .in6 = sin6_test }; + return _find_src_addr(&addr.generic, NULL, mark, uid) == 1; +} + +static int +_have_ipv4(unsigned mark, uid_t uid) { + static const struct sockaddr_in sin_test = { + .sin_family = AF_INET, + .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 + }; + sockaddr_union addr = { .in = sin_test }; + return _find_src_addr(&addr.generic, NULL, mark, uid) == 1; +} + +bool readBE32(FILE* fp, int32_t* result) { + int32_t tmp; + if (fread(&tmp, sizeof(tmp), 1, fp) != 1) { + return false; + } + *result = ntohl(tmp); + return true; +} + +#if defined(__ANDROID__) +// Returns 0 on success, else returns on error. +static int +android_getaddrinfo_proxy( + const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res, unsigned netid) +{ + int success = 0; + + // Clear this at start, as we use its non-NULLness later (in the + // error path) to decide if we have to free up any memory we + // allocated in the process (before failing). + *res = NULL; + + // Bogus things we can't serialize. Don't use the proxy. These will fail - let them. + if ((hostname != NULL && + strcspn(hostname, " \n\r\t^'\"") != strlen(hostname)) || + (servname != NULL && + strcspn(servname, " \n\r\t^'\"") != strlen(servname))) { + return EAI_NODATA; + } + + FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+"); + if (proxy == NULL) { + return EAI_SYSTEM; + } + netid = __netdClientDispatch.netIdForResolv(netid); + + // Send the request. + if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u", + hostname == NULL ? "^" : hostname, + servname == NULL ? "^" : servname, + hints == NULL ? -1 : hints->ai_flags, + hints == NULL ? -1 : hints->ai_family, + hints == NULL ? -1 : hints->ai_socktype, + hints == NULL ? -1 : hints->ai_protocol, + netid) < 0) { + goto exit; + } + // literal NULL byte at end, required by FrameworkListener + if (fputc(0, proxy) == EOF || + fflush(proxy) != 0) { + goto exit; + } + + char buf[4]; + // read result code for gethostbyaddr + if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) { + goto exit; + } + + int result_code = (int)strtol(buf, NULL, 10); + // verify the code itself + if (result_code != DnsProxyQueryResult) { + fread(buf, 1, sizeof(buf), proxy); + goto exit; + } + + struct addrinfo* ai = NULL; + struct addrinfo** nextres = res; + while (1) { + int32_t have_more; + if (!readBE32(proxy, &have_more)) { + break; + } + if (have_more == 0) { + success = 1; + break; + } + + ai = calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + if (ai == NULL) { + break; + } + ai->ai_addr = (struct sockaddr*)(ai + 1); + + // struct addrinfo { + // int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + // int ai_family; /* PF_xxx */ + // int ai_socktype; /* SOCK_xxx */ + // int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + // socklen_t ai_addrlen; /* length of ai_addr */ + // char *ai_canonname; /* canonical name for hostname */ + // struct sockaddr *ai_addr; /* binary address */ + // struct addrinfo *ai_next; /* next structure in linked list */ + // }; + + // Read the struct piece by piece because we might be a 32-bit process + // talking to a 64-bit netd. + int32_t addr_len; + bool success = + readBE32(proxy, &ai->ai_flags) && + readBE32(proxy, &ai->ai_family) && + readBE32(proxy, &ai->ai_socktype) && + readBE32(proxy, &ai->ai_protocol) && + readBE32(proxy, &addr_len); + if (!success) { + break; + } + + // Set ai_addrlen and read the ai_addr data. + ai->ai_addrlen = addr_len; + if (addr_len != 0) { + if ((size_t) addr_len > sizeof(struct sockaddr_storage)) { + // Bogus; too big. + break; + } + if (fread(ai->ai_addr, addr_len, 1, proxy) != 1) { + break; + } + } + + // The string for ai_cannonname. + int32_t name_len; + if (!readBE32(proxy, &name_len)) { + break; + } + if (name_len != 0) { + ai->ai_canonname = (char*) malloc(name_len); + if (fread(ai->ai_canonname, name_len, 1, proxy) != 1) { + break; + } + if (ai->ai_canonname[name_len - 1] != '\0') { + // The proxy should be returning this + // NULL-terminated. + break; + } + } + + *nextres = ai; + nextres = &ai->ai_next; + ai = NULL; + } + + if (ai != NULL) { + // Clean up partially-built addrinfo that we never ended up + // attaching to the response. + freeaddrinfo(ai); + } +exit: + if (proxy != NULL) { + fclose(proxy); + } + + if (success) { + return 0; + } + + // Proxy failed; + // clean up memory we might've allocated. + if (*res) { + freeaddrinfo(*res); + *res = NULL; + } + return EAI_NODATA; +} +#endif + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int +android_getaddrinfofornet(const char *hostname, const char *servname, + const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res) +{ + struct android_net_context netcontext = { + .app_netid = netid, + .app_mark = mark, + .dns_netid = netid, + .dns_mark = mark, + .uid = NET_CONTEXT_INVALID_UID, + }; + return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res); +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int +android_getaddrinfofornetcontext(const char *hostname, const char *servname, + const struct addrinfo *hints, const struct android_net_context *netcontext, + struct addrinfo **res) +{ + struct addrinfo sentinel; + struct addrinfo *cur; + int error = 0; + struct addrinfo ai; + struct addrinfo ai0; + struct addrinfo *pai; + const struct explore *ex; + + /* hostname is allowed to be NULL */ + /* servname is allowed to be NULL */ + /* hints is allowed to be NULL */ + assert(res != NULL); + assert(netcontext != NULL); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef INET6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype + && pai->ai_protocol != ex->e_protocol) { + ERR(EAI_BADHINTS); + } + } + } + } + + /* + * check for special cases. (1) numeric servname is disallowed if + * socktype/protocol are left unspecified. (2) servname is disallowed + * for raw and other inet{,6} sockets. + */ + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef PF_INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + ai0 = *pai; /* backup *pai */ + + if (pai->ai_family == PF_UNSPEC) { +#ifdef PF_INET6 + pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + } + error = get_portmatch(pai, servname); + if (error) + ERR(error); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + /* PF_UNSPEC entries are prepared for DNS queries only */ + if (ex->e_af == PF_UNSPEC) + continue; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + if (hostname == NULL) + error = explore_null(pai, servname, &cur->ai_next); + else + error = explore_numeric_scope(pai, hostname, servname, + &cur->ai_next); + + if (error) + goto free; + + while (cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numeric representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (hostname == NULL) + ERR(EAI_NODATA); + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + +#if defined(__ANDROID__) + int gai_error = android_getaddrinfo_proxy( + hostname, servname, hints, res, netcontext->app_netid); + if (gai_error != EAI_SYSTEM) { + return gai_error; + } +#endif + + /* + * hostname as alphabetical name. + * we would like to prefer AF_INET6 than AF_INET, so we'll make a + * outer loop by AFs. + */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + /* require exact match for family field */ + if (pai->ai_family != ex->e_af) + continue; + + if (!MATCH(pai->ai_socktype, ex->e_socktype, + WILD_SOCKTYPE(ex))) { + continue; + } + if (!MATCH(pai->ai_protocol, ex->e_protocol, + WILD_PROTOCOL(ex))) { + continue; + } + + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + error = explore_fqdn( + pai, hostname, servname, &cur->ai_next, netcontext); + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* XXX */ + if (sentinel.ai_next) + error = 0; + + if (error) + goto free; + if (error == 0) { + if (sentinel.ai_next) { + good: + *res = sentinel.ai_next; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + *res = NULL; + return error; +} + +/* + * FQDN hostname, DNS lookup + */ +static int +explore_fqdn(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res, + const struct android_net_context *netcontext) +{ + struct addrinfo *result; + struct addrinfo *cur; + int error = 0; + static const ns_dtab dtab[] = { + NS_FILES_CB(_files_getaddrinfo, NULL) + { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ + NS_NIS_CB(_yp_getaddrinfo, NULL) + { 0, 0, 0 } + }; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + result = NULL; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", + default_dns_files, hostname, pai, netcontext)) { + case NS_TRYAGAIN: + error = EAI_AGAIN; + goto free; + case NS_UNAVAIL: + error = EAI_FAIL; + goto free; + case NS_NOTFOUND: + error = EAI_NODATA; + goto free; + case NS_SUCCESS: + error = 0; + for (cur = result; cur; cur = cur->ai_next) { + GET_PORT(cur, servname); + /* canonname should be filled already */ + } + break; + } + + *res = result; + + return 0; + +free: + if (result) + freeaddrinfo(result); + return error; +} + +/* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(const struct addrinfo *pai, const char *servname, + struct addrinfo **res) +{ + int s; + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + assert(pai != NULL); + /* servname may be NULL */ + assert(res != NULL); + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname + */ +static int +explore_numeric(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res, const char *canonname) +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + switch (afd->a_af) { +#if 0 /*X/Open spec*/ + case AF_INET: + if (inet_aton(hostname, (struct in_addr *)pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + if ((pai->ai_flags & AI_CANONNAME)) { + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + GET_CANONNAME(cur->ai_next, canonname); + } + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; +#endif + default: + if (inet_pton(afd->a_af, hostname, pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + if ((pai->ai_flags & AI_CANONNAME)) { + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + GET_CANONNAME(cur->ai_next, canonname); + } + while (cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; + } + + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname with scope + */ +static int +explore_numeric_scope(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res) +{ +#if !defined(SCOPE_DELIMITER) || !defined(INET6) + return explore_numeric(pai, hostname, servname, res, hostname); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL, *scope, *addr; + struct sockaddr_in6 *sin6; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res, hostname); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res, hostname); + + /* + * Handle special case of + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; + addr = hostname2; + scope = cp + 1; + + error = explore_numeric(pai, addr, servname, res, hostname); + if (error == 0) { + u_int32_t scopeid; + + for (cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; + if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { + free(hostname2); + return(EAI_NODATA); /* XXX: is return OK? */ + } + sin6->sin6_scope_id = scopeid; + } + } + + free(hostname2); + + return error; +#endif +} + +static int +get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) +{ + + assert(pai != NULL); + assert(ai != NULL); + assert(str != NULL); + + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = strdup(str); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + } + return 0; +} + +static struct addrinfo * +get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) +{ + char *p; + struct addrinfo *ai; + + assert(pai != NULL); + assert(afd != NULL); + assert(addr != NULL); + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); + memset(ai->ai_addr, 0, (size_t)afd->a_socklen); + +#ifdef HAVE_SA_LEN + ai->ai_addr->sa_len = afd->a_socklen; +#endif + + ai->ai_addrlen = afd->a_socklen; +#if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__) + ai->__ai_pad0 = 0; +#endif + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(void *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); + return ai; +} + +static int +get_portmatch(const struct addrinfo *ai, const char *servname) +{ + + assert(ai != NULL); + /* servname may be NULL */ + + return get_port(ai, servname, 1); +} + +static int +get_port(const struct addrinfo *ai, const char *servname, int matchonly) +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + assert(ai != NULL); + /* servname may be NULL */ + + if (servname == NULL) + return 0; + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + break; + default: + return 0; + } + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: +#if 1 /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */ + allownumeric = 1; +#else + allownumeric = 0; +#endif + break; + default: + return EAI_SOCKTYPE; + } + + port = str2number(servname); + if (port >= 0) { + if (!allownumeric) + return EAI_SERVICE; + if (port < 0 || port > 65535) + return EAI_SERVICE; + port = htons(port); + } else { + if (ai->ai_flags & AI_NUMERICSERV) + return EAI_NONAME; + + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)(void *) + ai->ai_addr)->sin_port = port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)(void *) + ai->ai_addr)->sin6_port = port; + break; +#endif + } + } + + return 0; +} + +static const struct afd * +find_afd(int af) +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return NULL; + for (afd = afdl; afd->a_af; afd++) { + if (afd->a_af == af) + return afd; + } + return NULL; +} + +#ifdef INET6 +/* convert a string to a scope identifier. XXX: IPv6 specific */ +static int +ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) +{ + u_long lscopeid; + struct in6_addr *a6; + char *ep; + + assert(scope != NULL); + assert(sin6 != NULL); + assert(scopeid != NULL); + + a6 = &sin6->sin6_addr; + + /* empty scopeid portion is invalid */ + if (*scope == '\0') + return -1; + + if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { + /* + * We currently assume a one-to-one mapping between links + * and interfaces, so we simply use interface indices for + * like-local scopes. + */ + *scopeid = if_nametoindex(scope); + if (*scopeid == 0) + goto trynumeric; + return 0; + } + + /* still unclear about literal, allow numeric only - placeholder */ + if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) + goto trynumeric; + if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) + goto trynumeric; + else + goto trynumeric; /* global */ + + /* try to convert to a numeric id as a last resort */ + trynumeric: + errno = 0; + lscopeid = strtoul(scope, &ep, 10); + *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); + if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) + return 0; + else + return -1; +} +#endif + +/* code duplicate with gethnamaddr.c */ + +static const char AskedForGot[] = + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + +#define BOUNDED_INCR(x) \ + do { \ + BOUNDS_CHECK(cp, x); \ + cp += (x); \ + } while (/*CONSTCOND*/0) + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if (eom - (ptr) < (count)) { h_errno = NO_RECOVERY; return NULL; } \ + } while (/*CONSTCOND*/0) + +static struct addrinfo * +getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, + const struct addrinfo *pai) +{ + struct addrinfo sentinel, *cur; + struct addrinfo ai; + const struct afd *afd; + char *canonname; + const HEADER *hp; + const u_char *cp; + int n; + const u_char *eom; + char *bp, *ep; + int type, class, ancount, qdcount; + int haveanswer, had_error; + char tbuf[MAXDNAME]; + int (*name_ok) (const char *); + char hostbuf[8*1024]; + + assert(answer != NULL); + assert(qname != NULL); + assert(pai != NULL); + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + canonname = NULL; + eom = answer->buf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ + name_ok = res_hnok; + break; + default: + return NULL; /* XXX should be abort(); */ + } + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = hostbuf; + ep = hostbuf + sizeof hostbuf; + cp = answer->buf; + BOUNDED_INCR(HFIXEDSZ); + if (qdcount != 1) { + h_errno = NO_RECOVERY; + return (NULL); + } + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + h_errno = NO_RECOVERY; + return (NULL); + } + BOUNDED_INCR(n + QFIXEDSZ); + if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + h_errno = NO_RECOVERY; + return (NULL); + } + canonname = bp; + bp += n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = canonname; + } + haveanswer = 0; + had_error = 0; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + had_error++; + continue; + } + cp += n; /* name */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + type = _getshort(cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + BOUNDS_CHECK(cp, n); + if (class != C_IN) { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && + type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if ((n < 0) || !(*name_ok)(tbuf)) { + had_error++; + continue; + } + cp += n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + canonname = bp; + bp += n; + continue; + } + if (qtype == T_ANY) { + if (!(type == T_A || type == T_AAAA)) { + cp += n; + continue; + } + } else if (type != qtype) { + if (type != T_KEY && type != T_SIG) + syslog(LOG_NOTICE|LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class(C_IN), p_type(qtype), + p_type(type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_A: + case T_AAAA: + if (strcasecmp(canonname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, canonname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (type == T_A && n != INADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA && n != IN6ADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA) { + struct in6_addr in6; + memcpy(&in6, cp, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&in6)) { + cp += n; + continue; + } + } + if (!haveanswer) { + int nn; + + canonname = bp; + nn = strlen(bp) + 1; /* for the \0 */ + bp += nn; + } + + /* don't overwrite pai */ + ai = *pai; + ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; + afd = find_afd(ai.ai_family); + if (afd == NULL) { + cp += n; + continue; + } + cur->ai_next = get_ai(&ai, afd, (const char *)cp); + if (cur->ai_next == NULL) + had_error++; + while (cur && cur->ai_next) + cur = cur->ai_next; + cp += n; + break; + default: + abort(); + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + if (!canonname) + (void)get_canonname(pai, sentinel.ai_next, qname); + else + (void)get_canonname(pai, sentinel.ai_next, canonname); + h_errno = NETDB_SUCCESS; + return sentinel.ai_next; + } + + h_errno = NO_RECOVERY; + return NULL; +} + +struct addrinfo_sort_elem { + struct addrinfo *ai; + int has_src_addr; + sockaddr_union src_addr; + int original_order; +}; + +/*ARGSUSED*/ +static int +_get_scope(const struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) { + return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr); + } else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) { + /* + * RFC 4291 section 2.5.3 says loopback is to be treated as having + * link-local scope. + */ + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { + return IPV6_ADDR_SCOPE_SITELOCAL; + } else { + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else if (addr->sa_family == AF_INET) { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; + unsigned long int na = ntohl(addr4->sin_addr.s_addr); + + if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */ + (na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */ + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else { + /* + * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses + * and shared addresses (100.64.0.0/10), are assigned global scope. + */ + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else { + /* + * This should never happen. + * Return a scope with low priority as a last resort. + */ + return IPV6_ADDR_SCOPE_NODELOCAL; + } +} + +/* These macros are modelled after the ones in . */ + +/* RFC 4380, section 2.6 */ +#define IN6_IS_ADDR_TEREDO(a) \ + ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000))) + +/* RFC 3056, section 2. */ +#define IN6_IS_ADDR_6TO4(a) \ + (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02)) + +/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */ +#define IN6_IS_ADDR_6BONE(a) \ + (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe)) + +/* + * Get the label for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + */ + +/*ARGSUSED*/ +static int +_get_label(const struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET) { + return 4; + } else if (addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { + return 0; + } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { + return 4; + } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { + return 2; + } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { + return 5; + } else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) { + return 13; + } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) { + return 3; + } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { + return 11; + } else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { + return 12; + } else { + /* All other IPv6 addresses, including global unicast addresses. */ + return 1; + } + } else { + /* + * This should never happen. + * Return a semi-random label as a last resort. + */ + return 1; + } +} + +/* + * Get the precedence for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + */ + +/*ARGSUSED*/ +static int +_get_precedence(const struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET) { + return 35; + } else if (addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { + return 50; + } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { + return 35; + } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { + return 30; + } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { + return 5; + } else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) { + return 3; + } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) || + IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { + return 1; + } else { + /* All other IPv6 addresses, including global unicast addresses. */ + return 40; + } + } else { + return 1; + } +} + +/* + * Find number of matching initial bits between the two addresses a1 and a2. + */ + +/*ARGSUSED*/ +static int +_common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2) +{ + const char *p1 = (const char *)a1; + const char *p2 = (const char *)a2; + unsigned i; + + for (i = 0; i < sizeof(*a1); ++i) { + int x, j; + + if (p1[i] == p2[i]) { + continue; + } + x = p1[i] ^ p2[i]; + for (j = 0; j < CHAR_BIT; ++j) { + if (x & (1 << (CHAR_BIT - 1))) { + return i * CHAR_BIT + j; + } + x <<= 1; + } + } + return sizeof(*a1) * CHAR_BIT; +} + +/* + * Compare two source/destination address pairs. + * RFC 6724, section 6. + */ + +/*ARGSUSED*/ +static int +_rfc6724_compare(const void *ptr1, const void* ptr2) +{ + const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1; + const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2; + int scope_src1, scope_dst1, scope_match1; + int scope_src2, scope_dst2, scope_match2; + int label_src1, label_dst1, label_match1; + int label_src2, label_dst2, label_match2; + int precedence1, precedence2; + int prefixlen1, prefixlen2; + + /* Rule 1: Avoid unusable destinations. */ + if (a1->has_src_addr != a2->has_src_addr) { + return a2->has_src_addr - a1->has_src_addr; + } + + /* Rule 2: Prefer matching scope. */ + scope_src1 = _get_scope(&a1->src_addr.generic); + scope_dst1 = _get_scope(a1->ai->ai_addr); + scope_match1 = (scope_src1 == scope_dst1); + + scope_src2 = _get_scope(&a2->src_addr.generic); + scope_dst2 = _get_scope(a2->ai->ai_addr); + scope_match2 = (scope_src2 == scope_dst2); + + if (scope_match1 != scope_match2) { + return scope_match2 - scope_match1; + } + + /* + * Rule 3: Avoid deprecated addresses. + * TODO(sesse): We don't currently have a good way of finding this. + */ + + /* + * Rule 4: Prefer home addresses. + * TODO(sesse): We don't currently have a good way of finding this. + */ + + /* Rule 5: Prefer matching label. */ + label_src1 = _get_label(&a1->src_addr.generic); + label_dst1 = _get_label(a1->ai->ai_addr); + label_match1 = (label_src1 == label_dst1); + + label_src2 = _get_label(&a2->src_addr.generic); + label_dst2 = _get_label(a2->ai->ai_addr); + label_match2 = (label_src2 == label_dst2); + + if (label_match1 != label_match2) { + return label_match2 - label_match1; + } + + /* Rule 6: Prefer higher precedence. */ + precedence1 = _get_precedence(a1->ai->ai_addr); + precedence2 = _get_precedence(a2->ai->ai_addr); + if (precedence1 != precedence2) { + return precedence2 - precedence1; + } + + /* + * Rule 7: Prefer native transport. + * TODO(sesse): We don't currently have a good way of finding this. + */ + + /* Rule 8: Prefer smaller scope. */ + if (scope_dst1 != scope_dst2) { + return scope_dst1 - scope_dst2; + } + + /* + * Rule 9: Use longest matching prefix. + * We implement this for IPv6 only, as the rules in RFC 6724 don't seem + * to work very well directly applied to IPv4. (glibc uses information from + * the routing table for a custom IPv4 implementation here.) + */ + if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 && + a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) { + const struct sockaddr_in6 *a1_src = &a1->src_addr.in6; + const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr; + const struct sockaddr_in6 *a2_src = &a2->src_addr.in6; + const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr; + prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr); + prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr); + if (prefixlen1 != prefixlen2) { + return prefixlen2 - prefixlen1; + } + } + + /* + * Rule 10: Leave the order unchanged. + * We need this since qsort() is not necessarily stable. + */ + return a1->original_order - a2->original_order; +} + +/* + * Find the source address that will be used if trying to connect to the given + * address. src_addr must be large enough to hold a struct sockaddr_in6. + * + * Returns 1 if a source address was found, 0 if the address is unreachable, + * and -1 if a fatal error occurred. If 0 or -1, the contents of src_addr are + * undefined. + */ + +/*ARGSUSED*/ +static int +_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark, uid_t uid) +{ + int sock; + int ret; + socklen_t len; + + switch (addr->sa_family) { + case AF_INET: + len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; + default: + /* No known usable source address for non-INET families. */ + return 0; + } + + sock = socket(addr->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + if (sock == -1) { + if (errno == EAFNOSUPPORT) { + return 0; + } else { + return -1; + } + } + if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { + close(sock); + return 0; + } + if (uid > 0 && uid != NET_CONTEXT_INVALID_UID && fchown(sock, uid, (gid_t)-1) < 0) { + close(sock); + return 0; + } + do { + ret = __connect(sock, addr, len); + } while (ret == -1 && errno == EINTR); + + if (ret == -1) { + close(sock); + return 0; + } + + if (src_addr && getsockname(sock, src_addr, &len) == -1) { + close(sock); + return -1; + } + close(sock); + return 1; +} + +/* + * Sort the linked list starting at sentinel->ai_next in RFC6724 order. + * Will leave the list unchanged if an error occurs. + */ + +/*ARGSUSED*/ +static void +_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark, uid_t uid) +{ + struct addrinfo *cur; + int nelem = 0, i; + struct addrinfo_sort_elem *elems; + + cur = list_sentinel->ai_next; + while (cur) { + ++nelem; + cur = cur->ai_next; + } + + elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem)); + if (elems == NULL) { + goto error; + } + + /* + * Convert the linked list to an array that also contains the candidate + * source address for each destination address. + */ + for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) { + int has_src_addr; + assert(cur != NULL); + elems[i].ai = cur; + elems[i].original_order = i; + + has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark, uid); + if (has_src_addr == -1) { + goto error; + } + elems[i].has_src_addr = has_src_addr; + } + + /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */ + qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc6724_compare); + + list_sentinel->ai_next = elems[0].ai; + for (i = 0; i < nelem - 1; ++i) { + elems[i].ai->ai_next = elems[i + 1].ai; + } + elems[nelem - 1].ai->ai_next = NULL; + +error: + free(elems); +} + +/*ARGSUSED*/ +static int +_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) +{ + struct addrinfo *ai; + querybuf *buf, *buf2; + const char *name; + const struct addrinfo *pai; + struct addrinfo sentinel, *cur; + struct res_target q, q2; + res_state res; + const struct android_net_context *netcontext; + + name = va_arg(ap, char *); + pai = va_arg(ap, const struct addrinfo *); + netcontext = va_arg(ap, const struct android_net_context *); + //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); + + memset(&q, 0, sizeof(q)); + memset(&q2, 0, sizeof(q2)); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + buf2 = malloc(sizeof(*buf2)); + if (buf2 == NULL) { + free(buf); + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + + switch (pai->ai_family) { + case AF_UNSPEC: + /* prefer IPv6 */ + q.name = name; + q.qclass = C_IN; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + int query_ipv6 = 1, query_ipv4 = 1; + if (pai->ai_flags & AI_ADDRCONFIG) { + query_ipv6 = _have_ipv6(netcontext->app_mark, netcontext->uid); + query_ipv4 = _have_ipv4(netcontext->app_mark, netcontext->uid); + } + if (query_ipv6) { + q.qtype = T_AAAA; + if (query_ipv4) { + q.next = &q2; + q2.name = name; + q2.qclass = C_IN; + q2.qtype = T_A; + q2.answer = buf2->buf; + q2.anslen = sizeof(buf2->buf); + } + } else if (query_ipv4) { + q.qtype = T_A; + } else { + free(buf); + free(buf2); + return NS_NOTFOUND; + } + break; + case AF_INET: + q.name = name; + q.qclass = C_IN; + q.qtype = T_A; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + break; + case AF_INET6: + q.name = name; + q.qclass = C_IN; + q.qtype = T_AAAA; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + break; + default: + free(buf); + free(buf2); + return NS_UNAVAIL; + } + + res = __res_get_state(); + if (res == NULL) { + free(buf); + free(buf2); + return NS_NOTFOUND; + } + + /* this just sets our netid val in the thread private data so we don't have to + * modify the api's all the way down to res_send.c's res_nsend. We could + * fully populate the thread private data here, but if we get down there + * and have a cache hit that would be wasted, so we do the rest there on miss + */ + res_setnetcontext(res, netcontext); + if (res_searchN(name, &q, res) < 0) { + __res_put_state(res); + free(buf); + free(buf2); + return NS_NOTFOUND; + } + ai = getanswer(buf, q.n, q.name, q.qtype, pai); + if (ai) { + cur->ai_next = ai; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + if (q.next) { + ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); + if (ai) + cur->ai_next = ai; + } + free(buf); + free(buf2); + if (sentinel.ai_next == NULL) { + __res_put_state(res); + switch (h_errno) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + + _rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid); + + __res_put_state(res); + + *((struct addrinfo **)rv) = sentinel.ai_next; + return NS_SUCCESS; +} + +static void +_sethtent(FILE **hostf) +{ + + if (!*hostf) + *hostf = fopen(_PATH_HOSTS, "re"); + else + rewind(*hostf); +} + +static void +_endhtent(FILE **hostf) +{ + + if (*hostf) { + (void) fclose(*hostf); + *hostf = NULL; + } +} + +static struct addrinfo * +_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) +{ + char *p; + char *cp, *tname, *cname; + struct addrinfo hints, *res0, *res; + int error; + const char *addr; + char hostbuf[8*1024]; + +// fprintf(stderr, "_gethtent() name = '%s'\n", name); + assert(name != NULL); + assert(pai != NULL); + + if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) + return (NULL); + again: + if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) + return (NULL); + if (*p == '#') + goto again; + if (!(cp = strpbrk(p, "#\n"))) + goto again; + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + goto again; + *cp++ = '\0'; + addr = p; + /* if this is not something we're looking for, skip it. */ + cname = NULL; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (!cname) + cname = cp; + tname = cp; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; +// fprintf(stderr, "\ttname = '%s'", tname); + if (strcasecmp(name, tname) == 0) + goto found; + } + goto again; + +found: + hints = *pai; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(addr, NULL, &hints, &res0); + if (error) + goto again; + for (res = res0; res; res = res->ai_next) { + /* cover it up */ + res->ai_flags = pai->ai_flags; + + if (pai->ai_flags & AI_CANONNAME) { + if (get_canonname(pai, res, cname) != 0) { + freeaddrinfo(res0); + goto again; + } + } + } + return res0; +} + +/*ARGSUSED*/ +static int +_files_getaddrinfo(void *rv, void *cb_data, va_list ap) +{ + const char *name; + const struct addrinfo *pai; + struct addrinfo sentinel, *cur; + struct addrinfo *p; + FILE *hostf = NULL; + + name = va_arg(ap, char *); + pai = va_arg(ap, struct addrinfo *); + +// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + _sethtent(&hostf); + while ((p = _gethtent(&hostf, name, pai)) != NULL) { + cur->ai_next = p; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + _endhtent(&hostf); + + *((struct addrinfo **)rv) = sentinel.ai_next; + if (sentinel.ai_next == NULL) + return NS_NOTFOUND; + return NS_SUCCESS; +} + +/* resolver logic */ + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * + * Caller must parse answer and determine whether it answers the question. + */ +static int +res_queryN(const char *name, /* domain name */ struct res_target *target, + res_state res) +{ + u_char buf[MAXPACKET]; + HEADER *hp; + int n; + struct res_target *t; + int rcode; + int ancount; + + assert(name != NULL); + /* XXX: target may be NULL??? */ + + rcode = NOERROR; + ancount = 0; + + for (t = target; t; t = t->next) { + int class, type; + u_char *answer; + int anslen; + u_int oflags; + + hp = (HEADER *)(void *)t->answer; + oflags = res->_flags; + +again: + hp->rcode = NOERROR; /* default */ + + /* make it easier... */ + class = t->qclass; + type = t->qtype; + answer = t->answer; + anslen = t->anslen; +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_nquery(%s, %d, %d)\n", name, class, type); +#endif + + n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); +#ifdef RES_USE_EDNS0 + if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && + (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) + n = res_nopt(res, n, buf, sizeof(buf), anslen); +#endif + if (n <= 0) { +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_nquery: mkquery failed\n"); +#endif + h_errno = NO_RECOVERY; + return n; + } + n = res_nsend(res, buf, n, answer, anslen); +#if 0 + if (n < 0) { +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + h_errno = TRY_AGAIN; + return n; + } +#endif + + if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { + rcode = hp->rcode; /* record most recent error */ +#ifdef RES_USE_EDNS0 + /* if the query choked with EDNS0, retry without EDNS0 */ + if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0 && + ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { + res->_flags |= RES_F_EDNS0ERR; +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_nquery: retry without EDNS0\n"); +#endif + goto again; + } +#endif +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; rcode = %u, ancount=%u\n", hp->rcode, + ntohs(hp->ancount)); +#endif + continue; + } + + ancount += ntohs(hp->ancount); + + t->n = n; + } + + if (ancount == 0) { + switch (rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + return -1; + } + return ancount; +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error code, if any, is left in h_errno. + */ +static int +res_searchN(const char *name, struct res_target *target, res_state res) +{ + const char *cp, * const *domain; + HEADER *hp; + u_int dots; + int trailing_dot, ret, saved_herrno; + int got_nodata = 0, got_servfail = 0, tried_as_is = 0; + + assert(name != NULL); + assert(target != NULL); + + hp = (HEADER *)(void *)target->answer; /*XXX*/ + + errno = 0; + h_errno = HOST_NOT_FOUND; /* default, if we never query */ + dots = 0; + for (cp = name; *cp; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + + //fprintf(stderr, "res_searchN() name = '%s'\n", name); + + /* + * if there aren't any dots, it could be a user-level alias + */ + if (!dots && (cp = __hostalias(name)) != NULL) { + ret = res_queryN(cp, target, res); + return ret; + } + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + saved_herrno = -1; + if (dots >= res->ndots) { + ret = res_querydomainN(name, NULL, target, res); + if (ret > 0) + return (ret); + saved_herrno = h_errno; + tried_as_is++; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (res->options & RES_DEFNAMES)) || + (dots && !trailing_dot && (res->options & RES_DNSRCH))) { + int done = 0; + + /* Unfortunately we need to set stuff up before + * the domain stuff is tried. Will have a better + * fix after thread pools are used. + */ + _resolv_populate_res_for_net(res); + + for (domain = (const char * const *)res->dnsrch; + *domain && !done; + domain++) { + + ret = res_querydomainN(name, *domain, target, res); + if (ret > 0) + return ret; + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return -1; + } + + switch (h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + /* + * if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if (!(res->options & RES_DNSRCH)) + done++; + } + } + + /* + * if we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + ret = res_querydomainN(name, NULL, target, res); + if (ret > 0) + return ret; + } + + /* + * if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's h_errno + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless h_errno, that being the one from + * the last DNSRCH we did. + */ + if (saved_herrno != -1) + h_errno = saved_herrno; + else if (got_nodata) + h_errno = NO_DATA; + else if (got_servfail) + h_errno = TRY_AGAIN; + return -1; +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +static int +res_querydomainN(const char *name, const char *domain, + struct res_target *target, res_state res) +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + size_t n, d; + + assert(name != NULL); + /* XXX: target may be NULL??? */ + +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_querydomain(%s, %s)\n", + name, domain?domain:""); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name); + if (n + 1 > sizeof(nbuf)) { + h_errno = NO_RECOVERY; + return -1; + } + if (n > 0 && name[--n] == '.') { + strncpy(nbuf, name, n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + 1 + d + 1 > sizeof(nbuf)) { + h_errno = NO_RECOVERY; + return -1; + } + snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); + } + return res_queryN(longname, target, res); +} diff --git a/aosp/bionic/libc/dns/net/gethnamaddr.c b/aosp/bionic/libc/dns/net/gethnamaddr.c new file mode 100644 index 000000000..7e18840d4 --- /dev/null +++ b/aosp/bionic/libc/dns/net/gethnamaddr.c @@ -0,0 +1,1635 @@ +/* $NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $ */ + +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * 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, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + * - + * --Copyright-- + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "NetdClientDispatch.h" +#include "resolv_netid.h" +#include "resolv_private.h" +#include "resolv_cache.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ALIGNBYTES (sizeof(uintptr_t) - 1) +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) + +#ifndef LOG_AUTH +# define LOG_AUTH 0 +#endif + +#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ + +#include "nsswitch.h" +#include +#include + +#include "hostent.h" + +#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ + (ok)(nm) != 0) +#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok) +#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok) + +#define addalias(d, s, arr, siz) do { \ + if (d >= &arr[siz]) { \ + char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \ + if (xptr == NULL) \ + goto nospc; \ + d = xptr + (d - arr); \ + arr = xptr; \ + siz += 10; \ + } \ + *d++ = s; \ +} while (/*CONSTCOND*/0) + +#define setup(arr, siz) do { \ + arr = malloc((siz = 10) * sizeof(*arr)); \ + if (arr == NULL) \ + goto nospc; \ +} while (/*CONSTCOND*/0) + +// This should be synchronized to ResponseCode.h +static const int DnsProxyQueryResult = 222; + +static const char AskedForGot[] = + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + +static const struct android_net_context NETCONTEXT_UNSET = { + .app_mark = MARK_UNSET, + .app_netid = NETID_UNSET, + .dns_mark = MARK_UNSET, + .dns_netid = NETID_UNSET, + .uid = NET_CONTEXT_INVALID_UID +}; + +#define MAXPACKET (8*1024) + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +typedef union { + int32_t al; + char ac; +} align; + +#ifdef DEBUG +static void debugprintf(const char *, res_state, ...) + __attribute__((__format__(__printf__, 1, 3))); +#endif +static struct hostent *getanswer(const querybuf *, int, const char *, int, + res_state, struct hostent *, char *, size_t, int *); +static void map_v4v6_address(const char *, char *); +static void map_v4v6_hostent(struct hostent *, char **, char *); +static void addrsort(char **, int, res_state); + +void ht_sethostent(int); +void ht_endhostent(void); +struct hostent *ht_gethostbyname(char *); +struct hostent *ht_gethostbyaddr(const char *, int, int); +void dns_service(void); +#undef dn_skipname +int dn_skipname(const u_char *, const u_char *); +static int _dns_gethtbyaddr(void *, void *, va_list); +static int _dns_gethtbyname(void *, void *, va_list); + +static struct hostent *gethostbyname_internal(const char *, int, res_state, + struct hostent *, char *, size_t, int *, const struct android_net_context *); +static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(const void*, socklen_t, + int, struct hostent *, char *, size_t, int *, const struct android_net_context *); + +static const ns_src default_dns_files[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NSSRC_DNS, NS_SUCCESS }, + { 0, 0 } +}; + +static int h_errno_to_result(int* herrno_p) { + // glibc considers ERANGE a special case (and BSD uses ENOSPC instead). + if (*herrno_p == NETDB_INTERNAL && errno == ENOSPC) { + errno = ERANGE; + return errno; + } + // glibc considers HOST_NOT_FOUND not an error for the _r functions' return value. + return (*herrno_p != HOST_NOT_FOUND) ? *herrno_p : 0; +} + +#ifdef DEBUG +static void +debugprintf(const char *msg, res_state res, ...) +{ + _DIAGASSERT(msg != NULL); + + if (res->options & RES_DEBUG) { + int save = errno; + va_list ap; + + va_start (ap, res); + vprintf(msg, ap); + va_end (ap); + + errno = save; + } +} +#else +# define debugprintf(msg, res, num) /*nada*/ +#endif + +#define BOUNDED_INCR(x) \ + do { \ + BOUNDS_CHECK(cp, x); \ + cp += (x); \ + } while (/*CONSTCOND*/0) + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if (eom - (ptr) < (count)) \ + goto no_recovery; \ + } while (/*CONSTCOND*/0) + +static struct hostent * +getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, + res_state res, struct hostent *hent, char *buf, size_t buflen, int *he) +{ + const HEADER *hp; + const u_char *cp; + int n; + size_t qlen; + const u_char *eom, *erdata; + char *bp, **ap, **hap, *ep; + int type, class, ancount, qdcount; + int haveanswer, had_error; + int toobig = 0; + char tbuf[MAXDNAME]; + char **aliases; + size_t maxaliases; + char *addr_ptrs[MAXADDRS]; + const char *tname; + int (*name_ok)(const char *); + + _DIAGASSERT(answer != NULL); + _DIAGASSERT(qname != NULL); + + tname = qname; + hent->h_name = NULL; + eom = answer->buf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + *he = NO_RECOVERY; + return NULL; /* XXX should be abort(); */ + } + + setup(aliases, maxaliases); + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = buf; + ep = buf + buflen; + cp = answer->buf; + BOUNDED_INCR(HFIXEDSZ); + if (qdcount != 1) + goto no_recovery; + + n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); + if ((n < 0) || !maybe_ok(res, bp, name_ok)) + goto no_recovery; + + BOUNDED_INCR(n + QFIXEDSZ); + if (qtype == T_A || qtype == T_AAAA) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = (int)strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + goto no_recovery; + hent->h_name = bp; + bp += n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = hent->h_name; + } + hent->h_aliases = ap = aliases; + hent->h_addr_list = hap = addr_ptrs; + *ap = NULL; + *hap = NULL; + haveanswer = 0; + had_error = 0; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); + if ((n < 0) || !maybe_ok(res, bp, name_ok)) { + had_error++; + continue; + } + cp += n; /* name */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + type = _getshort(cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + BOUNDS_CHECK(cp, n); + erdata = cp + n; + if (class != C_IN) { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, + (int)sizeof tbuf); + if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) + goto no_recovery; + /* Store alias. */ + addalias(ap, bp, aliases, maxaliases); + n = (int)strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + bp += n; + /* Get canonical name. */ + n = (int)strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + hent->h_name = bp; + bp += n; + continue; + } + if (qtype == T_PTR && type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, + (int)sizeof tbuf); + if (n < 0 || !maybe_dnok(res, tbuf)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) + goto no_recovery; + /* Get canonical name. */ + n = (int)strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + tname = bp; + bp += n; + continue; + } + if (type != qtype) { + if (type != T_KEY && type != T_SIG) + syslog(LOG_NOTICE|LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class(C_IN), p_type(qtype), + p_type(type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_PTR: + if (strcasecmp(tname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); + if ((n < 0) || !maybe_hnok(res, bp)) { + had_error++; + break; + } +#if MULTI_PTRS_ARE_ALIASES + cp += n; + if (cp != erdata) + goto no_recovery; + if (!haveanswer) + hent->h_name = bp; + else + addalias(ap, bp, aliases, maxaliases); + if (n != -1) { + n = (int)strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + } + break; +#else + hent->h_name = bp; + if (res->options & RES_USE_INET6) { + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + map_v4v6_hostent(hent, &bp, ep); + } + goto success; +#endif + case T_A: + case T_AAAA: + if (strcasecmp(hent->h_name, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, hent->h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (n != hent->h_length) { + cp += n; + continue; + } + if (type == T_AAAA) { + struct in6_addr in6; + memcpy(&in6, cp, NS_IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&in6)) { + cp += n; + continue; + } + } + if (!haveanswer) { + int nn; + + hent->h_name = bp; + nn = (int)strlen(bp) + 1; /* for the \0 */ + bp += nn; + } + + bp += sizeof(align) - + (size_t)((u_long)bp % sizeof(align)); + + if (bp + n >= ep) { + debugprintf("size (%d) too big\n", res, n); + had_error++; + continue; + } + if (hap >= &addr_ptrs[MAXADDRS - 1]) { + if (!toobig++) { + debugprintf("Too many addresses (%d)\n", + res, MAXADDRS); + } + cp += n; + continue; + } + (void)memcpy(*hap++ = bp, cp, (size_t)n); + bp += n; + cp += n; + if (cp != erdata) + goto no_recovery; + break; + default: + abort(); + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + *ap = NULL; + *hap = NULL; + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (res->nsort && haveanswer > 1 && qtype == T_A) + addrsort(addr_ptrs, haveanswer, res); + if (!hent->h_name) { + n = (int)strlen(qname) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) + goto no_recovery; + strlcpy(bp, qname, (size_t)(ep - bp)); + hent->h_name = bp; + bp += n; + } + if (res->options & RES_USE_INET6) + map_v4v6_hostent(hent, &bp, ep); + goto success; + } +no_recovery: + free(aliases); + *he = NO_RECOVERY; + return NULL; +success: + bp = (char *)ALIGN(bp); + n = (int)(ap - aliases); + qlen = (n + 1) * sizeof(*hent->h_aliases); + if ((size_t)(ep - bp) < qlen) + goto nospc; + hent->h_aliases = (void *)bp; + memcpy(bp, aliases, qlen); + free(aliases); + aliases = NULL; + + bp += qlen; + n = (int)(hap - addr_ptrs); + qlen = (n + 1) * sizeof(*hent->h_addr_list); + if ((size_t)(ep - bp) < qlen) + goto nospc; + hent->h_addr_list = (void *)bp; + memcpy(bp, addr_ptrs, qlen); + *he = NETDB_SUCCESS; + return hent; +nospc: + free(aliases); + errno = ENOSPC; + *he = NETDB_INTERNAL; + return NULL; +} + +/* The prototype of gethostbyname_r is from glibc, not that in netbsd. */ +int +gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, + struct hostent **result, int *errorp) +{ + res_state res = __res_get_state(); + if (res == NULL) { + *result = NULL; + *errorp = NETDB_INTERNAL; + return -1; + } + + _DIAGASSERT(name != NULL); + + if (res->options & RES_USE_INET6) { + *result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, + &NETCONTEXT_UNSET); + if (*result) { + __res_put_state(res); + return 0; + } + } + *result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, + &NETCONTEXT_UNSET); + return h_errno_to_result(errorp); +} + +/* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */ +int +gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf, + size_t buflen, struct hostent **result, int *errorp) +{ + res_state res = __res_get_state(); + if (res == NULL) { + *result = NULL; + *errorp = NETDB_INTERNAL; + return -1; + } + *result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, + &NETCONTEXT_UNSET); + return h_errno_to_result(errorp); +} + +static struct hostent * +android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he) +{ + uint32_t size; + char buf[4]; + if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL; + + // This is reading serialized data from system/netd/server/DnsProxyListener.cpp + // and changes here need to be matched there. + int result_code = strtol(buf, NULL, 10); + if (result_code != DnsProxyQueryResult) { + fread(&size, 1, sizeof(size), proxy); + *he = HOST_NOT_FOUND; + return NULL; + } + + if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; + size = ntohl(size); + + memset(hp, 0, sizeof(*hp)); + char *ptr = hbuf; + char *hbuf_end = hbuf + hbuflen; + + if (ptr + size > hbuf_end) { + goto nospc; + } + if (fread(ptr, 1, size, proxy) != size) return NULL; + hp->h_name = ptr; + ptr += size; + + char *aliases_ptrs[MAXALIASES]; + char **aliases = &aliases_ptrs[0]; + + while (1) { + if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; + size = ntohl(size); + + if (size == 0) { + *aliases = NULL; + break; + } + if (ptr + size > hbuf_end) { + goto nospc; + } + if (fread(ptr, 1, size, proxy) != size) return NULL; + if (aliases < &aliases_ptrs[MAXALIASES - 1]) { + *aliases++ = ptr; + } + ptr += size; + } + + // Fix alignment after variable-length data. + ptr = (char*)ALIGN(ptr); + + int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases); + if (ptr + aliases_len > hbuf_end) { + goto nospc; + } + hp->h_aliases = (void*)ptr; + memcpy(ptr, aliases_ptrs, aliases_len); + ptr += aliases_len; + + if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; + hp->h_addrtype = ntohl(size); + + if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; + hp->h_length = ntohl(size); + + char *addr_ptrs[MAXADDRS]; + char **addr_p = &addr_ptrs[0]; + + while (1) { + if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL; + size = ntohl(size); + if (size == 0) { + *addr_p = NULL; + break; + } + if (ptr + size > hbuf_end) { + goto nospc; + } + if (fread(ptr, 1, size, proxy) != size) return NULL; + if (addr_p < &addr_ptrs[MAXADDRS - 1]) { + *addr_p++ = ptr; + } + ptr += size; + } + + // Fix alignment after variable-length data. + ptr = (char*)ALIGN(ptr); + + int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list); + if (ptr + addrs_len > hbuf_end) { + goto nospc; + } + hp->h_addr_list = (void*)ptr; + memcpy(ptr, addr_ptrs, addrs_len); + *he = NETDB_SUCCESS; + return hp; + +nospc: + *he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; +} + +static struct hostent * +gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf, + size_t buflen, int *he) +{ + const char *cp; + struct getnamaddr info; + char hbuf[MAXHOSTNAMELEN]; + size_t size; + static const ns_dtab dtab[] = { + NS_FILES_CB(_hf_gethtbyname, NULL) + { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ + NS_NIS_CB(_yp_gethtbyname, NULL) + NS_NULL_CB + }; + + _DIAGASSERT(name != NULL); + + switch (af) { + case AF_INET: + size = NS_INADDRSZ; + break; + case AF_INET6: + size = NS_IN6ADDRSZ; + break; + default: + *he = NETDB_INTERNAL; + errno = EAFNOSUPPORT; + return NULL; + } + if (buflen < size) + goto nospc; + + hp->h_addrtype = af; + hp->h_length = (int)size; + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_nquery() since we are not the only + * function that looks up host names. + */ + if (!strchr(name, '.') && (cp = res_hostalias(res, name, + hbuf, sizeof(hbuf)))) + name = cp; + + /* + * disallow names consisting only of digits/dots, unless + * they end in a dot. + */ + if (isdigit((u_char) name[0])) + for (cp = name;; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + /* + * All-numeric, no dot at the end. + * Fake up a hostent as if we'd actually + * done a lookup. + */ + goto fake; + } + if (!isdigit((u_char) *cp) && *cp != '.') + break; + } + if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) || + name[0] == ':') + for (cp = name;; ++cp) { + if (!*cp) { + if (*--cp == '.') + break; + /* + * All-IPv6-legal, no dot at the end. + * Fake up a hostent as if we'd actually + * done a lookup. + */ + goto fake; + } + if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') + break; + } + + *he = NETDB_INTERNAL; + info.hp = hp; + info.buf = buf; + info.buflen = buflen; + info.he = he; + if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname", + default_dns_files, name, strlen(name), af) != NS_SUCCESS) + return NULL; + *he = NETDB_SUCCESS; + return hp; +nospc: + *he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; +fake: + HENT_ARRAY(hp->h_addr_list, 1, buf, buflen); + HENT_ARRAY(hp->h_aliases, 0, buf, buflen); + + hp->h_aliases[0] = NULL; + if (size > buflen) + goto nospc; + + if (inet_pton(af, name, buf) <= 0) { + *he = HOST_NOT_FOUND; + return NULL; + } + hp->h_addr_list[0] = buf; + hp->h_addr_list[1] = NULL; + buf += size; + buflen -= size; + HENT_SCOPY(hp->h_name, name, buf, buflen); + if (res->options & RES_USE_INET6) + map_v4v6_hostent(hp, &buf, buf + buflen); + *he = NETDB_SUCCESS; + return hp; +} + +static struct hostent * +gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf, + size_t hbuflen, int *errorp, const struct android_net_context *netcontext) +{ + FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+"); + if (proxy == NULL) { + // Either we're not supposed to be using the proxy or the proxy is unavailable. + res_setnetcontext(res, netcontext); + return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp); + } + unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid); + + // This is writing to system/netd/server/DnsProxyListener.cpp and changes + // here need to be matched there. + if (fprintf(proxy, "gethostbyname %u %s %d", + netid, + name == NULL ? "^" : name, + af) < 0) { + fclose(proxy); + return NULL; + } + + if (fputc(0, proxy) == EOF || fflush(proxy) != 0) { + fclose(proxy); + return NULL; + } + + struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp); + fclose(proxy); + return result; +} + +/* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */ +int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf, + size_t buflen, struct hostent **result, int *h_errnop) +{ + *result = android_gethostbyaddrfornetcontext_proxy_internal( + addr, len, af, hp, buf, buflen, h_errnop, &NETCONTEXT_UNSET); + return h_errno_to_result(h_errnop); +} + +static struct hostent * +android_gethostbyaddrfornetcontext_real(const void *addr, socklen_t len, int af, struct hostent *hp, + char *buf, size_t buflen, int *he, + const struct android_net_context *netcontext) +{ + const u_char *uaddr = (const u_char *)addr; + socklen_t size; + struct getnamaddr info; + static const ns_dtab dtab[] = { + NS_FILES_CB(_hf_gethtbyaddr, NULL) + { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ + NS_NIS_CB(_yp_gethtbyaddr, NULL) + NS_NULL_CB + }; + + _DIAGASSERT(addr != NULL); + + if (af == AF_INET6 && len == NS_IN6ADDRSZ && + (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) || + IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) { + *he = HOST_NOT_FOUND; + return NULL; + } + if (af == AF_INET6 && len == NS_IN6ADDRSZ && + (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) || + IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) { + /* Unmap. */ + uaddr += NS_IN6ADDRSZ - NS_INADDRSZ; + addr = uaddr; + af = AF_INET; + len = NS_INADDRSZ; + } + switch (af) { + case AF_INET: + size = NS_INADDRSZ; + break; + case AF_INET6: + size = NS_IN6ADDRSZ; + break; + default: + errno = EAFNOSUPPORT; + *he = NETDB_INTERNAL; + return NULL; + } + if (size != len) { + errno = EINVAL; + *he = NETDB_INTERNAL; + return NULL; + } + info.hp = hp; + info.buf = buf; + info.buflen = buflen; + info.he = he; + *he = NETDB_INTERNAL; + if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr", + default_dns_files, uaddr, len, af, netcontext) != NS_SUCCESS) + return NULL; + *he = NETDB_SUCCESS; + return hp; +} + +static struct hostent* +android_gethostbyaddrfornetcontext_proxy_internal(const void* addr, socklen_t len, int af, + struct hostent *hp, char *hbuf, size_t hbuflen, int *he, + const struct android_net_context *netcontext) +{ + FILE* proxy = fdopen(__netdClientDispatch.dnsOpenProxy(), "r+"); + if (proxy == NULL) { + // Either we're not supposed to be using the proxy or the proxy is unavailable. + return android_gethostbyaddrfornetcontext_real(addr,len, af, hp, hbuf, hbuflen, he, netcontext); + } + char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6 + const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf)); + if (addrStr == NULL) { + fclose(proxy); + return NULL; + } + + unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid); + + if (fprintf(proxy, "gethostbyaddr %s %d %d %u", + addrStr, len, af, netid) < 0) { + fclose(proxy); + return NULL; + } + + if (fputc(0, proxy) == EOF || fflush(proxy) != 0) { + fclose(proxy); + return NULL; + } + + struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he); + fclose(proxy); + return result; +} + +struct hostent* +netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he) +{ + char *p, *name; + char *cp, **q; + int af, len; + size_t anum; + char **aliases; + size_t maxaliases; + struct in6_addr host_addr; + + if (hf == NULL) { + *he = NETDB_INTERNAL; + errno = EINVAL; + return NULL; + } + p = NULL; + setup(aliases, maxaliases); + + /* Allocate a new space to read file lines like upstream does. + * To keep reentrancy we cannot use __res_get_static()->hostbuf here, + * as the buffer may be used to store content for a previous hostent + * returned by non-reentrant functions like gethostbyname(). + */ + const size_t line_buf_size = sizeof(__res_get_static()->hostbuf); + if ((p = malloc(line_buf_size)) == NULL) { + goto nospc; + } + for (;;) { + if (!fgets(p, line_buf_size, hf)) { + free(p); + free(aliases); + *he = HOST_NOT_FOUND; + return NULL; + } + if (*p == '#') { + continue; + } + if (!(cp = strpbrk(p, "#\n"))) { + continue; + } + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + continue; + *cp++ = '\0'; + if (inet_pton(AF_INET6, p, &host_addr) > 0) { + af = AF_INET6; + len = NS_IN6ADDRSZ; + } else { + if (inet_pton(AF_INET, p, &host_addr) <= 0) + continue; + + res_state res = __res_get_state(); + if (res == NULL) + goto nospc; + if (res->options & RES_USE_INET6) { + map_v4v6_address(buf, buf); + af = AF_INET6; + len = NS_IN6ADDRSZ; + } else { + af = AF_INET; + len = NS_INADDRSZ; + } + __res_put_state(res); + } + + /* if this is not something we're looking for, skip it. */ + if (hent->h_addrtype != 0 && hent->h_addrtype != af) + continue; + if (hent->h_length != 0 && hent->h_length != len) + continue; + + while (*cp == ' ' || *cp == '\t') + cp++; + if ((cp = strpbrk(name = cp, " \t")) != NULL) + *cp++ = '\0'; + q = aliases; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + addalias(q, cp, aliases, maxaliases); + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + } + break; + } + hent->h_length = len; + hent->h_addrtype = af; + HENT_ARRAY(hent->h_addr_list, 1, buf, buflen); + anum = (size_t)(q - aliases); + HENT_ARRAY(hent->h_aliases, anum, buf, buflen); + HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf, + buflen); + hent->h_addr_list[1] = NULL; + + HENT_SCOPY(hent->h_name, name, buf, buflen); + for (size_t i = 0; i < anum; i++) + HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen); + hent->h_aliases[anum] = NULL; + + *he = NETDB_SUCCESS; + free(p); + free(aliases); + return hent; +nospc: + free(p); + free(aliases); + errno = ENOSPC; + *he = NETDB_INTERNAL; + return NULL; +} + +static void +map_v4v6_address(const char *src, char *dst) +{ + u_char *p = (u_char *)dst; + char tmp[NS_INADDRSZ]; + int i; + + _DIAGASSERT(src != NULL); + _DIAGASSERT(dst != NULL); + + /* Stash a temporary copy so our caller can update in place. */ + (void)memcpy(tmp, src, NS_INADDRSZ); + /* Mark this ipv6 addr as a mapped ipv4. */ + for (i = 0; i < 10; i++) + *p++ = 0x00; + *p++ = 0xff; + *p++ = 0xff; + /* Retrieve the saved copy and we're done. */ + (void)memcpy(p, tmp, NS_INADDRSZ); +} + +static void +map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) +{ + char **ap; + + _DIAGASSERT(hp != NULL); + _DIAGASSERT(bpp != NULL); + _DIAGASSERT(ep != NULL); + + if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) + return; + hp->h_addrtype = AF_INET6; + hp->h_length = NS_IN6ADDRSZ; + for (ap = hp->h_addr_list; *ap; ap++) { + int i = (int)(sizeof(align) - + (size_t)((u_long)*bpp % sizeof(align))); + + if (ep - *bpp < (i + NS_IN6ADDRSZ)) { + /* Out of memory. Truncate address list here. XXX */ + *ap = NULL; + return; + } + *bpp += i; + map_v4v6_address(*ap, *bpp); + *ap = *bpp; + *bpp += NS_IN6ADDRSZ; + } +} + +static void +addrsort(char **ap, int num, res_state res) +{ + int i, j; + char **p; + short aval[MAXADDRS]; + int needsort = 0; + + _DIAGASSERT(ap != NULL); + + p = ap; + for (i = 0; i < num; i++, p++) { + for (j = 0 ; (unsigned)j < res->nsort; j++) + if (res->sort_list[j].addr.s_addr == + (((struct in_addr *)(void *)(*p))->s_addr & + res->sort_list[j].mask)) + break; + aval[i] = j; + if (needsort == 0 && i > 0 && j < aval[i-1]) + needsort = i; + } + if (!needsort) + return; + + while (needsort < num) { + for (j = needsort - 1; j >= 0; j--) { + if (aval[j] > aval[j+1]) { + char *hp; + + i = aval[j]; + aval[j] = aval[j+1]; + aval[j+1] = i; + + hp = ap[j]; + ap[j] = ap[j+1]; + ap[j+1] = hp; + } else + break; + } + needsort++; + } +} + +/*ARGSUSED*/ +static int +_dns_gethtbyname(void *rv, void *cb_data, va_list ap) +{ + querybuf *buf; + int n, type; + struct hostent *hp; + const char *name; + res_state res; + struct getnamaddr *info = rv; + + _DIAGASSERT(rv != NULL); + + name = va_arg(ap, char *); + /* NOSTRICT skip string len */(void)va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); + + switch (info->hp->h_addrtype) { + case AF_INET: + info->hp->h_length = NS_INADDRSZ; + type = T_A; + break; + case AF_INET6: + info->hp->h_length = NS_IN6ADDRSZ; + type = T_AAAA; + break; + default: + return NS_UNAVAIL; + } + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + *info->he = NETDB_INTERNAL; + return NS_NOTFOUND; + } + res = __res_get_state(); + if (res == NULL) { + free(buf); + return NS_NOTFOUND; + } + n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf)); + if (n < 0) { + free(buf); + debugprintf("res_nsearch failed (%d)\n", res, n); + __res_put_state(res); + return NS_NOTFOUND; + } + hp = getanswer(buf, n, name, type, res, info->hp, info->buf, + info->buflen, info->he); + free(buf); + __res_put_state(res); + if (hp == NULL) + switch (*info->he) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + return NS_SUCCESS; +} + +/*ARGSUSED*/ +static int +_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) +{ + char qbuf[MAXDNAME + 1], *qp, *ep; + int n; + querybuf *buf; + struct hostent *hp; + const unsigned char *uaddr; + int advance; + res_state res; + char *bf; + size_t blen; + struct getnamaddr *info = rv; + const struct android_net_context *netcontext; + + _DIAGASSERT(rv != NULL); + + uaddr = va_arg(ap, unsigned char *); + info->hp->h_length = va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); + netcontext = va_arg(ap, const struct android_net_context *); + + switch (info->hp->h_addrtype) { + case AF_INET: + (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", + (uaddr[3] & 0xff), (uaddr[2] & 0xff), + (uaddr[1] & 0xff), (uaddr[0] & 0xff)); + break; + + case AF_INET6: + qp = qbuf; + ep = qbuf + sizeof(qbuf) - 1; + for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { + advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", + uaddr[n] & 0xf, + ((unsigned int)uaddr[n] >> 4) & 0xf); + if (advance > 0 && qp + advance < ep) + qp += advance; + else { + *info->he = NETDB_INTERNAL; + return NS_NOTFOUND; + } + } + if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { + *info->he = NETDB_INTERNAL; + return NS_NOTFOUND; + } + break; + default: + return NS_UNAVAIL; + } + + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + *info->he = NETDB_INTERNAL; + return NS_NOTFOUND; + } + res = __res_get_state(); + if (res == NULL) { + free(buf); + return NS_NOTFOUND; + } + res_setnetcontext(res, netcontext); + n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf)); + if (n < 0) { + free(buf); + debugprintf("res_nquery failed (%d)\n", res, n); + __res_put_state(res); + return NS_NOTFOUND; + } + hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, + info->buflen, info->he); + free(buf); + if (hp == NULL) { + __res_put_state(res); + switch (*info->he) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + + bf = (void *)(hp->h_addr_list + 2); + blen = (size_t)(bf - info->buf); + if (blen + info->hp->h_length > info->buflen) + goto nospc; + hp->h_addr_list[0] = bf; + hp->h_addr_list[1] = NULL; + (void)memcpy(bf, uaddr, (size_t)info->hp->h_length); + if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) { + if (blen + NS_IN6ADDRSZ > info->buflen) + goto nospc; + map_v4v6_address(bf, bf); + hp->h_addrtype = AF_INET6; + hp->h_length = NS_IN6ADDRSZ; + } + + __res_put_state(res); + *info->he = NETDB_SUCCESS; + return NS_SUCCESS; +nospc: + errno = ENOSPC; + *info->he = NETDB_INTERNAL; + return NS_UNAVAIL; +} + +#ifdef YP +/*ARGSUSED*/ +static struct hostent * +_yp_hostent(char *line, int af, struct getnamaddr *info) +{ + struct in6_addr host_addrs[MAXADDRS]; + char **aliases; + size_t maxaliases; + char *p = line; + char *cp, **q, *ptr; + size_t len, anum, i; + int addrok; + int more; + size_t naddrs; + struct hostent *hp = info->hp; + + _DIAGASSERT(line != NULL); + + hp->h_name = NULL; + hp->h_addrtype = af; + switch (af) { + case AF_INET: + hp->h_length = NS_INADDRSZ; + break; + case AF_INET6: + hp->h_length = NS_IN6ADDRSZ; + break; + default: + return NULL; + } + setup(aliases, maxaliases); + naddrs = 0; + q = aliases; + +nextline: + /* check for host_addrs overflow */ + if (naddrs >= __arraycount(host_addrs)) + goto done; + + more = 0; + cp = strpbrk(p, " \t"); + if (cp == NULL) + goto done; + *cp++ = '\0'; + + /* p has should have an address */ + addrok = inet_pton(af, p, &host_addrs[naddrs]); + if (addrok != 1) { + /* skip to the next line */ + while (cp && *cp) { + if (*cp == '\n') { + cp++; + goto nextline; + } + cp++; + } + goto done; + } + naddrs++; + + while (*cp == ' ' || *cp == '\t') + cp++; + p = cp; + cp = strpbrk(p, " \t\n"); + if (cp != NULL) { + if (*cp == '\n') + more = 1; + *cp++ = '\0'; + } + if (!hp->h_name) + hp->h_name = p; + else if (strcmp(hp->h_name, p) == 0) + ; + else + addalias(q, p, aliases, maxaliases); + p = cp; + if (more) + goto nextline; + + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (*cp == '\n') { + cp++; + goto nextline; + } + addalias(q, cp, aliases, maxaliases); + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + +done: + if (hp->h_name == NULL) { + free(aliases); + return NULL; + } + + ptr = info->buf; + len = info->buflen; + + anum = (size_t)(q - aliases); + HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len); + HENT_ARRAY(hp->h_aliases, anum, ptr, len); + + for (i = 0; i < naddrs; i++) + HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length, + ptr, len); + hp->h_addr_list[naddrs] = NULL; + + HENT_SCOPY(hp->h_name, hp->h_name, ptr, len); + + for (i = 0; i < anum; i++) + HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len); + hp->h_aliases[anum] = NULL; + free(aliases); + + return hp; +nospc: + free(aliases); + *info->he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; +} + +/*ARGSUSED*/ +int +_yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) +{ + struct hostent *hp = NULL; + char *ypcurrent; + int ypcurrentlen, r; + char name[INET6_ADDRSTRLEN]; /* XXX enough? */ + const unsigned char *uaddr; + int af; + const char *map; + struct getnamaddr *info = rv; + + _DIAGASSERT(rv != NULL); + + uaddr = va_arg(ap, unsigned char *); + /* NOSTRICT skip len */(void)va_arg(ap, int); + af = va_arg(ap, int); + + if (!__ypdomain) { + if (_yp_check(&__ypdomain) == 0) + return NS_UNAVAIL; + } + /* + * XXX unfortunately, we cannot support IPv6 extended scoped address + * notation here. gethostbyaddr() is not scope-aware. too bad. + */ + if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL) + return NS_UNAVAIL; + switch (af) { + case AF_INET: + map = "hosts.byaddr"; + break; + default: + map = "ipnodes.byaddr"; + break; + } + ypcurrent = NULL; + r = yp_match(__ypdomain, map, name, + (int)strlen(name), &ypcurrent, &ypcurrentlen); + if (r == 0) + hp = _yp_hostent(ypcurrent, af, info); + else + hp = NULL; + free(ypcurrent); + if (hp == NULL) { + *info->he = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} + +/*ARGSUSED*/ +int +_yp_gethtbyname(void *rv, void *cb_data, va_list ap) +{ + struct hostent *hp; + char *ypcurrent; + int ypcurrentlen, r; + const char *name; + int af; + const char *map; + struct getnamaddr *info = rv; + + _DIAGASSERT(rv != NULL); + + name = va_arg(ap, char *); + /* NOSTRICT skip string len */(void)va_arg(ap, int); + af = va_arg(ap, int); + + if (!__ypdomain) { + if (_yp_check(&__ypdomain) == 0) + return NS_UNAVAIL; + } + switch (af) { + case AF_INET: + map = "hosts.byname"; + break; + default: + map = "ipnodes.byname"; + break; + } + ypcurrent = NULL; + r = yp_match(__ypdomain, map, name, + (int)strlen(name), &ypcurrent, &ypcurrentlen); + if (r == 0) + hp = _yp_hostent(ypcurrent, af, info); + else + hp = NULL; + free(ypcurrent); + if (hp == NULL) { + *info->he = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} +#endif + +/* + * Non-reentrant versions. + */ + +struct hostent * +gethostbyname(const char *name) +{ + struct hostent *result = NULL; + res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */ + + gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno); + return result; +} + +struct hostent * +gethostbyname2(const char *name, int af) +{ + struct hostent *result = NULL; + res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */ + + gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno); + return result; +} + +// android_gethostby*fornet can be called in two different contexts. +// - In the proxy client context (proxy != NULL), |netid| is |app_netid|. +// - In the proxy listener context (proxy == NULL), |netid| is |dns_netid|. +// The netcontext is constructed before checking which context we are in. +// Therefore, we have to populate both fields, and rely on the downstream code to check whether +// |proxy == NULL|, and use that info to query the field that matches the caller's intent. +static struct android_net_context make_context(unsigned netid, unsigned mark) { + struct android_net_context netcontext = NETCONTEXT_UNSET; + netcontext.app_netid = netid; + netcontext.app_mark = mark; + netcontext.dns_netid = netid; + netcontext.dns_mark = mark; + return netcontext; +} + +struct hostent * +android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark) +{ + const struct android_net_context netcontext = make_context(netid, mark); + return android_gethostbynamefornetcontext(name, af, &netcontext); +} + +struct hostent * +android_gethostbynamefornetcontext(const char *name, int af, + const struct android_net_context *netcontext) +{ + struct hostent *hp; + res_state res = __res_get_state(); + if (res == NULL) + return NULL; + res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */ + hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), + &h_errno, netcontext); + __res_put_state(res); + return hp; +} + +struct hostent * +gethostbyaddr(const void *addr, socklen_t len, int af) +{ + return android_gethostbyaddrfornetcontext_proxy(addr, len, af, &NETCONTEXT_UNSET); +} + +struct hostent * +android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) +{ + const struct android_net_context netcontext = make_context(netid, mark); + return android_gethostbyaddrfornetcontext(addr, len, af, &netcontext); +} + +struct hostent * +android_gethostbyaddrfornetcontext(const void *addr, socklen_t len, int af, + const struct android_net_context *netcontext) +{ + return android_gethostbyaddrfornetcontext_proxy(addr, len, af, netcontext); +} + +__LIBC_HIDDEN__ struct hostent* +android_gethostbyaddrfornetcontext_proxy(const void* addr, socklen_t len, int af, + const struct android_net_context *netcontext) +{ + res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */ + return android_gethostbyaddrfornetcontext_proxy_internal(addr, len, af, &rs->host, rs->hostbuf, + sizeof(rs->hostbuf), &h_errno, netcontext); +} + +struct hostent * +gethostent(void) +{ + res_static rs = __res_get_static(); + if (!rs->hostf) { + sethostent_r(&rs->hostf); + if (!rs->hostf) { + h_errno = NETDB_INTERNAL; + return NULL; + } + } + memset(&rs->host, 0, sizeof(rs->host)); + return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno); +} diff --git a/aosp/bionic/libc/dns/net/getnameinfo.c b/aosp/bionic/libc/dns/net/getnameinfo.c new file mode 100644 index 000000000..31d07c59d --- /dev/null +++ b/aosp/bionic/libc/dns/net/getnameinfo.c @@ -0,0 +1,442 @@ +/* $NetBSD: getnameinfo.c,v 1.53 2012/09/26 23:13:00 christos Exp $ */ +/* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */ + +/* + * Copyright (c) 2000 Ben Harris. + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: + * 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 project 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 PROJECT 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 PROJECT 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. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - RFC2553 says that we should raise error on short buffer. X/Open says + * we need to truncate the result. We obey RFC2553 (and X/Open should be + * modified). ipngwg rough consensus seems to follow RFC2553. + * - What is "local" in NI_FQDN? + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if + * sin6_scope_id is filled - standardization status? + * XXX breaks backward compat for code that expects no scopeid. + * beware on merge. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: getnameinfo.c,v 1.53 2012/09/26 23:13:00 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "resolv_netid.h" +#include "resolv_private.h" +#include +#include +#include +#include +#include + +/* This macro is modelled after the ones in . */ +/* RFC 6052, section 2.1 */ +#define IN6_IS_ADDR_WKP(a) \ + ((((a)->s6_addr32[0]) == ntohl(0x0064ff9b)) && \ + (((a)->s6_addr32[1]) == 0) && \ + (((a)->s6_addr32[2]) == 0)) + +static const struct afd { + int a_af; + socklen_t a_addrlen; + socklen_t a_socklen; + int a_off; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0, 0}, +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int, unsigned, unsigned); +#ifdef INET6 +static int ip6_parsenumeric(const struct sockaddr *, const char *, char *, + socklen_t, int); +static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int); +#endif +static int getnameinfo_local(const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int); + +/* + * Top-level getnameinfo() code. Look at the address family, and pick an + * appropriate function to call. + */ +int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, + char* serv, size_t servlen, int flags) +{ + return android_getnameinfofornet(sa, salen, host, hostlen, serv, servlen, flags, + NETID_UNSET, MARK_UNSET); +} + +int android_getnameinfofornet(const struct sockaddr* sa, socklen_t salen, char* host, + size_t hostlen, char* serv, size_t servlen, int flags, unsigned netid, + unsigned mark) +{ + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + return getnameinfo_inet(sa, salen, host, hostlen, + serv, servlen, flags, netid, mark); + case AF_LOCAL: + return getnameinfo_local(sa, salen, host, hostlen, + serv, servlen, flags); + default: + return EAI_FAMILY; + } +} + +/* + * getnameinfo_local(): + * Format an local address into a printable format. + */ +/* ARGSUSED */ +static int +getnameinfo_local(const struct sockaddr *sa, socklen_t salen, + char *host, socklen_t hostlen, char *serv, socklen_t servlen, + int flags __attribute__((unused))) +{ + const struct sockaddr_un *sun = + (const struct sockaddr_un *)(const void *)sa; + + if (salen < (socklen_t) offsetof(struct sockaddr_un, sun_path)) { + return EAI_FAMILY; + } + + if (serv != NULL && servlen > 0) + serv[0] = '\0'; + + if (host && hostlen > 0) + strlcpy(host, sun->sun_path, + MIN((socklen_t) sizeof(sun->sun_path) + 1, hostlen)); + + return 0; +} + +/* + * getnameinfo_inet(): + * Format an IPv4 or IPv6 sockaddr into a printable string. + */ +static int +getnameinfo_inet(const struct sockaddr* sa, socklen_t salen, + char *host, socklen_t hostlen, + char *serv, socklen_t servlen, + int flags, unsigned netid, unsigned mark) +{ + const struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, i; + const char *addr; + uint32_t v4a; + char numserv[512]; + char numaddr[512]; + + /* sa is checked below */ + /* host may be NULL */ + /* serv may be NULL */ + + if (sa == NULL) + return EAI_FAIL; + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return EAI_FAMILY; + + found: + // http://b/1889275: callers should be allowed to provide too much + // space, but not too little. + if (salen < afd->a_socklen) { + return EAI_FAMILY; + } + + /* network byte order */ + port = ((const struct sockinet *)(const void *)sa)->si_port; + addr = (const char *)(const void *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that serv == NULL OR + * servlen == 0 means that the caller does not want the result. + */ + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) + 1 > (size_t)servlen) + return EAI_MEMORY; + strlcpy(serv, sp->s_name, servlen); + } else { + snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); + if (strlen(numserv) + 1 > (size_t)servlen) + return EAI_MEMORY; + strlcpy(serv, numserv, servlen); + } + } + + switch (sa->sa_family) { + case AF_INET: + v4a = (uint32_t) + ntohl(((const struct sockaddr_in *) + (const void *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0) + flags |= NI_NUMERICHOST; + break; +#ifdef INET6 + case AF_INET6: + { + const struct sockaddr_in6 *sin6; + sin6 = (const struct sockaddr_in6 *)(const void *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_WKP(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + flags |= NI_NUMERICHOST; + } + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } + } + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that host == NULL or + * hostlen == 0 means that the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + size_t numaddrlen; + + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return EAI_NONAME; + + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return EAI_SYSTEM; + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > (size_t)hostlen) /* don't forget terminator */ + return EAI_MEMORY; + strlcpy(host, numaddr, hostlen); + break; + } + } else { + // This code should only run in the app context, not inside netd, so netid is + // the app's netid. netd doesn't use getnameinfo for network requests. + const struct android_net_context netcontext = { .app_netid = netid, .app_mark = mark }; + hp = android_gethostbyaddrfornetcontext_proxy(addr, afd->a_addrlen, afd->a_af, &netcontext); + if (hp) { +#if 0 + /* + * commented out, since "for local host" is not + * implemented here - see RFC2553 p30 + */ + if (flags & NI_NOFQDN) { + char *p; + p = strchr(hp->h_name, '.'); + if (p) + TODO: Before uncommenting rewrite to avoid modifying hp. + *p = '\0'; + } +#endif + if (strlen(hp->h_name) + 1 > (size_t)hostlen) { + return EAI_MEMORY; + } + strlcpy(host, hp->h_name, hostlen); + } else { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return EAI_SYSTEM; + break; + } + } + } + return(0); +} + +#ifdef INET6 +static int +ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host, + socklen_t hostlen, int flags) +{ + size_t numaddrlen; + char numaddr[512]; + + assert(sa != NULL); + assert(addr != NULL); + assert(host != NULL); + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) + return EAI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > (size_t)hostlen) /* don't forget terminator */ + return EAI_OVERFLOW; + strlcpy(host, numaddr, hostlen); + + if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) { + char zonebuf[MAXHOSTNAMELEN]; + int zonelen; + + zonelen = ip6_sa2str( + (const struct sockaddr_in6 *)(const void *)sa, + zonebuf, sizeof(zonebuf), flags); + if (zonelen < 0) + return EAI_OVERFLOW; + if ((size_t) zonelen + 1 + numaddrlen + 1 > (size_t)hostlen) + return EAI_OVERFLOW; + /* construct */ + memcpy(host + numaddrlen + 1, zonebuf, + (size_t)zonelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + zonelen] = '\0'; + } + + return 0; +} + +/* ARGSUSED */ +static int +ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags) +{ + unsigned int ifindex; + const struct in6_addr *a6; + int n; + + assert(sa6 != NULL); + assert(buf != NULL); + + ifindex = (unsigned int)sa6->sin6_scope_id; + a6 = &sa6->sin6_addr; + +#ifdef NI_NUMERICSCOPE + if ((flags & NI_NUMERICSCOPE) != 0) { + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || n >= bufsiz) + return -1; + else + return n; + } +#endif + + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && + bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) { + return(strlen(p)); + } + } + + /* last resort */ + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || (size_t) n >= bufsiz) + return -1; + else + return n; +} +#endif /* INET6 */ diff --git a/aosp/bionic/libc/dns/net/getservent.c b/aosp/bionic/libc/dns/net/getservent.c new file mode 100644 index 000000000..03add59eb --- /dev/null +++ b/aosp/bionic/libc/dns/net/getservent.c @@ -0,0 +1,151 @@ +/* + * 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 + +#include +#include +#include + +#include "resolv_static.h" +#include "services.h" + +struct servent* getservent_r(res_static rs) { + const char* p; + const char* q; + int namelen; + int nn,count; + int total = 0; + int port; + char* p2; + + p = rs->servent_ptr; + if (p == NULL) + p = _services; + else if (p[0] == 0) + return NULL; + + /* first compute the total size */ + namelen = p[0]; + total += namelen + 1; + q = p + 1 + namelen + 3; /* skip name + port + proto */ + count = q[0]; /* get aliascount */ + q += 1; + + total += (count+1)*sizeof(char*); + for (nn = 0; nn < count; nn++) { + int len2 = q[0]; + total += 1 + len2; + q += 1 + len2; + } + + /* reallocate the thread-specific servent struct */ + p2 = realloc( (char*)rs->servent.s_aliases, total ); + if (p2 == NULL) + return NULL; + + /* now write to it */ + rs->servent.s_aliases = (char**) p2; + p2 += (count+1)*sizeof(char*); + rs->servent.s_name = p2; + p2 += namelen + 1; + rs->servent.s_proto = p2; + + /* copy name + port + setup protocol */ + memcpy( rs->servent.s_name, p+1, namelen ); + rs->servent.s_name[namelen] = 0; + p += 1 + namelen; + + /* s_port must be in network byte order */ + port = ((((unsigned char*)p)[0] << 8) | + ((unsigned char*)p)[1]); + + rs->servent.s_port = htons(port); + rs->servent.s_proto = p[2] == 't' ? "tcp" : "udp"; + p += 4; /* skip port(2) + proto(1) + aliascount(1) */ + + for (nn = 0; nn < count; nn++) { + int len2 = p[0]; + rs->servent.s_aliases[nn] = p2; + memcpy( p2, p+1, len2 ); + p2[len2] = 0; + p2 += len2 + 1; + p += len2 + 1; + } + rs->servent.s_aliases[nn] = NULL; + + rs->servent_ptr = p; + + return &rs->servent; +} + +void setservent(int stayopen) { + endservent(); +} + +void endservent(void) { + res_static rs = __res_get_static(); + if (rs) rs->servent_ptr = NULL; +} + +struct servent* getservent(void) { + res_static rs = __res_get_static(); + return rs ? getservent_r(rs) : NULL; +} + +struct servent* getservbyname(const char* name, const char* proto) { + res_static rs = __res_get_static(); + if (rs == NULL) return NULL; + + const char* old_servent_ptr = rs->servent_ptr; + rs->servent_ptr = NULL; + struct servent* s; + while ((s = getservent_r(rs)) != NULL) { + if (strcmp(s->s_name, name) == 0 && (proto == NULL || strcmp(s->s_proto, proto) == 0)) { + break; + } + } + rs->servent_ptr = old_servent_ptr; + return s; +} + +struct servent* getservbyport(int port, const char* proto) { + res_static rs = __res_get_static(); + if (rs == NULL) return NULL; + + const char* old_servent_ptr = rs->servent_ptr; + rs->servent_ptr = NULL; + struct servent* s; + while ((s = getservent_r(rs)) != NULL) { + if (s->s_port == port && (proto == NULL || strcmp(s->s_proto, proto) == 0)) { + break; + } + } + rs->servent_ptr = old_servent_ptr; + return s; +} diff --git a/aosp/bionic/libc/dns/net/nsdispatch.c b/aosp/bionic/libc/dns/net/nsdispatch.c new file mode 100644 index 000000000..d025592a0 --- /dev/null +++ b/aosp/bionic/libc/dns/net/nsdispatch.c @@ -0,0 +1,146 @@ +/* $NetBSD: nsdispatch.c,v 1.30 2005/11/29 03:11:59 christos Exp $ */ + +/*- + * Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn; and by Jason R. Thorpe. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c) 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * Jacques A. Vidrine, Safeport Network Services, and Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * 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 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 AUTHOR 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 + +#include +#include +#include +#include +#include + +static nss_method +_nsmethod(const char *source, const char *database __unused, const char *method __unused, + const ns_dtab disp_tab[], void **cb_data) +{ + int curdisp; + + if (disp_tab != NULL) { + for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) { + if (strcasecmp(source, disp_tab[curdisp].src) == 0) { + *cb_data = disp_tab[curdisp].cb_data; + return (disp_tab[curdisp].callback); + } + } + } + + *cb_data = NULL; + return (NULL); +} + +int +/*ARGSUSED*/ +nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, + const char *method, const ns_src defaults[], ...) +{ + va_list ap; + int i, result; + const ns_src *srclist; + int srclistsize; + nss_method cb; + void *cb_data; + + /* retval may be NULL */ + /* disp_tab may be NULL */ + assert(database != NULL); + assert(method != NULL); + assert(defaults != NULL); + if (database == NULL || method == NULL || defaults == NULL) + return (NS_UNAVAIL); + + srclist = defaults; + srclistsize = 0; + while (srclist[srclistsize].name != NULL) + srclistsize++; + + result = 0; + + for (i = 0; i < srclistsize; i++) { + cb = _nsmethod(srclist[i].name, database, method, + disp_tab, &cb_data); + result = 0; + if (cb != NULL) { + va_start(ap, defaults); + result = (*cb)(retval, cb_data, ap); + va_end(ap); + if (defaults[0].flags & NS_FORCEALL) + continue; + if (result & srclist[i].flags) + break; + /* Stop trying next resolver when there is a memory space fatal error. */ + if ((result & NS_UNAVAIL) != 0 && errno == ENOSPC) { + break; + } + } + } + result &= NS_STATUSMASK; /* clear private flags in result */ + + return (result ? result : NS_NOTFOUND); +} diff --git a/aosp/bionic/libc/dns/net/services.h b/aosp/bionic/libc/dns/net/services.h new file mode 100644 index 000000000..7f748f79f --- /dev/null +++ b/aosp/bionic/libc/dns/net/services.h @@ -0,0 +1,549 @@ +/* generated by genserv.py - do not edit */ +static const char _services[] = "\ +\6tcpmux\0\1t\0\ +\4echo\0\7t\0\ +\4echo\0\7u\0\ +\7discard\0\11t\2\4sink\4null\ +\7discard\0\11u\2\4sink\4null\ +\6systat\0\13t\1\5users\ +\7daytime\0\15t\0\ +\7daytime\0\15u\0\ +\7netstat\0\17t\0\ +\4qotd\0\21t\1\5quote\ +\3msp\0\22t\0\ +\3msp\0\22u\0\ +\7chargen\0\23t\2\6ttytst\6source\ +\7chargen\0\23u\2\6ttytst\6source\ +\10ftp-data\0\24t\0\ +\3ftp\0\25t\0\ +\3fsp\0\25u\1\4fspd\ +\3ssh\0\26t\0\ +\3ssh\0\26u\0\ +\6telnet\0\27t\0\ +\4smtp\0\31t\1\4mail\ +\4time\0\45t\1\11timserver\ +\4time\0\45u\1\11timserver\ +\3rlp\0\47u\1\10resource\ +\12nameserver\0\52t\1\4name\ +\5whois\0\53t\1\7nicname\ +\6tacacs\0\61t\0\ +\6tacacs\0\61u\0\ +\12re-mail-ck\0\62t\0\ +\12re-mail-ck\0\62u\0\ +\6domain\0\65t\0\ +\6domain\0\65u\0\ +\3mtp\0\71t\0\ +\11tacacs-ds\0\101t\0\ +\11tacacs-ds\0\101u\0\ +\6bootps\0\103t\0\ +\6bootps\0\103u\0\ +\6bootpc\0\104t\0\ +\6bootpc\0\104u\0\ +\4tftp\0\105u\0\ +\6gopher\0\106t\0\ +\6gopher\0\106u\0\ +\3rje\0\115t\1\6netrjs\ +\6finger\0\117t\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\ +\6supdup\0\137t\0\ +\11hostnames\0\145t\1\10hostname\ +\10iso-tsap\0\146t\1\4tsap\ +\10acr-nema\0\150t\1\5dicom\ +\10acr-nema\0\150u\1\5dicom\ +\10csnet-ns\0\151t\1\6cso-ns\ +\10csnet-ns\0\151u\1\6cso-ns\ +\7rtelnet\0\153t\0\ +\7rtelnet\0\153u\0\ +\4pop2\0\155t\2\12postoffice\5pop-2\ +\4pop2\0\155u\1\5pop-2\ +\4pop3\0\156t\1\5pop-3\ +\4pop3\0\156u\1\5pop-3\ +\6sunrpc\0\157t\1\12portmapper\ +\6sunrpc\0\157u\1\12portmapper\ +\4auth\0\161t\3\16authentication\3tap\5ident\ +\4sftp\0\163t\0\ +\11uucp-path\0\165t\0\ +\4nntp\0\167t\2\10readnews\4untp\ +\3ntp\0\173t\0\ +\3ntp\0\173u\0\ +\6pwdgen\0\201t\0\ +\6pwdgen\0\201u\0\ +\7loc-srv\0\207t\1\5epmap\ +\7loc-srv\0\207u\1\5epmap\ +\12netbios-ns\0\211t\0\ +\12netbios-ns\0\211u\0\ +\13netbios-dgm\0\212t\0\ +\13netbios-dgm\0\212u\0\ +\13netbios-ssn\0\213t\0\ +\13netbios-ssn\0\213u\0\ +\5imap2\0\217t\1\4imap\ +\5imap2\0\217u\1\4imap\ +\4snmp\0\241t\0\ +\4snmp\0\241u\0\ +\11snmp-trap\0\242t\1\10snmptrap\ +\11snmp-trap\0\242u\1\10snmptrap\ +\10cmip-man\0\243t\0\ +\10cmip-man\0\243u\0\ +\12cmip-agent\0\244t\0\ +\12cmip-agent\0\244u\0\ +\5mailq\0\256t\0\ +\5mailq\0\256u\0\ +\5xdmcp\0\261t\0\ +\5xdmcp\0\261u\0\ +\10nextstep\0\262t\2\10NeXTStep\10NextStep\ +\10nextstep\0\262u\2\10NeXTStep\10NextStep\ +\3bgp\0\263t\0\ +\3bgp\0\263u\0\ +\10prospero\0\277t\0\ +\10prospero\0\277u\0\ +\3irc\0\302t\0\ +\3irc\0\302u\0\ +\4smux\0\307t\0\ +\4smux\0\307u\0\ +\7at-rtmp\0\311t\0\ +\7at-rtmp\0\311u\0\ +\6at-nbp\0\312t\0\ +\6at-nbp\0\312u\0\ +\7at-echo\0\314t\0\ +\7at-echo\0\314u\0\ +\6at-zis\0\316t\0\ +\6at-zis\0\316u\0\ +\4qmtp\0\321t\0\ +\4qmtp\0\321u\0\ +\5z3950\0\322t\1\4wais\ +\5z3950\0\322u\1\4wais\ +\3ipx\0\325t\0\ +\3ipx\0\325u\0\ +\5imap3\0\334t\0\ +\5imap3\0\334u\0\ +\7pawserv\1\131t\0\ +\7pawserv\1\131u\0\ +\5zserv\1\132t\0\ +\5zserv\1\132u\0\ +\7fatserv\1\133t\0\ +\7fatserv\1\133u\0\ +\13rpc2portmap\1\161t\0\ +\13rpc2portmap\1\161u\0\ +\11codaauth2\1\162t\0\ +\11codaauth2\1\162u\0\ +\11clearcase\1\163t\1\11Clearcase\ +\11clearcase\1\163u\1\11Clearcase\ +\11ulistserv\1\164t\0\ +\11ulistserv\1\164u\0\ +\4ldap\1\205t\0\ +\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\ +\6isakmp\1\364u\0\ +\4rtsp\2\52t\0\ +\4rtsp\2\52u\0\ +\3nqs\2\137t\0\ +\3nqs\2\137u\0\ +\12npmp-local\2\142t\1\16dqs313_qmaster\ +\12npmp-local\2\142u\1\16dqs313_qmaster\ +\10npmp-gui\2\143t\1\14dqs313_execd\ +\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\ +\4biff\2\0u\1\6comsat\ +\5login\2\1t\0\ +\3who\2\1u\1\4whod\ +\5shell\2\2t\1\3cmd\ +\6syslog\2\2u\0\ +\7printer\2\3t\1\7spooler\ +\4talk\2\5u\0\ +\5ntalk\2\6u\0\ +\5route\2\10u\2\6router\6routed\ +\5timed\2\15u\1\12timeserver\ +\5tempo\2\16t\1\7newdate\ +\7courier\2\22t\1\3rpc\ +\12conference\2\23t\1\4chat\ +\7netnews\2\24t\1\10readnews\ +\7netwall\2\25u\0\ +\6gdomap\2\32t\0\ +\6gdomap\2\32u\0\ +\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\ +\12submission\2\113t\0\ +\12submission\2\113u\0\ +\5ldaps\2\174t\0\ +\5ldaps\2\174u\0\ +\4tinc\2\217t\0\ +\4tinc\2\217u\0\ +\4silc\2\302t\0\ +\4silc\2\302u\0\ +\14kerberos-adm\2\355t\0\ +\7webster\2\375t\0\ +\7webster\2\375u\0\ +\5rsync\3\151t\0\ +\5rsync\3\151u\0\ +\11ftps-data\3\335t\0\ +\4ftps\3\336t\0\ +\7telnets\3\340t\0\ +\7telnets\3\340u\0\ +\5imaps\3\341t\0\ +\5imaps\3\341u\0\ +\4ircs\3\342t\0\ +\4ircs\3\342u\0\ +\5pop3s\3\343t\0\ +\5pop3s\3\343u\0\ +\5socks\4\70t\0\ +\5socks\4\70u\0\ +\6proofd\4\105t\0\ +\6proofd\4\105u\0\ +\5rootd\4\106t\0\ +\5rootd\4\106u\0\ +\7openvpn\4\252t\0\ +\7openvpn\4\252u\0\ +\13rmiregistry\4\113t\0\ +\13rmiregistry\4\113u\0\ +\5kazaa\4\276t\0\ +\5kazaa\4\276u\0\ +\6nessus\4\331t\0\ +\6nessus\4\331u\0\ +\11lotusnote\5\110t\1\12lotusnotes\ +\11lotusnote\5\110u\1\12lotusnotes\ +\10ms-sql-s\5\231t\0\ +\10ms-sql-s\5\231u\0\ +\10ms-sql-m\5\232t\0\ +\10ms-sql-m\5\232u\0\ +\12ingreslock\5\364t\0\ +\12ingreslock\5\364u\0\ +\13prospero-np\5\365t\0\ +\13prospero-np\5\365u\0\ +\13datametrics\6\155t\1\12old-radius\ +\13datametrics\6\155u\1\12old-radius\ +\13sa-msg-port\6\156t\1\13old-radacct\ +\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\ +\5venus\11\176u\0\ +\10venus-se\11\177t\0\ +\10venus-se\11\177u\0\ +\7codasrv\11\200t\0\ +\7codasrv\11\200u\0\ +\12codasrv-se\11\201t\0\ +\12codasrv-se\11\201u\0\ +\3mon\12\27t\0\ +\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\1\6gds_db\ +\6gds-db\13\352u\1\6gds_db\ +\5icpv2\14\72t\1\3icp\ +\5icpv2\14\72u\1\3icp\ +\5mysql\14\352t\0\ +\5mysql\14\352u\0\ +\3nut\15\245t\0\ +\3nut\15\245u\0\ +\6distcc\16\60t\0\ +\6distcc\16\60u\0\ +\4daap\16\151t\0\ +\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\ +\5x11-1\27\161u\0\ +\5x11-2\27\162t\0\ +\5x11-2\27\162u\0\ +\5x11-3\27\163t\0\ +\5x11-3\27\163u\0\ +\5x11-4\27\164t\0\ +\5x11-4\27\164u\0\ +\5x11-5\27\165t\0\ +\5x11-5\27\165u\0\ +\5x11-6\27\166t\0\ +\5x11-6\27\166u\0\ +\5x11-7\27\167t\0\ +\5x11-7\27\167u\0\ +\14gnutella-svc\30\312t\0\ +\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\ +\15afs3-callback\33\131u\0\ +\15afs3-prserver\33\132t\0\ +\15afs3-prserver\33\132u\0\ +\15afs3-vlserver\33\133t\0\ +\15afs3-vlserver\33\133u\0\ +\15afs3-kaserver\33\134t\0\ +\15afs3-kaserver\33\134u\0\ +\13afs3-volser\33\135t\0\ +\13afs3-volser\33\135u\0\ +\13afs3-errors\33\136t\0\ +\13afs3-errors\33\136u\0\ +\10afs3-bos\33\137t\0\ +\10afs3-bos\33\137u\0\ +\13afs3-update\33\140t\0\ +\13afs3-update\33\140u\0\ +\13afs3-rmtsys\33\141t\0\ +\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\ +\3hkp\54\153u\0\ +\4bprd\65\230t\0\ +\4bprd\65\230u\0\ +\5bpdbm\65\231t\0\ +\5bpdbm\65\231u\0\ +\13bpjava-msvc\65\232t\0\ +\13bpjava-msvc\65\232u\0\ +\5vnetd\65\234t\0\ +\5vnetd\65\234u\0\ +\4bpcd\65\326t\0\ +\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\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\ +\4swat\3\205t\0\ +\4kpop\4\125t\0\ +\5knetd\10\5t\0\ +\12zephyr-srv\10\66u\0\ +\12zephyr-clt\10\67u\0\ +\11zephyr-hm\10\70u\0\ +\7eklogin\10\71t\0\ +\2kx\10\77t\0\ +\5iprop\10\111t\0\ +\12supfilesrv\3\147t\0\ +\12supfiledbg\4\147t\0\ +\11linuxconf\0\142t\0\ +\10poppassd\0\152t\0\ +\10poppassd\0\152u\0\ +\5ssmtp\1\321t\1\5smtps\ +\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\ +\7customs\3\351t\0\ +\7customs\3\351u\0\ +\7skkserv\4\232t\0\ +\7predict\4\272u\0\ +\6rmtcfg\4\324t\0\ +\5wipld\5\24t\0\ +\4xtel\5\41t\0\ +\5xtelw\5\42t\0\ +\7support\5\371t\0\ +\7cfinger\7\323t\0\ +\4frox\10\111t\0\ +\10ninstall\10\146t\0\ +\10ninstall\10\146u\0\ +\10zebrasrv\12\50t\0\ +\5zebra\12\51t\0\ +\4ripd\12\52t\0\ +\6ripngd\12\53t\0\ +\5ospfd\12\54t\0\ +\4bgpd\12\55t\0\ +\6ospf6d\12\56t\0\ +\7ospfapi\12\57t\0\ +\5isisd\12\60t\0\ +\10afbackup\13\254t\0\ +\10afbackup\13\254u\0\ +\11afmbackup\13\255t\0\ +\11afmbackup\13\255u\0\ +\5xtell\20\200t\0\ +\3fax\21\315t\0\ +\7hylafax\21\317t\0\ +\7distmp3\21\370t\0\ +\5munin\23\125t\1\4lrrd\ +\13enbd-cstatd\23\273t\0\ +\13enbd-sstatd\23\274t\0\ +\4pcrd\24\37t\0\ +\6noclog\24\352t\0\ +\6noclog\24\352u\0\ +\7hostmon\24\353t\0\ +\7hostmon\24\353u\0\ +\5rplay\25\263u\0\ +\4nrpe\26\42t\0\ +\4nsca\26\43t\0\ +\4mrtd\26\52t\0\ +\6bgpsim\26\53t\0\ +\5canna\26\60t\0\ +\11sane-port\31\246t\2\4sane\5saned\ +\4ircd\32\13t\0\ +\10zope-ftp\37\125t\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\ +\11amidxtape\47\143t\0\ +\5smsqp\53\301t\0\ +\5smsqp\53\301u\0\ +\6xpilot\73\361t\0\ +\6xpilot\73\361u\0\ +\10sgi-cmsd\102\151u\0\ +\10sgi-crsd\102\152u\0\ +\7sgi-gcd\102\153u\0\ +\7sgi-cad\102\154t\0\ +\7isdnlog\116\53t\0\ +\7isdnlog\116\53u\0\ +\5vboxd\116\54t\0\ +\5vboxd\116\54u\0\ +\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\ +\0"; + diff --git a/aosp/bionic/libc/dns/net/sethostent.c b/aosp/bionic/libc/dns/net/sethostent.c new file mode 100644 index 000000000..a743a543e --- /dev/null +++ b/aosp/bionic/libc/dns/net/sethostent.c @@ -0,0 +1,285 @@ +/* $NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $ */ + +/* + * Copyright (c) 1985, 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 +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)sethostent.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp "; +#else +__RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hostent.h" +#include "resolv_private.h" + +#define ALIGNBYTES (sizeof(uintptr_t) - 1) +#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) + +#ifndef _REENTRANT +void res_close(void); +#endif + +static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *); + +void +/*ARGSUSED*/ +sethostent(int stayopen) +{ + res_static rs = __res_get_static(); + if (rs) sethostent_r(&rs->hostf); +} + +void +endhostent(void) +{ + res_static rs = __res_get_static(); + if (rs) endhostent_r(&rs->hostf); +} + +void +sethostent_r(FILE **hf) +{ + if (!*hf) + *hf = fopen(_PATH_HOSTS, "re"); + else + rewind(*hf); +} + +void +endhostent_r(FILE **hf) +{ + if (*hf) { + (void)fclose(*hf); + *hf = NULL; + } +} + +/*ARGSUSED*/ +int +_hf_gethtbyname(void *rv, void *cb_data, va_list ap) +{ + struct hostent *hp; + const char *name; + int af; + struct getnamaddr *info = rv; + + _DIAGASSERT(rv != NULL); + + name = va_arg(ap, char *); + /* NOSTRICT skip string len */(void)va_arg(ap, int); + af = va_arg(ap, int); + +#if 0 + { + res_state res = __res_get_state(); + if (res == NULL) + return NS_NOTFOUND; + if (res->options & RES_USE_INET6) + hp = _hf_gethtbyname2(name, AF_INET6, info); + else + hp = NULL; + if (hp == NULL) + hp = _hf_gethtbyname2(name, AF_INET, info); + __res_put_state(res); + } +#else + hp = _hf_gethtbyname2(name, af, info); +#endif + if (hp == NULL) { + if (*info->he == NETDB_INTERNAL && errno == ENOSPC) { + return NS_UNAVAIL; // glibc compatibility. + } + *info->he = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} + +struct hostent * +_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info) +{ + struct hostent *hp, hent; + char *buf, *ptr; + size_t len, anum, num, i; + FILE *hf; + char *aliases[MAXALIASES]; + char *addr_ptrs[MAXADDRS]; + + _DIAGASSERT(name != NULL); + + hf = NULL; + sethostent_r(&hf); + if (hf == NULL) { + errno = EINVAL; + *info->he = NETDB_INTERNAL; + return NULL; + } + + if ((ptr = buf = malloc(len = info->buflen)) == NULL) { + *info->he = NETDB_INTERNAL; + return NULL; + } + + anum = 0; /* XXX: gcc */ + hent.h_name = NULL; /* XXX: gcc */ + hent.h_addrtype = 0; /* XXX: gcc */ + hent.h_length = 0; /* XXX: gcc */ + + for (num = 0; num < MAXADDRS;) { + info->hp->h_addrtype = af; + info->hp->h_length = 0; + + hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, + info->he); + if (hp == NULL) { + if (*info->he == NETDB_INTERNAL && errno == ENOSPC) { + goto nospc; // glibc compatibility. + } + break; + } + + if (strcasecmp(hp->h_name, name) != 0) { + char **cp; + for (cp = hp->h_aliases; *cp != NULL; cp++) + if (strcasecmp(*cp, name) == 0) + break; + if (*cp == NULL) continue; + } + + if (num == 0) { + hent.h_addrtype = af = hp->h_addrtype; + hent.h_length = hp->h_length; + + HENT_SCOPY(hent.h_name, hp->h_name, ptr, len); + for (anum = 0; hp->h_aliases[anum]; anum++) { + if (anum >= MAXALIASES) + goto nospc; + HENT_SCOPY(aliases[anum], hp->h_aliases[anum], + ptr, len); + } + ptr = (void *)ALIGN(ptr); + if ((size_t)(ptr - buf) >= info->buflen) + goto nospc; + } + + if (num >= MAXADDRS) + goto nospc; + HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr, + len); + num++; + } + endhostent_r(&hf); + + if (num == 0) { + *info->he = HOST_NOT_FOUND; + free(buf); + return NULL; + } + + hp = info->hp; + ptr = info->buf; + len = info->buflen; + + hp->h_addrtype = hent.h_addrtype; + hp->h_length = hent.h_length; + + HENT_ARRAY(hp->h_aliases, anum, ptr, len); + HENT_ARRAY(hp->h_addr_list, num, ptr, len); + + for (i = 0; i < num; i++) + HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr, + len); + hp->h_addr_list[num] = NULL; + + HENT_SCOPY(hp->h_name, hent.h_name, ptr, len); + + for (i = 0; i < anum; i++) + HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len); + hp->h_aliases[anum] = NULL; + + free(buf); + return hp; +nospc: + *info->he = NETDB_INTERNAL; + free(buf); + errno = ENOSPC; + return NULL; +} + +/*ARGSUSED*/ +int +_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap) +{ + struct hostent *hp; + const unsigned char *addr; + struct getnamaddr *info = rv; + FILE *hf; + + _DIAGASSERT(rv != NULL); + + addr = va_arg(ap, unsigned char *); + info->hp->h_length = va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); + + hf = NULL; + sethostent_r(&hf); + if (hf == NULL) { + *info->he = NETDB_INTERNAL; + return NS_UNAVAIL; + } + while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, + info->he)) != NULL) + if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length)) + break; + endhostent_r(&hf); + + if (hp == NULL) { + if (errno == ENOSPC) return NS_UNAVAIL; // glibc compatibility. + *info->he = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} diff --git a/aosp/bionic/libc/dns/resolv/herror.c b/aosp/bionic/libc/dns/resolv/herror.c new file mode 100644 index 000000000..9aaf696b9 --- /dev/null +++ b/aosp/bionic/libc/dns/resolv/herror.c @@ -0,0 +1,133 @@ +/* $NetBSD: herror.c,v 1.4 2004/05/23 05:09:52 christos Exp $ */ + +/* + * Copyright (c) 1987, 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka Exp"; +#else +__RCSID("$NetBSD: herror.c,v 1.4 2004/05/23 05:09:52 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +#include +#include + +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include + +#ifndef DE_CONST +#define DE_CONST(c,v) v = ((c) ? \ + strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL) +#endif + +const char * const h_errlist[] = { + "Resolver Error 0 (no error)", + "Unknown host", /* 1 HOST_NOT_FOUND */ + "Host name lookup failure", /* 2 TRY_AGAIN */ + "Unknown server error", /* 3 NO_RECOVERY */ + "No address associated with name", /* 4 NO_ADDRESS */ +}; +const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; + +/* + * herror -- + * print the error indicated by the h_errno value. + */ +void +herror(const char *s) { + struct iovec iov[4], *v = iov; + char *t; + + if (s != NULL && *s != '\0') { + DE_CONST(s, t); + v->iov_base = t; + v->iov_len = strlen(t); + v++; + DE_CONST(": ", t); + v->iov_base = t; + v->iov_len = 2; + v++; + } + DE_CONST(hstrerror(h_errno), t); + v->iov_base = t; + v->iov_len = strlen(v->iov_base); + v++; + DE_CONST("\n", t); + v->iov_base = t; + v->iov_len = 1; + writev(STDERR_FILENO, iov, (v - iov) + 1); +} + +/* + * hstrerror -- + * return the string associated with a given "host" errno value. + */ +const char * +hstrerror(int err) { + if (err < 0) + return ("Resolver internal error"); + else if (err < h_nerr) + return (h_errlist[err]); + return ("Unknown resolver error"); +} diff --git a/aosp/bionic/libc/dns/resolv/res_cache.c b/aosp/bionic/libc/dns/resolv/res_cache.c new file mode 100644 index 000000000..f4c590f60 --- /dev/null +++ b/aosp/bionic/libc/dns/resolv/res_cache.c @@ -0,0 +1,2343 @@ +/* + * 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 "resolv_cache.h" + +#include +#include +#include +#include +#include +#include +#include "pthread.h" + +#include +#include +#include +#include +#include + +#include +#include "resolv_private.h" +#include "resolv_netid.h" +#include "res_private.h" + +#include + +/* This code implements a small and *simple* DNS resolver cache. + * + * It is only used to cache DNS answers for a time defined by the smallest TTL + * among the answer records in order to reduce DNS traffic. It is not supposed + * to be a full DNS cache, since we plan to implement that in the future in a + * dedicated process running on the system. + * + * Note that its design is kept simple very intentionally, i.e.: + * + * - it takes raw DNS query packet data as input, and returns raw DNS + * answer packet data as output + * + * (this means that two similar queries that encode the DNS name + * differently will be treated distinctly). + * + * the smallest TTL value among the answer records are used as the time + * to keep an answer in the cache. + * + * this is bad, but we absolutely want to avoid parsing the answer packets + * (and should be solved by the later full DNS cache process). + * + * - the implementation is just a (query-data) => (answer-data) hash table + * with a trivial least-recently-used expiration policy. + * + * Doing this keeps the code simple and avoids to deal with a lot of things + * that a full DNS cache is expected to do. + * + * The API is also very simple: + * + * - the client calls _resolv_cache_get() to obtain a handle to the cache. + * this will initialize the cache on first usage. the result can be NULL + * if the cache is disabled. + * + * - the client calls _resolv_cache_lookup() before performing a query + * + * if the function returns RESOLV_CACHE_FOUND, a copy of the answer data + * has been copied into the client-provided answer buffer. + * + * if the function returns RESOLV_CACHE_NOTFOUND, the client should perform + * a request normally, *then* call _resolv_cache_add() to add the received + * answer to the cache. + * + * if the function returns RESOLV_CACHE_UNSUPPORTED, the client should + * perform a request normally, and *not* call _resolv_cache_add() + * + * note that RESOLV_CACHE_UNSUPPORTED is also returned if the answer buffer + * is too short to accomodate the cached result. + */ + +/* default number of entries kept in the cache. This value has been + * determined by browsing through various sites and counting the number + * of corresponding requests. Keep in mind that our framework is currently + * performing two requests per name lookup (one for IPv4, the other for IPv6) + * + * www.google.com 4 + * www.ysearch.com 6 + * www.amazon.com 8 + * www.nytimes.com 22 + * www.espn.com 28 + * www.msn.com 28 + * www.lemonde.fr 35 + * + * (determined in 2009-2-17 from Paris, France, results may vary depending + * on location) + * + * most high-level websites use lots of media/ad servers with different names + * but these are generally reused when browsing through the site. + * + * As such, a value of 64 should be relatively comfortable at the moment. + * + * ****************************************** + * * NOTE - this has changed. + * * 1) we've added IPv6 support so each dns query results in 2 responses + * * 2) we've made this a system-wide cache, so the cost is less (it's not + * * duplicated in each process) and the need is greater (more processes + * * making different requests). + * * Upping by 2x for IPv6 + * * Upping by another 5x for the centralized nature + * ***************************************** + */ +#define CONFIG_MAX_ENTRIES 64 * 2 * 5 + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +/* set to 1 to debug cache operations */ +#define DEBUG 0 + +/* set to 1 to debug query data */ +#define DEBUG_DATA 0 + +#if DEBUG +#define __DEBUG__ +#else +#define __DEBUG__ __attribute__((unused)) +#endif + +#undef XLOG + +#define XLOG(...) ({ \ + if (DEBUG) { \ + async_safe_format_log(ANDROID_LOG_DEBUG,"libc",__VA_ARGS__); \ + } else { \ + ((void)0); \ + } \ +}) + +/** BOUNDED BUFFER FORMATTING + **/ + +/* technical note: + * + * the following debugging routines are used to append data to a bounded + * buffer they take two parameters that are: + * + * - p : a pointer to the current cursor position in the buffer + * this value is initially set to the buffer's address. + * + * - end : the address of the buffer's limit, i.e. of the first byte + * after the buffer. this address should never be touched. + * + * IMPORTANT: it is assumed that end > buffer_address, i.e. + * that the buffer is at least one byte. + * + * the _bprint_() functions return the new value of 'p' after the data + * has been appended, and also ensure the following: + * + * - the returned value will never be strictly greater than 'end' + * + * - a return value equal to 'end' means that truncation occured + * (in which case, end[-1] will be set to 0) + * + * - after returning from a _bprint_() function, the content of the buffer + * is always 0-terminated, even in the event of truncation. + * + * these conventions allow you to call _bprint_ functions multiple times and + * only check for truncation at the end of the sequence, as in: + * + * char buff[1000], *p = buff, *end = p + sizeof(buff); + * + * p = _bprint_c(p, end, '"'); + * p = _bprint_s(p, end, my_string); + * p = _bprint_c(p, end, '"'); + * + * if (p >= end) { + * // buffer was too small + * } + * + * printf( "%s", buff ); + */ + +/* add a char to a bounded buffer */ +char* +_bprint_c( char* p, char* end, int c ) +{ + if (p < end) { + if (p+1 == end) + *p++ = 0; + else { + *p++ = (char) c; + *p = 0; + } + } + return p; +} + +/* add a sequence of bytes to a bounded buffer */ +char* +_bprint_b( char* p, char* end, const char* buf, int len ) +{ + int avail = end - p; + + if (avail <= 0 || len <= 0) + return p; + + if (avail > len) + avail = len; + + memcpy( p, buf, avail ); + p += avail; + + if (p < end) + p[0] = 0; + else + end[-1] = 0; + + return p; +} + +/* add a string to a bounded buffer */ +char* +_bprint_s( char* p, char* end, const char* str ) +{ + return _bprint_b(p, end, str, strlen(str)); +} + +/* add a formatted string to a bounded buffer */ +char* _bprint( char* p, char* end, const char* format, ... ) __DEBUG__; +char* _bprint( char* p, char* end, const char* format, ... ) +{ + int avail, n; + va_list args; + + avail = end - p; + + if (avail <= 0) + return p; + + va_start(args, format); + n = vsnprintf( p, avail, format, args); + va_end(args); + + /* certain C libraries return -1 in case of truncation */ + if (n < 0 || n > avail) + n = avail; + + p += n; + /* certain C libraries do not zero-terminate in case of truncation */ + if (p == end) + p[-1] = 0; + + return p; +} + +/* add a hex value to a bounded buffer, up to 8 digits */ +char* +_bprint_hex( char* p, char* end, unsigned value, int numDigits ) +{ + char text[sizeof(unsigned)*2]; + int nn = 0; + + while (numDigits-- > 0) { + text[nn++] = "0123456789abcdef"[(value >> (numDigits*4)) & 15]; + } + return _bprint_b(p, end, text, nn); +} + +/* add the hexadecimal dump of some memory area to a bounded buffer */ +char* +_bprint_hexdump( char* p, char* end, const uint8_t* data, int datalen ) +{ + int lineSize = 16; + + while (datalen > 0) { + int avail = datalen; + int nn; + + if (avail > lineSize) + avail = lineSize; + + for (nn = 0; nn < avail; nn++) { + if (nn > 0) + p = _bprint_c(p, end, ' '); + p = _bprint_hex(p, end, data[nn], 2); + } + for ( ; nn < lineSize; nn++ ) { + p = _bprint_s(p, end, " "); + } + p = _bprint_s(p, end, " "); + + for (nn = 0; nn < avail; nn++) { + int c = data[nn]; + + if (c < 32 || c > 127) + c = '.'; + + p = _bprint_c(p, end, c); + } + p = _bprint_c(p, end, '\n'); + + data += avail; + datalen -= avail; + } + return p; +} + +/* dump the content of a query of packet to the log */ +void XLOG_BYTES( const void* base, int len ) __DEBUG__; +void XLOG_BYTES( const void* base, int len ) +{ + if (DEBUG_DATA) { + char buff[1024]; + char* p = buff, *end = p + sizeof(buff); + + p = _bprint_hexdump(p, end, base, len); + XLOG("%s",buff); + } +} __DEBUG__ + +static time_t +_time_now( void ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + return tv.tv_sec; +} + +/* reminder: the general format of a DNS packet is the following: + * + * HEADER (12 bytes) + * QUESTION (variable) + * ANSWER (variable) + * AUTHORITY (variable) + * ADDITIONNAL (variable) + * + * the HEADER is made of: + * + * ID : 16 : 16-bit unique query identification field + * + * QR : 1 : set to 0 for queries, and 1 for responses + * Opcode : 4 : set to 0 for queries + * AA : 1 : set to 0 for queries + * TC : 1 : truncation flag, will be set to 0 in queries + * RD : 1 : recursion desired + * + * RA : 1 : recursion available (0 in queries) + * Z : 3 : three reserved zero bits + * RCODE : 4 : response code (always 0=NOERROR in queries) + * + * QDCount: 16 : question count + * ANCount: 16 : Answer count (0 in queries) + * NSCount: 16: Authority Record count (0 in queries) + * ARCount: 16: Additionnal Record count (0 in queries) + * + * the QUESTION is made of QDCount Question Record (QRs) + * the ANSWER is made of ANCount RRs + * the AUTHORITY is made of NSCount RRs + * the ADDITIONNAL is made of ARCount RRs + * + * Each Question Record (QR) is made of: + * + * QNAME : variable : Query DNS NAME + * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255) + * CLASS : 16 : class of query (IN=1) + * + * Each Resource Record (RR) is made of: + * + * NAME : variable : DNS NAME + * TYPE : 16 : type of query (A=1, PTR=12, MX=15, AAAA=28, ALL=255) + * CLASS : 16 : class of query (IN=1) + * TTL : 32 : seconds to cache this RR (0=none) + * RDLENGTH: 16 : size of RDDATA in bytes + * RDDATA : variable : RR data (depends on TYPE) + * + * Each QNAME contains a domain name encoded as a sequence of 'labels' + * terminated by a zero. Each label has the following format: + * + * LEN : 8 : lenght of label (MUST be < 64) + * NAME : 8*LEN : label length (must exclude dots) + * + * A value of 0 in the encoding is interpreted as the 'root' domain and + * terminates the encoding. So 'www.android.com' will be encoded as: + * + * <3>www<7>android<3>com<0> + * + * Where represents the byte with value 'n' + * + * Each NAME reflects the QNAME of the question, but has a slightly more + * complex encoding in order to provide message compression. This is achieved + * by using a 2-byte pointer, with format: + * + * TYPE : 2 : 0b11 to indicate a pointer, 0b01 and 0b10 are reserved + * OFFSET : 14 : offset to another part of the DNS packet + * + * The offset is relative to the start of the DNS packet and must point + * A pointer terminates the encoding. + * + * The NAME can be encoded in one of the following formats: + * + * - a sequence of simple labels terminated by 0 (like QNAMEs) + * - a single pointer + * - a sequence of simple labels terminated by a pointer + * + * A pointer shall always point to either a pointer of a sequence of + * labels (which can themselves be terminated by either a 0 or a pointer) + * + * The expanded length of a given domain name should not exceed 255 bytes. + * + * NOTE: we don't parse the answer packets, so don't need to deal with NAME + * records, only QNAMEs. + */ + +#define DNS_HEADER_SIZE 12 + +#define DNS_TYPE_A "\00\01" /* big-endian decimal 1 */ +#define DNS_TYPE_PTR "\00\014" /* big-endian decimal 12 */ +#define DNS_TYPE_MX "\00\017" /* big-endian decimal 15 */ +#define DNS_TYPE_AAAA "\00\034" /* big-endian decimal 28 */ +#define DNS_TYPE_ALL "\00\0377" /* big-endian decimal 255 */ + +#define DNS_CLASS_IN "\00\01" /* big-endian decimal 1 */ + +typedef struct { + const uint8_t* base; + const uint8_t* end; + const uint8_t* cursor; +} DnsPacket; + +static void +_dnsPacket_init( DnsPacket* packet, const uint8_t* buff, int bufflen ) +{ + packet->base = buff; + packet->end = buff + bufflen; + packet->cursor = buff; +} + +static void +_dnsPacket_rewind( DnsPacket* packet ) +{ + packet->cursor = packet->base; +} + +static void +_dnsPacket_skip( DnsPacket* packet, int count ) +{ + const uint8_t* p = packet->cursor + count; + + if (p > packet->end) + p = packet->end; + + packet->cursor = p; +} + +static int +_dnsPacket_readInt16( DnsPacket* packet ) +{ + const uint8_t* p = packet->cursor; + + if (p+2 > packet->end) + return -1; + + packet->cursor = p+2; + return (p[0]<< 8) | p[1]; +} + +/** QUERY CHECKING + **/ + +/* check bytes in a dns packet. returns 1 on success, 0 on failure. + * the cursor is only advanced in the case of success + */ +static int +_dnsPacket_checkBytes( DnsPacket* packet, int numBytes, const void* bytes ) +{ + const uint8_t* p = packet->cursor; + + if (p + numBytes > packet->end) + return 0; + + if (memcmp(p, bytes, numBytes) != 0) + return 0; + + packet->cursor = p + numBytes; + return 1; +} + +/* parse and skip a given QNAME stored in a query packet, + * from the current cursor position. returns 1 on success, + * or 0 for malformed data. + */ +static int +_dnsPacket_checkQName( DnsPacket* packet ) +{ + const uint8_t* p = packet->cursor; + const uint8_t* end = packet->end; + + for (;;) { + int c; + + if (p >= end) + break; + + c = *p++; + + if (c == 0) { + packet->cursor = p; + return 1; + } + + /* we don't expect label compression in QNAMEs */ + if (c >= 64) + break; + + p += c; + /* we rely on the bound check at the start + * of the loop here */ + } + /* malformed data */ + XLOG("malformed QNAME"); + return 0; +} + +/* parse and skip a given QR stored in a packet. + * returns 1 on success, and 0 on failure + */ +static int +_dnsPacket_checkQR( DnsPacket* packet ) +{ + if (!_dnsPacket_checkQName(packet)) + return 0; + + /* TYPE must be one of the things we support */ + if (!_dnsPacket_checkBytes(packet, 2, DNS_TYPE_A) && + !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_PTR) && + !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_MX) && + !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_AAAA) && + !_dnsPacket_checkBytes(packet, 2, DNS_TYPE_ALL)) + { + XLOG("unsupported TYPE"); + return 0; + } + /* CLASS must be IN */ + if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN)) { + XLOG("unsupported CLASS"); + return 0; + } + + return 1; +} + +/* check the header of a DNS Query packet, return 1 if it is one + * type of query we can cache, or 0 otherwise + */ +static int +_dnsPacket_checkQuery( DnsPacket* packet ) +{ + const uint8_t* p = packet->base; + int qdCount, anCount, dnCount, arCount; + + if (p + DNS_HEADER_SIZE > packet->end) { + XLOG("query packet too small"); + return 0; + } + + /* QR must be set to 0, opcode must be 0 and AA must be 0 */ + /* RA, Z, and RCODE must be 0 */ + if ((p[2] & 0xFC) != 0 || (p[3] & 0xCF) != 0) { + XLOG("query packet flags unsupported"); + return 0; + } + + /* Note that we ignore the TC, RD, CD, and AD bits here for the + * following reasons: + * + * - there is no point for a query packet sent to a server + * to have the TC bit set, but the implementation might + * set the bit in the query buffer for its own needs + * between a _resolv_cache_lookup and a + * _resolv_cache_add. We should not freak out if this + * is the case. + * + * - we consider that the result from a query might depend on + * the RD, AD, and CD bits, so these bits + * should be used to differentiate cached result. + * + * this implies that these bits are checked when hashing or + * comparing query packets, but not TC + */ + + /* ANCOUNT, DNCOUNT and ARCOUNT must be 0 */ + qdCount = (p[4] << 8) | p[5]; + anCount = (p[6] << 8) | p[7]; + dnCount = (p[8] << 8) | p[9]; + arCount = (p[10]<< 8) | p[11]; + + if (anCount != 0 || dnCount != 0 || arCount > 1) { + XLOG("query packet contains non-query records"); + return 0; + } + + if (qdCount == 0) { + XLOG("query packet doesn't contain query record"); + return 0; + } + + /* Check QDCOUNT QRs */ + packet->cursor = p + DNS_HEADER_SIZE; + + for (;qdCount > 0; qdCount--) + if (!_dnsPacket_checkQR(packet)) + return 0; + + return 1; +} + +/** QUERY DEBUGGING + **/ +#if DEBUG +static char* +_dnsPacket_bprintQName(DnsPacket* packet, char* bp, char* bend) +{ + const uint8_t* p = packet->cursor; + const uint8_t* end = packet->end; + int first = 1; + + for (;;) { + int c; + + if (p >= end) + break; + + c = *p++; + + if (c == 0) { + packet->cursor = p; + return bp; + } + + /* we don't expect label compression in QNAMEs */ + if (c >= 64) + break; + + if (first) + first = 0; + else + bp = _bprint_c(bp, bend, '.'); + + bp = _bprint_b(bp, bend, (const char*)p, c); + + p += c; + /* we rely on the bound check at the start + * of the loop here */ + } + /* malformed data */ + bp = _bprint_s(bp, bend, ""); + return bp; +} + +static char* +_dnsPacket_bprintQR(DnsPacket* packet, char* p, char* end) +{ +#define QQ(x) { DNS_TYPE_##x, #x } + static const struct { + const char* typeBytes; + const char* typeString; + } qTypes[] = + { + QQ(A), QQ(PTR), QQ(MX), QQ(AAAA), QQ(ALL), + { NULL, NULL } + }; + int nn; + const char* typeString = NULL; + + /* dump QNAME */ + p = _dnsPacket_bprintQName(packet, p, end); + + /* dump TYPE */ + p = _bprint_s(p, end, " ("); + + for (nn = 0; qTypes[nn].typeBytes != NULL; nn++) { + if (_dnsPacket_checkBytes(packet, 2, qTypes[nn].typeBytes)) { + typeString = qTypes[nn].typeString; + break; + } + } + + if (typeString != NULL) + p = _bprint_s(p, end, typeString); + else { + int typeCode = _dnsPacket_readInt16(packet); + p = _bprint(p, end, "UNKNOWN-%d", typeCode); + } + + p = _bprint_c(p, end, ')'); + + /* skip CLASS */ + _dnsPacket_skip(packet, 2); + return p; +} + +/* this function assumes the packet has already been checked */ +static char* +_dnsPacket_bprintQuery( DnsPacket* packet, char* p, char* end ) +{ + int qdCount; + + if (packet->base[2] & 0x1) { + p = _bprint_s(p, end, "RECURSIVE "); + } + + _dnsPacket_skip(packet, 4); + qdCount = _dnsPacket_readInt16(packet); + _dnsPacket_skip(packet, 6); + + for ( ; qdCount > 0; qdCount-- ) { + p = _dnsPacket_bprintQR(packet, p, end); + } + return p; +} +#endif + + +/** QUERY HASHING SUPPORT + ** + ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKET HAS ALREADY + ** BEEN SUCCESFULLY CHECKED. + **/ + +/* use 32-bit FNV hash function */ +#define FNV_MULT 16777619U +#define FNV_BASIS 2166136261U + +static unsigned +_dnsPacket_hashBytes( DnsPacket* packet, int numBytes, unsigned hash ) +{ + const uint8_t* p = packet->cursor; + const uint8_t* end = packet->end; + + while (numBytes > 0 && p < end) { + hash = hash*FNV_MULT ^ *p++; + } + packet->cursor = p; + return hash; +} + + +static unsigned +_dnsPacket_hashQName( DnsPacket* packet, unsigned hash ) +{ + const uint8_t* p = packet->cursor; + const uint8_t* end = packet->end; + + for (;;) { + int c; + + if (p >= end) { /* should not happen */ + XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__); + break; + } + + c = *p++; + + if (c == 0) + break; + + if (c >= 64) { + XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__); + break; + } + if (p + c >= end) { + XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n", + __FUNCTION__); + break; + } + while (c > 0) { + hash = hash*FNV_MULT ^ *p++; + c -= 1; + } + } + packet->cursor = p; + return hash; +} + +static unsigned +_dnsPacket_hashQR( DnsPacket* packet, unsigned hash ) +{ + hash = _dnsPacket_hashQName(packet, hash); + hash = _dnsPacket_hashBytes(packet, 4, hash); /* TYPE and CLASS */ + return hash; +} + +static unsigned +_dnsPacket_hashRR( DnsPacket* packet, unsigned hash ) +{ + int rdlength; + hash = _dnsPacket_hashQR(packet, hash); + hash = _dnsPacket_hashBytes(packet, 4, hash); /* TTL */ + rdlength = _dnsPacket_readInt16(packet); + hash = _dnsPacket_hashBytes(packet, rdlength, hash); /* RDATA */ + return hash; +} + +static unsigned +_dnsPacket_hashQuery( DnsPacket* packet ) +{ + unsigned hash = FNV_BASIS; + int count, arcount; + _dnsPacket_rewind(packet); + + /* ignore the ID */ + _dnsPacket_skip(packet, 2); + + /* we ignore the TC bit for reasons explained in + * _dnsPacket_checkQuery(). + * + * however we hash the RD bit to differentiate + * between answers for recursive and non-recursive + * queries. + */ + hash = hash*FNV_MULT ^ (packet->base[2] & 1); + + /* mark the first header byte as processed */ + _dnsPacket_skip(packet, 1); + + /* process the second header byte */ + hash = _dnsPacket_hashBytes(packet, 1, hash); + + /* read QDCOUNT */ + count = _dnsPacket_readInt16(packet); + + /* assume: ANcount and NScount are 0 */ + _dnsPacket_skip(packet, 4); + + /* read ARCOUNT */ + arcount = _dnsPacket_readInt16(packet); + + /* hash QDCOUNT QRs */ + for ( ; count > 0; count-- ) + hash = _dnsPacket_hashQR(packet, hash); + + /* hash ARCOUNT RRs */ + for ( ; arcount > 0; arcount-- ) + hash = _dnsPacket_hashRR(packet, hash); + + return hash; +} + + +/** QUERY COMPARISON + ** + ** THE FOLLOWING CODE ASSUMES THAT THE INPUT PACKETS HAVE ALREADY + ** BEEN SUCCESFULLY CHECKED. + **/ + +static int +_dnsPacket_isEqualDomainName( DnsPacket* pack1, DnsPacket* pack2 ) +{ + const uint8_t* p1 = pack1->cursor; + const uint8_t* end1 = pack1->end; + const uint8_t* p2 = pack2->cursor; + const uint8_t* end2 = pack2->end; + + for (;;) { + int c1, c2; + + if (p1 >= end1 || p2 >= end2) { + XLOG("%s: INTERNAL_ERROR: read-overflow !!\n", __FUNCTION__); + break; + } + c1 = *p1++; + c2 = *p2++; + if (c1 != c2) + break; + + if (c1 == 0) { + pack1->cursor = p1; + pack2->cursor = p2; + return 1; + } + if (c1 >= 64) { + XLOG("%s: INTERNAL_ERROR: malformed domain !!\n", __FUNCTION__); + break; + } + if ((p1+c1 > end1) || (p2+c1 > end2)) { + XLOG("%s: INTERNAL_ERROR: simple label read-overflow !!\n", + __FUNCTION__); + break; + } + if (memcmp(p1, p2, c1) != 0) + break; + p1 += c1; + p2 += c1; + /* we rely on the bound checks at the start of the loop */ + } + /* not the same, or one is malformed */ + XLOG("different DN"); + return 0; +} + +static int +_dnsPacket_isEqualBytes( DnsPacket* pack1, DnsPacket* pack2, int numBytes ) +{ + const uint8_t* p1 = pack1->cursor; + const uint8_t* p2 = pack2->cursor; + + if ( p1 + numBytes > pack1->end || p2 + numBytes > pack2->end ) + return 0; + + if ( memcmp(p1, p2, numBytes) != 0 ) + return 0; + + pack1->cursor += numBytes; + pack2->cursor += numBytes; + return 1; +} + +static int +_dnsPacket_isEqualQR( DnsPacket* pack1, DnsPacket* pack2 ) +{ + /* compare domain name encoding + TYPE + CLASS */ + if ( !_dnsPacket_isEqualDomainName(pack1, pack2) || + !_dnsPacket_isEqualBytes(pack1, pack2, 2+2) ) + return 0; + + return 1; +} + +static int +_dnsPacket_isEqualRR( DnsPacket* pack1, DnsPacket* pack2 ) +{ + int rdlength1, rdlength2; + /* compare query + TTL */ + if ( !_dnsPacket_isEqualQR(pack1, pack2) || + !_dnsPacket_isEqualBytes(pack1, pack2, 4) ) + return 0; + + /* compare RDATA */ + rdlength1 = _dnsPacket_readInt16(pack1); + rdlength2 = _dnsPacket_readInt16(pack2); + if ( rdlength1 != rdlength2 || + !_dnsPacket_isEqualBytes(pack1, pack2, rdlength1) ) + return 0; + + return 1; +} + +static int +_dnsPacket_isEqualQuery( DnsPacket* pack1, DnsPacket* pack2 ) +{ + int count1, count2, arcount1, arcount2; + + /* compare the headers, ignore most fields */ + _dnsPacket_rewind(pack1); + _dnsPacket_rewind(pack2); + + /* compare RD, ignore TC, see comment in _dnsPacket_checkQuery */ + if ((pack1->base[2] & 1) != (pack2->base[2] & 1)) { + XLOG("different RD"); + return 0; + } + + if (pack1->base[3] != pack2->base[3]) { + XLOG("different CD or AD"); + return 0; + } + + /* mark ID and header bytes as compared */ + _dnsPacket_skip(pack1, 4); + _dnsPacket_skip(pack2, 4); + + /* compare QDCOUNT */ + count1 = _dnsPacket_readInt16(pack1); + count2 = _dnsPacket_readInt16(pack2); + if (count1 != count2 || count1 < 0) { + XLOG("different QDCOUNT"); + return 0; + } + + /* assume: ANcount and NScount are 0 */ + _dnsPacket_skip(pack1, 4); + _dnsPacket_skip(pack2, 4); + + /* compare ARCOUNT */ + arcount1 = _dnsPacket_readInt16(pack1); + arcount2 = _dnsPacket_readInt16(pack2); + if (arcount1 != arcount2 || arcount1 < 0) { + XLOG("different ARCOUNT"); + return 0; + } + + /* compare the QDCOUNT QRs */ + for ( ; count1 > 0; count1-- ) { + if (!_dnsPacket_isEqualQR(pack1, pack2)) { + XLOG("different QR"); + return 0; + } + } + + /* compare the ARCOUNT RRs */ + for ( ; arcount1 > 0; arcount1-- ) { + if (!_dnsPacket_isEqualRR(pack1, pack2)) { + XLOG("different additional RR"); + return 0; + } + } + return 1; +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +/* cache entry. for simplicity, 'hash' and 'hlink' are inlined in this + * structure though they are conceptually part of the hash table. + * + * similarly, mru_next and mru_prev are part of the global MRU list + */ +typedef struct Entry { + unsigned int hash; /* hash value */ + struct Entry* hlink; /* next in collision chain */ + struct Entry* mru_prev; + struct Entry* mru_next; + + const uint8_t* query; + int querylen; + const uint8_t* answer; + int answerlen; + time_t expires; /* time_t when the entry isn't valid any more */ + int id; /* for debugging purpose */ +} Entry; + +/** + * Find the TTL for a negative DNS result. This is defined as the minimum + * of the SOA records TTL and the MINIMUM-TTL field (RFC-2308). + * + * Return 0 if not found. + */ +static u_long +answer_getNegativeTTL(ns_msg handle) { + int n, nscount; + u_long result = 0; + ns_rr rr; + + nscount = ns_msg_count(handle, ns_s_ns); + for (n = 0; n < nscount; n++) { + if ((ns_parserr(&handle, ns_s_ns, n, &rr) == 0) && (ns_rr_type(rr) == ns_t_soa)) { + const u_char *rdata = ns_rr_rdata(rr); // find the data + const u_char *edata = rdata + ns_rr_rdlen(rr); // add the len to find the end + int len; + u_long ttl, rec_result = ns_rr_ttl(rr); + + // find the MINIMUM-TTL field from the blob of binary data for this record + // skip the server name + len = dn_skipname(rdata, edata); + if (len == -1) continue; // error skipping + rdata += len; + + // skip the admin name + len = dn_skipname(rdata, edata); + if (len == -1) continue; // error skipping + rdata += len; + + if (edata - rdata != 5*NS_INT32SZ) continue; + // skip: serial number + refresh interval + retry interval + expiry + rdata += NS_INT32SZ * 4; + // finally read the MINIMUM TTL + ttl = ns_get32(rdata); + if (ttl < rec_result) { + rec_result = ttl; + } + // Now that the record is read successfully, apply the new min TTL + if (n == 0 || rec_result < result) { + result = rec_result; + } + } + } + return result; +} + +/** + * Parse the answer records and find the appropriate + * smallest TTL among the records. This might be from + * the answer records if found or from the SOA record + * if it's a negative result. + * + * The returned TTL is the number of seconds to + * keep the answer in the cache. + * + * In case of parse error zero (0) is returned which + * indicates that the answer shall not be cached. + */ +static u_long +answer_getTTL(const void* answer, int answerlen) +{ + ns_msg handle; + int ancount, n; + u_long result, ttl; + ns_rr rr; + + result = 0; + if (ns_initparse(answer, answerlen, &handle) >= 0) { + // get number of answer records + ancount = ns_msg_count(handle, ns_s_an); + + if (ancount == 0) { + // a response with no answers? Cache this negative result. + result = answer_getNegativeTTL(handle); + } else { + for (n = 0; n < ancount; n++) { + if (ns_parserr(&handle, ns_s_an, n, &rr) == 0) { + ttl = ns_rr_ttl(rr); + if (n == 0 || ttl < result) { + result = ttl; + } + } else { + XLOG("ns_parserr failed ancount no = %d. errno = %s\n", n, strerror(errno)); + } + } + } + } else { + XLOG("ns_parserr failed. %s\n", strerror(errno)); + } + + XLOG("TTL = %lu\n", result); + + return result; +} + +static void +entry_free( Entry* e ) +{ + /* everything is allocated in a single memory block */ + if (e) { + free(e); + } +} + +static __inline__ void +entry_mru_remove( Entry* e ) +{ + e->mru_prev->mru_next = e->mru_next; + e->mru_next->mru_prev = e->mru_prev; +} + +static __inline__ void +entry_mru_add( Entry* e, Entry* list ) +{ + Entry* first = list->mru_next; + + e->mru_next = first; + e->mru_prev = list; + + list->mru_next = e; + first->mru_prev = e; +} + +/* compute the hash of a given entry, this is a hash of most + * data in the query (key) */ +static unsigned +entry_hash( const Entry* e ) +{ + DnsPacket pack[1]; + + _dnsPacket_init(pack, e->query, e->querylen); + return _dnsPacket_hashQuery(pack); +} + +/* initialize an Entry as a search key, this also checks the input query packet + * returns 1 on success, or 0 in case of unsupported/malformed data */ +static int +entry_init_key( Entry* e, const void* query, int querylen ) +{ + DnsPacket pack[1]; + + memset(e, 0, sizeof(*e)); + + e->query = query; + e->querylen = querylen; + e->hash = entry_hash(e); + + _dnsPacket_init(pack, query, querylen); + + return _dnsPacket_checkQuery(pack); +} + +/* allocate a new entry as a cache node */ +static Entry* +entry_alloc( const Entry* init, const void* answer, int answerlen ) +{ + Entry* e; + int size; + + size = sizeof(*e) + init->querylen + answerlen; + e = calloc(size, 1); + if (e == NULL) + return e; + + e->hash = init->hash; + e->query = (const uint8_t*)(e+1); + e->querylen = init->querylen; + + memcpy( (char*)e->query, init->query, e->querylen ); + + e->answer = e->query + e->querylen; + e->answerlen = answerlen; + + memcpy( (char*)e->answer, answer, e->answerlen ); + + return e; +} + +static int +entry_equals( const Entry* e1, const Entry* e2 ) +{ + DnsPacket pack1[1], pack2[1]; + + if (e1->querylen != e2->querylen) { + return 0; + } + _dnsPacket_init(pack1, e1->query, e1->querylen); + _dnsPacket_init(pack2, e2->query, e2->querylen); + + return _dnsPacket_isEqualQuery(pack1, pack2); +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +/* We use a simple hash table with external collision lists + * for simplicity, the hash-table fields 'hash' and 'hlink' are + * inlined in the Entry structure. + */ + +/* Maximum time for a thread to wait for an pending request */ +#define PENDING_REQUEST_TIMEOUT 20; + +typedef struct pending_req_info { + unsigned int hash; + pthread_cond_t cond; + struct pending_req_info* next; +} PendingReqInfo; + +typedef struct resolv_cache { + int max_entries; + int num_entries; + Entry mru_list; + int last_id; + Entry* entries; + PendingReqInfo pending_requests; +} Cache; + +struct resolv_cache_info { + unsigned netid; + Cache* cache; + struct resolv_cache_info* next; + int nscount; + char* nameservers[MAXNS]; + struct addrinfo* nsaddrinfo[MAXNS]; + int revision_id; // # times the nameservers have been replaced + struct __res_params params; + struct __res_stats nsstats[MAXNS]; + char defdname[MAXDNSRCHPATH]; + int dnsrch_offset[MAXDNSRCH+1]; // offsets into defdname +}; + +#define HTABLE_VALID(x) ((x) != NULL && (x) != HTABLE_DELETED) + +static pthread_once_t _res_cache_once = PTHREAD_ONCE_INIT; +static void _res_cache_init(void); + +// lock protecting everything in the _resolve_cache_info structs (next ptr, etc) +static pthread_mutex_t _res_cache_list_lock; + +/* gets cache associated with a network, or NULL if none exists */ +static struct resolv_cache* _find_named_cache_locked(unsigned netid); + +static void +_cache_flush_pending_requests_locked( struct resolv_cache* cache ) +{ + struct pending_req_info *ri, *tmp; + if (cache) { + ri = cache->pending_requests.next; + + while (ri) { + tmp = ri; + ri = ri->next; + pthread_cond_broadcast(&tmp->cond); + + pthread_cond_destroy(&tmp->cond); + free(tmp); + } + + cache->pending_requests.next = NULL; + } +} + +/* Return 0 if no pending request is found matching the key. + * If a matching request is found the calling thread will wait until + * the matching request completes, then update *cache and return 1. */ +static int +_cache_check_pending_request_locked( struct resolv_cache** cache, Entry* key, unsigned netid ) +{ + struct pending_req_info *ri, *prev; + int exist = 0; + + if (*cache && key) { + ri = (*cache)->pending_requests.next; + prev = &(*cache)->pending_requests; + while (ri) { + if (ri->hash == key->hash) { + exist = 1; + break; + } + prev = ri; + ri = ri->next; + } + + if (!exist) { + ri = calloc(1, sizeof(struct pending_req_info)); + if (ri) { + ri->hash = key->hash; + pthread_cond_init(&ri->cond, NULL); + prev->next = ri; + } + } else { + struct timespec ts = {0,0}; + XLOG("Waiting for previous request"); + ts.tv_sec = _time_now() + PENDING_REQUEST_TIMEOUT; + pthread_cond_timedwait(&ri->cond, &_res_cache_list_lock, &ts); + /* Must update *cache as it could have been deleted. */ + *cache = _find_named_cache_locked(netid); + } + } + + return exist; +} + +/* notify any waiting thread that waiting on a request + * matching the key has been added to the cache */ +static void +_cache_notify_waiting_tid_locked( struct resolv_cache* cache, Entry* key ) +{ + struct pending_req_info *ri, *prev; + + if (cache && key) { + ri = cache->pending_requests.next; + prev = &cache->pending_requests; + while (ri) { + if (ri->hash == key->hash) { + pthread_cond_broadcast(&ri->cond); + break; + } + prev = ri; + ri = ri->next; + } + + // remove item from list and destroy + if (ri) { + prev->next = ri->next; + pthread_cond_destroy(&ri->cond); + free(ri); + } + } +} + +/* notify the cache that the query failed */ +void +_resolv_cache_query_failed( unsigned netid, + const void* query, + int querylen) +{ + Entry key[1]; + Cache* cache; + + if (!entry_init_key(key, query, querylen)) + return; + + pthread_mutex_lock(&_res_cache_list_lock); + + cache = _find_named_cache_locked(netid); + + if (cache) { + _cache_notify_waiting_tid_locked(cache, key); + } + + pthread_mutex_unlock(&_res_cache_list_lock); +} + +static struct resolv_cache_info* _find_cache_info_locked(unsigned netid); + +static void +_cache_flush_locked( Cache* cache ) +{ + int nn; + + for (nn = 0; nn < cache->max_entries; nn++) + { + Entry** pnode = (Entry**) &cache->entries[nn]; + + while (*pnode != NULL) { + Entry* node = *pnode; + *pnode = node->hlink; + entry_free(node); + } + } + + // flush pending request + _cache_flush_pending_requests_locked(cache); + + cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list; + cache->num_entries = 0; + cache->last_id = 0; + + XLOG("*************************\n" + "*** DNS CACHE FLUSHED ***\n" + "*************************"); +} + +static int +_res_cache_get_max_entries( void ) +{ + int cache_size = CONFIG_MAX_ENTRIES; + + const char* cache_mode = getenv("ANDROID_DNS_MODE"); + if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) { + // Don't use the cache in local mode. This is used by the proxy itself. + cache_size = 0; + } + + XLOG("cache size: %d", cache_size); + return cache_size; +} + +static struct resolv_cache* +_resolv_cache_create( void ) +{ + struct resolv_cache* cache; + + cache = calloc(sizeof(*cache), 1); + if (cache) { + cache->max_entries = _res_cache_get_max_entries(); + cache->entries = calloc(sizeof(*cache->entries), cache->max_entries); + if (cache->entries) { + cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list; + XLOG("%s: cache created\n", __FUNCTION__); + } else { + free(cache); + cache = NULL; + } + } + return cache; +} + + +#if DEBUG +static void +_dump_query( const uint8_t* query, int querylen ) +{ + char temp[256], *p=temp, *end=p+sizeof(temp); + DnsPacket pack[1]; + + _dnsPacket_init(pack, query, querylen); + p = _dnsPacket_bprintQuery(pack, p, end); + XLOG("QUERY: %s", temp); +} + +static void +_cache_dump_mru( Cache* cache ) +{ + char temp[512], *p=temp, *end=p+sizeof(temp); + Entry* e; + + p = _bprint(temp, end, "MRU LIST (%2d): ", cache->num_entries); + for (e = cache->mru_list.mru_next; e != &cache->mru_list; e = e->mru_next) + p = _bprint(p, end, " %d", e->id); + + XLOG("%s", temp); +} + +static void +_dump_answer(const void* answer, int answerlen) +{ + res_state statep; + FILE* fp; + char* buf; + int fileLen; + + fp = fopen("/data/reslog.txt", "w+e"); + if (fp != NULL) { + statep = __res_get_state(); + + res_pquery(statep, answer, answerlen, fp); + + //Get file length + fseek(fp, 0, SEEK_END); + fileLen=ftell(fp); + fseek(fp, 0, SEEK_SET); + buf = (char *)malloc(fileLen+1); + if (buf != NULL) { + //Read file contents into buffer + fread(buf, fileLen, 1, fp); + XLOG("%s\n", buf); + free(buf); + } + fclose(fp); + remove("/data/reslog.txt"); + } + else { + errno = 0; // else debug is introducing error signals + XLOG("%s: can't open file\n", __FUNCTION__); + } +} +#endif + +#if DEBUG +# define XLOG_QUERY(q,len) _dump_query((q), (len)) +# define XLOG_ANSWER(a, len) _dump_answer((a), (len)) +#else +# define XLOG_QUERY(q,len) ((void)0) +# define XLOG_ANSWER(a,len) ((void)0) +#endif + +/* This function tries to find a key within the hash table + * In case of success, it will return a *pointer* to the hashed key. + * In case of failure, it will return a *pointer* to NULL + * + * So, the caller must check '*result' to check for success/failure. + * + * The main idea is that the result can later be used directly in + * calls to _resolv_cache_add or _resolv_cache_remove as the 'lookup' + * parameter. This makes the code simpler and avoids re-searching + * for the key position in the htable. + * + * The result of a lookup_p is only valid until you alter the hash + * table. + */ +static Entry** +_cache_lookup_p( Cache* cache, + Entry* key ) +{ + int index = key->hash % cache->max_entries; + Entry** pnode = (Entry**) &cache->entries[ index ]; + + while (*pnode != NULL) { + Entry* node = *pnode; + + if (node == NULL) + break; + + if (node->hash == key->hash && entry_equals(node, key)) + break; + + pnode = &node->hlink; + } + return pnode; +} + +/* Add a new entry to the hash table. 'lookup' must be the + * result of an immediate previous failed _lookup_p() call + * (i.e. with *lookup == NULL), and 'e' is the pointer to the + * newly created entry + */ +static void +_cache_add_p( Cache* cache, + Entry** lookup, + Entry* e ) +{ + *lookup = e; + e->id = ++cache->last_id; + entry_mru_add(e, &cache->mru_list); + cache->num_entries += 1; + + XLOG("%s: entry %d added (count=%d)", __FUNCTION__, + e->id, cache->num_entries); +} + +/* Remove an existing entry from the hash table, + * 'lookup' must be the result of an immediate previous + * and succesful _lookup_p() call. + */ +static void +_cache_remove_p( Cache* cache, + Entry** lookup ) +{ + Entry* e = *lookup; + + XLOG("%s: entry %d removed (count=%d)", __FUNCTION__, + e->id, cache->num_entries-1); + + entry_mru_remove(e); + *lookup = e->hlink; + entry_free(e); + cache->num_entries -= 1; +} + +/* Remove the oldest entry from the hash table. + */ +static void +_cache_remove_oldest( Cache* cache ) +{ + Entry* oldest = cache->mru_list.mru_prev; + Entry** lookup = _cache_lookup_p(cache, oldest); + + if (*lookup == NULL) { /* should not happen */ + XLOG("%s: OLDEST NOT IN HTABLE ?", __FUNCTION__); + return; + } + if (DEBUG) { + XLOG("Cache full - removing oldest"); + XLOG_QUERY(oldest->query, oldest->querylen); + } + _cache_remove_p(cache, lookup); +} + +/* Remove all expired entries from the hash table. + */ +static void _cache_remove_expired(Cache* cache) { + Entry* e; + time_t now = _time_now(); + + for (e = cache->mru_list.mru_next; e != &cache->mru_list;) { + // Entry is old, remove + if (now >= e->expires) { + Entry** lookup = _cache_lookup_p(cache, e); + if (*lookup == NULL) { /* should not happen */ + XLOG("%s: ENTRY NOT IN HTABLE ?", __FUNCTION__); + return; + } + e = e->mru_next; + _cache_remove_p(cache, lookup); + } else { + e = e->mru_next; + } + } +} + +ResolvCacheStatus +_resolv_cache_lookup( unsigned netid, + const void* query, + int querylen, + void* answer, + int answersize, + int *answerlen ) +{ + Entry key[1]; + Entry** lookup; + Entry* e; + time_t now; + Cache* cache; + + ResolvCacheStatus result = RESOLV_CACHE_NOTFOUND; + + XLOG("%s: lookup", __FUNCTION__); + XLOG_QUERY(query, querylen); + + /* we don't cache malformed queries */ + if (!entry_init_key(key, query, querylen)) { + XLOG("%s: unsupported query", __FUNCTION__); + return RESOLV_CACHE_UNSUPPORTED; + } + /* lookup cache */ + pthread_once(&_res_cache_once, _res_cache_init); + pthread_mutex_lock(&_res_cache_list_lock); + + cache = _find_named_cache_locked(netid); + if (cache == NULL) { + result = RESOLV_CACHE_UNSUPPORTED; + goto Exit; + } + + /* see the description of _lookup_p to understand this. + * the function always return a non-NULL pointer. + */ + lookup = _cache_lookup_p(cache, key); + e = *lookup; + + if (e == NULL) { + XLOG( "NOT IN CACHE"); + // calling thread will wait if an outstanding request is found + // that matching this query + if (!_cache_check_pending_request_locked(&cache, key, netid) || cache == NULL) { + goto Exit; + } else { + lookup = _cache_lookup_p(cache, key); + e = *lookup; + if (e == NULL) { + goto Exit; + } + } + } + + now = _time_now(); + + /* remove stale entries here */ + if (now >= e->expires) { + XLOG( " NOT IN CACHE (STALE ENTRY %p DISCARDED)", *lookup ); + XLOG_QUERY(e->query, e->querylen); + _cache_remove_p(cache, lookup); + goto Exit; + } + + *answerlen = e->answerlen; + if (e->answerlen > answersize) { + /* NOTE: we return UNSUPPORTED if the answer buffer is too short */ + result = RESOLV_CACHE_UNSUPPORTED; + XLOG(" ANSWER TOO LONG"); + goto Exit; + } + + memcpy( answer, e->answer, e->answerlen ); + + /* bump up this entry to the top of the MRU list */ + if (e != cache->mru_list.mru_next) { + entry_mru_remove( e ); + entry_mru_add( e, &cache->mru_list ); + } + + XLOG( "FOUND IN CACHE entry=%p", e ); + result = RESOLV_CACHE_FOUND; + +Exit: + pthread_mutex_unlock(&_res_cache_list_lock); + return result; +} + + +void +_resolv_cache_add( unsigned netid, + const void* query, + int querylen, + const void* answer, + int answerlen ) +{ + Entry key[1]; + Entry* e; + Entry** lookup; + u_long ttl; + Cache* cache = NULL; + + /* don't assume that the query has already been cached + */ + if (!entry_init_key( key, query, querylen )) { + XLOG( "%s: passed invalid query ?", __FUNCTION__); + return; + } + + pthread_mutex_lock(&_res_cache_list_lock); + + cache = _find_named_cache_locked(netid); + if (cache == NULL) { + goto Exit; + } + + XLOG( "%s: query:", __FUNCTION__ ); + XLOG_QUERY(query,querylen); + XLOG_ANSWER(answer, answerlen); +#if DEBUG_DATA + XLOG( "answer:"); + XLOG_BYTES(answer,answerlen); +#endif + + lookup = _cache_lookup_p(cache, key); + e = *lookup; + + if (e != NULL) { /* should not happen */ + XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD", + __FUNCTION__, e); + goto Exit; + } + + if (cache->num_entries >= cache->max_entries) { + _cache_remove_expired(cache); + if (cache->num_entries >= cache->max_entries) { + _cache_remove_oldest(cache); + } + /* need to lookup again */ + lookup = _cache_lookup_p(cache, key); + e = *lookup; + if (e != NULL) { + XLOG("%s: ALREADY IN CACHE (%p) ? IGNORING ADD", + __FUNCTION__, e); + goto Exit; + } + } + + ttl = answer_getTTL(answer, answerlen); + if (ttl > 0) { + e = entry_alloc(key, answer, answerlen); + if (e != NULL) { + e->expires = ttl + _time_now(); + _cache_add_p(cache, lookup, e); + } + } +#if DEBUG + _cache_dump_mru(cache); +#endif +Exit: + if (cache != NULL) { + _cache_notify_waiting_tid_locked(cache, key); + } + pthread_mutex_unlock(&_res_cache_list_lock); +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +// Head of the list of caches. Protected by _res_cache_list_lock. +static struct resolv_cache_info _res_cache_list; + +/* insert resolv_cache_info into the list of resolv_cache_infos */ +static void _insert_cache_info_locked(struct resolv_cache_info* cache_info); +/* creates a resolv_cache_info */ +static struct resolv_cache_info* _create_cache_info( void ); +/* gets a resolv_cache_info associated with a network, or NULL if not found */ +static struct resolv_cache_info* _find_cache_info_locked(unsigned netid); +/* look up the named cache, and creates one if needed */ +static struct resolv_cache* _get_res_cache_for_net_locked(unsigned netid); +/* empty the named cache */ +static void _flush_cache_for_net_locked(unsigned netid); +/* empty the nameservers set for the named cache */ +static void _free_nameservers_locked(struct resolv_cache_info* cache_info); +/* return 1 if the provided list of name servers differs from the list of name servers + * currently attached to the provided cache_info */ +static int _resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info, + const char** servers, int numservers); +/* clears the stats samples contained withing the given cache_info */ +static void _res_cache_clear_stats_locked(struct resolv_cache_info* cache_info); + +static void +_res_cache_init(void) +{ + memset(&_res_cache_list, 0, sizeof(_res_cache_list)); + pthread_mutex_init(&_res_cache_list_lock, NULL); +} + +static struct resolv_cache* +_get_res_cache_for_net_locked(unsigned netid) +{ + struct resolv_cache* cache = _find_named_cache_locked(netid); + if (!cache) { + struct resolv_cache_info* cache_info = _create_cache_info(); + if (cache_info) { + cache = _resolv_cache_create(); + if (cache) { + cache_info->cache = cache; + cache_info->netid = netid; + _insert_cache_info_locked(cache_info); + } else { + free(cache_info); + } + } + } + return cache; +} + +void +_resolv_flush_cache_for_net(unsigned netid) +{ + pthread_once(&_res_cache_once, _res_cache_init); + pthread_mutex_lock(&_res_cache_list_lock); + + _flush_cache_for_net_locked(netid); + + pthread_mutex_unlock(&_res_cache_list_lock); +} + +static void +_flush_cache_for_net_locked(unsigned netid) +{ + struct resolv_cache* cache = _find_named_cache_locked(netid); + if (cache) { + _cache_flush_locked(cache); + } + + // Also clear the NS statistics. + struct resolv_cache_info* cache_info = _find_cache_info_locked(netid); + _res_cache_clear_stats_locked(cache_info); +} + +void _resolv_delete_cache_for_net(unsigned netid) +{ + pthread_once(&_res_cache_once, _res_cache_init); + pthread_mutex_lock(&_res_cache_list_lock); + + struct resolv_cache_info* prev_cache_info = &_res_cache_list; + + while (prev_cache_info->next) { + struct resolv_cache_info* cache_info = prev_cache_info->next; + + if (cache_info->netid == netid) { + prev_cache_info->next = cache_info->next; + _cache_flush_locked(cache_info->cache); + free(cache_info->cache->entries); + free(cache_info->cache); + _free_nameservers_locked(cache_info); + free(cache_info); + break; + } + + prev_cache_info = prev_cache_info->next; + } + + pthread_mutex_unlock(&_res_cache_list_lock); +} + +static struct resolv_cache_info* +_create_cache_info(void) +{ + struct resolv_cache_info* cache_info; + + cache_info = calloc(sizeof(*cache_info), 1); + return cache_info; +} + +static void +_insert_cache_info_locked(struct resolv_cache_info* cache_info) +{ + struct resolv_cache_info* last; + + for (last = &_res_cache_list; last->next; last = last->next); + + last->next = cache_info; + +} + +static struct resolv_cache* +_find_named_cache_locked(unsigned netid) { + + struct resolv_cache_info* info = _find_cache_info_locked(netid); + + if (info != NULL) return info->cache; + + return NULL; +} + +static struct resolv_cache_info* +_find_cache_info_locked(unsigned netid) +{ + struct resolv_cache_info* cache_info = _res_cache_list.next; + + while (cache_info) { + if (cache_info->netid == netid) { + break; + } + + cache_info = cache_info->next; + } + return cache_info; +} + +void +_resolv_set_default_params(struct __res_params* params) { + params->sample_validity = NSSAMPLE_VALIDITY; + params->success_threshold = SUCCESS_THRESHOLD; + params->min_samples = 0; + params->max_samples = 0; + params->base_timeout_msec = 0; // 0 = legacy algorithm +} + +int +_resolv_set_nameservers_for_net(unsigned netid, const char** servers, unsigned numservers, + const char *domains, const struct __res_params* params) +{ + char sbuf[NI_MAXSERV]; + register char *cp; + int *offset; + struct addrinfo* nsaddrinfo[MAXNS]; + + if (numservers > MAXNS) { + XLOG("%s: numservers=%u, MAXNS=%u", __FUNCTION__, numservers, MAXNS); + return E2BIG; + } + + // Parse the addresses before actually locking or changing any state, in case there is an error. + // As a side effect this also reduces the time the lock is kept. + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_flags = AI_NUMERICHOST + }; + snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT); + for (unsigned i = 0; i < numservers; i++) { + // The addrinfo structures allocated here are freed in _free_nameservers_locked(). + int rt = getaddrinfo(servers[i], sbuf, &hints, &nsaddrinfo[i]); + if (rt != 0) { + for (unsigned j = 0 ; j < i ; j++) { + freeaddrinfo(nsaddrinfo[j]); + nsaddrinfo[j] = NULL; + } + XLOG("%s: getaddrinfo(%s)=%s", __FUNCTION__, servers[i], gai_strerror(rt)); + return EINVAL; + } + } + + pthread_once(&_res_cache_once, _res_cache_init); + pthread_mutex_lock(&_res_cache_list_lock); + + // creates the cache if not created + _get_res_cache_for_net_locked(netid); + + struct resolv_cache_info* cache_info = _find_cache_info_locked(netid); + + if (cache_info != NULL) { + uint8_t old_max_samples = cache_info->params.max_samples; + if (params != NULL) { + cache_info->params = *params; + } else { + _resolv_set_default_params(&cache_info->params); + } + + if (!_resolv_is_nameservers_equal_locked(cache_info, servers, numservers)) { + // free current before adding new + _free_nameservers_locked(cache_info); + unsigned i; + for (i = 0; i < numservers; i++) { + cache_info->nsaddrinfo[i] = nsaddrinfo[i]; + cache_info->nameservers[i] = strdup(servers[i]); + XLOG("%s: netid = %u, addr = %s\n", __FUNCTION__, netid, servers[i]); + } + cache_info->nscount = numservers; + + // Clear the NS statistics because the mapping to nameservers might have changed. + _res_cache_clear_stats_locked(cache_info); + + // increment the revision id to ensure that sample state is not written back if the + // servers change; in theory it would suffice to do so only if the servers or + // max_samples actually change, in practice the overhead of checking is higher than the + // cost, and overflows are unlikely + ++cache_info->revision_id; + } else { + if (cache_info->params.max_samples != old_max_samples) { + // If the maximum number of samples changes, the overhead of keeping the most recent + // samples around is not considered worth the effort, so they are cleared instead. + // All other parameters do not affect shared state: Changing these parameters does + // not invalidate the samples, as they only affect aggregation and the conditions + // under which servers are considered usable. + _res_cache_clear_stats_locked(cache_info); + ++cache_info->revision_id; + } + for (unsigned j = 0; j < numservers; j++) { + freeaddrinfo(nsaddrinfo[j]); + } + } + + // Always update the search paths, since determining whether they actually changed is + // complex due to the zero-padding, and probably not worth the effort. Cache-flushing + // however is not // necessary, since the stored cache entries do contain the domain, not + // just the host name. + // code moved from res_init.c, load_domain_search_list + strlcpy(cache_info->defdname, domains, sizeof(cache_info->defdname)); + if ((cp = strchr(cache_info->defdname, '\n')) != NULL) + *cp = '\0'; + + cp = cache_info->defdname; + offset = cache_info->dnsrch_offset; + while (offset < cache_info->dnsrch_offset + MAXDNSRCH) { + while (*cp == ' ' || *cp == '\t') /* skip leading white space */ + cp++; + if (*cp == '\0') /* stop if nothing more to do */ + break; + *offset++ = cp - cache_info->defdname; /* record this search domain */ + while (*cp) { /* zero-terminate it */ + if (*cp == ' '|| *cp == '\t') { + *cp++ = '\0'; + break; + } + cp++; + } + } + *offset = -1; /* cache_info->dnsrch_offset has MAXDNSRCH+1 items */ + } + + pthread_mutex_unlock(&_res_cache_list_lock); + return 0; +} + +static int +_resolv_is_nameservers_equal_locked(struct resolv_cache_info* cache_info, + const char** servers, int numservers) +{ + if (cache_info->nscount != numservers) { + return 0; + } + + // Compare each name server against current name servers. + // TODO: this is incorrect if the list of current or previous nameservers + // contains duplicates. This does not really matter because the framework + // filters out duplicates, but we should probably fix it. It's also + // insensitive to the order of the nameservers; we should probably fix that + // too. + for (int i = 0; i < numservers; i++) { + for (int j = 0 ; ; j++) { + if (j >= numservers) { + return 0; + } + if (strcmp(cache_info->nameservers[i], servers[j]) == 0) { + break; + } + } + } + + return 1; +} + +static void +_free_nameservers_locked(struct resolv_cache_info* cache_info) +{ + int i; + for (i = 0; i < cache_info->nscount; i++) { + free(cache_info->nameservers[i]); + cache_info->nameservers[i] = NULL; + if (cache_info->nsaddrinfo[i] != NULL) { + freeaddrinfo(cache_info->nsaddrinfo[i]); + cache_info->nsaddrinfo[i] = NULL; + } + cache_info->nsstats[i].sample_count = + cache_info->nsstats[i].sample_next = 0; + } + cache_info->nscount = 0; + _res_cache_clear_stats_locked(cache_info); + ++cache_info->revision_id; +} + +void +_resolv_populate_res_for_net(res_state statp) +{ + if (statp == NULL) { + return; + } + + pthread_once(&_res_cache_once, _res_cache_init); + pthread_mutex_lock(&_res_cache_list_lock); + + struct resolv_cache_info* info = _find_cache_info_locked(statp->netid); + if (info != NULL) { + int nserv; + struct addrinfo* ai; + XLOG("%s: %u\n", __FUNCTION__, statp->netid); + for (nserv = 0; nserv < MAXNS; nserv++) { + ai = info->nsaddrinfo[nserv]; + if (ai == NULL) { + break; + } + + if ((size_t) ai->ai_addrlen <= sizeof(statp->_u._ext.ext->nsaddrs[0])) { + if (statp->_u._ext.ext != NULL) { + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); + statp->nsaddr_list[nserv].sin_family = AF_UNSPEC; + } else { + if ((size_t) ai->ai_addrlen + <= sizeof(statp->nsaddr_list[0])) { + memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, + ai->ai_addrlen); + } else { + statp->nsaddr_list[nserv].sin_family = AF_UNSPEC; + } + } + } else { + XLOG("%s: found too long addrlen", __FUNCTION__); + } + } + statp->nscount = nserv; + // now do search domains. Note that we cache the offsets as this code runs alot + // but the setting/offset-computer only runs when set/changed + // WARNING: Don't use str*cpy() here, this string contains zeroes. + memcpy(statp->defdname, info->defdname, sizeof(statp->defdname)); + register char **pp = statp->dnsrch; + register int *p = info->dnsrch_offset; + while (pp < statp->dnsrch + MAXDNSRCH && *p != -1) { + *pp++ = &statp->defdname[0] + *p++; + } + } + pthread_mutex_unlock(&_res_cache_list_lock); +} + +/* Resolver reachability statistics. */ + +static void +_res_cache_add_stats_sample_locked(struct __res_stats* stats, const struct __res_sample* sample, + int max_samples) { + // Note: This function expects max_samples > 0, otherwise a (harmless) modification of the + // allocated but supposedly unused memory for samples[0] will happen + XLOG("%s: adding sample to stats, next = %d, count = %d", __FUNCTION__, + stats->sample_next, stats->sample_count); + stats->samples[stats->sample_next] = *sample; + if (stats->sample_count < max_samples) { + ++stats->sample_count; + } + if (++stats->sample_next >= max_samples) { + stats->sample_next = 0; + } +} + +static void +_res_cache_clear_stats_locked(struct resolv_cache_info* cache_info) { + if (cache_info) { + for (int i = 0 ; i < MAXNS ; ++i) { + cache_info->nsstats->sample_count = cache_info->nsstats->sample_next = 0; + } + } +} + +int +android_net_res_stats_get_info_for_net(unsigned netid, int* nscount, + struct sockaddr_storage servers[MAXNS], int* dcount, char domains[MAXDNSRCH][MAXDNSRCHPATH], + struct __res_params* params, struct __res_stats stats[MAXNS]) { + int revision_id = -1; + pthread_mutex_lock(&_res_cache_list_lock); + + struct resolv_cache_info* info = _find_cache_info_locked(netid); + if (info) { + if (info->nscount > MAXNS) { + pthread_mutex_unlock(&_res_cache_list_lock); + XLOG("%s: nscount %d > MAXNS %d", __FUNCTION__, info->nscount, MAXNS); + errno = EFAULT; + return -1; + } + int i; + for (i = 0; i < info->nscount; i++) { + // Verify that the following assumptions are held, failure indicates corruption: + // - getaddrinfo() may never return a sockaddr > sockaddr_storage + // - all addresses are valid + // - there is only one address per addrinfo thanks to numeric resolution + int addrlen = info->nsaddrinfo[i]->ai_addrlen; + if (addrlen < (int) sizeof(struct sockaddr) || + addrlen > (int) sizeof(servers[0])) { + pthread_mutex_unlock(&_res_cache_list_lock); + XLOG("%s: nsaddrinfo[%d].ai_addrlen == %d", __FUNCTION__, i, addrlen); + errno = EMSGSIZE; + return -1; + } + if (info->nsaddrinfo[i]->ai_addr == NULL) { + pthread_mutex_unlock(&_res_cache_list_lock); + XLOG("%s: nsaddrinfo[%d].ai_addr == NULL", __FUNCTION__, i); + errno = ENOENT; + return -1; + } + if (info->nsaddrinfo[i]->ai_next != NULL) { + pthread_mutex_unlock(&_res_cache_list_lock); + XLOG("%s: nsaddrinfo[%d].ai_next != NULL", __FUNCTION__, i); + errno = ENOTUNIQ; + return -1; + } + } + *nscount = info->nscount; + for (i = 0; i < info->nscount; i++) { + memcpy(&servers[i], info->nsaddrinfo[i]->ai_addr, info->nsaddrinfo[i]->ai_addrlen); + stats[i] = info->nsstats[i]; + } + for (i = 0; i < MAXDNSRCH; i++) { + const char* cur_domain = info->defdname + info->dnsrch_offset[i]; + // dnsrch_offset[i] can either be -1 or point to an empty string to indicate the end + // of the search offsets. Checking for < 0 is not strictly necessary, but safer. + // TODO: Pass in a search domain array instead of a string to + // _resolv_set_nameservers_for_net() and make this double check unnecessary. + if (info->dnsrch_offset[i] < 0 || + ((size_t)info->dnsrch_offset[i]) >= sizeof(info->defdname) || !cur_domain[0]) { + break; + } + strlcpy(domains[i], cur_domain, MAXDNSRCHPATH); + } + *dcount = i; + *params = info->params; + revision_id = info->revision_id; + } + + pthread_mutex_unlock(&_res_cache_list_lock); + return revision_id; +} + +int +_resolv_cache_get_resolver_stats( unsigned netid, struct __res_params* params, + struct __res_stats stats[MAXNS]) { + int revision_id = -1; + pthread_mutex_lock(&_res_cache_list_lock); + + struct resolv_cache_info* info = _find_cache_info_locked(netid); + if (info) { + memcpy(stats, info->nsstats, sizeof(info->nsstats)); + *params = info->params; + revision_id = info->revision_id; + } + + pthread_mutex_unlock(&_res_cache_list_lock); + return revision_id; +} + +void +_resolv_cache_add_resolver_stats_sample( unsigned netid, int revision_id, int ns, + const struct __res_sample* sample, int max_samples) { + if (max_samples <= 0) return; + + pthread_mutex_lock(&_res_cache_list_lock); + + struct resolv_cache_info* info = _find_cache_info_locked(netid); + + if (info && info->revision_id == revision_id) { + _res_cache_add_stats_sample_locked(&info->nsstats[ns], sample, max_samples); + } + + pthread_mutex_unlock(&_res_cache_list_lock); +} diff --git a/aosp/bionic/libc/dns/resolv/res_comp.c b/aosp/bionic/libc/dns/resolv/res_comp.c new file mode 100644 index 000000000..987b2287c --- /dev/null +++ b/aosp/bionic/libc/dns/resolv/res_comp.c @@ -0,0 +1,266 @@ +/* $NetBSD: res_comp.c,v 1.6 2004/05/22 23:47:09 christos Exp $ */ + +/* + * Copyright (c) 1985, 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * 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, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * 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 ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_comp.c,v 1.1.2.1.4.1 2004/03/09 08:33:54 marka Exp"; +#else +__RCSID("$NetBSD: res_comp.c,v 1.6 2004/05/22 23:47:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include + +/* + * Expand compressed domain name 'src' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eom' points to the first location after the message, + * 'dst' is a pointer to a buffer of size 'dstsiz' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +dn_expand(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, int dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +dn_comp(const char *src, u_char *dst, int dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +dn_skipname(const u_char *ptr, const u_char *eom) { + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/* + * Verify that a domain name uses an acceptable character set. + */ + +/* + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ + +/* BIONIC: We also accept underscores in the middle of labels. + * This extension is needed to make resolution on some VPN networks + * work properly. + */ + +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) +#define underscorechar(c) ((c) == 0x5f) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c) || underscorechar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +int +res_hnok(const char *dn) { + int pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + ; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + pch = ch, ch = nch; + } + return (1); +} + +/* + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(const char *dn) { + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/* + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(const char *dn) { + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return (1); + + /* otherwise