Merge "librust_baremetal: No HAVE_ASSEMBLER___MEMCPY_CHK"
diff --git a/OWNERS b/OWNERS
index 670f88d..3818b1d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,6 +1,7 @@
 enh@google.com
 
 cferris@google.com
+chiahungduan@google.com
 danalbert@google.com
 rprichard@google.com
 yabinc@google.com
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 13c8911..c5a6ac3 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -475,3 +475,7 @@
 There are no plans to remove support for ELF files using the older
 OS private use constants for RELR, nor for ELF files using packed
 relocations.
+
+You can read more about relative relocations
+and their long and complicated history at
+https://maskray.me/blog/2021-10-31-relative-relocations-and-relr.
diff --git a/libc/Android.bp b/libc/Android.bp
index 0bd1852..b86313c 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -248,10 +248,14 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "tzcode/**/*.c",
         "tzcode/bionic.cpp",
-        "upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one.
+        // tzcode doesn't include strptime or wcsftime, so we use the OpenBSD
+        // code (with some local changes in the strptime case).
+        "upstream-openbsd/lib/libc/locale/_def_time.c",
+        "upstream-openbsd/lib/libc/time/wcsftime.c",
     ],
 
     cflags: [
@@ -291,6 +295,7 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "dns/**/*.c*",
 
@@ -326,6 +331,7 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-freebsd/lib/libc/gen/ldexp.c",
         "upstream-freebsd/lib/libc/stdlib/getopt_long.c",
@@ -392,6 +398,7 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-freebsd/lib/libc/gen/glob.c",
     ],
@@ -419,6 +426,7 @@
 cc_library_static {
 
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-netbsd/common/lib/libc/stdlib/random.c",
         "upstream-netbsd/lib/libc/gen/nice.c",
@@ -476,6 +484,7 @@
 cc_library_static {
     name: "libc_openbsd_ndk",
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-openbsd/lib/libc/gen/alarm.c",
         "upstream-openbsd/lib/libc/gen/ctype_.c",
@@ -594,6 +603,7 @@
 cc_library_static {
     name: "libc_openbsd_large_stack",
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "stdio/vfprintf.cpp",
         "stdio/vfwprintf.cpp",
@@ -623,6 +633,7 @@
 // automatically included.
 cc_library_static {
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         // These two depend on getentropy, which isn't in libc_ndk.a.
         "upstream-openbsd/lib/libc/crypt/arc4random.c",
@@ -722,6 +733,7 @@
 
 cc_library_static {
     defaults: ["libc_defaults"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-openbsd/android/gdtoa_support.cpp",
         "upstream-openbsd/lib/libc/gdtoa/dmisc.c",
@@ -763,7 +775,7 @@
 }
 
 // ========================================================
-// libc_fortify.a - container for our FORITFY
+// libc_fortify.a - container for our FORTIFY
 // implementation details
 // ========================================================
 cc_library_static {
@@ -1189,6 +1201,7 @@
         "bionic/termios.cpp",
         "bionic/thread_private.cpp",
         "bionic/threads.cpp",
+        "bionic/time_l.cpp",
         "bionic/timespec_get.cpp",
         "bionic/tmpfile.cpp",
         "bionic/umount.cpp",
@@ -1431,6 +1444,7 @@
 
     whole_static_libs: [
         "gwp_asan",
+        "gwp_asan_crash_handler",
         "libarm-optimized-routines-string",
         "libasync_safe",
         "libc_bionic_ndk",
@@ -1673,6 +1687,7 @@
         cflags: ["-DLIBC_STATIC"],
         whole_static_libs: [
             "gwp_asan",
+            "gwp_asan_crash_handler",
             "libc_init_static",
             "libc_common_static",
             "libc_unwind_static",
@@ -1682,6 +1697,7 @@
         srcs: [ ":libc_sources_shared" ],
         whole_static_libs: [
             "gwp_asan",
+            "gwp_asan_crash_handler",
             "libc_init_dynamic",
             "libc_common_shared",
             "libunwind-exported",
@@ -2822,6 +2838,7 @@
 
 cc_library_host_static {
     name: "libfts",
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "bionic/fts.c",
         "upstream-openbsd/lib/libc/stdlib/recallocarray.c",
@@ -2864,6 +2881,7 @@
 cc_library_host_static {
     name: "libb64",
     visibility: ["//external/musl"],
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: ["upstream-openbsd/lib/libc/net/base64.c"],
     export_include_dirs: ["b64/include"],
     local_include_dirs: [
diff --git a/libc/NOTICE b/libc/NOTICE
index 332885d..a6ca8b7 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -2579,6 +2579,36 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 1994 Winning Strategies, 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.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+     This product includes software developed by Winning Strategies, Inc.
+4. 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
@@ -2779,41 +2809,6 @@
 
 -------------------------------------------------------------------
 
-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.
 
@@ -2879,6 +2874,34 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 1997, 1998, 2005, 2008 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.
+
+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 <Todd.Miller@courtesan.com>
 
 Permission to use, copy, modify, and distribute this software for any
diff --git a/libc/SECCOMP_BLOCKLIST_APP.TXT b/libc/SECCOMP_BLOCKLIST_APP.TXT
index f14e11c..049d577 100644
--- a/libc/SECCOMP_BLOCKLIST_APP.TXT
+++ b/libc/SECCOMP_BLOCKLIST_APP.TXT
@@ -22,8 +22,10 @@
 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     setfsgid:setfsgid32(gid_t) lp32
+int     setfsgid:setfsgid(gid_t)   lp64
+int     setfsuid:setfsuid32(uid_t) lp32
+int     setfsuid:setfsuid(uid_t)   lp64
 int     setgroups:setgroups32(int, const gid_t*)   lp32
 int     setgroups:setgroups(int, const gid_t*)     lp64
 
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 1b9054b..08017f1 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -26,41 +26,47 @@
 # This file is processed by a python script named gensyscalls.py, run via
 # genrules in Android.bp.
 
-int     __execve:execve(const char*, char* const*, char* const*)  all
+# Calls that have historical 16-bit variants camping on the best names (CONFIG_UID16).
+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
+int getgroups:getgroups32(int, gid_t*) lp32
+int getgroups:getgroups(int, gid_t*)   lp64
+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
+int setfsgid:setfsgid32(gid_t) lp32
+int setfsgid:setfsgid(gid_t)   lp64
+int setfsuid:setfsuid32(uid_t) lp32
+int setfsuid:setfsuid(uid_t)   lp64
 
-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
+ssize_t readahead(int, off64_t, size_t) all
+pid_t getpgid(pid_t) all
+pid_t getppid() all
+pid_t getsid(pid_t) all
+pid_t setsid() all
+int kill(pid_t, int) all
+int tgkill(pid_t tgid, pid_t tid, int sig) all
+
+void* __brk:brk(void*) all
+int __execve:execve(const char*, char* const*, char* const*)  all
+int __ptrace:ptrace(int request, int pid, void* addr, void* data) all
 
 # <sys/resource.h>
 int getrusage(int, struct rusage*)  all
@@ -336,9 +342,6 @@
 
 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
 
diff --git a/libc/arch-arm64/dynamic_function_dispatch.cpp b/libc/arch-arm64/dynamic_function_dispatch.cpp
index bbd4218..cd55311 100644
--- a/libc/arch-arm64/dynamic_function_dispatch.cpp
+++ b/libc/arch-arm64/dynamic_function_dispatch.cpp
@@ -41,6 +41,12 @@
     }
 }
 
+typedef void* memcmp_func(void*, const void*, size_t);
+DEFINE_IFUNC_FOR(memcmp) {
+    // TODO: enable the SVE version.
+    RETURN_FUNC(memcmp_func, __memcmp_aarch64);
+}
+
 typedef void* memcpy_func(void*, const void*, size_t);
 DEFINE_IFUNC_FOR(memcpy) {
     if (arg->_hwcap & HWCAP_ASIMD) {
@@ -61,11 +67,8 @@
 
 typedef int stpcpy_func(char*, const char*);
 DEFINE_IFUNC_FOR(stpcpy) {
-    if (arg->_hwcap2 & HWCAP2_MTE) {
-        RETURN_FUNC(stpcpy_func, __stpcpy_aarch64_mte);
-    } else {
-        RETURN_FUNC(stpcpy_func, __stpcpy_aarch64);
-    }
+    // TODO: enable the SVE version.
+    RETURN_FUNC(stpcpy_func, __stpcpy_aarch64);
 }
 
 typedef char* strchr_func(const char*, int);
@@ -88,20 +91,14 @@
 
 typedef int strcmp_func(const char*, const char*);
 DEFINE_IFUNC_FOR(strcmp) {
-    if (arg->_hwcap2 & HWCAP2_MTE) {
-        RETURN_FUNC(strcmp_func, __strcmp_aarch64_mte);
-    } else {
-        RETURN_FUNC(strcmp_func, __strcmp_aarch64);
-    }
+    // TODO: enable the SVE version.
+    RETURN_FUNC(strcmp_func, __strcmp_aarch64);
 }
 
 typedef int strcpy_func(char*, const char*);
 DEFINE_IFUNC_FOR(strcpy) {
-    if (arg->_hwcap2 & HWCAP2_MTE) {
-        RETURN_FUNC(strcpy_func, __strcpy_aarch64_mte);
-    } else {
-        RETURN_FUNC(strcpy_func, __strcpy_aarch64);
-    }
+    // TODO: enable the SVE version.
+    RETURN_FUNC(strcpy_func, __strcpy_aarch64);
 }
 
 typedef size_t strlen_func(const char*);
@@ -115,11 +112,14 @@
 
 typedef int strncmp_func(const char*, const char*, int);
 DEFINE_IFUNC_FOR(strncmp) {
-    if (arg->_hwcap2 & HWCAP2_MTE) {
-        RETURN_FUNC(strncmp_func, __strncmp_aarch64_mte);
-    } else {
-        RETURN_FUNC(strncmp_func, __strncmp_aarch64);
-    }
+    // TODO: enable the SVE version.
+    RETURN_FUNC(strncmp_func, __strncmp_aarch64);
+}
+
+typedef size_t strnlen_func(const char*);
+DEFINE_IFUNC_FOR(strnlen) {
+    // TODO: enable the SVE version.
+    RETURN_FUNC(strnlen_func, __strnlen_aarch64);
 }
 
 typedef char* strrchr_func(const char*, int);
diff --git a/libc/arch-arm64/static_function_dispatch.S b/libc/arch-arm64/static_function_dispatch.S
index d00f071..c7557f8 100644
--- a/libc/arch-arm64/static_function_dispatch.S
+++ b/libc/arch-arm64/static_function_dispatch.S
@@ -34,15 +34,17 @@
 END(name)
 
 FUNCTION_DELEGATE(memchr, __memchr_aarch64_mte)
+FUNCTION_DELEGATE(memcmp, __memcmp_aarch64)
 FUNCTION_DELEGATE(memcpy, __memcpy_aarch64)
 FUNCTION_DELEGATE(memmove, __memmove_aarch64)
-FUNCTION_DELEGATE(stpcpy, __stpcpy_aarch64_mte)
+FUNCTION_DELEGATE(stpcpy, __stpcpy_aarch64)
 FUNCTION_DELEGATE(strchr, __strchr_aarch64_mte)
 FUNCTION_DELEGATE(strchrnul, __strchrnul_aarch64_mte)
-FUNCTION_DELEGATE(strcmp, __strcmp_aarch64_mte)
-FUNCTION_DELEGATE(strcpy, __strcpy_aarch64_mte)
+FUNCTION_DELEGATE(strcmp, __strcmp_aarch64)
+FUNCTION_DELEGATE(strcpy, __strcpy_aarch64)
 FUNCTION_DELEGATE(strlen, __strlen_aarch64_mte)
 FUNCTION_DELEGATE(strrchr, __strrchr_aarch64_mte)
-FUNCTION_DELEGATE(strncmp, __strncmp_aarch64_mte)
+FUNCTION_DELEGATE(strncmp, __strncmp_aarch64)
+FUNCTION_DELEGATE(strnlen, __strnlen_aarch64)
 
 NOTE_GNU_PROPERTY()
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index fc59c88..251633d 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -36,6 +36,7 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include "gwp_asan/crash_handler.h"
 #include "gwp_asan/guarded_pool_allocator.h"
 #include "gwp_asan/options.h"
 #include "gwp_asan_wrappers.h"
@@ -189,6 +190,7 @@
 }
 
 bool GwpAsanInitialized = false;
+bool GwpAsanRecoverable = false;
 
 // The probability (1 / SampleRate) that an allocation gets chosen to be put
 // into the special GWP-ASan pool.
@@ -222,8 +224,32 @@
 static const char* kMaxAllocsTargetedSyspropPrefix = "libc.debug.gwp_asan.max_allocs.";
 static const char* kMaxAllocsEnvVar = "GWP_ASAN_MAX_ALLOCS";
 
+static const char* kRecoverableSystemSysprop = "libc.debug.gwp_asan.recoverable.system_default";
+static const char* kRecoverableAppSysprop = "libc.debug.gwp_asan.recoverable.app_default";
+static const char* kRecoverableTargetedSyspropPrefix = "libc.debug.gwp_asan.recoverable.";
+static const char* kRecoverableEnvVar = "GWP_ASAN_RECOVERABLE";
+
 static const char kPersistPrefix[] = "persist.";
 
+bool NeedsGwpAsanRecovery(void* fault_ptr) {
+  fault_ptr = untag_address(fault_ptr);
+  return GwpAsanInitialized && GwpAsanRecoverable &&
+         __gwp_asan_error_is_mine(GuardedAlloc.getAllocatorState(),
+                                  reinterpret_cast<uintptr_t>(fault_ptr));
+}
+
+void GwpAsanPreCrashHandler(void* fault_ptr) {
+  fault_ptr = untag_address(fault_ptr);
+  if (!NeedsGwpAsanRecovery(fault_ptr)) return;
+  GuardedAlloc.preCrashReport(fault_ptr);
+}
+
+void GwpAsanPostCrashHandler(void* fault_ptr) {
+  fault_ptr = untag_address(fault_ptr);
+  if (!NeedsGwpAsanRecovery(fault_ptr)) return;
+  GuardedAlloc.postCrashReportRecoverableOnly(fault_ptr);
+}
+
 void SetDefaultGwpAsanOptions(Options* options, unsigned* process_sample_rate,
                               const android_mallopt_gwp_asan_options_t& mallopt_options) {
   options->Enabled = true;
@@ -236,14 +262,17 @@
   *process_sample_rate = 1;
   if (mallopt_options.desire == Action::TURN_ON_WITH_SAMPLING) {
     *process_sample_rate = kDefaultProcessSampling;
+  } else if (mallopt_options.desire == Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING) {
+    *process_sample_rate = kDefaultProcessSampling;
+    options->Recoverable = true;
+    GwpAsanRecoverable = true;
   }
 }
 
-bool GetGwpAsanOption(unsigned long long* result,
-                      const android_mallopt_gwp_asan_options_t& mallopt_options,
-                      const char* system_sysprop, const char* app_sysprop,
-                      const char* targeted_sysprop_prefix, const char* env_var,
-                      const char* descriptive_name) {
+bool GetGwpAsanOptionImpl(char* value_out,
+                          const android_mallopt_gwp_asan_options_t& mallopt_options,
+                          const char* system_sysprop, const char* app_sysprop,
+                          const char* targeted_sysprop_prefix, const char* env_var) {
   const char* basename = "";
   if (mallopt_options.program_name) basename = __gnu_basename(mallopt_options.program_name);
 
@@ -278,17 +307,25 @@
     sysprop_names[3] = persist_default_sysprop;
   }
 
-  char settings_buf[PROP_VALUE_MAX];
-  if (!get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
-                                       settings_buf, PROP_VALUE_MAX)) {
+  return get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
+                                         value_out, PROP_VALUE_MAX);
+}
+
+bool GetGwpAsanIntegerOption(unsigned long long* result,
+                             const android_mallopt_gwp_asan_options_t& mallopt_options,
+                             const char* system_sysprop, const char* app_sysprop,
+                             const char* targeted_sysprop_prefix, const char* env_var,
+                             const char* descriptive_name) {
+  char buffer[PROP_VALUE_MAX];
+  if (!GetGwpAsanOptionImpl(buffer, mallopt_options, system_sysprop, app_sysprop,
+                            targeted_sysprop_prefix, env_var)) {
     return false;
   }
-
   char* end;
-  unsigned long long value = strtoull(settings_buf, &end, 10);
+  unsigned long long value = strtoull(buffer, &end, 10);
   if (value == ULLONG_MAX || *end != '\0') {
     warning_log("Invalid GWP-ASan %s: \"%s\". Using default value instead.", descriptive_name,
-                settings_buf);
+                buffer);
     return false;
   }
 
@@ -296,6 +333,33 @@
   return true;
 }
 
+bool GetGwpAsanBoolOption(bool* result, const android_mallopt_gwp_asan_options_t& mallopt_options,
+                          const char* system_sysprop, const char* app_sysprop,
+                          const char* targeted_sysprop_prefix, const char* env_var,
+                          const char* descriptive_name) {
+  char buffer[PROP_VALUE_MAX] = {};
+  if (!GetGwpAsanOptionImpl(buffer, mallopt_options, system_sysprop, app_sysprop,
+                            targeted_sysprop_prefix, env_var)) {
+    return false;
+  }
+
+  if (strncasecmp(buffer, "1", PROP_VALUE_MAX) == 0 ||
+      strncasecmp(buffer, "true", PROP_VALUE_MAX) == 0) {
+    *result = true;
+    return true;
+  } else if (strncasecmp(buffer, "0", PROP_VALUE_MAX) == 0 ||
+             strncasecmp(buffer, "false", PROP_VALUE_MAX) == 0) {
+    *result = false;
+    return true;
+  }
+
+  warning_log(
+      "Invalid GWP-ASan %s: \"%s\". Using default value \"%s\" instead. Valid values are \"true\", "
+      "\"1\", \"false\", or \"0\".",
+      descriptive_name, buffer, *result ? "true" : "false");
+  return false;
+}
+
 // Initialize the GWP-ASan options structure in *options, taking into account whether someone has
 // asked for specific GWP-ASan settings. The order of priority is:
 //  1. Environment variables.
@@ -310,22 +374,23 @@
   bool had_overrides = false;
 
   unsigned long long buf;
-  if (GetGwpAsanOption(&buf, mallopt_options, kSampleRateSystemSysprop, kSampleRateAppSysprop,
-                       kSampleRateTargetedSyspropPrefix, kSampleRateEnvVar, "sample rate")) {
+  if (GetGwpAsanIntegerOption(&buf, mallopt_options, kSampleRateSystemSysprop,
+                              kSampleRateAppSysprop, kSampleRateTargetedSyspropPrefix,
+                              kSampleRateEnvVar, "sample rate")) {
     options->SampleRate = buf;
     had_overrides = true;
   }
 
-  if (GetGwpAsanOption(&buf, mallopt_options, kProcessSamplingSystemSysprop,
-                       kProcessSamplingAppSysprop, kProcessSamplingTargetedSyspropPrefix,
-                       kProcessSamplingEnvVar, "process sampling rate")) {
+  if (GetGwpAsanIntegerOption(&buf, mallopt_options, kProcessSamplingSystemSysprop,
+                              kProcessSamplingAppSysprop, kProcessSamplingTargetedSyspropPrefix,
+                              kProcessSamplingEnvVar, "process sampling rate")) {
     *process_sample_rate = buf;
     had_overrides = true;
   }
 
-  if (GetGwpAsanOption(&buf, mallopt_options, kMaxAllocsSystemSysprop, kMaxAllocsAppSysprop,
-                       kMaxAllocsTargetedSyspropPrefix, kMaxAllocsEnvVar,
-                       "maximum simultaneous allocations")) {
+  if (GetGwpAsanIntegerOption(&buf, mallopt_options, kMaxAllocsSystemSysprop, kMaxAllocsAppSysprop,
+                              kMaxAllocsTargetedSyspropPrefix, kMaxAllocsEnvVar,
+                              "maximum simultaneous allocations")) {
     options->MaxSimultaneousAllocations = buf;
     had_overrides = true;
   } else if (had_overrides) {
@@ -337,6 +402,16 @@
     options->MaxSimultaneousAllocations =
         /* default */ kDefaultMaxAllocs / frequency_multiplier;
   }
+
+  bool recoverable = false;
+  if (GetGwpAsanBoolOption(&recoverable, mallopt_options, kRecoverableSystemSysprop,
+                           kRecoverableAppSysprop, kRecoverableTargetedSyspropPrefix,
+                           kRecoverableEnvVar, "recoverable")) {
+    options->Recoverable = recoverable;
+    GwpAsanRecoverable = recoverable;
+    had_overrides = true;
+  }
+
   return had_overrides;
 }
 
@@ -396,6 +471,9 @@
 
   __libc_shared_globals()->gwp_asan_state = GuardedAlloc.getAllocatorState();
   __libc_shared_globals()->gwp_asan_metadata = GuardedAlloc.getMetadataRegion();
+  __libc_shared_globals()->debuggerd_needs_gwp_asan_recovery = NeedsGwpAsanRecovery;
+  __libc_shared_globals()->debuggerd_gwp_asan_pre_crash_report = GwpAsanPreCrashHandler;
+  __libc_shared_globals()->debuggerd_gwp_asan_post_crash_report = GwpAsanPostCrashHandler;
 
   return true;
 }
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 97e8d15..802a94f 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -371,6 +371,7 @@
 extern "C" const char* __scudo_get_stack_depot_addr();
 extern "C" const char* __scudo_get_region_info_addr();
 extern "C" const char* __scudo_get_ring_buffer_addr();
+extern "C" size_t __scudo_get_ring_buffer_size();
 
 // Initializes memory allocation framework once per process.
 static void MallocInitImpl(libc_globals* globals) {
@@ -383,6 +384,7 @@
   __libc_shared_globals()->scudo_stack_depot = __scudo_get_stack_depot_addr();
   __libc_shared_globals()->scudo_region_info = __scudo_get_region_info_addr();
   __libc_shared_globals()->scudo_ring_buffer = __scudo_get_ring_buffer_addr();
+  __libc_shared_globals()->scudo_ring_buffer_size = __scudo_get_ring_buffer_size();
 #endif
 
   // Prefer malloc debug since it existed first and is a more complete
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index dd6b129..1c06c9e 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -88,7 +88,7 @@
     case _SC_PAGESIZE:
     case _SC_PAGE_SIZE:
       // _SC_PAGESIZE and _SC_PAGE_SIZE are distinct, but return the same value.
-      return static_cast<long>(getauxval(AT_PAGESZ));
+      return getpagesize();
 
     case _SC_PHYS_PAGES:        return get_phys_pages();
 
diff --git a/libm/riscv64/sqrt.S b/libc/bionic/time_l.cpp
similarity index 89%
rename from libm/riscv64/sqrt.S
rename to libc/bionic/time_l.cpp
index 0db1335..e5fa9a5 100644
--- a/libm/riscv64/sqrt.S
+++ b/libc/bionic/time_l.cpp
@@ -26,14 +26,9 @@
  * SUCH DAMAGE.
  */
 
-#include <private/bionic_asm.h>
+#include <time.h>
+//#include <xlocale.h>
 
-ENTRY(sqrt)
-  fsqrt.d fa0, fa0
-  ret
-END(sqrt)
-
-ENTRY(sqrtf)
-  fsqrt.s fa0, fa0
-  ret
-END(sqrtf)
+char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t) {
+  return strptime(buf, fmt, tm);
+}
diff --git a/libc/include/execinfo.h b/libc/include/execinfo.h
index 347ae92..88f4ae7 100644
--- a/libc/include/execinfo.h
+++ b/libc/include/execinfo.h
@@ -47,7 +47,7 @@
  *
  * Available since API level 33.
  */
-int backtrace(void** buffer, int size) __INTRODUCED_IN(33);
+int backtrace(void* _Nonnull * _Nonnull buffer, int size) __INTRODUCED_IN(33);
 
 /**
  * [backtrace_symbols(3)](https://man7.org/linux/man-pages/man3/backtrace_symbols.3.html)
@@ -59,7 +59,7 @@
  *
  * Available since API level 33.
  */
-char** backtrace_symbols(void* const* buffer, int size) __INTRODUCED_IN(33);
+char* _Nullable * _Nullable backtrace_symbols(void* _Nonnull const* _Nonnull buffer, int size) __INTRODUCED_IN(33);
 
 /**
  * [backtrace_symbols_fd(3)](https://man7.org/linux/man-pages/man3/backtrace_symbols_fd.3.html)
@@ -69,6 +69,6 @@
  *
  * Available since API level 33.
  */
-void backtrace_symbols_fd(void* const* buffer, int size, int fd) __INTRODUCED_IN(33);
+void backtrace_symbols_fd(void* _Nonnull const* _Nonnull buffer, int size, int fd) __INTRODUCED_IN(33);
 
 __END_DECLS
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index 1ea94e6..1ec932b 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -111,9 +111,9 @@
  * Returns a new file descriptor on success and returns -1 and sets `errno` on
  * failure.
  */
-int creat(const char* __path, mode_t __mode);
+int creat(const char* _Nonnull __path, mode_t __mode);
 /** See creat(). */
-int creat64(const char* __path, mode_t __mode) __INTRODUCED_IN(21);
+int creat64(const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(21);
 
 /**
  * [openat(2)](http://man7.org/linux/man-pages/man2/openat.2.html)
@@ -122,9 +122,9 @@
  * Returns a new file descriptor on success and returns -1 and sets `errno` on
  * failure.
  */
-int openat(int __dir_fd, const char* __path, int __flags, ...);
+int openat(int __dir_fd, const char* _Nonnull __path, int __flags, ...);
 /** See openat(). */
-int openat64(int __dir_fd, const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int openat64(int __dir_fd, const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
 
 /**
  * [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)
@@ -133,9 +133,9 @@
  * Returns a new file descriptor on success and returns -1 and sets `errno` on
  * failure.
  */
-int open(const char* __path, int __flags, ...);
+int open(const char* _Nonnull __path, int __flags, ...);
 /** See open(). */
-int open64(const char* __path, int __flags, ...) __INTRODUCED_IN(21);
+int open64(const char* _Nonnull __path, int __flags, ...) __INTRODUCED_IN(21);
 
 /**
  * [splice(2)](http://man7.org/linux/man-pages/man2/splice.2.html)
@@ -149,7 +149,7 @@
  *
  * Available since API level 21.
  */
-ssize_t splice(int __in_fd, off64_t* __in_offset, int __out_fd, off64_t* __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t splice(int __in_fd, off64_t* __BIONIC_COMPLICATED_NULLNESS __in_offset, int __out_fd, off64_t* __BIONIC_COMPLICATED_NULLNESS __out_offset, size_t __length, unsigned int __flags) __INTRODUCED_IN(21);
 
 /**
  * [tee(2)](http://man7.org/linux/man-pages/man2/tee.2.html)
@@ -177,7 +177,7 @@
  *
  * Available since API level 21.
  */
-ssize_t vmsplice(int __fd, const struct iovec* __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
+ssize_t vmsplice(int __fd, const struct iovec* _Nonnull __iov, size_t __count, unsigned int __flags) __INTRODUCED_IN(21);
 
 /**
  * [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html)
diff --git a/libc/include/inttypes.h b/libc/include/inttypes.h
index 7a409d8..f8b7f7d 100644
--- a/libc/include/inttypes.h
+++ b/libc/include/inttypes.h
@@ -257,10 +257,10 @@
 __BEGIN_DECLS
 intmax_t imaxabs(intmax_t __i) __attribute_const__ __INTRODUCED_IN(19);
 imaxdiv_t imaxdiv(intmax_t __numerator, intmax_t __denominator) __attribute_const__ __INTRODUCED_IN(19);
-intmax_t strtoimax(const char* __s, char** __end_ptr, int __base);
-uintmax_t strtoumax(const char* __s, char** __end_ptr, int __base);
-intmax_t wcstoimax(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21);
-uintmax_t wcstoumax(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21);
+intmax_t strtoimax(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base);
+uintmax_t strtoumax(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, int __base);
+intmax_t wcstoimax(const wchar_t* _Nonnull __s, wchar_t* _Nullable * _Nullable __end_ptr, int __base) __INTRODUCED_IN(21);
+uintmax_t wcstoumax(const wchar_t* _Nonnull __s, wchar_t* _Nullable * _Nullable __end_ptr, int __base) __INTRODUCED_IN(21);
 __END_DECLS
 
 #endif
diff --git a/libc/include/langinfo.h b/libc/include/langinfo.h
index d9d8c15..2b43892 100644
--- a/libc/include/langinfo.h
+++ b/libc/include/langinfo.h
@@ -92,8 +92,8 @@
 #define NOEXPR 54
 #define CRNCYSTR 55
 
-char* nl_langinfo(nl_item __item) __INTRODUCED_IN(26);
-char* nl_langinfo_l(nl_item __item, locale_t __l) __INTRODUCED_IN(26);
+char* _Nonnull nl_langinfo(nl_item __item) __INTRODUCED_IN(26);
+char* _Nonnull nl_langinfo_l(nl_item __item, locale_t _Nonnull __l) __INTRODUCED_IN(26);
 
 __END_DECLS
 
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 40786fa..02bda60 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -40,7 +40,7 @@
  * Returns a pointer to the allocated memory on success and returns a null
  * pointer and sets `errno` on failure.
  */
-void* malloc(size_t __byte_count) __mallocfunc __BIONIC_ALLOC_SIZE(1) __wur;
+void* _Nullable malloc(size_t __byte_count) __mallocfunc __BIONIC_ALLOC_SIZE(1) __wur;
 
 /**
  * [calloc(3)](http://man7.org/linux/man-pages/man3/calloc.3.html) allocates
@@ -49,7 +49,7 @@
  * Returns a pointer to the allocated memory on success and returns a null
  * pointer and sets `errno` on failure.
  */
-void* calloc(size_t __item_count, size_t __item_size) __mallocfunc __BIONIC_ALLOC_SIZE(1,2) __wur;
+void* _Nullable calloc(size_t __item_count, size_t __item_size) __mallocfunc __BIONIC_ALLOC_SIZE(1,2) __wur;
 
 /**
  * [realloc(3)](http://man7.org/linux/man-pages/man3/realloc.3.html) resizes
@@ -58,7 +58,7 @@
  * Returns a pointer (which may be different from `__ptr`) to the resized
  * memory on success and returns a null pointer and sets `errno` on failure.
  */
-void* realloc(void* __ptr, size_t __byte_count) __BIONIC_ALLOC_SIZE(2) __wur;
+void* _Nullable realloc(void* _Nullable __ptr, size_t __byte_count) __BIONIC_ALLOC_SIZE(2) __wur;
 
 /**
  * [reallocarray(3)](http://man7.org/linux/man-pages/man3/realloc.3.html) resizes
@@ -70,13 +70,13 @@
  * Returns a pointer (which may be different from `__ptr`) to the resized
  * memory on success and returns a null pointer and sets `errno` on failure.
  */
-void* reallocarray(void* __ptr, size_t __item_count, size_t __item_size) __BIONIC_ALLOC_SIZE(2, 3) __wur __INTRODUCED_IN(29);
+void* _Nullable reallocarray(void* _Nullable __ptr, size_t __item_count, size_t __item_size) __BIONIC_ALLOC_SIZE(2, 3) __wur __INTRODUCED_IN(29);
 
 /**
  * [free(3)](http://man7.org/linux/man-pages/man3/free.3.html) deallocates
  * memory on the heap.
  */
-void free(void* __ptr);
+void free(void* _Nullable __ptr);
 
 /**
  * [memalign(3)](http://man7.org/linux/man-pages/man3/memalign.3.html) allocates
@@ -87,7 +87,7 @@
  *
  * See also posix_memalign().
  */
-void* memalign(size_t __alignment, size_t __byte_count) __mallocfunc __BIONIC_ALLOC_SIZE(2) __wur;
+void* _Nullable memalign(size_t __alignment, size_t __byte_count) __mallocfunc __BIONIC_ALLOC_SIZE(2) __wur;
 
 /**
  * [malloc_usable_size(3)](http://man7.org/linux/man-pages/man3/malloc_usable_size.3.html)
@@ -95,7 +95,7 @@
  *
  * Available since API level 17.
  */
-size_t malloc_usable_size(const void* __ptr) __INTRODUCED_IN(17);
+size_t malloc_usable_size(const void* _Nullable __ptr) __INTRODUCED_IN(17);
 
 #define __MALLINFO_BODY \
   /** Total number of non-mmapped bytes currently allocated from OS. */ \
@@ -168,7 +168,7 @@
  *
  * Available since API level 23.
  */
-int malloc_info(int __must_be_zero, FILE* __fp) __INTRODUCED_IN(23);
+int malloc_info(int __must_be_zero, FILE* _Nonnull __fp) __INTRODUCED_IN(23);
 
 /**
  * mallopt() option to set the decay time. Valid values are 0 and 1.
@@ -329,7 +329,7 @@
  *
  * See also: [extra documentation](https://android.googlesource.com/platform/bionic/+/master/libc/malloc_hooks/README.md)
  */
-extern void* (*volatile __malloc_hook)(size_t __byte_count, const void* __caller) __INTRODUCED_IN(28);
+extern void* _Nonnull (*volatile _Nonnull __malloc_hook)(size_t __byte_count, const void* _Nonnull __caller) __INTRODUCED_IN(28);
 
 /**
  * [__realloc_hook(3)](http://man7.org/linux/man-pages/man3/__realloc_hook.3.html)
@@ -340,7 +340,7 @@
  *
  * See also: [extra documentation](https://android.googlesource.com/platform/bionic/+/master/libc/malloc_hooks/README.md)
  */
-extern void* (*volatile __realloc_hook)(void* __ptr, size_t __byte_count, const void* __caller) __INTRODUCED_IN(28);
+extern void* _Nonnull (*volatile _Nonnull __realloc_hook)(void* _Nullable __ptr, size_t __byte_count, const void* _Nonnull __caller) __INTRODUCED_IN(28);
 
 /**
  * [__free_hook(3)](http://man7.org/linux/man-pages/man3/__free_hook.3.html)
@@ -351,7 +351,7 @@
  *
  * See also: [extra documentation](https://android.googlesource.com/platform/bionic/+/master/libc/malloc_hooks/README.md)
  */
-extern void (*volatile __free_hook)(void* __ptr, const void* __caller) __INTRODUCED_IN(28);
+extern void (*volatile _Nonnull __free_hook)(void* _Nullable __ptr, const void* _Nonnull __caller) __INTRODUCED_IN(28);
 
 /**
  * [__memalign_hook(3)](http://man7.org/linux/man-pages/man3/__memalign_hook.3.html)
@@ -362,6 +362,6 @@
  *
  * See also: [extra documentation](https://android.googlesource.com/platform/bionic/+/master/libc/malloc_hooks/README.md)
  */
-extern void* (*volatile __memalign_hook)(size_t __alignment, size_t __byte_count, const void* __caller) __INTRODUCED_IN(28);
+extern void* _Nonnull (*volatile _Nonnull __memalign_hook)(size_t __alignment, size_t __byte_count, const void* _Nonnull __caller) __INTRODUCED_IN(28);
 
 __END_DECLS
diff --git a/libc/include/math.h b/libc/include/math.h
index 040dc96..a5fa7c3 100644
--- a/libc/include/math.h
+++ b/libc/include/math.h
@@ -137,9 +137,9 @@
 float expm1f(float __x);
 long double expm1l(long double __x) __RENAME_LDBL(expm1, 3, 21);
 
-double frexp(double __x, int* __exponent);
-float frexpf(float __x, int* __exponent);
-long double frexpl(long double __x, int* __exponent) __RENAME_LDBL(frexp, 3, 21);
+double frexp(double __x, int* _Nonnull __exponent);
+float frexpf(float __x, int* _Nonnull __exponent);
+long double frexpl(long double __x, int* _Nonnull __exponent) __RENAME_LDBL(frexp, 3, 21);
 
 int ilogb(double __x) __attribute_const__;
 int ilogbf(float __x) __attribute_const__;
@@ -169,9 +169,9 @@
 float logbf(float __x);
 long double logbl(long double __x) __RENAME_LDBL(logb, 3, 18);
 
-double modf(double __x, double* __integral_part);
-float modff(float __x, float* __integral_part);
-long double modfl(long double __x, long double* __integral_part) __RENAME_LDBL(modf, 3, 21);
+double modf(double __x, double* _Nonnull __integral_part);
+float modff(float __x, float* _Nonnull __integral_part);
+long double modfl(long double __x, long double* _Nonnull __integral_part) __RENAME_LDBL(modf, 3, 21);
 
 double scalbn(double __x, int __exponent);
 float scalbnf(float __x, int __exponent);
@@ -266,17 +266,17 @@
 float remainderf(float __x, float __y);
 long double remainderl(long double __x, long double __y) __RENAME_LDBL(remainder, 3, 21);
 
-double remquo(double __x, double __y, int* __quotient_bits);
-float remquof(float __x, float __y, int* __quotient_bits);
-long double remquol(long double __x, long double __y, int* __quotient_bits) __RENAME_LDBL(remquo, 3, 21);
+double remquo(double __x, double __y, int* _Nonnull __quotient_bits);
+float remquof(float __x, float __y, int* _Nonnull __quotient_bits);
+long double remquol(long double __x, long double __y, int* _Nonnull __quotient_bits) __RENAME_LDBL(remquo, 3, 21);
 
 double copysign(double __value, double __sign) __attribute_const__;
 float copysignf(float __value, float __sign) __attribute_const__;
 long double copysignl(long double __value, long double __sign) __RENAME_LDBL(copysign, 3, 3) __attribute_const__;
 
-double nan(const char* __kind) __attribute_const__;
-float nanf(const char* __kind) __attribute_const__;
-long double nanl(const char* __kind) __RENAME_LDBL(nan, 13, 13) __attribute_const__;
+double nan(const char* _Nonnull __kind) __attribute_const__;
+float nanf(const char* _Nonnull __kind) __attribute_const__;
+long double nanl(const char* _Nonnull __kind) __RENAME_LDBL(nan, 13, 13) __attribute_const__;
 
 double nextafter(double __x, double __y);
 float nextafterf(float __x, float __y);
@@ -364,10 +364,10 @@
 double drem(double __x, double __y);
 int finite(double __x) __attribute_const__;
 int isnanf(float __x) __attribute_const__;
-double gamma_r(double __x, int* __sign);
-double lgamma_r(double __x, int* __sign);
+double gamma_r(double __x, int* _Nonnull __sign);
+double lgamma_r(double __x, int* _Nonnull __sign);
 double significand(double __x);
-long double lgammal_r(long double __x, int* __sign) __INTRODUCED_IN(23);
+long double lgammal_r(long double __x, int* _Nonnull __sign) __INTRODUCED_IN(23);
 long double significandl(long double __x) __INTRODUCED_IN(21);
 float dremf(float __x, float __y);
 int finitef(float __x) __attribute_const__;
@@ -379,12 +379,12 @@
 float y0f(float __x);
 float y1f(float __x);
 float ynf(int __n, float __x);
-float gammaf_r(float __x, int* __sign);
-float lgammaf_r(float __x, int* __sign);
+float gammaf_r(float __x, int* _Nonnull __sign);
+float lgammaf_r(float __x, int* _Nonnull __sign);
 float significandf(float __x);
-void sincos(double __x, double* __sin, double* __cos);
-void sincosf(float __x, float* __sin, float* __cos);
-void sincosl(long double __x, long double* __sin, long double* __cos);
+void sincos(double __x, double* _Nonnull __sin, double* _Nonnull __cos);
+void sincosf(float __x, float* _Nonnull __sin, float* _Nonnull __cos);
+void sincosl(long double __x, long double* _Nonnull __sin, long double* _Nonnull __cos);
 #endif
 
 /* GNU extensions. */
diff --git a/libc/include/nl_types.h b/libc/include/nl_types.h
index 1c80e4e..f4d7f43 100644
--- a/libc/include/nl_types.h
+++ b/libc/include/nl_types.h
@@ -62,7 +62,7 @@
  *
  * Available since API level 28.
  */
-nl_catd catopen(const char* __name, int __flag) __INTRODUCED_IN(26);
+nl_catd _Nonnull catopen(const char* _Nonnull __name, int __flag) __INTRODUCED_IN(26);
 
 /**
  * [catgets(3)](http://man7.org/linux/man-pages/man3/catgets.3.html) translates the given message
@@ -72,13 +72,13 @@
  *
  * Available since API level 28.
  */
-char* catgets(nl_catd __catalog, int __set_number, int __msg_number, const char* __msg) __INTRODUCED_IN(26);
+char* _Nonnull catgets(nl_catd _Nonnull __catalog, int __set_number, int __msg_number, const char* _Nonnull __msg) __INTRODUCED_IN(26);
 
 /**
  * [catclose(3)](http://man7.org/linux/man-pages/man3/catclose.3.html) closes a message catalog.
  *
  * On Android, this always returns -1 with `errno` set to `EBADF`.
  */
-int catclose(nl_catd __catalog) __INTRODUCED_IN(26);
+int catclose(nl_catd _Nonnull __catalog) __INTRODUCED_IN(26);
 
 __END_DECLS
diff --git a/libc/include/regex.h b/libc/include/regex.h
index be1418e..be33819 100644
--- a/libc/include/regex.h
+++ b/libc/include/regex.h
@@ -49,8 +49,8 @@
 typedef struct {
 	int re_magic;
 	size_t re_nsub;		/* number of parenthesized subexpressions */
-	const char * _Null_unspecified re_endp;	/* end pointer for REG_PEND */
-	struct re_guts * _Null_unspecified re_g;	/* none of your business :-) */
+	const char * __BIONIC_COMPLICATED_NULLNESS re_endp;	/* end pointer for REG_PEND */
+	struct re_guts * __BIONIC_COMPLICATED_NULLNESS re_g;	/* none of your business :-) */
 } regex_t;
 
 typedef struct {
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 532e4a5..edfcb5d 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -54,40 +54,40 @@
 int __libc_current_sigrtmin(void) __INTRODUCED_IN(21);
 int __libc_current_sigrtmax(void) __INTRODUCED_IN(21);
 
-extern const char* const sys_siglist[_NSIG];
-extern const char* const sys_signame[_NSIG]; /* BSD compatibility. */
+extern const char* _Nonnull const sys_siglist[_NSIG];
+extern const char* _Nonnull const sys_signame[_NSIG]; /* BSD compatibility. */
 
 #define si_timerid si_tid /* glibc compatibility. */
 
-int sigaction(int __signal, const struct sigaction* __new_action, struct sigaction* __old_action);
-int sigaction64(int __signal, const struct sigaction64* __new_action, struct sigaction64* __old_action) __INTRODUCED_IN(28);
+int sigaction(int __signal, const struct sigaction* _Nullable __new_action, struct sigaction* _Nullable __old_action);
+int sigaction64(int __signal, const struct sigaction64* _Nullable __new_action, struct sigaction64* _Nullable __old_action) __INTRODUCED_IN(28);
 
 int siginterrupt(int __signal, int __flag);
 
 #if __ANDROID_API__ >= 21
-sighandler_t signal(int __signal, sighandler_t __handler) __INTRODUCED_IN(21);
-int sigaddset(sigset_t* __set, int __signal) __INTRODUCED_IN(21);
-int sigaddset64(sigset64_t* __set, int __signal) __INTRODUCED_IN(28);
-int sigdelset(sigset_t* __set, int __signal) __INTRODUCED_IN(21);
-int sigdelset64(sigset64_t* __set, int __signal) __INTRODUCED_IN(28);
-int sigemptyset(sigset_t* __set) __INTRODUCED_IN(21);
-int sigemptyset64(sigset64_t* __set) __INTRODUCED_IN(28);
-int sigfillset(sigset_t* __set) __INTRODUCED_IN(21);
-int sigfillset64(sigset64_t* __set) __INTRODUCED_IN(28);
-int sigismember(const sigset_t* __set, int __signal) __INTRODUCED_IN(21);
-int sigismember64(const sigset64_t* __set, int __signal) __INTRODUCED_IN(28);
+sighandler_t _Nonnull signal(int __signal, sighandler_t _Nullable __handler) __INTRODUCED_IN(21);
+int sigaddset(sigset_t* _Nonnull __set, int __signal) __INTRODUCED_IN(21);
+int sigaddset64(sigset64_t* _Nonnull __set, int __signal) __INTRODUCED_IN(28);
+int sigdelset(sigset_t* _Nonnull __set, int __signal) __INTRODUCED_IN(21);
+int sigdelset64(sigset64_t* _Nonnull __set, int __signal) __INTRODUCED_IN(28);
+int sigemptyset(sigset_t* _Nonnull __set) __INTRODUCED_IN(21);
+int sigemptyset64(sigset64_t* _Nonnull __set) __INTRODUCED_IN(28);
+int sigfillset(sigset_t* _Nonnull __set) __INTRODUCED_IN(21);
+int sigfillset64(sigset64_t* _Nonnull __set) __INTRODUCED_IN(28);
+int sigismember(const sigset_t* _Nonnull __set, int __signal) __INTRODUCED_IN(21);
+int sigismember64(const sigset64_t* _Nonnull __set, int __signal) __INTRODUCED_IN(28);
 #else
 // Implemented as static inlines before 21.
 #endif
 
-int sigpending(sigset_t* __set);
-int sigpending64(sigset64_t* __set) __INTRODUCED_IN(28);
-int sigprocmask(int __how, const sigset_t* __new_set, sigset_t* __old_set);
-int sigprocmask64(int __how, const sigset64_t* __new_set, sigset64_t* __old_set) __INTRODUCED_IN(28);
-int sigsuspend(const sigset_t* __mask);
-int sigsuspend64(const sigset64_t* __mask) __INTRODUCED_IN(28);
-int sigwait(const sigset_t* __set, int* __signal);
-int sigwait64(const sigset64_t* __set, int* __signal) __INTRODUCED_IN(28);
+int sigpending(sigset_t* _Nonnull __set);
+int sigpending64(sigset64_t* _Nonnull __set) __INTRODUCED_IN(28);
+int sigprocmask(int __how, const sigset_t* _Nullable __new_set, sigset_t* _Nullable __old_set);
+int sigprocmask64(int __how, const sigset64_t* _Nullable __new_set, sigset64_t* _Nullable __old_set) __INTRODUCED_IN(28);
+int sigsuspend(const sigset_t* _Nonnull __mask);
+int sigsuspend64(const sigset64_t* _Nonnull __mask) __INTRODUCED_IN(28);
+int sigwait(const sigset_t* _Nonnull __set, int* _Nonnull __signal);
+int sigwait64(const sigset64_t* _Nonnull __set, int* _Nonnull __signal) __INTRODUCED_IN(28);
 
 int sighold(int __signal)
   __attribute__((deprecated("use sigprocmask() or pthread_sigmask() instead")))
@@ -99,7 +99,7 @@
 int sigrelse(int __signal)
   __attribute__((deprecated("use sigprocmask() or pthread_sigmask() instead")))
   __INTRODUCED_IN(26);
-sighandler_t sigset(int __signal, sighandler_t __handler)
+sighandler_t _Nonnull sigset(int __signal, sighandler_t _Nullable __handler)
   __attribute__((deprecated("use sigaction() instead"))) __INTRODUCED_IN(26);
 
 int raise(int __signal);
@@ -107,24 +107,24 @@
 int killpg(int __pgrp, int __signal);
 int tgkill(int __tgid, int __tid, int __signal);
 
-int sigaltstack(const stack_t* __new_signal_stack, stack_t* __old_signal_stack);
+int sigaltstack(const stack_t* _Nullable __new_signal_stack, stack_t*  _Nullable __old_signal_stack);
 
-void psiginfo(const siginfo_t* __info, const char* __msg) __INTRODUCED_IN(17);
-void psignal(int __signal, const char* __msg) __INTRODUCED_IN(17);
+void psiginfo(const siginfo_t* _Nonnull __info, const char* _Nullable __msg) __INTRODUCED_IN(17);
+void psignal(int __signal, const char* _Nullable __msg) __INTRODUCED_IN(17);
 
 int pthread_kill(pthread_t __pthread, int __signal);
 #if defined(__USE_GNU)
 int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(29);
 #endif
 
-int pthread_sigmask(int __how, const sigset_t* __new_set, sigset_t* __old_set);
-int pthread_sigmask64(int __how, const sigset64_t* __new_set, sigset64_t* __old_set) __INTRODUCED_IN(28);
+int pthread_sigmask(int __how, const sigset_t* _Nullable __new_set, sigset_t* _Nullable __old_set);
+int pthread_sigmask64(int __how, const sigset64_t* _Nullable __new_set, sigset64_t* _Nullable __old_set) __INTRODUCED_IN(28);
 
 int sigqueue(pid_t __pid, int __signal, const union sigval __value) __INTRODUCED_IN(23);
-int sigtimedwait(const sigset_t* __set, siginfo_t* __info, const struct timespec* __timeout) __INTRODUCED_IN(23);
-int sigtimedwait64(const sigset64_t* __set, siginfo_t* __info, const struct timespec* __timeout) __INTRODUCED_IN(28);
-int sigwaitinfo(const sigset_t* __set, siginfo_t* __info) __INTRODUCED_IN(23);
-int sigwaitinfo64(const sigset64_t* __set, siginfo_t* __info) __INTRODUCED_IN(28);
+int sigtimedwait(const sigset_t* _Nonnull __set, siginfo_t* _Nullable __info, const struct timespec* _Nullable __timeout) __INTRODUCED_IN(23);
+int sigtimedwait64(const sigset64_t* _Nonnull __set, siginfo_t* _Nullable __info, const struct timespec* _Nullable __timeout) __INTRODUCED_IN(28);
+int sigwaitinfo(const sigset_t* _Nonnull __set, siginfo_t* _Nullable __info) __INTRODUCED_IN(23);
+int sigwaitinfo64(const sigset64_t* _Nonnull __set, siginfo_t* _Nullable __info) __INTRODUCED_IN(28);
 
 __END_DECLS
 
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 5b9d99b..484757e 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -63,6 +63,14 @@
 #define __BIONIC_ALIGN(__value, __alignment) (((__value) + (__alignment)-1) & ~((__alignment)-1))
 
 /*
+ * The nullness constraints of this parameter or return value are
+ * quite complex. This is used to highlight spots where developers
+ * are encouraged to read relevant manuals or code to understand
+ * the full picture of nullness for this pointer.
+ */
+#define __BIONIC_COMPLICATED_NULLNESS _Null_unspecified
+
+/*
  * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
  * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
  * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
diff --git a/libc/include/sys/eventfd.h b/libc/include/sys/eventfd.h
index 1b6ad29..1ad11e3 100644
--- a/libc/include/sys/eventfd.h
+++ b/libc/include/sys/eventfd.h
@@ -62,7 +62,7 @@
  *
  * Returns 0 on success, or returns -1 otherwise.
  */
-int eventfd_read(int __fd, eventfd_t* __value);
+int eventfd_read(int __fd, eventfd_t* _Nonnull __value);
 
 /**
  * [eventfd_write(3)](http://man7.org/linux/man-pages/man2/eventfd.2.html) is a convenience
diff --git a/libc/include/sys/klog.h b/libc/include/sys/klog.h
index b33d11b..b60c2c4 100644
--- a/libc/include/sys/klog.h
+++ b/libc/include/sys/klog.h
@@ -66,6 +66,6 @@
  * This system call is not available to applications.
  * Use syslog() or `<android/log.h>` instead.
  */
-int klogctl(int __type, char* __buf, int __buf_size);
+int klogctl(int __type, char* __BIONIC_COMPLICATED_NULLNESS __buf, int __buf_size);
 
 __END_DECLS
diff --git a/libc/include/sys/quota.h b/libc/include/sys/quota.h
index f8faee7..79c653d 100644
--- a/libc/include/sys/quota.h
+++ b/libc/include/sys/quota.h
@@ -51,6 +51,6 @@
  *
  * Available since API level 26.
  */
-int quotactl(int __cmd, const char* __special, int __id, char* __addr) __INTRODUCED_IN(26);
+int quotactl(int __cmd, const char* _Nullable __special, int __id, char* __BIONIC_COMPLICATED_NULLNESS __addr) __INTRODUCED_IN(26);
 
 __END_DECLS
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index 623631e..53e3e26 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -136,20 +136,20 @@
 #define S_TYPEISSHM(__sb) 0
 #define S_TYPEISTMO(__sb) 0
 
-int chmod(const char* __path, mode_t __mode);
+int chmod(const char* _Nonnull __path, mode_t __mode);
 int fchmod(int __fd, mode_t __mode);
-int mkdir(const char* __path, mode_t __mode);
+int mkdir(const char* _Nonnull __path, mode_t __mode);
 
-int fstat(int __fd, struct stat* __buf);
-int fstat64(int __fd, struct stat64* __buf) __RENAME_STAT64(fstat, 3, 21);
-int fstatat(int __dir_fd, const char* __path, struct stat* __buf, int __flags);
-int fstatat64(int __dir_fd, const char* __path, struct stat64* __buf, int __flags) __RENAME_STAT64(fstatat, 3, 21);
-int lstat(const char* __path, struct stat* __buf);
-int lstat64(const char* __path, struct stat64* __buf) __RENAME_STAT64(lstat, 3, 21);
-int stat(const char* __path, struct stat* __buf);
-int stat64(const char* __path, struct stat64* __buf) __RENAME_STAT64(stat, 3, 21);
+int fstat(int __fd, struct stat* _Nonnull __buf);
+int fstat64(int __fd, struct stat64* _Nonnull __buf) __RENAME_STAT64(fstat, 3, 21);
+int fstatat(int __dir_fd, const char* _Nonnull __path, struct stat* _Nonnull __buf, int __flags);
+int fstatat64(int __dir_fd, const char* _Nonnull __path, struct stat64* _Nonnull __buf, int __flags) __RENAME_STAT64(fstatat, 3, 21);
+int lstat(const char* _Nonnull __path, struct stat* _Nonnull __buf);
+int lstat64(const char* _Nonnull __path, struct stat64* _Nonnull __buf) __RENAME_STAT64(lstat, 3, 21);
+int stat(const char* _Nonnull __path, struct stat* _Nonnull __buf);
+int stat64(const char* _Nonnull __path, struct stat64* _Nonnull __buf) __RENAME_STAT64(stat, 3, 21);
 
-int mknod(const char* __path, mode_t __mode, dev_t __dev);
+int mknod(const char* _Nonnull __path, mode_t __mode, dev_t __dev);
 mode_t umask(mode_t __mask);
 
 #if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
@@ -157,21 +157,58 @@
 #endif
 
 #if __ANDROID_API__ >= 21
-int mkfifo(const char* __path, mode_t __mode) __INTRODUCED_IN(21);
+int mkfifo(const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(21);
 #else
 // Implemented as a static inline before 21.
 #endif
 
-int mkfifoat(int __dir_fd, const char* __path, mode_t __mode) __INTRODUCED_IN(23);
+int mkfifoat(int __dir_fd, const char* _Nonnull __path, mode_t __mode) __INTRODUCED_IN(23);
 
-int fchmodat(int __dir_fd, const char* __path, mode_t __mode, int __flags);
-int mkdirat(int __dir_fd, const char* __path, mode_t __mode);
-int mknodat(int __dir_fd, const char* __path, mode_t __mode, dev_t __dev) __INTRODUCED_IN(21);
+int fchmodat(int __dir_fd, const char* _Nonnull __path, mode_t __mode, int __flags);
+int mkdirat(int __dir_fd, const char* _Nonnull __path, mode_t __mode);
+int mknodat(int __dir_fd, const char* _Nonnull __path, mode_t __mode, dev_t __dev) __INTRODUCED_IN(21);
 
+/**
+ * Used in the tv_nsec field of an argument to utimensat()/futimens()
+ * to set that time to the current time.
+ */
 #define UTIME_NOW  ((1L << 30) - 1L)
+
+/**
+ * Used in the tv_nsec field of an argument to utimensat()/futimens()
+ * to _not_ set that time.
+ */
 #define UTIME_OMIT ((1L << 30) - 2L)
-int utimensat(int __dir_fd, const char* __path, const struct timespec __times[2], int __flags);
-int futimens(int __dir_fd, const struct timespec __times[2]) __INTRODUCED_IN(19);
+
+/**
+ * [utimensat(2)](https://man7.org/linux/man-pages/man2/utimensat.2.html) sets
+ * file timestamps.
+ *
+ * Note: Linux supports `__path` being NULL (in which case `__dir_fd` need not
+ * be a directory), allowing futimens() to be implemented with utimensat().
+ * For normal use of utimensat(), though, `__path` should be non-null.
+ *
+ * `__times[0]` is the access time (atime), and `__times[1]` the last modification time (mtime).
+ * If `__times` is NULL, both times are set to the current time.
+ * See also UTIME_NOW and UTIME_OMIT.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
+int utimensat(int __dir_fd, const char* __BIONIC_COMPLICATED_NULLNESS __path, const struct timespec __times[_Nullable 2], int __flags);
+
+/**
+ * [futimens(2)](https://man7.org/linux/man-pages/man2/utimensat.2.html) sets
+ * the given file descriptor's timestamp.
+ *
+ * `__times[0]` is the access time (atime), and `__times[1]` the last modification time (mtime).
+ * If `__times` is NULL, both times are set to the current time.
+ * See also UTIME_NOW and UTIME_OMIT.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 19.
+ */
+int futimens(int __fd, const struct timespec __times[_Nullable 2]) __INTRODUCED_IN(19);
 
 #if defined(__USE_GNU)
 /**
@@ -179,8 +216,10 @@
  * extended file status information.
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 30.
  */
-int statx(int __dir_fd, const char* __path, int __flags, unsigned __mask, struct statx* __buf) __INTRODUCED_IN(30);
+int statx(int __dir_fd, const char* _Nonnull __path, int __flags, unsigned __mask, struct statx* _Nonnull __buf) __INTRODUCED_IN(30);
 #endif
 
 __END_DECLS
diff --git a/libc/include/sys/sysinfo.h b/libc/include/sys/sysinfo.h
index 4ecf986..cae5c49 100644
--- a/libc/include/sys/sysinfo.h
+++ b/libc/include/sys/sysinfo.h
@@ -43,7 +43,7 @@
  *
  * Returns 0 on success, and returns -1 and sets `errno` on failure.
  */
-int sysinfo(struct sysinfo* __info);
+int sysinfo(struct sysinfo* _Nonnull __info);
 
 /**
  * [get_nprocs_conf(3)](http://man7.org/linux/man-pages/man3/get_nprocs_conf.3.html) returns
diff --git a/libc/include/syslog.h b/libc/include/syslog.h
index 45de253..d89d769 100644
--- a/libc/include/syslog.h
+++ b/libc/include/syslog.h
@@ -133,9 +133,10 @@
 
 /**
  * [openlog(3)](http://man7.org/linux/man-pages/man3/openlog.3.html) sets
- * the log tag to `__prefix`. On Android, the other two arguments are ignored.
+ * the log tag to `__prefix`, which can be NULL to return to the default of
+ * getprogname(). On Android, the other two arguments are ignored.
  */
-void openlog(const char* __prefix, int __option, int __facility);
+void openlog(const char* _Nullable __prefix, int __option, int __facility);
 
 /**
  * [setlogmask(3)](http://man7.org/linux/man-pages/man3/setlogmask.3.html)
@@ -149,13 +150,13 @@
  * the printf()-like message and logs it with the given priority, unless
  * suppressed by setlogmask(). On Android, the output goes to logcat.
  */
-void syslog(int __priority, const char* __fmt, ...) __printflike(2, 3);
+void syslog(int __priority, const char* _Nonnull __fmt, ...) __printflike(2, 3);
 
 /**
  * [vsyslog(3)](http://man7.org/linux/man-pages/man3/vsyslog.3.html) formats
  * the vprintf()-like message and logs it with the given priority, unless
  * suppressed by setlogmask(). On Android, the output goes to logcat.
  */
-void vsyslog(int __priority, const char* __fmt, va_list __args) __printflike(2, 0);
+void vsyslog(int __priority, const char* _Nonnull __fmt, va_list __args) __printflike(2, 0);
 
 __END_DECLS
diff --git a/libc/include/termios.h b/libc/include/termios.h
index e3f388c..92ac24b 100644
--- a/libc/include/termios.h
+++ b/libc/include/termios.h
@@ -49,19 +49,19 @@
  * [cfgetispeed(3)](http://man7.org/linux/man-pages/man3/cfgetispeed.3.html)
  * returns the terminal input baud rate.
  */
-speed_t cfgetispeed(const struct termios* __t) __INTRODUCED_IN(21);
+speed_t cfgetispeed(const struct termios* _Nonnull __t) __INTRODUCED_IN(21);
 
 /**
  * [cfgetospeed(3)](http://man7.org/linux/man-pages/man3/cfgetospeed.3.html)
  * returns the terminal output baud rate.
  */
-speed_t cfgetospeed(const struct termios* __t) __INTRODUCED_IN(21);
+speed_t cfgetospeed(const struct termios* _Nonnull __t) __INTRODUCED_IN(21);
 
 /**
  * [cfmakeraw(3)](http://man7.org/linux/man-pages/man3/cfmakeraw.3.html)
  * configures the terminal for "raw" mode.
  */
-void cfmakeraw(struct termios* __t) __INTRODUCED_IN(21);
+void cfmakeraw(struct termios* _Nonnull __t) __INTRODUCED_IN(21);
 
 /**
  * [cfsetspeed(3)](http://man7.org/linux/man-pages/man3/cfsetspeed.3.html)
@@ -69,7 +69,7 @@
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
  */
-int cfsetspeed(struct termios* __t, speed_t __speed) __INTRODUCED_IN(21);
+int cfsetspeed(struct termios* _Nonnull __t, speed_t __speed) __INTRODUCED_IN(21);
 
 /**
  * [cfsetispeed(3)](http://man7.org/linux/man-pages/man3/cfsetispeed.3.html)
@@ -77,7 +77,7 @@
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
  */
-int cfsetispeed(struct termios* __t, speed_t __speed) __INTRODUCED_IN(21);
+int cfsetispeed(struct termios* _Nonnull _t, speed_t __speed) __INTRODUCED_IN(21);
 
 /**
  * [cfsetospeed(3)](http://man7.org/linux/man-pages/man3/cfsetospeed.3.html)
@@ -85,7 +85,7 @@
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
  */
-int cfsetospeed(struct termios* __t, speed_t __speed) __INTRODUCED_IN(21);
+int cfsetospeed(struct termios* _Nonnull __t, speed_t __speed) __INTRODUCED_IN(21);
 
 /**
  * [tcdrain(3)](http://man7.org/linux/man-pages/man3/tcdrain.3.html)
@@ -120,7 +120,7 @@
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
  */
-int tcgetattr(int __fd, struct termios* __t) __INTRODUCED_IN(21);
+int tcgetattr(int __fd, struct termios* _Nonnull __t) __INTRODUCED_IN(21);
 
 /**
  * [tcgetsid(3)](http://man7.org/linux/man-pages/man3/tcgetsid.3.html)
@@ -145,7 +145,7 @@
  *
  * Returns 0 on success and returns -1 and sets `errno` on failure.
  */
-int tcsetattr(int __fd, int __optional_actions, const struct termios* __t) __INTRODUCED_IN(21);
+int tcsetattr(int __fd, int __optional_actions, const struct termios* _Nonnull __t) __INTRODUCED_IN(21);
 
 #endif
 
diff --git a/libc/include/time.h b/libc/include/time.h
index 0db14ff..4b005c6 100644
--- a/libc/include/time.h
+++ b/libc/include/time.h
@@ -37,7 +37,7 @@
 
 #define CLOCKS_PER_SEC 1000000
 
-extern char* tzname[];
+extern char* _Nonnull tzname[];
 extern int daylight;
 extern long int timezone;
 
@@ -54,62 +54,64 @@
   int tm_yday;
   int tm_isdst;
   long int tm_gmtoff;
-  const char* tm_zone;
+  const char* _Nullable tm_zone;
 };
 
 #define TM_ZONE tm_zone
 
-time_t time(time_t* __t);
-int nanosleep(const struct timespec* __request, struct timespec* __remainder);
+time_t time(time_t* _Nullable __t);
+int nanosleep(const struct timespec* _Nonnull __request, struct timespec* _Nullable __remainder);
 
-char* asctime(const struct tm* __tm);
-char* asctime_r(const struct tm* __tm, char* __buf);
+char* _Nullable asctime(const struct tm* _Nonnull __tm);
+char* _Nullable asctime_r(const struct tm* _Nonnull __tm, char* _Nonnull __buf);
 
 double difftime(time_t __lhs, time_t __rhs);
-time_t mktime(struct tm* __tm);
+time_t mktime(struct tm* _Nonnull __tm);
 
-struct tm* localtime(const time_t* __t);
-struct tm* localtime_r(const time_t* __t, struct tm* __tm);
+struct tm* _Nullable localtime(const time_t* _Nonnull __t);
+struct tm* _Nullable localtime_r(const time_t* _Nonnull __t, struct tm* _Nonnull __tm);
 
-struct tm* gmtime(const time_t* __t);
-struct tm* gmtime_r(const time_t* __t, struct tm* __tm);
+struct tm* _Nullable gmtime(const time_t* _Nonnull __t);
+struct tm* _Nullable gmtime_r(const time_t* _Nonnull __t, struct tm* _Nonnull __tm);
 
-char* strptime(const char* __s, const char* __fmt, struct tm* __tm) __strftimelike(2);
-char* strptime_l(const char* __s, const char* __fmt, struct tm* __tm, locale_t __l) __strftimelike(2) __INTRODUCED_IN(28);
+char* _Nullable strptime(const char* _Nonnull __s, const char* _Nonnull __fmt, struct tm* _Nonnull __tm) __strftimelike(2);
+char* _Nullable strptime_l(const char* _Nonnull __s, const char* _Nonnull __fmt, struct tm* _Nonnull __tm, locale_t _Nonnull __l) __strftimelike(2) __INTRODUCED_IN(28);
 
-size_t strftime(char* __buf, size_t __n, const char* __fmt, const struct tm* __tm) __strftimelike(3);
+size_t strftime(char* _Nonnull __buf, size_t __n, const char* _Nonnull __fmt, const struct tm* _Nullable __tm) __strftimelike(3);
 #if __ANDROID_API__ >= 21
-size_t strftime_l(char* __buf, size_t __n, const char* __fmt, const struct tm* __tm, locale_t __l) __strftimelike(3) __INTRODUCED_IN(21);
+size_t strftime_l(char* _Nonnull __buf, size_t __n, const char* _Nonnull __fmt, const struct tm* _Nullable __tm, locale_t _Nonnull __l) __strftimelike(3) __INTRODUCED_IN(21);
 #else
 // Implemented as static inline before 21.
 #endif
 
-char* ctime(const time_t* __t);
-char* ctime_r(const time_t* __t, char* __buf);
+
+char* _Nullable ctime(const time_t* _Nonnull __t);
+char* _Nullable ctime_r(const time_t* _Nonnull __t, char* _Nonnull __buf);
 
 void tzset(void);
 
 clock_t clock(void);
 
-int clock_getcpuclockid(pid_t __pid, clockid_t* __clock) __INTRODUCED_IN(23);
+int clock_getcpuclockid(pid_t __pid, clockid_t* _Nonnull __clock) __INTRODUCED_IN(23);
 
-int clock_getres(clockid_t __clock, struct timespec* __resolution);
-int clock_gettime(clockid_t __clock, struct timespec* __ts);
-int clock_nanosleep(clockid_t __clock, int __flags, const struct timespec* __request, struct timespec* __remainder);
-int clock_settime(clockid_t __clock, const struct timespec* __ts);
 
-int timer_create(clockid_t __clock, struct sigevent* __event, timer_t* __timer_ptr);
-int timer_delete(timer_t __timer);
-int timer_settime(timer_t __timer, int __flags, const struct itimerspec* __new_value, struct itimerspec* __old_value);
-int timer_gettime(timer_t __timer, struct itimerspec* __ts);
-int timer_getoverrun(timer_t __timer);
+int clock_getres(clockid_t __clock, struct timespec* _Nullable __resolution);
+int clock_gettime(clockid_t __clock, struct timespec* _Nonnull __ts);
+int clock_nanosleep(clockid_t __clock, int __flags, const struct timespec* _Nonnull __request, struct timespec* _Nullable __remainder);
+int clock_settime(clockid_t __clock, const struct timespec* _Nonnull __ts);
+
+int timer_create(clockid_t __clock, struct sigevent* _Nullable __event, timer_t _Nonnull * _Nonnull __timer_ptr);
+int timer_delete(timer_t _Nonnull __timer);
+int timer_settime(timer_t _Nonnull __timer, int __flags, const struct itimerspec* _Nonnull __new_value, struct itimerspec* _Nullable __old_value);
+int timer_gettime(timer_t _Nonnull _timer, struct itimerspec* _Nonnull __ts);
+int timer_getoverrun(timer_t _Nonnull __timer);
 
 /* Non-standard extensions that are in the BSDs and glibc. */
-time_t timelocal(struct tm* __tm);
-time_t timegm(struct tm* __tm);
+time_t timelocal(struct tm* _Nonnull __tm);
+time_t timegm(struct tm* _Nonnull __tm);
 
 #define TIME_UTC 1
-int timespec_get(struct timespec* __ts, int __base) __INTRODUCED_IN(29);
+int timespec_get(struct timespec* _Nonnull __ts, int __base) __INTRODUCED_IN(29);
 
 __END_DECLS
 
diff --git a/libc/include/time64.h b/libc/include/time64.h
index 905669d..7d70030 100644
--- a/libc/include/time64.h
+++ b/libc/include/time64.h
@@ -47,17 +47,17 @@
 
 typedef int64_t time64_t;
 
-char* asctime64(const struct tm*);
-char* asctime64_r(const struct tm*, char*);
-char* ctime64(const time64_t*);
-char* ctime64_r(const time64_t*, char*);
-struct tm* gmtime64(const time64_t*);
-struct tm* gmtime64_r(const time64_t*, struct tm*);
-struct tm* localtime64(const time64_t*);
-struct tm* localtime64_r(const time64_t*, struct tm*);
-time64_t mktime64(const struct tm*);
-time64_t timegm64(const struct tm*);
-time64_t timelocal64(const struct tm*);
+char* _Nullable asctime64(const struct tm* _Nonnull);
+char* _Nullable asctime64_r(const struct tm* _Nonnull, char* _Nonnull);
+char* _Nullable ctime64(const time64_t* _Nonnull);
+char* _Nullable ctime64_r(const time64_t* _Nonnull, char* _Nonnull);
+struct tm* _Nullable gmtime64(const time64_t* _Nonnull);
+struct tm* _Nullable gmtime64_r(const time64_t* _Nonnull, struct tm* _Nonnull);
+struct tm* _Nullable localtime64(const time64_t* _Nonnull);
+struct tm* _Nullable localtime64_r(const time64_t* _Nonnull, struct tm* _Nonnull);
+time64_t mktime64(const struct tm* _Nonnull);
+time64_t timegm64(const struct tm* _Nonnull);
+time64_t timelocal64(const struct tm* _Nonnull);
 
 __END_DECLS
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 3efc9a2..566caaa 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -73,7 +73,7 @@
 #define _PC_PRIO_IO 18
 #define _PC_SYNC_IO 19
 
-extern char** environ;
+extern char* _Nullable * _Nullable environ;
 
 __noreturn void _exit(int __status);
 
@@ -89,15 +89,15 @@
 pid_t  getsid(pid_t __pid) __INTRODUCED_IN(17);
 pid_t  setsid(void);
 
-int execv(const char* __path, char* const* __argv);
-int execvp(const char* __file, char* const* __argv);
-int execvpe(const char* __file, char* const* __argv, char* const* __envp) __INTRODUCED_IN(21);
-int execve(const char* __file, char* const* __argv, char* const* __envp);
-int execl(const char* __path, const char* __arg0, ...) __attribute__((__sentinel__));
-int execlp(const char* __file, const char* __arg0, ...) __attribute__((__sentinel__));
-int execle(const char* __path, const char* __arg0, ... /*,  char* const* __envp */)
+int execv(const char* _Nonnull __path, char* _Nullable const* _Nullable __argv);
+int execvp(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv);
+int execvpe(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp) __INTRODUCED_IN(21);
+int execve(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp);
+int execl(const char* _Nonnull __path, const char* _Nullable __arg0, ...) __attribute__((__sentinel__));
+int execlp(const char* _Nonnull __file, const char* _Nullable __arg0, ...) __attribute__((__sentinel__));
+int execle(const char* _Nonnull __path, const char* _Nullable __arg0, ... /*,  char* const* __envp */)
     __attribute__((__sentinel__(1)));
-int fexecve(int __fd, char* const* __argv, char* const* __envp) __INTRODUCED_IN(28);
+int fexecve(int __fd, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp) __INTRODUCED_IN(28);
 
 int nice(int __incr);
 
@@ -193,40 +193,40 @@
 uid_t geteuid(void);
 gid_t getgid(void);
 gid_t getegid(void);
-int getgroups(int __size, gid_t* __list);
-int setgroups(size_t __size, const gid_t* __list);
-int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
-int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
-char* getlogin(void);
-int getlogin_r(char* __buffer, size_t __buffer_size) __INTRODUCED_IN(28);
+int getgroups(int __size, gid_t* _Nullable __list);
+int setgroups(size_t __size, const gid_t* _Nullable __list);
+int getresuid(uid_t* _Nonnull __ruid, uid_t* _Nonnull __euid, uid_t* _Nonnull __suid);
+int getresgid(gid_t* _Nonnull __rgid, gid_t* _Nonnull __egid, gid_t* _Nonnull __sgid);
+char* _Nullable getlogin(void);
+int getlogin_r(char* _Nonnull __buffer, size_t __buffer_size) __INTRODUCED_IN(28);
 
 long fpathconf(int __fd, int __name);
-long pathconf(const char* __path, int __name);
+long pathconf(const char* _Nonnull __path, int __name);
 
-int access(const char* __path, int __mode);
-int faccessat(int __dirfd, const char* __path, int __mode, int __flags);
-int link(const char* __old_path, const char* __new_path);
-int linkat(int __old_dir_fd, const char* __old_path, int __new_dir_fd, const char* __new_path, int __flags) __INTRODUCED_IN(21);
-int unlink(const char* __path);
-int unlinkat(int __dirfd, const char* __path, int __flags);
-int chdir(const char* __path);
+int access(const char* _Nonnull __path, int __mode);
+int faccessat(int __dirfd, const char* _Nonnull __path, int __mode, int __flags);
+int link(const char* _Nonnull __old_path, const char* _Nonnull __new_path);
+int linkat(int __old_dir_fd, const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path, int __flags) __INTRODUCED_IN(21);
+int unlink(const char* _Nonnull __path);
+int unlinkat(int __dirfd, const char* _Nonnull __path, int __flags);
+int chdir(const char* _Nonnull __path);
 int fchdir(int __fd);
-int rmdir(const char* __path);
-int pipe(int __fds[2]);
+int rmdir(const char* _Nonnull __path);
+int pipe(int __fds[_Nonnull 2]);
 #if defined(__USE_GNU)
-int pipe2(int __fds[2], int __flags);
+int pipe2(int __fds[_Nonnull 2], int __flags);
 #endif
-int chroot(const char* __path);
-int symlink(const char* __old_path, const char* __new_path);
-int symlinkat(const char* __old_path, int __new_dir_fd, const char* __new_path) __INTRODUCED_IN(21);
-ssize_t readlink(const char* __path, char* __buf, size_t __buf_size);
-ssize_t readlinkat(int __dir_fd, const char* __path, char* __buf, size_t __buf_size)
+int chroot(const char* _Nonnull __path);
+int symlink(const char* _Nonnull __old_path, const char* _Nonnull __new_path);
+int symlinkat(const char* _Nonnull __old_path, int __new_dir_fd, const char* _Nonnull __new_path) __INTRODUCED_IN(21);
+ssize_t readlink(const char* _Nonnull __path, char* _Nonnull __buf, size_t __buf_size);
+ssize_t readlinkat(int __dir_fd, const char* _Nonnull __path, char* _Nonnull __buf, size_t __buf_size)
     __INTRODUCED_IN(21);
-int chown(const char* __path, uid_t __owner, gid_t __group);
+int chown(const char* _Nonnull __path, uid_t __owner, gid_t __group);
 int fchown(int __fd, uid_t __owner, gid_t __group);
-int fchownat(int __dir_fd, const char* __path, uid_t __owner, gid_t __group, int __flags);
-int lchown(const char* __path, uid_t __owner, gid_t __group);
-char* getcwd(char* __buf, size_t __size);
+int fchownat(int __dir_fd, const char* _Nonnull __path, uid_t __owner, gid_t __group, int __flags);
+int lchown(const char* _Nonnull __path, uid_t __owner, gid_t __group);
+char* _Nullable getcwd(char* _Nullable __buf, size_t __size);
 
 void sync(void);
 #if defined(__USE_GNU)
@@ -235,8 +235,29 @@
 
 int close(int __fd);
 
-ssize_t read(int __fd, void* __buf, size_t __count);
-ssize_t write(int __fd, const void* __buf, size_t __count);
+/**
+ * [read(2)](https://man7.org/linux/man-pages/man2/read.2.html) reads
+ * up to `__count` bytes from file descriptor `__fd` into `__buf`.
+ *
+ * Note: `__buf` is not normally nullable, but may be null in the
+ * special case of a zero-length read(), which while not generally
+ * useful may be meaningful to some device drivers.
+ *
+ * Returns the number of bytes read on success, and returns -1 and sets `errno` on failure.
+ */
+ssize_t read(int __fd, void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);
+
+/**
+ * [write(2)](https://man7.org/linux/man-pages/man2/write.2.html) writes
+ * up to `__count` bytes to file descriptor `__fd` from `__buf`.
+ *
+ * Note: `__buf` is not normally nullable, but may be null in the
+ * special case of a zero-length write(), which while not generally
+ * useful may be meaningful to some device drivers.
+ *
+ * Returns the number of bytes written on success, and returns -1 and sets `errno` on failure.
+ */
+ssize_t write(int __fd, const void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);
 
 int dup(int __old_fd);
 int dup2(int __old_fd, int __new_fd);
@@ -246,23 +267,23 @@
 
 /* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
 #if defined(__USE_FILE_OFFSET64)
-int truncate(const char* __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
+int truncate(const char* _Nonnull __path, off_t __length) __RENAME(truncate64) __INTRODUCED_IN(21);
 off_t lseek(int __fd, off_t __offset, int __whence) __RENAME(lseek64);
-ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset) __RENAME(pread64);
-ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset) __RENAME(pwrite64);
+ssize_t pread(int __fd, void* _Nonnull __buf, size_t __count, off_t __offset) __RENAME(pread64);
+ssize_t pwrite(int __fd, const void* _Nonnull __buf, size_t __count, off_t __offset) __RENAME(pwrite64);
 int ftruncate(int __fd, off_t __length) __RENAME(ftruncate64);
 #else
-int truncate(const char* __path, off_t __length);
+int truncate(const char* _Nonnull __path, off_t __length);
 off_t lseek(int __fd, off_t __offset, int __whence);
-ssize_t pread(int __fd, void* __buf, size_t __count, off_t __offset);
-ssize_t pwrite(int __fd, const void* __buf, size_t __count, off_t __offset);
+ssize_t pread(int __fd, void* _Nonnull __buf, size_t __count, off_t __offset);
+ssize_t pwrite(int __fd, const void* _Nonnull __buf, size_t __count, off_t __offset);
 int ftruncate(int __fd, off_t __length);
 #endif
 
-int truncate64(const char* __path, off64_t __length) __INTRODUCED_IN(21);
+int truncate64(const char* _Nonnull __path, off64_t __length) __INTRODUCED_IN(21);
 off64_t lseek64(int __fd, off64_t __offset, int __whence);
-ssize_t pread64(int __fd, void* __buf, size_t __count, off64_t __offset);
-ssize_t pwrite64(int __fd, const void* __buf, size_t __count, off64_t __offset);
+ssize_t pread64(int __fd, void* _Nonnull __buf, size_t __count, off64_t __offset);
+ssize_t pwrite64(int __fd, const void* _Nonnull __buf, size_t __count, off64_t __offset);
 int ftruncate64(int __fd, off64_t __length);
 
 int pause(void);
@@ -270,17 +291,17 @@
 unsigned int sleep(unsigned int __seconds);
 int usleep(useconds_t __microseconds);
 
-int gethostname(char* __buf, size_t __buf_size);
-int sethostname(const char* __name, size_t __n) __INTRODUCED_IN(23);
+int gethostname(char* _Nonnull _buf, size_t __buf_size);
+int sethostname(const char* _Nonnull __name, size_t __n) __INTRODUCED_IN(23);
 
-int brk(void* __addr);
-void* sbrk(ptrdiff_t __increment);
+int brk(void* _Nonnull __addr);
+void* _Nullable sbrk(ptrdiff_t __increment);
 
 int isatty(int __fd);
-char* ttyname(int __fd);
-int ttyname_r(int __fd, char* __buf, size_t __buf_size);
+char* _Nullable ttyname(int __fd);
+int ttyname_r(int __fd, char* _Nonnull __buf, size_t __buf_size);
 
-int acct(const char* __path);
+int acct(const char* _Nullable __path);
 
 #if __ANDROID_API__ >= 21
 int getpagesize(void) __INTRODUCED_IN(21);
@@ -310,8 +331,8 @@
     } while (_rc == -1 && errno == EINTR); \
     _rc; })
 
-int getdomainname(char* __buf, size_t __buf_size) __INTRODUCED_IN(26);
-int setdomainname(const char* __name, size_t __n) __INTRODUCED_IN(26);
+int getdomainname(char* _Nonnull __buf, size_t __buf_size) __INTRODUCED_IN(26);
+int setdomainname(const char* _Nonnull __name, size_t __n) __INTRODUCED_IN(26);
 
 /**
  * [copy_file_range(2)](https://man7.org/linux/man-pages/man2/copy_file_range.2.html) copies
@@ -322,10 +343,10 @@
  * Returns the number of bytes copied on success, and returns -1 and sets
  * `errno` on failure.
  */
-ssize_t copy_file_range(int __fd_in, off64_t* __off_in, int __fd_out, off64_t* __off_out, size_t __length, unsigned int __flags) __INTRODUCED_IN(34);
+ssize_t copy_file_range(int __fd_in, off64_t* _Nullable __off_in, int __fd_out, off64_t* _Nullable __off_out, size_t __length, unsigned int __flags) __INTRODUCED_IN(34);
 
 #if __ANDROID_API__ >= 28
-void swab(const void* __src, void* __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
+void swab(const void* _Nonnull __src, void* _Nonnull __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
 #endif
 
 /**
diff --git a/libc/include/utmp.h b/libc/include/utmp.h
index cb72ce2..7aa5718 100644
--- a/libc/include/utmp.h
+++ b/libc/include/utmp.h
@@ -99,7 +99,7 @@
 /**
  * Does nothing.
  */
-int utmpname(const char* __path);
+int utmpname(const char* _Nonnull __path);
 /**
  * Does nothing.
  */
@@ -107,11 +107,11 @@
 /**
  * Does nothing.
  */
-struct utmp* getutent(void);
+struct utmp* _Nullable getutent(void);
 /**
  * Does nothing.
  */
-struct utmp* pututline(const struct utmp* __entry);
+struct utmp* _Nullable pututline(const struct utmp* _Nonnull __entry);
 /**
  * Does nothing.
  */
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index e7a157e..373d497 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -176,6 +176,11 @@
         "bionic_libc_platform_headers",
     ],
 
+    // The clang-analyzer-unix.Malloc and other warnings in these
+    // unit tests are either false positive or in
+    // negative tests that can be ignored.
+    tidy: false,
+
     srcs: [
         "tests/malloc_debug_system_tests.cpp",
     ],
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 6a81277..be577bc 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -87,35 +87,65 @@
         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
     },
     {
+        "bt_sz",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceSize},
+    },
+    {
         "backtrace_min_size",
         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
     },
     {
+        "bt_min_sz",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMinSize},
+    },
+    {
         "backtrace_max_size",
         {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
     },
-
+    {
+        "bt_max_sz",
+        {BACKTRACE_SPECIFIC_SIZES, &Config::SetBacktraceMaxSize},
+    },
     {
         "backtrace",
         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
     },
     {
+        "bt",
+        {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktrace},
+    },
+    {
         "backtrace_enable_on_signal",
         {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
     },
-
+    {
+        "bt_en_on_sig",
+        {BACKTRACE | TRACK_ALLOCS, &Config::SetBacktraceEnableOnSignal},
+    },
     {
         "backtrace_dump_on_exit",
         {0, &Config::SetBacktraceDumpOnExit},
     },
     {
+        "bt_dmp_on_ex",
+        {0, &Config::SetBacktraceDumpOnExit},
+    },
+    {
         "backtrace_dump_prefix",
         {0, &Config::SetBacktraceDumpPrefix},
     },
     {
+        "bt_dmp_pre",
+        {0, &Config::SetBacktraceDumpPrefix},
+    },
+    {
         "backtrace_full",
         {BACKTRACE_FULL, &Config::VerifyValueEmpty},
     },
+    {
+        "bt_full",
+        {BACKTRACE_FULL, &Config::VerifyValueEmpty},
+    },
 
     {
         "fill",
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index 3667624..fddc4a3 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -200,6 +200,20 @@
 that is extra thorough and can unwind through Java frames. This will run
 slower than the normal backtracing function.
 
+### bt, bt\_dmp\_on\_ex, bt\_dmp\_pre, bt\_en\_on\_sig, bt\_full, bt\_max\_sz, bt\_min\_sz, bt\_sz
+As of U, add shorter aliases for backtrace related options to avoid property length restrictions.
+
+| Alias           | Option                        |
+|:----------------|:------------------------------|
+| bt              | backtrace                     |
+| bt\_dmp\_on\_ex | backtrace\_dump\_on\_exit     |
+| bt\_dmp\_pre    | backtrace\_dump\_prefix       |
+| bt\_en\_on\_sig | backtrace\_enable\_on\_signal |
+| bt\_full        | backtrace\_full               |
+| bt\_max\_sz     | backtrace\_max\_size          |
+| bt\_min\_sz     | backtrace\_min\_size          |
+| bt\_sz          | backtrace\_size               |
+
 ### check\_unreachable\_on\_signal
 As of Android U, this option will trigger a check for unreachable memory
 in a process. Specifically, if the signal SIGRTMAX - 16 (which is 48 on
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index a829a09..8a77170 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -28,6 +28,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <pthread.h>
 #include <stdatomic.h>
 #include <stdint.h>
@@ -52,40 +53,51 @@
   return dprintf(fd, "%d: thread_done 0x0\n", tid_) > 0;
 }
 
-AllocEntry::AllocEntry(void* pointer) : pointer_(pointer) {}
+AllocEntry::AllocEntry(void* pointer, uint64_t start_ns, uint64_t end_ns)
+    : pointer_(pointer), start_ns_(start_ns), end_ns_(end_ns) {}
 
-MallocEntry::MallocEntry(void* pointer, size_t size) : AllocEntry(pointer), size_(size) {}
+MallocEntry::MallocEntry(void* pointer, size_t size, uint64_t start_ns, uint64_t end_ns)
+    : AllocEntry(pointer, start_ns, end_ns), size_(size) {}
 
 bool MallocEntry::Write(int fd) const {
-  return dprintf(fd, "%d: malloc %p %zu\n", tid_, pointer_, size_) > 0;
+  return dprintf(fd, "%d: malloc %p %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, size_,
+                 start_ns_, end_ns_) > 0;
 }
 
-FreeEntry::FreeEntry(void* pointer) : AllocEntry(pointer) {}
+FreeEntry::FreeEntry(void* pointer, uint64_t start_ns, uint64_t end_ns)
+    : AllocEntry(pointer, start_ns, end_ns) {}
 
 bool FreeEntry::Write(int fd) const {
-  return dprintf(fd, "%d: free %p\n", tid_, pointer_) > 0;
+  return dprintf(fd, "%d: free %p %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, start_ns_, end_ns_) >
+         0;
 }
 
-CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size)
-    : MallocEntry(pointer, size), nmemb_(nmemb) {}
+CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size, uint64_t start_ns,
+                         uint64_t end_ns)
+    : MallocEntry(pointer, size, start_ns, end_ns), nmemb_(nmemb) {}
 
 bool CallocEntry::Write(int fd) const {
-  return dprintf(fd, "%d: calloc %p %zu %zu\n", tid_, pointer_, nmemb_, size_) > 0;
+  return dprintf(fd, "%d: calloc %p %zu %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, nmemb_,
+                 size_, start_ns_, end_ns_) > 0;
 }
 
-ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer)
-    : MallocEntry(pointer, size), old_pointer_(old_pointer) {}
+ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer, uint64_t start_ns,
+                           uint64_t end_ns)
+    : MallocEntry(pointer, size, start_ns, end_ns), old_pointer_(old_pointer) {}
 
 bool ReallocEntry::Write(int fd) const {
-  return dprintf(fd, "%d: realloc %p %p %zu\n", tid_, pointer_, old_pointer_, size_) > 0;
+  return dprintf(fd, "%d: realloc %p %p %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_,
+                 old_pointer_, size_, start_ns_, end_ns_) > 0;
 }
 
 // aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
-MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment)
-    : MallocEntry(pointer, size), alignment_(alignment) {}
+MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment, uint64_t start_ns,
+                             uint64_t end_ns)
+    : MallocEntry(pointer, size, start_ns, end_ns), alignment_(alignment) {}
 
 bool MemalignEntry::Write(int fd) const {
-  return dprintf(fd, "%d: memalign %p %zu %zu\n", tid_, pointer_, alignment_, size_) > 0;
+  return dprintf(fd, "%d: memalign %p %zu %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_,
+                 alignment_, size_, start_ns_, end_ns_) > 0;
 }
 
 struct ThreadData {
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index 43dba6a..a02c956 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -68,19 +68,23 @@
 
 class AllocEntry : public RecordEntry {
  public:
-  explicit AllocEntry(void* pointer);
+  explicit AllocEntry(void* pointer, uint64_t st, uint64_t et);
   virtual ~AllocEntry() = default;
 
  protected:
   void* pointer_;
 
+  // The start/end time of this operation.
+  uint64_t start_ns_;
+  uint64_t end_ns_;
+
  private:
   BIONIC_DISALLOW_COPY_AND_ASSIGN(AllocEntry);
 };
 
 class MallocEntry : public AllocEntry {
  public:
-  MallocEntry(void* pointer, size_t size);
+  MallocEntry(void* pointer, size_t size, uint64_t st, uint64_t et);
   virtual ~MallocEntry() = default;
 
   bool Write(int fd) const override;
@@ -94,7 +98,7 @@
 
 class FreeEntry : public AllocEntry {
  public:
-  explicit FreeEntry(void* pointer);
+  explicit FreeEntry(void* pointer, uint64_t st, uint64_t et);
   virtual ~FreeEntry() = default;
 
   bool Write(int fd) const override;
@@ -105,7 +109,7 @@
 
 class CallocEntry : public MallocEntry {
  public:
-  CallocEntry(void* pointer, size_t size, size_t nmemb);
+  CallocEntry(void* pointer, size_t nmemb, size_t size, uint64_t st, uint64_t et);
   virtual ~CallocEntry() = default;
 
   bool Write(int fd) const override;
@@ -119,7 +123,7 @@
 
 class ReallocEntry : public MallocEntry {
  public:
-  ReallocEntry(void* pointer, size_t size, void* old_pointer);
+  ReallocEntry(void* pointer, size_t size, void* old_pointer, uint64_t st, uint64_t et);
   virtual ~ReallocEntry() = default;
 
   bool Write(int fd) const override;
@@ -134,7 +138,7 @@
 // aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
 class MemalignEntry : public MallocEntry {
  public:
-  MemalignEntry(void* pointer, size_t size, size_t alignment);
+  MemalignEntry(void* pointer, size_t size, size_t alignment, uint64_t st, uint64_t et);
   virtual ~MemalignEntry() = default;
 
   bool Write(int fd) const override;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 617858a..7b0f599 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -68,6 +68,100 @@
 bool* g_zygote_child;
 
 const MallocDispatch* g_dispatch;
+
+static __always_inline uint64_t Nanotime() {
+  struct timespec t = {};
+  clock_gettime(CLOCK_MONOTONIC, &t);
+  return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+
+namespace {
+// A TimedResult contains the result of from malloc end_ns al. functions and the
+// start/end timestamps.
+struct TimedResult {
+  uint64_t start_ns = 0;
+  uint64_t end_ns = 0;
+  union {
+    size_t s;
+    int i;
+    void* p;
+  } v;
+
+  uint64_t GetStartTimeNS() const { return start_ns; }
+  uint64_t GetEndTimeNS() const { return end_ns; }
+  void SetStartTimeNS(uint64_t t) { start_ns = t; }
+  void SetEndTimeNS(uint64_t t) { end_ns = t; }
+
+  template <typename T>
+  void setValue(T);
+  template <>
+  void setValue(size_t s) {
+    v.s = s;
+  }
+  template <>
+  void setValue(int i) {
+    v.i = i;
+  }
+  template <>
+  void setValue(void* p) {
+    v.p = p;
+  }
+
+  template <typename T>
+  T getValue() const;
+  template <>
+  size_t getValue<size_t>() const {
+    return v.s;
+  }
+  template <>
+  int getValue<int>() const {
+    return v.i;
+  }
+  template <>
+  void* getValue<void*>() const {
+    return v.p;
+  }
+};
+
+class ScopedTimer {
+ public:
+  ScopedTimer(TimedResult& res) : res_(res) { res_.start_ns = Nanotime(); }
+
+  ~ScopedTimer() { res_.end_ns = Nanotime(); }
+
+ private:
+  TimedResult& res_;
+};
+
+}  // namespace
+
+template <typename MallocFn, typename... Args>
+static TimedResult TimerCall(MallocFn fn, Args... args) {
+  TimedResult ret;
+  decltype((g_dispatch->*fn)(args...)) r;
+  if (g_debug->config().options() & RECORD_ALLOCS) {
+    ScopedTimer t(ret);
+    r = (g_dispatch->*fn)(args...);
+  } else {
+    r = (g_dispatch->*fn)(args...);
+  }
+  ret.setValue<decltype(r)>(r);
+  return ret;
+}
+
+template <typename MallocFn, typename... Args>
+static TimedResult TimerCallVoid(MallocFn fn, Args... args) {
+  TimedResult ret;
+  {
+    ScopedTimer t(ret);
+    (g_dispatch->*fn)(args...);
+  }
+  return ret;
+}
+
+#define TCALL(FUNC, ...) TimerCall(&MallocDispatch::FUNC, __VA_ARGS__);
+#define TCALLVOID(FUNC, ...) TimerCallVoid(&MallocDispatch::FUNC, __VA_ARGS__);
+
 // ------------------------------------------------------------------------
 
 // ------------------------------------------------------------------------
@@ -400,6 +494,9 @@
 
 void debug_free_malloc_leak_info(uint8_t* info) {
   g_dispatch->free(info);
+  // Purge the memory that was freed since a significant amount of
+  // memory could have been allocated and freed.
+  g_dispatch->mallopt(M_PURGE, 0);
 }
 
 size_t debug_malloc_usable_size(void* pointer) {
@@ -419,7 +516,7 @@
   return InternalMallocUsableSize(pointer);
 }
 
-static void* InternalMalloc(size_t size) {
+static TimedResult InternalMalloc(size_t size) {
   if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
     debug_dump_heap(android::base::StringPrintf(
                         "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
@@ -430,30 +527,35 @@
     size = 1;
   }
 
+  TimedResult result;
+
   size_t real_size = size + g_debug->extra_bytes();
   if (real_size < size) {
     // Overflow.
     errno = ENOMEM;
-    return nullptr;
+    result.setValue<void*>(nullptr);
+    return result;
   }
 
   if (size > PointerInfoType::MaxSize()) {
     errno = ENOMEM;
-    return nullptr;
+    result.setValue<void*>(nullptr);
+    return result;
   }
 
-  void* pointer;
   if (g_debug->HeaderEnabled()) {
-    Header* header =
-        reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+    result = TCALL(memalign, MINIMUM_ALIGNMENT_BYTES, real_size);
+    Header* header = reinterpret_cast<Header*>(result.getValue<void*>());
     if (header == nullptr) {
-      return nullptr;
+      return result;
     }
-    pointer = InitHeader(header, header, size);
+    result.setValue<void*>(InitHeader(header, header, size));
   } else {
-    pointer = g_dispatch->malloc(real_size);
+    result = TCALL(malloc, real_size);
   }
 
+  void* pointer = result.getValue<void*>();
+
   if (pointer != nullptr) {
     if (g_debug->TrackPointers()) {
       PointerData::Add(pointer, size);
@@ -466,7 +568,8 @@
       memset(pointer, g_debug->config().fill_alloc_value(), bytes);
     }
   }
-  return pointer;
+
+  return result;
 }
 
 void* debug_malloc(size_t size) {
@@ -479,16 +582,17 @@
   ScopedDisableDebugCalls disable;
   ScopedBacktraceSignalBlocker blocked;
 
-  void* pointer = InternalMalloc(size);
+  TimedResult result = InternalMalloc(size);
 
   if (g_debug->config().options() & RECORD_ALLOCS) {
-    g_debug->record->AddEntry(new MallocEntry(pointer, size));
+    g_debug->record->AddEntry(new MallocEntry(result.getValue<void*>(), size,
+                                              result.GetStartTimeNS(), result.GetEndTimeNS()));
   }
 
-  return pointer;
+  return result.getValue<void*>();
 }
 
-static void InternalFree(void* pointer) {
+static TimedResult InternalFree(void* pointer) {
   if ((g_debug->config().options() & BACKTRACE) && g_debug->pointer->ShouldDumpAndReset()) {
     debug_dump_heap(android::base::StringPrintf(
                         "%s.%d.txt", g_debug->config().backtrace_dump_prefix().c_str(), getpid())
@@ -530,6 +634,7 @@
     PointerData::Remove(pointer);
   }
 
+  TimedResult result;
   if (g_debug->config().options() & FREE_TRACK) {
     // Do not add the allocation until we are done modifying the pointer
     // itself. This avoids a race if a lot of threads are all doing
@@ -537,15 +642,15 @@
     // pointer from another thread, while still trying to free it in
     // this function.
     pointer = PointerData::AddFreed(pointer, bytes);
-    if (pointer != nullptr) {
-      if (g_debug->HeaderEnabled()) {
-        pointer = g_debug->GetHeader(pointer)->orig_pointer;
-      }
-      g_dispatch->free(pointer);
+    if (pointer != nullptr && g_debug->HeaderEnabled()) {
+      pointer = g_debug->GetHeader(pointer)->orig_pointer;
     }
+    result = TCALLVOID(free, pointer);
   } else {
-    g_dispatch->free(free_pointer);
+    result = TCALLVOID(free, free_pointer);
   }
+
+  return result;
 }
 
 void debug_free(void* pointer) {
@@ -558,15 +663,16 @@
   ScopedDisableDebugCalls disable;
   ScopedBacktraceSignalBlocker blocked;
 
-  if (g_debug->config().options() & RECORD_ALLOCS) {
-    g_debug->record->AddEntry(new FreeEntry(pointer));
-  }
-
   if (!VerifyPointer(pointer, "free")) {
     return;
   }
 
-  InternalFree(pointer);
+  TimedResult result = InternalFree(pointer);
+
+  if (g_debug->config().options() & RECORD_ALLOCS) {
+    g_debug->record->AddEntry(
+        new FreeEntry(pointer, result.GetStartTimeNS(), result.GetEndTimeNS()));
+  }
 }
 
 void* debug_memalign(size_t alignment, size_t bytes) {
@@ -588,6 +694,7 @@
     return nullptr;
   }
 
+  TimedResult result;
   void* pointer;
   if (g_debug->HeaderEnabled()) {
     // Make the alignment a power of two.
@@ -610,7 +717,8 @@
       return nullptr;
     }
 
-    pointer = g_dispatch->malloc(real_size);
+    result = TCALL(malloc, real_size);
+    pointer = result.getValue<void*>();
     if (pointer == nullptr) {
       return nullptr;
     }
@@ -620,6 +728,7 @@
     value += (-value % alignment);
 
     Header* header = g_debug->GetHeader(reinterpret_cast<void*>(value));
+    // Don't need to update `result` here because we only need the timestamps.
     pointer = InitHeader(header, pointer, bytes);
   } else {
     size_t real_size = bytes + g_debug->extra_bytes();
@@ -628,7 +737,8 @@
       errno = ENOMEM;
       return nullptr;
     }
-    pointer = g_dispatch->memalign(alignment, real_size);
+    result = TCALL(memalign, alignment, real_size);
+    pointer = result.getValue<void*>();
   }
 
   if (pointer != nullptr) {
@@ -644,7 +754,8 @@
     }
 
     if (g_debug->config().options() & RECORD_ALLOCS) {
-      g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment));
+      g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment,
+                                                  result.GetStartTimeNS(), result.GetEndTimeNS()));
     }
   }
 
@@ -662,10 +773,12 @@
   ScopedBacktraceSignalBlocker blocked;
 
   if (pointer == nullptr) {
-    pointer = InternalMalloc(bytes);
+    TimedResult result = InternalMalloc(bytes);
     if (g_debug->config().options() & RECORD_ALLOCS) {
-      g_debug->record->AddEntry(new ReallocEntry(pointer, bytes, nullptr));
+      g_debug->record->AddEntry(new ReallocEntry(result.getValue<void*>(), bytes, nullptr,
+                                                 result.GetStartTimeNS(), result.GetEndTimeNS()));
     }
+    pointer = result.getValue<void*>();
     return pointer;
   }
 
@@ -674,11 +787,13 @@
   }
 
   if (bytes == 0) {
+    TimedResult result = InternalFree(pointer);
+
     if (g_debug->config().options() & RECORD_ALLOCS) {
-      g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer));
+      g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer, result.GetStartTimeNS(),
+                                                 result.GetEndTimeNS()));
     }
 
-    InternalFree(pointer);
     return nullptr;
   }
 
@@ -697,6 +812,7 @@
     return nullptr;
   }
 
+  TimedResult result;
   void* new_pointer;
   size_t prev_size;
   if (g_debug->HeaderEnabled()) {
@@ -730,7 +846,8 @@
     }
 
     // Allocate the new size.
-    new_pointer = InternalMalloc(bytes);
+    result = InternalMalloc(bytes);
+    new_pointer = result.getValue<void*>();
     if (new_pointer == nullptr) {
       errno = ENOMEM;
       return nullptr;
@@ -738,14 +855,18 @@
 
     prev_size = header->usable_size;
     memcpy(new_pointer, pointer, prev_size);
-    InternalFree(pointer);
+    TimedResult free_time = InternalFree(pointer);
+    // `realloc` is split into two steps, update the end time to the finish time
+    // of the second operation.
+    result.SetEndTimeNS(free_time.GetEndTimeNS());
   } else {
     if (g_debug->TrackPointers()) {
       PointerData::Remove(pointer);
     }
 
     prev_size = g_dispatch->malloc_usable_size(pointer);
-    new_pointer = g_dispatch->realloc(pointer, real_size);
+    result = TCALL(realloc, pointer, real_size);
+    new_pointer = result.getValue<void*>();
     if (new_pointer == nullptr) {
       return nullptr;
     }
@@ -767,7 +888,8 @@
   }
 
   if (g_debug->config().options() & RECORD_ALLOCS) {
-    g_debug->record->AddEntry(new ReallocEntry(new_pointer, bytes, pointer));
+    g_debug->record->AddEntry(new ReallocEntry(new_pointer, bytes, pointer, result.GetStartTimeNS(),
+                                               result.GetEndTimeNS()));
   }
 
   return new_pointer;
@@ -807,21 +929,24 @@
   }
 
   void* pointer;
+  TimedResult result;
   if (g_debug->HeaderEnabled()) {
     // Need to guarantee the alignment of the header.
-    Header* header =
-        reinterpret_cast<Header*>(g_dispatch->memalign(MINIMUM_ALIGNMENT_BYTES, real_size));
+    result = TCALL(memalign, MINIMUM_ALIGNMENT_BYTES, real_size);
+    Header* header = reinterpret_cast<Header*>(result.getValue<void*>());
     if (header == nullptr) {
       return nullptr;
     }
     memset(header, 0, g_dispatch->malloc_usable_size(header));
     pointer = InitHeader(header, header, size);
   } else {
-    pointer = g_dispatch->calloc(1, real_size);
+    result = TCALL(calloc, 1, real_size);
+    pointer = result.getValue<void*>();
   }
 
   if (g_debug->config().options() & RECORD_ALLOCS) {
-    g_debug->record->AddEntry(new CallocEntry(pointer, bytes, nmemb));
+    g_debug->record->AddEntry(
+        new CallocEntry(pointer, nmemb, bytes, result.GetStartTimeNS(), result.GetEndTimeNS()));
   }
 
   if (pointer != nullptr && g_debug->TrackPointers()) {
@@ -995,6 +1120,10 @@
     dprintf(fd, "%s", content.c_str());
   }
   dprintf(fd, "END\n");
+
+  // Purge the memory that was allocated and freed during this operation
+  // since it can be large enough to expand the RSS significantly.
+  g_dispatch->mallopt(M_PURGE, 0);
 }
 
 bool debug_write_malloc_leak_info(FILE* fp) {
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index 0a0eaef..bc7af6d 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -215,6 +215,13 @@
   ASSERT_FALSE(config->backtrace_enable_on_signal());
   ASSERT_FALSE(config->backtrace_dump_on_exit());
 
+  ASSERT_TRUE(InitConfig("bt=23")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+  ASSERT_EQ(23U, config->backtrace_frames());
+  ASSERT_TRUE(config->backtrace_enabled());
+  ASSERT_FALSE(config->backtrace_enable_on_signal());
+  ASSERT_FALSE(config->backtrace_dump_on_exit());
+
   ASSERT_TRUE(InitConfig("backtrace")) << getFakeLogPrint();
   ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(16U, config->backtrace_frames());
@@ -222,6 +229,13 @@
   ASSERT_FALSE(config->backtrace_enable_on_signal());
   ASSERT_FALSE(config->backtrace_dump_on_exit());
 
+  ASSERT_TRUE(InitConfig("bt")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+  ASSERT_EQ(16U, config->backtrace_frames());
+  ASSERT_TRUE(config->backtrace_enabled());
+  ASSERT_FALSE(config->backtrace_enable_on_signal());
+  ASSERT_FALSE(config->backtrace_dump_on_exit());
+
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
@@ -234,6 +248,13 @@
   ASSERT_TRUE(config->backtrace_enable_on_signal());
   ASSERT_FALSE(config->backtrace_dump_on_exit());
 
+  ASSERT_TRUE(InitConfig("bt_en_on_sig=64")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+  ASSERT_EQ(64U, config->backtrace_frames());
+  ASSERT_FALSE(config->backtrace_enabled());
+  ASSERT_TRUE(config->backtrace_enable_on_signal());
+  ASSERT_FALSE(config->backtrace_dump_on_exit());
+
   ASSERT_TRUE(InitConfig("backtrace_enable_on_signal")) << getFakeLogPrint();
   ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
   ASSERT_EQ(16U, config->backtrace_frames());
@@ -241,6 +262,13 @@
   ASSERT_TRUE(config->backtrace_enable_on_signal());
   ASSERT_FALSE(config->backtrace_dump_on_exit());
 
+  ASSERT_TRUE(InitConfig("bt_en_on_sig")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE | TRACK_ALLOCS, config->options());
+  ASSERT_EQ(16U, config->backtrace_frames());
+  ASSERT_FALSE(config->backtrace_enabled());
+  ASSERT_TRUE(config->backtrace_enable_on_signal());
+  ASSERT_FALSE(config->backtrace_dump_on_exit());
+
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
@@ -288,6 +316,10 @@
   ASSERT_EQ(0U, config->options());
   ASSERT_TRUE(config->backtrace_dump_on_exit());
 
+  ASSERT_TRUE(InitConfig("bt_dmp_on_ex")) << getFakeLogPrint();
+  ASSERT_EQ(0U, config->options());
+  ASSERT_TRUE(config->backtrace_dump_on_exit());
+
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
@@ -307,10 +339,18 @@
   ASSERT_EQ(0U, config->options());
   ASSERT_EQ("/data/local/tmp/backtrace_heap", config->backtrace_dump_prefix());
 
+  ASSERT_TRUE(InitConfig("bt_dmp_pre")) << getFakeLogPrint();
+  ASSERT_EQ(0U, config->options());
+  ASSERT_EQ("/data/local/tmp/backtrace_heap", config->backtrace_dump_prefix());
+
   ASSERT_TRUE(InitConfig("backtrace_dump_prefix=/fake/location")) << getFakeLogPrint();
   ASSERT_EQ(0U, config->options());
   ASSERT_EQ("/fake/location", config->backtrace_dump_prefix());
 
+  ASSERT_TRUE(InitConfig("bt_dmp_pre=/fake/location")) << getFakeLogPrint();
+  ASSERT_EQ(0U, config->options());
+  ASSERT_EQ("/fake/location", config->backtrace_dump_prefix());
+
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
@@ -319,6 +359,9 @@
   ASSERT_TRUE(InitConfig("backtrace_full")) << getFakeLogPrint();
   ASSERT_EQ(BACKTRACE_FULL, config->options());
 
+  ASSERT_TRUE(InitConfig("bt_full")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_FULL, config->options());
+
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
@@ -786,6 +829,11 @@
   ASSERT_EQ(37U, config->backtrace_min_size_bytes());
   ASSERT_EQ(37U, config->backtrace_max_size_bytes());
 
+  ASSERT_TRUE(InitConfig("bt_sz=39")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(39U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(39U, config->backtrace_max_size_bytes());
+
   ASSERT_FALSE(InitConfig("backtrace_size")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_size=0")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_size=-1")) << getFakeLogPrint();
@@ -808,6 +856,11 @@
   ASSERT_EQ(9U, config->backtrace_min_size_bytes());
   ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
 
+  ASSERT_TRUE(InitConfig("bt_min_sz=11")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(11U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(SIZE_MAX, config->backtrace_max_size_bytes());
+
   ASSERT_FALSE(InitConfig("backtrace_min_size")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_min_size=0")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_min_size=-1")) << getFakeLogPrint();
@@ -830,6 +883,11 @@
   ASSERT_EQ(0U, config->backtrace_min_size_bytes());
   ASSERT_EQ(13U, config->backtrace_max_size_bytes());
 
+  ASSERT_TRUE(InitConfig("bt_max_sz=15")) << getFakeLogPrint();
+  ASSERT_EQ(BACKTRACE_SPECIFIC_SIZES, config->options());
+  ASSERT_EQ(0U, config->backtrace_min_size_bytes());
+  ASSERT_EQ(15U, config->backtrace_max_size_bytes());
+
   ASSERT_FALSE(InitConfig("backtrace_max_size")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_max_size=0")) << getFakeLogPrint();
   ASSERT_FALSE(InitConfig("backtrace_max_size=-1")) << getFakeLogPrint();
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index c6378f5..bf3ed14 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -184,6 +184,23 @@
   return diff;
 }
 
+static void VerifyRecords(std::vector<std::string>& expected, std::string& actual) {
+  size_t offset = 0;
+  for (std::string& str : expected) {
+    ASSERT_STREQ(str.c_str(), actual.substr(offset, str.size()).c_str());
+    if (str.find("thread_done") != std::string::npos) {
+      offset = actual.find_first_of("\n", offset) + 1;
+      continue;
+    }
+    offset += str.size() + 1;
+    uint64_t st = strtoull(&actual[offset], nullptr, 10);
+    offset = actual.find_first_of(" ", offset) + 1;
+    uint64_t et = strtoull(&actual[offset], nullptr, 10);
+    ASSERT_GT(et, st);
+    offset = actual.find_first_of("\n", offset) + 1;
+  }
+}
+
 void VerifyAllocCalls(bool all_options) {
   size_t alloc_size = 1024;
 
@@ -2171,61 +2188,61 @@
 #endif
 
 void VerifyRecordAllocs(const std::string& record_filename) {
-  std::string expected;
+  std::vector<std::string> expected;
 
   void* pointer = debug_malloc(10);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 10\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 10", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
-  pointer = debug_calloc(1, 20);
+  pointer = debug_calloc(20, 1);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: calloc %p 20 1\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: calloc %p 20 1", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   pointer = debug_realloc(nullptr, 30);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: realloc %p 0x0 30\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: realloc %p 0x0 30", getpid(), pointer));
   void* old_pointer = pointer;
   pointer = debug_realloc(pointer, 2048);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: realloc %p %p 2048\n", getpid(),
-                                          pointer, old_pointer);
+  expected.push_back(
+      android::base::StringPrintf("%d: realloc %p %p 2048", getpid(), pointer, old_pointer));
   debug_realloc(pointer, 0);
-  expected += android::base::StringPrintf("%d: realloc 0x0 %p 0\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: realloc 0x0 %p 0", getpid(), pointer));
 
   pointer = debug_memalign(16, 40);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 16 40\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: memalign %p 16 40", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   pointer = debug_aligned_alloc(32, 64);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 32 64\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: memalign %p 32 64", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   ASSERT_EQ(0, debug_posix_memalign(&pointer, 32, 50));
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 32 50\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: memalign %p 32 50", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
   pointer = debug_pvalloc(60);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 4096 4096\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: memalign %p 4096 4096", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   pointer = debug_valloc(70);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: memalign %p 4096 70\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: memalign %p 4096 70", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 #endif
 
   // Dump all of the data accumulated so far.
@@ -2235,7 +2252,7 @@
   std::string actual;
   ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
-  ASSERT_STREQ(expected.c_str(), actual.c_str());
+  VerifyRecords(expected, actual);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -2256,23 +2273,23 @@
 TEST_F(MallocDebugTest, record_allocs_max) {
   InitRecordAllocs("record_allocs=5");
 
-  std::string expected;
+  std::vector<std::string> expected;
 
   void* pointer = debug_malloc(10);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 10\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 10", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   pointer = debug_malloc(20);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 20\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 20", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   pointer = debug_malloc(1024);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 1024\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 1024", getpid(), pointer));
   debug_free(pointer);
 
   // Dump all of the data accumulated so far.
@@ -2282,7 +2299,7 @@
   std::string actual;
   ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
-  ASSERT_STREQ(expected.c_str(), actual.c_str());
+  VerifyRecords(expected, actual);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ(
@@ -2303,9 +2320,10 @@
   });
   thread.join();
 
-  std::string expected = android::base::StringPrintf("%d: malloc %p 100\n", tid, pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", tid, pointer);
-  expected += android::base::StringPrintf("%d: thread_done 0x0\n", tid);
+  std::vector<std::string> expected;
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 100", tid, pointer));
+  expected.push_back(android::base::StringPrintf("%d: free %p", tid, pointer));
+  expected.push_back(android::base::StringPrintf("%d: thread_done 0x0", tid));
 
   // Dump all of the data accumulated so far.
   ASSERT_TRUE(kill(getpid(), SIGRTMAX - 18) == 0);
@@ -2314,7 +2332,7 @@
   std::string actual;
   ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
 
-  ASSERT_STREQ(expected.c_str(), actual.c_str());
+  VerifyRecords(expected, actual);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
@@ -2329,13 +2347,13 @@
 
   ASSERT_EQ(0, symlink("/data/local/tmp/does_not_exist", record_filename.c_str()));
 
-  std::string expected;
+  std::vector<std::string> expected;
 
   void* pointer = debug_malloc(10);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 10\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 10", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   // Dump all of the data accumulated so far.
   ASSERT_TRUE(kill(getpid(), SIGRTMAX - 18) == 0);
@@ -2351,7 +2369,8 @@
   ASSERT_TRUE(kill(getpid(), SIGRTMAX - 18) == 0);
 
   ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
-  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  VerifyRecords(expected, actual);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   std::string expected_log = android::base::StringPrintf(
@@ -2375,13 +2394,13 @@
 TEST_F(MallocDebugTest, record_allocs_write_entries_does_not_allocate) {
   InitRecordAllocs("record_allocs=5");
 
-  std::string expected;
+  std::vector<std::string> expected;
 
   void* pointer = debug_malloc(10);
   ASSERT_TRUE(pointer != nullptr);
-  expected += android::base::StringPrintf("%d: malloc %p 10\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: malloc %p 10", getpid(), pointer));
   debug_free(pointer);
-  expected += android::base::StringPrintf("%d: free %p\n", getpid(), pointer);
+  expected.push_back(android::base::StringPrintf("%d: free %p", getpid(), pointer));
 
   malloc_disable();
   kill(getpid(), SIGRTMAX - 18);
@@ -2389,7 +2408,8 @@
 
   std::string actual;
   ASSERT_TRUE(android::base::ReadFileToString(record_filename, &actual));
-  ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+  VerifyRecords(expected, actual);
 
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
diff --git a/libc/malloc_hooks/Android.bp b/libc/malloc_hooks/Android.bp
index 01394da..6b4e606 100644
--- a/libc/malloc_hooks/Android.bp
+++ b/libc/malloc_hooks/Android.bp
@@ -59,6 +59,11 @@
     name: "malloc_hooks_system_tests",
     isolated: true,
 
+    // The clang-analyzer-unix.Malloc and other warnings in these
+    // unit tests are either false positive or in
+    // negative tests that can be ignored.
+    tidy: false,
+
     srcs: [
         "tests/malloc_hooks_tests.cpp",
     ],
diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h
index ecc8743..3c290fc 100644
--- a/libc/platform/bionic/malloc.h
+++ b/libc/platform/bionic/malloc.h
@@ -121,15 +121,28 @@
   // apply to system apps. They use the "libc.debug.gwp_asan.*.system_default"
   // sysprops.
   enum Action {
-    // The app has opted-in to GWP-ASan, and should always have it enabled. This
-    // should only be used by apps.
+    // Enable GWP-ASan. This is used by apps that have `gwpAsanMode=always` in
+    // the manifest.
     TURN_ON_FOR_APP,
-    // System processes apps have GWP-ASan enabled by default, but use the
-    // process sampling method.
+    // Enable GWP-ASan, but only a small percentage of the time. This is used by
+    // system processes and system apps, and we use a lottery to determine which
+    // processes have GWP-ASan enabled. This allows us to mitigate system-wide
+    // memory overhead concerns, as each GWP-ASan enabled process uses ~70KiB of
+    // extra memory.
     TURN_ON_WITH_SAMPLING,
-    // Non-system apps don't have GWP-ASan by default.
+    // Don't enable GWP-ASan, unless overwritten by a system property or
+    // environment variable. This is used by apps that have `gwpAsanMode=never`
+    // in the manifest. Prior to Android 14, this also was used by non-system
+    // apps that didn't specify a `gwpAsanMode` in their manifest.
     DONT_TURN_ON_UNLESS_OVERRIDDEN,
-    // Note: GWP-ASan cannot be disabled once it's been enabled.
+    // Enable GWP-ASan, but only a small percentage of the time, and enable it
+    // in the non-crashing ("recoverable") mode. In Android 14, this is used by
+    // apps that don't specify `gwpAsanMode` (or use `gwpAsanMode=default`) in
+    // their manifest. GWP-ASan will detect heap memory safety bugs in this
+    // mode, and bug reports will be created by debuggerd, however the process
+    // will recover and continue to function as if the memory safety bug wasn't
+    // detected.
+    TURN_ON_FOR_APP_SAMPLED_NON_CRASHING,
   };
 
   Action desire = DONT_TURN_ON_UNLESS_OVERRIDDEN;
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index c7e951d..c375cc4 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -107,10 +107,14 @@
 
   const gwp_asan::AllocatorState* gwp_asan_state = nullptr;
   const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr;
+  bool (*debuggerd_needs_gwp_asan_recovery)(void* fault_addr) = nullptr;
+  void (*debuggerd_gwp_asan_pre_crash_report)(void* fault_addr) = nullptr;
+  void (*debuggerd_gwp_asan_post_crash_report)(void* fault_addr) = nullptr;
 
   const char* scudo_stack_depot = nullptr;
   const char* scudo_region_info = nullptr;
   const char* scudo_ring_buffer = nullptr;
+  size_t scudo_ring_buffer_size = 0;
 
   HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
   bool initial_memtag_stack = false;
diff --git a/libc/tzcode/localedef.h b/libc/tzcode/localedef.h
new file mode 100644
index 0000000..19d4df9
--- /dev/null
+++ b/libc/tzcode/localedef.h
@@ -0,0 +1,106 @@
+/*	$OpenBSD: localedef.h,v 1.1 2016/05/23 00:05:15 guenther Exp $	*/
+/*	$NetBSD: localedef.h,v 1.4 1996/04/09 20:55:31 cgd Exp $	*/
+
+/*
+ * Copyright (c) 1994 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Winning Strategies, Inc.
+ * 4. 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.
+ */
+
+#ifndef _LOCALEDEF_H_
+#define _LOCALEDEF_H_
+
+#include <sys/types.h>
+
+typedef struct
+{
+	char *yesexpr;
+	char *noexpr;
+	char *yesstr;
+	char *nostr;
+} _MessagesLocale;
+
+
+typedef struct
+{
+	char *int_curr_symbol;
+	char *currency_symbol;
+	char *mon_decimal_point;
+	char *mon_thousands_sep;
+	char *mon_grouping;
+	char *positive_sign;
+	char *negative_sign;
+	char int_frac_digits;
+	char frac_digits;
+	char p_cs_precedes;
+	char p_sep_by_space;
+	char n_cs_precedes;
+	char n_sep_by_space;
+	char p_sign_posn;
+	char n_sign_posn;
+	char int_p_cs_precedes;
+	char int_p_sep_by_space;
+	char int_n_cs_precedes;
+	char int_n_sep_by_space;
+	char int_p_sign_posn;
+	char int_n_sign_posn;
+} _MonetaryLocale;
+
+
+typedef struct
+{
+	const char *decimal_point;
+	const char *thousands_sep;
+	const char *grouping;
+} _NumericLocale;
+
+
+typedef struct {
+	const char *abday[7];
+	const char *day[7];
+	const char *abmon[12];
+	const char *mon[12];
+	const char *am_pm[2];
+	const char *d_t_fmt;
+	const char *d_fmt;
+	const char *t_fmt;
+	const char *t_fmt_ampm;
+} _TimeLocale;
+
+
+//__BEGIN_HIDDEN_DECLS
+extern const _MessagesLocale *_CurrentMessagesLocale;
+extern const _MessagesLocale  _DefaultMessagesLocale;
+extern const _MonetaryLocale *_CurrentMonetaryLocale;
+extern const _MonetaryLocale  _DefaultMonetaryLocale;
+extern const _NumericLocale *_CurrentNumericLocale;
+extern const _NumericLocale  _DefaultNumericLocale;
+extern const _TimeLocale *_CurrentTimeLocale;
+extern const _TimeLocale  _DefaultTimeLocale;
+//__END_HIDDEN_DECLS
+
+#endif /* !_LOCALEDEF_H_ */
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 7e8e234..fe9e10f 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -1,8 +1,7 @@
-/*  $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */
-/*  $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $    */
-
+/*	$OpenBSD: strptime.c,v 1.30 2019/05/12 12:49:52 schwarze Exp $ */
+/*	$NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $	*/
 /*-
- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code was contributed to The NetBSD Foundation by Klaus Klein.
@@ -15,13 +14,6 @@
  * 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
@@ -36,65 +28,40 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-//#include <sys/localedef.h>
 #include <ctype.h>
-#include <errno.h>
 #include <locale.h>
-#include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <time.h>
+
+#include "localedef.h"
+#include "private.h"
 #include "tzfile.h"
 
-static const struct {
-    const char *abday[7];
-    const char *day[7];
-    const char *abmon[12];
-    const char *mon[12];
-    const char *am_pm[2];
-    const char *d_t_fmt;
-    const char *d_fmt;
-    const char *t_fmt;
-    const char *t_fmt_ampm;
-} _DefaultTimeLocale = {
-    {
-        "Sun","Mon","Tue","Wed","Thu","Fri","Sat",
-    },
-    {
-        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
-        "Friday", "Saturday"
-    },
-    {
-        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-    },
-    {
-        "January", "February", "March", "April", "May", "June", "July",
-        "August", "September", "October", "November", "December"
-    },
-    {
-        "AM", "PM"
-    },
-    "%a %b %d %H:%M:%S %Y",
-    "%m/%d/%y",
-    "%H:%M:%S",
-    "%I:%M:%S %p"
-};
+// Android: ignore OpenBSD's DEF_WEAK() stuff.
+#define DEF_WEAK(sym) /* */
+// Android: this code is not pointer-sign clean.
+#pragma clang diagnostic ignored "-Wpointer-sign"
+#pragma clang diagnostic ignored "-Wunused-function"
 
-#define _ctloc(x) (_DefaultTimeLocale.x)
+#define	_ctloc(x)		(_CurrentTimeLocale->x)
 
 /*
  * We do not implement alternate representations. However, we always
  * check whether a given modifier is allowed for a certain conversion.
  */
-#define _ALT_E          0x01
-#define _ALT_O          0x02
-#define _LEGAL_ALT(x)       { if (alt_format & ~(x)) return (0); }
+#define _ALT_E			0x01
+#define _ALT_O			0x02
+#define	_LEGAL_ALT(x)		{ if (alt_format & ~(x)) return (0); }
 
-
-struct century_relyear {
-    int century;
-    int relyear;
-};
+/*
+ * We keep track of some of the fields we set in order to compute missing ones.
+ */
+#define FIELD_TM_MON	(1 << 0)
+#define FIELD_TM_MDAY	(1 << 1)
+#define FIELD_TM_WDAY	(1 << 2)
+#define FIELD_TM_YDAY	(1 << 3)
+#define FIELD_TM_YEAR	(1 << 4)
 
 static char gmt[] = { "GMT" };
 static char utc[] = { "UTC" };
@@ -106,9 +73,15 @@
        "EDT",    "CDT",    "MDT",    "PDT",    "\0\0\0"
 };
 
-static  int _conv_num(const unsigned char **, int *, int, int);
-static  unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
-        struct century_relyear *);
+static const int mon_lengths[2][MONSPERYEAR] = {
+        { 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	int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t);
+static	int _conv_num(const unsigned char **, int *, int, int);
+static	int leaps_thru_end_of(const int y);
+static	char *_strptime(const char *, const char *, struct tm *, int);
 static	const u_char *_find_string(const u_char *, int *, const char * const *,
 	    const char * const *, int);
 
@@ -116,335 +89,353 @@
 char *
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
-    struct century_relyear cr;
-    cr.century = TM_YEAR_BASE;
-    cr.relyear = -1;
-    return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
+	return(_strptime(buf, fmt, tm, 1));
 }
+DEF_WEAK(strptime);
 
-static unsigned char *
-_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
+static char *
+_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize)
 {
-    unsigned char c;
-    const unsigned char *bp, *ep;
-    size_t len = 0;
-    int alt_format, i, offs;
-    int neg = 0;
+	unsigned char c;
+	const unsigned char *bp, *ep;
+	size_t len;
+	int alt_format, i, offs;
+	int neg = 0;
+	static int century, relyear, fields;
 
-    bp = (unsigned char *)buf;
-    while ((c = *fmt) != '\0') {
-        /* Clear `alternate' modifier prior to new conversion. */
-        alt_format = 0;
+	if (initialize) {
+		century = TM_YEAR_BASE;
+		relyear = -1;
+		fields = 0;
+	}
 
-        /* Eat up white-space. */
-        if (isspace(c)) {
-            while (isspace(*bp))
-                bp++;
+	bp = (const unsigned char *)buf;
+	while ((c = *fmt) != '\0') {
+		/* Clear `alternate' modifier prior to new conversion. */
+		alt_format = 0;
 
-            fmt++;
-            continue;
-        }
+		/* Eat up white-space. */
+		if (isspace(c)) {
+			while (isspace(*bp))
+				bp++;
 
-        if ((c = *fmt++) != '%')
-            goto literal;
+			fmt++;
+			continue;
+		}
+
+		if ((c = *fmt++) != '%')
+			goto literal;
 
 
-again:      switch (c = *fmt++) {
-        case '%':   /* "%%" is converted to "%". */
+again:		switch (c = *fmt++) {
+		case '%':	/* "%%" is converted to "%". */
 literal:
-        if (c != *bp++)
-            return (NULL);
+		if (c != *bp++)
+			return (NULL);
 
-        break;
+		break;
 
-        /*
-         * "Alternative" modifiers. Just set the appropriate flag
-         * and start over again.
-         */
-        case 'E':   /* "%E?" alternative conversion modifier. */
-            _LEGAL_ALT(0);
-            alt_format |= _ALT_E;
-            goto again;
+		/*
+		 * "Alternative" modifiers. Just set the appropriate flag
+		 * and start over again.
+		 */
+		case 'E':	/* "%E?" alternative conversion modifier. */
+			_LEGAL_ALT(0);
+			alt_format |= _ALT_E;
+			goto again;
 
-        case 'O':   /* "%O?" alternative conversion modifier. */
-            _LEGAL_ALT(0);
-            alt_format |= _ALT_O;
-            goto again;
+		case 'O':	/* "%O?" alternative conversion modifier. */
+			_LEGAL_ALT(0);
+			alt_format |= _ALT_O;
+			goto again;
 
-        /*
-         * "Complex" conversion rules, implemented through recursion.
-         */
-        case 'c':   /* Date and time, using the locale's format. */
-            _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, cr)))
-                return (NULL);
-            break;
+		/*
+		 * "Complex" conversion rules, implemented through recursion.
+		 */
+		case 'c':	/* Date and time, using the locale's format. */
+			_LEGAL_ALT(_ALT_E);
+			if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0)))
+				return (NULL);
+			break;
 
-        case 'D':   /* The date as "%m/%d/%y". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
-                return (NULL);
-            break;
+		case 'D':	/* The date as "%m/%d/%y". */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0)))
+				return (NULL);
+			break;
 
-        case 'F':  /* The date as "%Y-%m-%d". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
-                return (NULL);
-            continue;
+		case 'F':	/* The date as "%Y-%m-%d". */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%Y-%m-%d", tm, 0)))
+				return (NULL);
+			continue;
 
-        case 'R':   /* The time as "%H:%M". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
-                return (NULL);
-            break;
+		case 'R':	/* The time as "%H:%M". */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%H:%M", tm, 0)))
+				return (NULL);
+			break;
 
-        case 'r':   /* The time as "%I:%M:%S %p". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
-                return (NULL);
-            break;
+		case 'r':	/* The time as "%I:%M:%S %p". */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0)))
+				return (NULL);
+			break;
 
-        case 'T':   /* The time as "%H:%M:%S". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
-                return (NULL);
-            break;
+		case 'T':	/* The time as "%H:%M:%S". */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0)))
+				return (NULL);
+			break;
 
-        case 'v':  /* The date as "%e-%b-%Y". */
-            _LEGAL_ALT(0);
-            if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
-                return (NULL);
-            break;
+		case 'v':	/* Android: the date as "%e-%b-%Y" for strftime() compat; glibc does this too. */
+			_LEGAL_ALT(0);
+			if (!(bp = _strptime(bp, "%e-%b-%Y", tm, 0)))
+				return (NULL);
+			break;
 
-        case 'X':   /* The time, using the locale's format. */
-            _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
-                return (NULL);
-            break;
+		case 'X':	/* The time, using the locale's format. */
+			_LEGAL_ALT(_ALT_E);
+			if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))
+				return (NULL);
+			break;
 
-        case 'x':   /* The date, using the locale's format. */
-            _LEGAL_ALT(_ALT_E);
-            if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
-                return (NULL);
-            break;
+		case 'x':	/* The date, using the locale's format. */
+			_LEGAL_ALT(_ALT_E);
+			if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0)))
+				return (NULL);
+			break;
 
-        /*
-         * "Elementary" conversion rules.
-         */
-        case 'A':   /* The day of week, using the locale's form. */
-        case 'a':
-            _LEGAL_ALT(0);
-            for (i = 0; i < 7; i++) {
-                /* Full name. */
-                len = strlen(_ctloc(day[i]));
-                if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0)
-                    break;
+		/*
+		 * "Elementary" conversion rules.
+		 */
+		case 'A':	/* The day of week, using the locale's form. */
+		case 'a':
+			_LEGAL_ALT(0);
+			for (i = 0; i < 7; i++) {
+				/* Full name. */
+				len = strlen(_ctloc(day[i]));
+				if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
+					break;
 
-                /* Abbreviated name. */
-                len = strlen(_ctloc(abday[i]));
-                if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0)
-                    break;
-            }
+				/* Abbreviated name. */
+				len = strlen(_ctloc(abday[i]));
+				if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
+					break;
+			}
 
-            /* Nothing matched. */
-            if (i == 7)
-                return (NULL);
+			/* Nothing matched. */
+			if (i == 7)
+				return (NULL);
 
-            tm->tm_wday = i;
-            bp += len;
-            break;
+			tm->tm_wday = i;
+			bp += len;
+			fields |= FIELD_TM_WDAY;
+			break;
 
-        case 'B':   /* The month, using the locale's form. */
-        case 'b':
-        case 'h':
-            _LEGAL_ALT(0);
-            for (i = 0; i < 12; i++) {
-                /* Full name. */
-                len = strlen(_ctloc(mon[i]));
-                if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0)
-                    break;
+		case 'B':	/* The month, using the locale's form. */
+		case 'b':
+		case 'h':
+			_LEGAL_ALT(0);
+			for (i = 0; i < 12; i++) {
+				/* Full name. */
+				len = strlen(_ctloc(mon[i]));
+				if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
+					break;
 
-                /* Abbreviated name. */
-                len = strlen(_ctloc(abmon[i]));
-                if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0)
-                    break;
-            }
+				/* Abbreviated name. */
+				len = strlen(_ctloc(abmon[i]));
+				if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
+					break;
+			}
 
-            /* Nothing matched. */
-            if (i == 12)
-                return (NULL);
+			/* Nothing matched. */
+			if (i == 12)
+				return (NULL);
 
-            tm->tm_mon = i;
-            bp += len;
-            break;
+			tm->tm_mon = i;
+			bp += len;
+			fields |= FIELD_TM_MON;
+			break;
 
-        case 'C':   /* The century number. */
-            _LEGAL_ALT(_ALT_E);
-            if (!(_conv_num(&bp, &i, 0, 99)))
-                return (NULL);
+		case 'C':	/* The century number. */
+			_LEGAL_ALT(_ALT_E);
+			if (!(_conv_num(&bp, &i, 0, 99)))
+				return (NULL);
 
-            cr->century = i * 100;
-            break;
+			century = i * 100;
+			break;
 
-        case 'd':   /* The day of month. */
-        case 'e':
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
-                return (NULL);
-            break;
+		case 'e':	/* The day of month. */
+			if (isspace(*bp))
+				bp++;
+			/* FALLTHROUGH */
+		case 'd':
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
+				return (NULL);
+			fields |= FIELD_TM_MDAY;
+			break;
 
-        case 'k':   /* The hour (24-hour clock representation). */
-            _LEGAL_ALT(0);
-            /* FALLTHROUGH */
-        case 'H':
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
-                return (NULL);
-            break;
+		case 'k':	/* The hour (24-hour clock representation). */
+			_LEGAL_ALT(0);
+			/* FALLTHROUGH */
+		case 'H':
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
+				return (NULL);
+			break;
 
-        case 'l':   /* The hour (12-hour clock representation). */
-            _LEGAL_ALT(0);
-            /* FALLTHROUGH */
-        case 'I':
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
-                return (NULL);
-            break;
+		case 'l':	/* The hour (12-hour clock representation). */
+			_LEGAL_ALT(0);
+			/* FALLTHROUGH */
+		case 'I':
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
+				return (NULL);
+			break;
 
-        case 'j':   /* The day of year. */
-            _LEGAL_ALT(0);
-            if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
-                return (NULL);
-            tm->tm_yday--;
-            break;
+		case 'j':	/* The day of year. */
+			_LEGAL_ALT(0);
+			if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
+				return (NULL);
+			tm->tm_yday--;
+			fields |= FIELD_TM_YDAY;
+			break;
 
-        case 'M':   /* The minute. */
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
-                return (NULL);
-            break;
+		case 'M':	/* The minute. */
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
+				return (NULL);
+			break;
 
-        case 'm':   /* The month. */
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
-                return (NULL);
-            tm->tm_mon--;
-            break;
+		case 'm':	/* The month. */
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
+				return (NULL);
+			tm->tm_mon--;
+			fields |= FIELD_TM_MON;
+			break;
 
-        case 'P':
-        case 'p':   /* The locale's equivalent of AM/PM. */
-            _LEGAL_ALT(0);
-            /* AM? */
-            len = strlen(_ctloc(am_pm[0]));
-            if (strncasecmp(_ctloc(am_pm[0]), (const char*)bp, len) == 0) {
-                if (tm->tm_hour > 12)   /* i.e., 13:00 AM ?! */
-                    return (NULL);
-                else if (tm->tm_hour == 12)
-                    tm->tm_hour = 0;
+		case 'P':	/* Android addition for strftime() compat; glibc does this too. */
+		case 'p':	/* The locale's equivalent of AM/PM. */
+			_LEGAL_ALT(0);
+			/* AM? */
+			len = strlen(_ctloc(am_pm[0]));
+			if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) {
+				if (tm->tm_hour > 12)	/* i.e., 13:00 AM ?! */
+					return (NULL);
+				else if (tm->tm_hour == 12)
+					tm->tm_hour = 0;
 
-                bp += len;
-                break;
-            }
-            /* PM? */
-            len = strlen(_ctloc(am_pm[1]));
-            if (strncasecmp(_ctloc(am_pm[1]), (const char*)bp, len) == 0) {
-                if (tm->tm_hour > 12)   /* i.e., 13:00 PM ?! */
-                    return (NULL);
-                else if (tm->tm_hour < 12)
-                    tm->tm_hour += 12;
+				bp += len;
+				break;
+			}
+			/* PM? */
+			len = strlen(_ctloc(am_pm[1]));
+			if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) {
+				if (tm->tm_hour > 12)	/* i.e., 13:00 PM ?! */
+					return (NULL);
+				else if (tm->tm_hour < 12)
+					tm->tm_hour += 12;
 
-                bp += len;
-                break;
-            }
+				bp += len;
+				break;
+			}
 
-            /* Nothing matched. */
-            return (NULL);
+			/* Nothing matched. */
+			return (NULL);
 
-        case 'S':   /* The seconds. */
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
-                return (NULL);
-            break;
+		case 'S':	/* The seconds. */
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_sec, 0, 60)))
+				return (NULL);
+			break;
+		case 's':	/* Seconds since epoch */
+			{
+				// Android change based on FreeBSD's implementation.
+				int saved_errno = errno;
+				errno = 0;
+				const unsigned char* old_bp = bp;
+				long n = strtol((const char*) bp, (char**) &bp, 10);
+				errno = saved_errno;
+				time_t t = n;
+				if (bp == old_bp || errno == ERANGE ||
+				    ((long) t) != n) return NULL;
 
-        case 's':
-            {
-                // Android addition, based on FreeBSD's implementation.
-                int saved_errno = errno;
-                errno = 0;
-                const unsigned char* old_bp = bp;
-                long n = strtol((const char*) bp, (char**) &bp, 10);
-                time_t t = n;
-                if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
-                    errno = saved_errno;
-                    return NULL;
-                }
-                errno = saved_errno;
+				if (localtime_r(&t, tm) == NULL) return NULL;
 
-                if (localtime_r(&t, tm) == NULL) return NULL;
-            }
-            break;
+				//int64_t i64;
+				//if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
+				//	return (NULL);
+				//if (!gmtime_r(&i64, tm))
+				//	return (NULL);
+				fields = 0xffff;	 /* everything */
+			}
+			break;
+		case 'U':	/* The week of year, beginning on sunday. */
+		case 'W':	/* The week of year, beginning on monday. */
+			_LEGAL_ALT(_ALT_O);
+			/*
+			 * XXX This is bogus, as we can not assume any valid
+			 * information present in the tm structure at this
+			 * point to calculate a real value, so just check the
+			 * range for now.
+			 */
+			 if (!(_conv_num(&bp, &i, 0, 53)))
+				return (NULL);
+			 break;
 
+		case 'w':	/* The day of week, beginning on sunday. */
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
+				return (NULL);
+			fields |= FIELD_TM_WDAY;
+			break;
 
-        case 'U':   /* The week of year, beginning on sunday. */
-        case 'W':   /* The week of year, beginning on monday. */
-            _LEGAL_ALT(_ALT_O);
-            /*
-             * XXX This is bogus, as we can not assume any valid
-             * information present in the tm structure at this
-             * point to calculate a real value, so just check the
-             * range for now.
-             */
-             if (!(_conv_num(&bp, &i, 0, 53)))
-                return (NULL);
-             break;
+		case 'u':	/* The day of week, monday = 1. */
+			_LEGAL_ALT(_ALT_O);
+			if (!(_conv_num(&bp, &i, 1, 7)))
+				return (NULL);
+			tm->tm_wday = i % 7;
+			fields |= FIELD_TM_WDAY;
+			continue;
 
-        case 'w':   /* The day of week, beginning on sunday. */
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
-                return (NULL);
-            break;
+		case 'g':	/* The year corresponding to the ISO week
+				 * number but without the century.
+				 */
+			if (!(_conv_num(&bp, &i, 0, 99)))
+				return (NULL);
+			continue;
 
-        case 'u':  /* The day of week, monday = 1. */
-            _LEGAL_ALT(_ALT_O);
-            if (!(_conv_num(&bp, &i, 1, 7)))
-                return (NULL);
-            tm->tm_wday = i % 7;
-            continue;
+		case 'G':	/* The year corresponding to the ISO week
+				 * number with century.
+				 */
+			do
+				bp++;
+			while (isdigit(*bp));
+			continue;
 
-        case 'g':  /* The year corresponding to the ISO week
-                    * number but without the century.
-                    */
-            if (!(_conv_num(&bp, &i, 0, 99)))
-                return (NULL);
-            continue;
+		case 'V':	/* The ISO 8601:1988 week number as decimal */
+			if (!(_conv_num(&bp, &i, 0, 53)))
+				return (NULL);
+			continue;
 
-        case 'G':  /* The year corresponding to the ISO week
-                    * number with century.
-                    */
-            do
-                bp++;
-            while (isdigit(*bp));
-            continue;
+		case 'Y':	/* The year. */
+			_LEGAL_ALT(_ALT_E);
+			if (!(_conv_num(&bp, &i, 0, 9999)))
+				return (NULL);
 
-        case 'V':  /* The ISO 8601:1988 week number as decimal */
-            if (!(_conv_num(&bp, &i, 0, 53)))
-                return (NULL);
-            continue;
+			relyear = -1;
+			tm->tm_year = i - TM_YEAR_BASE;
+			fields |= FIELD_TM_YEAR;
+			break;
 
-        case 'Y':   /* The year. */
-            _LEGAL_ALT(_ALT_E);
-            if (!(_conv_num(&bp, &i, 0, 9999)))
-                return (NULL);
-
-            cr->relyear = -1;
-            tm->tm_year = i - TM_YEAR_BASE;
-            break;
-
-        case 'y':   /* The year within the century (2 digits). */
-            _LEGAL_ALT(_ALT_E | _ALT_O);
-            if (!(_conv_num(&bp, &cr->relyear, 0, 99)))
-                return (NULL);
-            break;
+		case 'y':	/* The year within the century (2 digits). */
+			_LEGAL_ALT(_ALT_E | _ALT_O);
+			if (!(_conv_num(&bp, &relyear, 0, 99)))
+				return (NULL);
+			break;
 
 		case 'Z':
 			tzset();
@@ -548,42 +539,78 @@
 			tm->tm_zone = NULL;	/* XXX */
 			continue;
 
-        /*
-         * Miscellaneous conversions.
-         */
-        case 'n':   /* Any kind of white-space. */
-        case 't':
-            _LEGAL_ALT(0);
-            while (isspace(*bp))
-                bp++;
-            break;
+		/*
+		 * Miscellaneous conversions.
+		 */
+		case 'n':	/* Any kind of white-space. */
+		case 't':
+			_LEGAL_ALT(0);
+			while (isspace(*bp))
+				bp++;
+			break;
 
 
-        default:    /* Unknown/unsupported conversion. */
-            return (NULL);
-        }
+		default:	/* Unknown/unsupported conversion. */
+			return (NULL);
+		}
 
 
-    }
+	}
 
-    /*
-     * We need to evaluate the two digit year spec (%y)
-     * last as we can get a century spec (%C) at any time.
-     */
-    if (cr->relyear != -1) {
-        if (cr->century == TM_YEAR_BASE) {
-            if (cr->relyear <= 68)
-                tm->tm_year = cr->relyear + 2000 - TM_YEAR_BASE;
-            else
-                tm->tm_year = cr->relyear + 1900 - TM_YEAR_BASE;
-        } else {
-            tm->tm_year = cr->relyear + cr->century - TM_YEAR_BASE;
-        }
-    }
+	/*
+	 * We need to evaluate the two digit year spec (%y)
+	 * last as we can get a century spec (%C) at any time.
+	 */
+	if (relyear != -1) {
+		if (century == TM_YEAR_BASE) {
+			if (relyear <= 68)
+				tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
+			else
+				tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
+		} else {
+			tm->tm_year = relyear + century - TM_YEAR_BASE;
+		}
+		fields |= FIELD_TM_YEAR;
+	}
 
-    return (unsigned char*)bp;
+	/* Compute some missing values when possible. */
+	if (fields & FIELD_TM_YEAR) {
+		const int year = tm->tm_year + TM_YEAR_BASE;
+		const int *mon_lens = mon_lengths[isleap(year)];
+		if (!(fields & FIELD_TM_YDAY) &&
+		    (fields & FIELD_TM_MON) && (fields & FIELD_TM_MDAY)) {
+			tm->tm_yday = tm->tm_mday - 1;
+			for (i = 0; i < tm->tm_mon; i++)
+				tm->tm_yday += mon_lens[i];
+			fields |= FIELD_TM_YDAY;
+		}
+		if (fields & FIELD_TM_YDAY) {
+			int days = tm->tm_yday;
+			if (!(fields & FIELD_TM_WDAY)) {
+				tm->tm_wday = EPOCH_WDAY +
+				    ((year - EPOCH_YEAR) % DAYSPERWEEK) *
+				    (DAYSPERNYEAR % DAYSPERWEEK) +
+				    leaps_thru_end_of(year - 1) -
+				    leaps_thru_end_of(EPOCH_YEAR - 1) +
+				    tm->tm_yday;
+				tm->tm_wday %= DAYSPERWEEK;
+				if (tm->tm_wday < 0)
+					tm->tm_wday += DAYSPERWEEK;
+			}
+			if (!(fields & FIELD_TM_MON)) {
+				tm->tm_mon = 0;
+				while (tm->tm_mon < MONSPERYEAR && days >= mon_lens[tm->tm_mon])
+					days -= mon_lens[tm->tm_mon++];
+			}
+			if (!(fields & FIELD_TM_MDAY))
+				tm->tm_mday = days + 1;
+		}
+	}
+
+	return ((char *)bp);
 }
 
+
 static int
 _conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
 {
@@ -607,6 +634,29 @@
 	return (1);
 }
 
+static int
+_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t ulim)
+{
+	int result = 0;
+	int64_t rulim = ulim;
+
+	if (**buf < '0' || **buf > '9')
+		return (0);
+
+	/* we use rulim to break out of the loop when we run out of digits */
+	do {
+		result *= 10;
+		result += *(*buf)++ - '0';
+		rulim /= 10;
+	} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
+
+	if (result < llim || result > ulim)
+		return (0);
+
+	*dest = result;
+	return (1);
+}
+
 static const u_char *
 _find_string(const u_char *bp, int *tgt, const char * const *n1,
 		const char * const *n2, int c)
@@ -629,6 +679,9 @@
 	return NULL;
 }
 
-char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t l) {
-  return strptime(buf, fmt, tm);
+static int
+leaps_thru_end_of(const int y)
+{
+	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+		-(leaps_thru_end_of(-(y + 1)) + 1);
 }
diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_time.c b/libc/upstream-openbsd/lib/libc/locale/_def_time.c
new file mode 100644
index 0000000..ba83fb8
--- /dev/null
+++ b/libc/upstream-openbsd/lib/libc/locale/_def_time.c
@@ -0,0 +1,36 @@
+/*	$OpenBSD: _def_time.c,v 1.6 2016/05/23 00:05:15 guenther Exp $ */
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#include <locale.h>
+#include "localedef.h"
+
+const _TimeLocale _DefaultTimeLocale =
+{
+	{
+		"Sun","Mon","Tue","Wed","Thu","Fri","Sat",
+	},
+	{
+		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+		"Friday", "Saturday"
+	},
+	{
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	},
+	{
+		"January", "February", "March", "April", "May", "June", "July",
+		"August", "September", "October", "November", "December"
+	},
+	{
+		"AM", "PM"
+	},
+	"%a %b %e %H:%M:%S %Y",
+	"%m/%d/%y",
+	"%H:%M:%S",
+	"%I:%M:%S %p"
+};
+
+const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale;
diff --git a/libdl/libdl.cpp b/libdl/libdl.cpp
index a56a5ab..20f08d9 100644
--- a/libdl/libdl.cpp
+++ b/libdl/libdl.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include <android/dlext.h>
 #include <dlfcn.h>
 #include <link.h>
+#include <signal.h>
 #include <stdlib.h>
-#include <android/dlext.h>
 
 // These functions are exported by the loader
 // TODO(dimitry): replace these with reference to libc.so
@@ -72,6 +73,9 @@
 __attribute__((__weak__, visibility("default")))
 int __loader_android_get_application_target_sdk_version();
 
+__attribute__((__weak__, visibility("default"))) bool __loader_android_handle_signal(
+    int signal_number, siginfo_t* info, void* context);
+
 // Proxy calls to bionic loader
 __attribute__((__weak__))
 void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
@@ -138,4 +142,14 @@
   return __loader_android_get_application_target_sdk_version();
 }
 
+// Returns true if this function handled the signal, false if the caller should handle the signal
+// itself. This function returns true if the sigchain handler should immediately return, which
+// happens when the signal came from GWP-ASan, and we've dumped a debuggerd report and patched up
+// the GWP-ASan allocator to recover from the fault, and regular execution of the program can
+// continue.
+__attribute__((__weak__)) bool android_handle_signal(int signal_number, siginfo_t* info,
+                                                     void* context) {
+  return __loader_android_handle_signal(signal_number, info, context);
+}
+
 } // extern "C"
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 473bdf2..043ec53 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -45,4 +45,5 @@
   global:
     android_get_LD_LIBRARY_PATH;
     __cfi_init;
+    android_handle_signal;
 } LIBC_OMR1;
diff --git a/libm/Android.bp b/libm/Android.bp
index 2748871..cc0d666 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -29,6 +29,7 @@
 
     whole_static_libs: ["libarm-optimized-routines-math"],
 
+    tidy_disabled_srcs: ["upstream-*/**/*.c"],
     srcs: [
         "upstream-freebsd/lib/msun/bsdsrc/b_tgamma.c",
         "upstream-freebsd/lib/msun/src/catrig.c",
@@ -105,8 +106,6 @@
         "upstream-freebsd/lib/msun/src/s_conj.c",
         "upstream-freebsd/lib/msun/src/s_conjf.c",
         "upstream-freebsd/lib/msun/src/s_conjl.c",
-        "upstream-freebsd/lib/msun/src/s_copysign.c",
-        "upstream-freebsd/lib/msun/src/s_copysignf.c",
         "upstream-freebsd/lib/msun/src/s_cos.c",
         "upstream-freebsd/lib/msun/src/s_cospi.c",
         "upstream-freebsd/lib/msun/src/s_cpow.c",
@@ -234,7 +233,6 @@
                 "upstream-freebsd/lib/msun/src/s_cbrtl.c",
                 "upstream-freebsd/lib/msun/src/s_ceill.c",
                 "upstream-freebsd/lib/msun/src/s_clogl.c",
-                "upstream-freebsd/lib/msun/src/s_copysignl.c",
                 "upstream-freebsd/lib/msun/src/e_coshl.c",
                 "upstream-freebsd/lib/msun/src/s_cosl.c",
                 "upstream-freebsd/lib/msun/src/s_csqrtl.c",
@@ -284,11 +282,10 @@
         arm: {
             srcs: [
                 "arm/fenv.c",
-                "arm/floor.S",
-                "arm/sqrt.S",
             ],
             exclude_srcs: [
                 "upstream-freebsd/lib/msun/src/s_floor.c",
+                "upstream-freebsd/lib/msun/src/s_floorf.c",
             ],
             instruction_set: "arm",
             pack_relocations: false,
@@ -304,14 +301,10 @@
         arm64: {
             srcs: [
                 "arm64/fenv.c",
-                "arm64/lrint.S",
-                "arm64/sqrt.S",
             ],
             exclude_srcs: [
                 "upstream-freebsd/lib/msun/src/s_ceil.c",
                 "upstream-freebsd/lib/msun/src/s_ceilf.c",
-                "upstream-freebsd/lib/msun/src/s_copysign.c",
-                "upstream-freebsd/lib/msun/src/s_copysignf.c",
                 "upstream-freebsd/lib/msun/src/s_floor.c",
                 "upstream-freebsd/lib/msun/src/s_floorf.c",
                 "upstream-freebsd/lib/msun/src/s_fma.c",
@@ -341,16 +334,12 @@
         riscv64: {
             srcs: [
                 "riscv64/fenv.c",
-                "riscv64/lrint.S",
-                "riscv64/sqrt.S",
             ],
 
             exclude_srcs: [
                 // TODO: do the rest when our clang has https://reviews.llvm.org/D136508.
                 // TODO: "upstream-freebsd/lib/msun/src/s_ceil.c",
                 // TODO: "upstream-freebsd/lib/msun/src/s_ceilf.c",
-                "upstream-freebsd/lib/msun/src/s_copysign.c",
-                "upstream-freebsd/lib/msun/src/s_copysignf.c",
                 // TODO: "upstream-freebsd/lib/msun/src/s_floor.c",
                 // TODO: "upstream-freebsd/lib/msun/src/s_floorf.c",
                 "upstream-freebsd/lib/msun/src/s_fma.c",
@@ -380,18 +369,8 @@
         x86: {
             srcs: [
                 "i387/fenv.c",
-                "x86/ceil.S",
-                "x86/ceilf.S",
-                "x86/floor.S",
-                "x86/floorf.S",
                 "x86/lrint.S",
                 "x86/lrintf.S",
-                "x86/rint.S",
-                "x86/rintf.S",
-                "x86/sqrt.S",
-                "x86/sqrtf.S",
-                "x86/trunc.S",
-                "x86/truncf.S",
             ],
             exclude_srcs: [
                 "upstream-freebsd/lib/msun/src/s_ceil.c",
@@ -407,6 +386,9 @@
             ],
             local_include_dirs: ["i387"],
             pack_relocations: false,
+            // The x86 ABI doesn't include this, which is needed for the
+            // roundss/roundsd instructions that we've used since Android M.
+            cflags: ["-msse4.1"],
             ldflags: ["-Wl,--hash-style=both"],
             version_script: ":libm.x86.map",
         },
@@ -414,18 +396,8 @@
         x86_64: {
             srcs: [
                 "amd64/fenv.c",
-                "x86_64/ceil.S",
-                "x86_64/ceilf.S",
-                "x86_64/floor.S",
-                "x86_64/floorf.S",
                 "x86_64/lrint.S",
                 "x86_64/lrintf.S",
-                "x86_64/rint.S",
-                "x86_64/rintf.S",
-                "x86_64/sqrt.S",
-                "x86_64/sqrtf.S",
-                "x86_64/trunc.S",
-                "x86_64/truncf.S",
             ],
             exclude_srcs: [
                 "upstream-freebsd/lib/msun/src/s_ceil.c",
diff --git a/libm/NOTICE b/libm/NOTICE
index bce49ad..61dd125 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -1148,37 +1148,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
-Johnny Qiu <joqiu@nvidia.com>
-Shu Zhang <chazhang@nvidia.com>
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must 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) 2014, Intel Corporation
 All rights reserved.
 
diff --git a/libm/arm/floor.S b/libm/arm/floor.S
deleted file mode 100644
index 3af8f76..0000000
--- a/libm/arm/floor.S
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
- * Johnny Qiu <joqiu@nvidia.com>
- * Shu Zhang <chazhang@nvidia.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must 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.
- */
-
-#include <float.h>
-#include <private/bionic_asm.h>
-
-ENTRY(floor)    /* x in r0, r1 */
-
-        and             r3, r1, #0x80000000     /* sign(x) */
-        bic             r1, r1, #0x80000000     /* x = abs(x) */
-
-        /* extract exp of x */
-        lsr             r2, r1, #20
-        sub             r2, r2, #0x3fc
-        subs            r2, r2, #0x3            /* r2 <- exp */
-
-        /* |x| < 1.0? */
-        blt             .Lx_lt_one
-
-        /* x < 0? */
-        cmp             r3, #0
-        bne             .Lclr_frac_neg
-
-        /* |x| <= 2^20? */
-        cmp             r2, #20
-        ble             .Lclr_frac_r1
-
-        /* |x| < 2^52? */
-        cmp             r2, #52
-        blt             .Lclr_frac_r0
-
-        /* return x */
-        bx              lr
-
-.Lclr_frac_r1:
-        rsb             r2, r2, #20
-        lsr             r1, r1, r2
-        lsl             r1, r1, r2
-        mov             r0, #0
-        bx              lr
-
-.Lclr_frac_r0:
-        rsb             r2, r2, #52
-        lsr             r0, r0, r2
-        lsl             r0, r0, r2
-        bx              lr
-
-.Lclr_frac_neg:
-        /* |x| <= 2^20? */
-        cmp             r2, #20
-        ble             .Lclr_frac_r1_neg
-
-        /* |x| < 2^52? */
-        cmp             r2, #52
-        blt             .Lclr_frac_r0_neg
-
-        /* return x */
-        orr             r1, r1, #0x80000000
-        bx              lr
-
-.Lclr_frac_r1_neg:
-        rsb             r2, r2, #20
-        mov             r3, #1
-        lsl             r3, r3, r2
-        sub             r3, r3, #1
-        and             r3, r1, r3
-        orr             r3, r3, r0
-        lsr             r1, r1, r2
-        lsl             r1, r1, r2
-        mov             r0, #0
-        b               .Lreturn_x_neg
-
-.Lclr_frac_r0_neg:
-        rsb             r2, r2, #52
-        mov             r3, #1
-        lsl             r3, r3, r2
-        sub             r3, r3, #1
-        and             r3, r0, r3
-        lsr             r0, r0, r2
-        lsl             r0, r0, r2
-        b               .Lreturn_x_neg
-
-.Lx_lt_one:
-        /* x == +-0? */
-        cmp             r0, #0
-        cmpeq           r1, #0
-        orreq           r1, r1, r3
-        bxeq            lr
-
-        /* (x > 0) ? 0 : -1 */
-        mov             r1, #0x00100000
-        mov             r0, #0
-        cmp             r3, #0
-        movne           r1, #0xc0000000
-        sub             r1, r1, #0x00100000
-        bx              lr
-
-.Lreturn_x_neg:
-        cmp             r3, #0
-        orr             r1, r1, #0x80000000
-        bxeq            lr
-
-        vmov            d16, r0, r1
-        vmov.f64        d18, #1.0
-        vsub.f64        d16, d16, d18
-        vmov            r0, r1, d16
-        bx              lr
-
-END(floor)
-
-ALIAS_SYMBOL(floorl, floor);
diff --git a/libm/arm/sqrt.S b/libm/arm/sqrt.S
deleted file mode 100644
index f2981f4..0000000
--- a/libm/arm/sqrt.S
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013-2014, NVIDIA Corporation.  All rights reserved.
- * Johnny Qiu <joqiu@nvidia.com>
- * Shu Zhang <chazhang@nvidia.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must 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.
- */
-
-#include <float.h>
-#include <private/bionic_asm.h>
-
-ENTRY(sqrt)
-    vmov.f64    d0, r0, r1
-    vsqrt.f64   d0, d0
-    vmov.f64    r0, r1, d0
-    bx          lr
-END(sqrt)
-
-ENTRY(sqrtf)
-    vmov.f32    s0, r0
-    vsqrt.f32   s0, s0
-    vmov.f32    r0, s0
-    bx          lr
-END(sqrtf)
-
-ALIAS_SYMBOL(sqrtl, sqrt);
diff --git a/libm/arm64/lrint.S b/libm/arm64/lrint.S
deleted file mode 100644
index e835d08..0000000
--- a/libm/arm64/lrint.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 <private/bionic_asm.h>
-
-ENTRY(lrint)
-  frintX d0, d0
-  fcvtzs x0, d0
-  ret
-END(lrint)
-
-ENTRY(lrintf)
-  frintX s0, s0
-  fcvtzs x0, s0
-  ret
-END(lrintf)
-
-// sizeof(long) and sizeof(long long) are the same for aarch64
-ALIAS_SYMBOL(llrint, lrint);
-
-ALIAS_SYMBOL(llrintf, lrintf);
-
-NOTE_GNU_PROPERTY()
diff --git a/libm/arm64/sqrt.S b/libm/arm64/sqrt.S
deleted file mode 100644
index 0659b13..0000000
--- a/libm/arm64/sqrt.S
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 <private/bionic_asm.h>
-
-ENTRY(sqrt)
-  fsqrt d0, d0
-  ret
-END(sqrt)
-
-ENTRY(sqrtf)
-  fsqrt s0, s0
-  ret
-END(sqrtf)
-
-NOTE_GNU_PROPERTY()
diff --git a/libm/builtins.cpp b/libm/builtins.cpp
index 58cd81d..96c006d 100644
--- a/libm/builtins.cpp
+++ b/libm/builtins.cpp
@@ -22,19 +22,36 @@
 float fabsf(float x) { return __builtin_fabsf(x); }
 long double fabsl(long double x) { return __builtin_fabsl(x); }
 
-#if defined(__aarch64__)
+#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
 float ceilf(float x) { return __builtin_ceilf(x); }
 double ceil(double x) { return __builtin_ceil(x); }
+#if defined(__ILP32__)
+__weak_reference(ceil, ceill);
+#endif
 #endif
 
-#if defined(__aarch64__) || defined(__riscv)
 double copysign(double x, double y) { return __builtin_copysign(x, y); }
 float copysignf(float x, float y) { return __builtin_copysignf(x, y); }
-#endif
+long double copysignl(long double x, long double y) { return __builtin_copysignl(x, y); }
 
-#if defined(__aarch64__)
+#if defined(__arm__) && (__ARM_ARCH < 8)
+// armv8 arm32 has a single-instruction implementation for these, but
+// armv7 arm32 doesn't, so __builtin_ doesn't work for arm32.
+#include "math_private.h"
+namespace s_floor {
+#include "upstream-freebsd/lib/msun/src/s_floor.c"
+}
+namespace s_floorf {
+#include "upstream-freebsd/lib/msun/src/s_floorf.c"
+}
+float floorf(float x) { return s_floorf::floorf(x); }
+double floor(double x) { return s_floor::floor(x); }
+#elif defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
 float floorf(float x) { return __builtin_floorf(x); }
 double floor(double x) { return __builtin_floor(x); }
+#if defined(__ILP32__)
+__weak_reference(floor, floorl);
+#endif
 #endif
 
 #if defined(__aarch64__) || defined(__riscv)
@@ -46,20 +63,45 @@
 
 float fminf(float x, float y) { return __builtin_fminf(x, y); }
 double fmin(double x, double y) { return __builtin_fmin(x, y); }
+#endif
 
+#if defined(__aarch64__) || defined(__riscv)
+long lrint(double x) { return __builtin_lrint(x); }
+long lrintf(float x) { return __builtin_lrintf(x); }
+long long llrint(double x) { return __builtin_llrint(x); }
+long long llrintf(float x) { return __builtin_llrintf(x); }
+#endif
+
+#if defined(__aarch64__) || defined(__riscv)
 long lround(double x) { return __builtin_lround(x); }
 long lroundf(float x) { return __builtin_lroundf(x); }
 long long llround(double x) { return __builtin_llround(x); }
 long long llroundf(float x) { return __builtin_llroundf(x); }
 #endif
 
-#if defined(__aarch64__)
+#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
 float rintf(float x) { return __builtin_rintf(x); }
 double rint(double x) { return __builtin_rint(x); }
+#if defined(__ILP32__)
+__weak_reference(rint, rintl);
+#endif
+#endif
 
+#if defined(__aarch64__)
 float roundf(float x) { return __builtin_roundf(x); }
 double round(double x) { return __builtin_round(x); }
+#endif
 
+float sqrtf(float x) { return __builtin_sqrtf(x); }
+double sqrt(double x) { return __builtin_sqrt(x); }
+#if defined(__ILP32__)
+__weak_reference(sqrt, sqrtl);
+#endif
+
+#if defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
 float truncf(float x) { return __builtin_truncf(x); }
 double trunc(double x) { return __builtin_trunc(x); }
+#if defined(__ILP32__)
+__weak_reference(trunc, truncl);
+#endif
 #endif
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index 26edfeb..5f9b980 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -24,7 +24,6 @@
 // Android works around those cases by replacing the broken functions with our own trivial stubs
 // that call the regular "double" function.
 
-long double copysignl(long double a1, long double a2) { return copysign(a1, a2); }
 long double fmaxl(long double a1, long double a2) { return fmax(a1, a2); }
 long double fmodl(long double a1, long double a2) { return fmod(a1, a2); }
 long double fminl(long double a1, long double a2) { return fmin(a1, a2); }
diff --git a/libm/riscv64/lrint.S b/libm/riscv64/lrint.S
deleted file mode 100644
index eb13833..0000000
--- a/libm/riscv64/lrint.S
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <private/bionic_asm.h>
-
-ENTRY(lrint)
-  fcvt.l.d a0, fa0, dyn
-  ret
-END(lrint)
-
-ENTRY(lrintf)
-  fcvt.l.s a0, fa0, dyn
-  ret
-END(lrintf)
-
-// sizeof(long) and sizeof(long long) are the same for riscv64
-ALIAS_SYMBOL(llrint, lrint);
-
-ALIAS_SYMBOL(llrintf, lrintf);
diff --git a/libm/x86/ceil.S b/libm/x86/ceil.S
deleted file mode 100644
index 6302037..0000000
--- a/libm/x86/ceil.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(ceil)
-	mov    %esp,%eax
-	and    $0xfffffff8,%eax
-	movsd  0x4(%esp),%xmm0
-	roundsd $0x2,%xmm0,%xmm0
-	movlpd %xmm0,-0x8(%eax)
-	fldl   -0x8(%eax)
-	ret
-END(ceil)
-
-ALIAS_SYMBOL(ceill, ceil);
diff --git a/libm/x86/ceilf.S b/libm/x86/ceilf.S
deleted file mode 100644
index 51eb440..0000000
--- a/libm/x86/ceilf.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(ceilf)
-	movss  0x4(%esp),%xmm0
-	roundss $0x2,%xmm0,%xmm0
-	movss  %xmm0,-0x4(%esp)
-	flds   -0x4(%esp)
-	ret
-END(ceilf)
diff --git a/libm/x86/floor.S b/libm/x86/floor.S
deleted file mode 100644
index b859736..0000000
--- a/libm/x86/floor.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(floor)
-	mov    %esp,%eax
-	and    $0xfffffff8,%eax
-	movsd  0x4(%esp),%xmm0
-	roundsd $0x1,%xmm0,%xmm0
-	movlpd %xmm0,-0x8(%eax)
-	fldl   -0x8(%eax)
-	ret
-END(floor)
-
-ALIAS_SYMBOL(floorl, floor);
diff --git a/libm/x86/floorf.S b/libm/x86/floorf.S
deleted file mode 100644
index 79b9073..0000000
--- a/libm/x86/floorf.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(floorf)
-	movss  0x4(%esp),%xmm0
-	roundss $0x1,%xmm0,%xmm0
-	movss  %xmm0,-0x4(%esp)
-	flds   -0x4(%esp)
-	ret
-END(floorf)
diff --git a/libm/x86/rint.S b/libm/x86/rint.S
deleted file mode 100644
index 282d3ed..0000000
--- a/libm/x86/rint.S
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(rint)
-  subl    $12,%esp
-  movsd   16(%esp),%xmm0
-  roundsd $4,%xmm0,%xmm0
-  movsd   %xmm0,(%esp)
-  fldl    (%esp)
-  addl    $12,%esp
-  ret
-END(rint)
-
-// LP32 sizeof(long double) == sizeof(double).
-ALIAS_SYMBOL(rintl, rint);
diff --git a/libm/x86/rintf.S b/libm/x86/rintf.S
deleted file mode 100644
index d5cbe78..0000000
--- a/libm/x86/rintf.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(rintf)
-  subl    $12,%esp
-  movss   16(%esp),%xmm0
-  roundss $4,%xmm0,%xmm0
-  movss   %xmm0,(%esp)
-  flds    (%esp)
-  add     $12,%esp
-  ret
-END(rintf)
diff --git a/libm/x86/sqrt.S b/libm/x86/sqrt.S
deleted file mode 100644
index c9d434d..0000000
--- a/libm/x86/sqrt.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(sqrt)
-	mov		%esp,%eax
-	and		$0xfffffff8,%eax
-	movsd	0x4(%esp),%xmm0
-	sqrtsd	%xmm0,%xmm0
-	movlpd	%xmm0,-0x8(%eax)
-	fldl   -0x8(%eax)
-	ret
-END(sqrt)
-
-ALIAS_SYMBOL(sqrtl, sqrt);
diff --git a/libm/x86/sqrtf.S b/libm/x86/sqrtf.S
deleted file mode 100644
index 78c183b..0000000
--- a/libm/x86/sqrtf.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(sqrtf)
-	movss  0x4(%esp),%xmm0
-	sqrtss %xmm0,%xmm0
-	movss  %xmm0,-0x4(%esp)
-	flds   -0x4(%esp)
-	ret
-END(sqrtf)
diff --git a/libm/x86/trunc.S b/libm/x86/trunc.S
deleted file mode 100644
index da9d5fb..0000000
--- a/libm/x86/trunc.S
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(trunc)
-	mov    %esp,%eax
-	and    $0xfffffff8,%eax
-	movsd  0x4(%esp),%xmm0
-	roundsd $0x3,%xmm0,%xmm0
-	movlpd %xmm0,-0x8(%eax)
-	fldl   -0x8(%eax)
-	ret
-END(trunc)
-
-ALIAS_SYMBOL(truncl, trunc);
diff --git a/libm/x86/truncf.S b/libm/x86/truncf.S
deleted file mode 100644
index d3e3f4a..0000000
--- a/libm/x86/truncf.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(truncf)
-	movss  0x4(%esp),%xmm0
-	roundss $0x3,%xmm0,%xmm0
-	movss  %xmm0,-0x4(%esp)
-	flds   -0x4(%esp)
-	ret
-END(truncf)
diff --git a/libm/x86_64/ceil.S b/libm/x86_64/ceil.S
deleted file mode 100644
index d4492c4..0000000
--- a/libm/x86_64/ceil.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(ceil)
-roundsd $0x2,%xmm0,%xmm0
-retq
-END(ceil)
diff --git a/libm/x86_64/ceilf.S b/libm/x86_64/ceilf.S
deleted file mode 100644
index 0e1ca95..0000000
--- a/libm/x86_64/ceilf.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(ceilf)
-roundss $0x2,%xmm0,%xmm0
-retq
-END(ceilf)
diff --git a/libm/x86_64/floor.S b/libm/x86_64/floor.S
deleted file mode 100644
index dc80e88..0000000
--- a/libm/x86_64/floor.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(floor)
-roundsd $0x1,%xmm0,%xmm0
-retq
-END(floor)
diff --git a/libm/x86_64/floorf.S b/libm/x86_64/floorf.S
deleted file mode 100644
index 832f9c5..0000000
--- a/libm/x86_64/floorf.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(floorf)
-roundss $0x1,%xmm0,%xmm0
-retq
-END(floorf)
diff --git a/libm/x86_64/rint.S b/libm/x86_64/rint.S
deleted file mode 100644
index 9731daa..0000000
--- a/libm/x86_64/rint.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(rint)
-  roundsd $0x4,%xmm0,%xmm0
-  retq
-END(rint)
diff --git a/libm/x86_64/rintf.S b/libm/x86_64/rintf.S
deleted file mode 100644
index c3e98bf..0000000
--- a/libm/x86_64/rintf.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(rintf)
-  roundss $0x4,%xmm0,%xmm0
-  retq
-END(rintf)
diff --git a/libm/x86_64/sqrt.S b/libm/x86_64/sqrt.S
deleted file mode 100644
index ee97026..0000000
--- a/libm/x86_64/sqrt.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(sqrt)
-sqrtsd %xmm0,%xmm0
-retq
-END(sqrt)
diff --git a/libm/x86_64/sqrtf.S b/libm/x86_64/sqrtf.S
deleted file mode 100644
index 910407f..0000000
--- a/libm/x86_64/sqrtf.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(sqrtf)
-sqrtss %xmm0,%xmm0
-retq
-END(sqrtf)
diff --git a/libm/x86_64/trunc.S b/libm/x86_64/trunc.S
deleted file mode 100644
index fe18b40..0000000
--- a/libm/x86_64/trunc.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(trunc)
-roundsd $0x3,%xmm0,%xmm0
-retq
-END(trunc)
diff --git a/libm/x86_64/truncf.S b/libm/x86_64/truncf.S
deleted file mode 100644
index eeee1d7..0000000
--- a/libm/x86_64/truncf.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-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 <private/bionic_asm.h>
-
-ENTRY(truncf)
-roundss $0x3,%xmm0,%xmm0
-retq
-END(truncf)
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index af05027..a3f5246 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -28,8 +28,9 @@
 
 #include "linker.h"
 #include "linker_cfi.h"
-#include "linker_globals.h"
+#include "linker_debuggerd.h"
 #include "linker_dlwarning.h"
+#include "linker_globals.h"
 
 #include <link.h>
 #include <pthread.h>
@@ -92,6 +93,8 @@
 #if defined(__arm__)
 _Unwind_Ptr __loader_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) __LINKER_PUBLIC__;
 #endif
+bool __loader_android_handle_signal(int signal_number, siginfo_t* info,
+                                    void* context) __LINKER_PUBLIC__;
 }
 
 static pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -302,6 +305,10 @@
   return __libc_shared_globals();
 }
 
+bool __loader_android_handle_signal(int signal_number, siginfo_t* info, void* context) {
+  return debuggerd_handle_signal(signal_number, info, context);
+}
+
 static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
 static soinfo* __libdl_info = nullptr;
 
diff --git a/linker/ld_android.cpp b/linker/ld_android.cpp
index 0239c30..1c03106 100644
--- a/linker/ld_android.cpp
+++ b/linker/ld_android.cpp
@@ -44,6 +44,7 @@
 __strong_alias(__loader_android_set_application_target_sdk_version, __internal_linker_error);
 __strong_alias(__loader_android_update_LD_LIBRARY_PATH, __internal_linker_error);
 __strong_alias(__loader_cfi_fail, __internal_linker_error);
+__strong_alias(__loader_android_handle_signal, __internal_linker_error);
 __strong_alias(__loader_dl_iterate_phdr, __internal_linker_error);
 __strong_alias(__loader_dladdr, __internal_linker_error);
 __strong_alias(__loader_dlclose, __internal_linker_error);
diff --git a/linker/linker.arm.map b/linker/linker.arm.map
index be438ca..b805cd6 100644
--- a/linker/linker.arm.map
+++ b/linker/linker.arm.map
@@ -24,6 +24,7 @@
     __loader_remove_thread_local_dtor;
     __loader_shared_globals;
     rtld_db_dlactivity;
+    __loader_android_handle_signal;
   local:
     *;
 };
diff --git a/linker/linker.generic.map b/linker/linker.generic.map
index f3c01c0..4d7f236 100644
--- a/linker/linker.generic.map
+++ b/linker/linker.generic.map
@@ -23,6 +23,7 @@
     __loader_remove_thread_local_dtor;
     __loader_shared_globals;
     rtld_db_dlactivity;
+    __loader_android_handle_signal;
   local:
     *;
 };
diff --git a/linker/linker_debuggerd.h b/linker/linker_debuggerd.h
index d701879..95f99e7 100644
--- a/linker/linker_debuggerd.h
+++ b/linker/linker_debuggerd.h
@@ -28,4 +28,7 @@
 
 #pragma once
 
+#include <signal.h>
+
 void linker_debuggerd_init();
+extern "C" bool debuggerd_handle_signal(int signal_number, siginfo_t* info, void* context);
diff --git a/linker/linker_debuggerd_android.cpp b/linker/linker_debuggerd_android.cpp
index cba6345..ab6fc30 100644
--- a/linker/linker_debuggerd_android.cpp
+++ b/linker/linker_debuggerd_android.cpp
@@ -43,6 +43,18 @@
       .scudo_stack_depot = __libc_shared_globals()->scudo_stack_depot,
       .scudo_region_info = __libc_shared_globals()->scudo_region_info,
       .scudo_ring_buffer = __libc_shared_globals()->scudo_ring_buffer,
+      .scudo_ring_buffer_size = __libc_shared_globals()->scudo_ring_buffer_size,
+  };
+}
+
+static gwp_asan_callbacks_t get_gwp_asan_callbacks() {
+  return {
+      .debuggerd_needs_gwp_asan_recovery =
+          __libc_shared_globals()->debuggerd_needs_gwp_asan_recovery,
+      .debuggerd_gwp_asan_pre_crash_report =
+          __libc_shared_globals()->debuggerd_gwp_asan_pre_crash_report,
+      .debuggerd_gwp_asan_post_crash_report =
+          __libc_shared_globals()->debuggerd_gwp_asan_post_crash_report,
   };
 }
 #endif
@@ -52,9 +64,10 @@
   // so don't pass in any process info from the bootstrap linker.
   debuggerd_callbacks_t callbacks = {
 #if defined(__ANDROID_APEX__)
-      .get_process_info = get_process_info,
+    .get_process_info = get_process_info,
+    .get_gwp_asan_callbacks = get_gwp_asan_callbacks,
 #endif
-      .post_dump = notify_gdb_of_libraries,
+    .post_dump = notify_gdb_of_libraries,
   };
   debuggerd_init(&callbacks);
 }
diff --git a/linker/linker_debuggerd_stub.cpp b/linker/linker_debuggerd_stub.cpp
index 631e6e4..c671dd9 100644
--- a/linker/linker_debuggerd_stub.cpp
+++ b/linker/linker_debuggerd_stub.cpp
@@ -28,5 +28,11 @@
 
 #include "linker_debuggerd.h"
 
+#include <signal.h>
+
 void linker_debuggerd_init() {
 }
+extern "C" bool debuggerd_handle_signal(int /* signal_number */, siginfo_t* /* info */,
+                                        void* /* context */) {
+  return false;
+}
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f0e7b1b..833157e 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -203,35 +203,29 @@
   ElfW(Addr) entry_point;
 };
 
-static ExecutableInfo get_executable_info() {
+static ExecutableInfo get_executable_info(const char* arg_path) {
   ExecutableInfo result = {};
+  char const* exe_path = "/proc/self/exe";
 
-  if (is_first_stage_init()) {
-    // /proc fs is not mounted when first stage init starts. Therefore we can't
-    // use /proc/self/exe for init.
-    stat("/init", &result.file_stat);
-
-    // /init may be a symlink, so try to read it as such.
-    char path[PATH_MAX];
-    ssize_t path_len = readlink("/init", path, sizeof(path));
-    if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-      result.path = "/init";
-    } else {
-      result.path = std::string(path, path_len);
+  // Stat "/proc/self/exe" instead of executable_path because
+  // the executable could be unlinked by this point and it should
+  // not cause a crash (see http://b/31084669)
+  if (TEMP_FAILURE_RETRY(stat(exe_path, &result.file_stat) == -1)) {
+    // Fallback to argv[0] for the case where /proc isn't available
+    if (TEMP_FAILURE_RETRY(stat(arg_path, &result.file_stat) == -1)) {
+      async_safe_fatal("unable to stat either \"/proc/self/exe\" or \"%s\": %s",
+          arg_path, strerror(errno));
     }
+    exe_path = arg_path;
+  }
+
+  // Path might be a symlink
+  char sym_path[PATH_MAX];
+  ssize_t sym_path_len = readlink(exe_path, sym_path, sizeof(sym_path));
+  if (sym_path_len > 0 && sym_path_len < static_cast<ssize_t>(sizeof(sym_path))) {
+    result.path = std::string(sym_path, sym_path_len);
   } else {
-    // Stat "/proc/self/exe" instead of executable_path because
-    // the executable could be unlinked by this point and it should
-    // not cause a crash (see http://b/31084669)
-    if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &result.file_stat)) != 0) {
-      async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
-    }
-    char path[PATH_MAX];
-    ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
-    if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-      async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
-    }
-    result.path = std::string(path, path_len);
+    result.path = std::string(exe_path, strlen(exe_path));
   }
 
   result.phdr = reinterpret_cast<const ElfW(Phdr)*>(getauxval(AT_PHDR));
@@ -359,7 +353,7 @@
   }
 
   const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) :
-                                                get_executable_info();
+                                                get_executable_info(args.argv[0]);
 
   INFO("[ Linking executable \"%s\" ]", exe_info.path.c_str());
 
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 19f0cab..73cfced 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -175,7 +175,8 @@
   if (did_load_) {
     return true;
   }
-  if (ReserveAddressSpace(address_space) && LoadSegments() && FindPhdr() &&
+  bool reserveSuccess = ReserveAddressSpace(address_space);
+  if (reserveSuccess && LoadSegments() && FindPhdr() &&
       FindGnuPropertySection()) {
     did_load_ = true;
 #if defined(__aarch64__)
@@ -186,6 +187,13 @@
     }
 #endif
   }
+  if (reserveSuccess && !did_load_) {
+    if (load_start_ != nullptr && load_size_ != 0) {
+      if (!mapped_by_caller_) {
+        munmap(load_start_, load_size_);
+      }
+    }
+  }
 
   return did_load_;
 }
diff --git a/tests/gwp_asan_test.cpp b/tests/gwp_asan_test.cpp
index 5f5e3dd..38661c7 100644
--- a/tests/gwp_asan_test.cpp
+++ b/tests/gwp_asan_test.cpp
@@ -34,6 +34,7 @@
 #if defined(__BIONIC__)
 
 #include "android-base/file.h"
+#include "android-base/test_utils.h"
 #include "gwp_asan/options.h"
 #include "platform/bionic/malloc.h"
 #include "sys/system_properties.h"
@@ -57,7 +58,13 @@
 // the torture mode is is generally 40,000, so that svelte devices don't
 // explode, as this uses ~163MiB RAM (4KiB per live allocation).
 TEST(gwp_asan_integration, malloc_tests_under_torture) {
-  RunGwpAsanTest("malloc.*:-malloc.mallinfo*");
+  if (running_with_hwasan()) {
+    // Skip the malloc.zeroed tests since they fail in this particular config.
+    // TODO(b/267386540): Need to fix this problem.
+    RunGwpAsanTest("malloc.*:-malloc.mallinfo*:malloc.zeroed*");
+  } else {
+    RunGwpAsanTest("malloc.*:-malloc.mallinfo*");
+  }
 }
 
 class SyspropRestorer {
diff --git a/tests/headers/posix/Android.bp b/tests/headers/posix/Android.bp
index 4a20d45..0809cdb 100644
--- a/tests/headers/posix/Android.bp
+++ b/tests/headers/posix/Android.bp
@@ -33,8 +33,5 @@
         darwin: {
             enabled: false,
         },
-        musl: {
-            enabled: false,
-        },
     },
 }
diff --git a/tests/headers/posix/fcntl_h.c b/tests/headers/posix/fcntl_h.c
index a55fe89..418add0 100644
--- a/tests/headers/posix/fcntl_h.c
+++ b/tests/headers/posix/fcntl_h.c
@@ -84,7 +84,11 @@
 
   // POSIX: "The <fcntl.h> header shall define the symbolic constants for
   // file modes for use as values of mode_t as described in <sys/stat.h>."
+  // Musl only defines the file mode bits (S_IFUSR, etc.) and not the file
+  // type bits (S_IFMT, etc.).
+#if !defined(ANDROID_HOST_MUSL)
 #include "sys_stat_h_mode_constants.h"
+#endif
 
   MACRO(AT_FDCWD);
 #if !defined(__BIONIC__) // See comment in "faccessat.cpp".
diff --git a/tests/headers/posix/limits_h.c b/tests/headers/posix/limits_h.c
index 143f717..7e92d81 100644
--- a/tests/headers/posix/limits_h.c
+++ b/tests/headers/posix/limits_h.c
@@ -32,15 +32,17 @@
 
 static void limits_h() {
   // These are only defined if they're constants.
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(AIO_LISTIO_MAX);
   MACRO(AIO_MAX);
 #endif
-#if !defined(__BIONIC__)
+#if !defined(__BIONIC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(AIO_PRIO_DELTA_MAX);
 #endif
 #if !defined(__BIONIC__) && !defined(__GLIBC__)
   MACRO(ARG_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(ATEXIT_MAX);
   MACRO(CHILD_MAX);
 #endif
@@ -50,14 +52,16 @@
   MACRO(HOST_NAME_MAX);
   MACRO(IOV_MAX);
   MACRO(LOGIN_NAME_MAX);
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(MQ_OPEN_MAX);
 #endif
 #if !defined(__BIONIC__)
   MACRO(MQ_PRIO_MAX);
 #endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(OPEN_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__)
   MACRO(PAGESIZE);
   MACRO(PAGE_SIZE);
 #endif
@@ -66,19 +70,25 @@
 #if !defined(__BIONIC__)
   MACRO(PTHREAD_STACK_MIN);
 #endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(PTHREAD_THREADS_MAX);
 #endif
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(RTSIG_MAX);
+#endif
 #if !defined(__BIONIC__) && !defined(__GLIBC__)
   MACRO(SEM_NSEMS_MAX);
 #endif
   MACRO(SEM_VALUE_MAX);
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(SIGQUEUE_MAX);
   MACRO(SS_REPL_MAX);
   MACRO(STREAM_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__)
   MACRO(SYMLOOP_MAX);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(TIMER_MAX);
 #endif
 #if !defined(__BIONIC__)
@@ -90,10 +100,14 @@
 
 #if !defined(__BIONIC__) && !defined(__GLIBC__)
   MACRO(FILESIZEBITS);
+#endif
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(LINK_MAX);
 #endif
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(MAX_CANON);
   MACRO(MAX_INPUT);
+#endif
   MACRO(NAME_MAX);
   MACRO(PATH_MAX);
   MACRO(PIPE_BUF);
@@ -104,7 +118,7 @@
   MACRO(POSIX_REC_MIN_XFER_SIZE);
   MACRO(POSIX_REC_XFER_ALIGN);
 #endif
-#if !defined(__BIONIC__) && !defined(__GLIBC__)
+#if !defined(__BIONIC__) && !defined(__GLIBC__) && !defined(ANDROID_HOST_MUSL)
   MACRO(SYMLINK_MAX);
 #endif
 
diff --git a/tests/headers/posix/unistd_h.c b/tests/headers/posix/unistd_h.c
index b713f53..0b2cee5 100644
--- a/tests/headers/posix/unistd_h.c
+++ b/tests/headers/posix/unistd_h.c
@@ -51,8 +51,10 @@
   MACRO(_POSIX_MESSAGE_PASSING);
   MACRO(_POSIX_MONOTONIC_CLOCK);
   MACRO(_POSIX_NO_TRUNC);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_PRIORITIZED_IO);
   MACRO(_POSIX_PRIORITY_SCHEDULING);
+#endif
   MACRO(_POSIX_RAW_SOCKETS);
   MACRO(_POSIX_READER_WRITER_LOCKS);
   MACRO(_POSIX_REALTIME_SIGNALS);
@@ -63,35 +65,51 @@
   MACRO(_POSIX_SHELL);
   MACRO(_POSIX_SPAWN);
   MACRO(_POSIX_SPIN_LOCKS);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_SPORADIC_SERVER);
   MACRO(_POSIX_SYNCHRONIZED_IO);
+#endif
   MACRO(_POSIX_THREAD_ATTR_STACKADDR);
   MACRO(_POSIX_THREAD_ATTR_STACKSIZE);
   MACRO(_POSIX_THREAD_CPUTIME);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_THREAD_PRIO_INHERIT);
   MACRO(_POSIX_THREAD_PRIO_PROTECT);
+#endif
   MACRO(_POSIX_THREAD_PRIORITY_SCHEDULING);
   MACRO(_POSIX_THREAD_PROCESS_SHARED);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_THREAD_ROBUST_PRIO_INHERIT);
   MACRO(_POSIX_THREAD_ROBUST_PRIO_PROTECT);
+#endif
   MACRO(_POSIX_THREAD_SAFE_FUNCTIONS);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_THREAD_SPORADIC_SERVER);
+#endif
   MACRO(_POSIX_THREADS);
   MACRO(_POSIX_TIMEOUTS);
   MACRO(_POSIX_TIMERS);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX_TYPED_MEMORY_OBJECTS);
+#endif
   MACRO(_POSIX2_C_BIND);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_POSIX2_CHAR_TERM);
   MACRO(_POSIX2_LOCALEDEF);
   MACRO(_POSIX2_SW_DEV);
+#endif
 #if 0 // No libc I can find actually has this.
   MACRO(_POSIX2_UPE);
 #endif
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_XOPEN_CRYPT);
+#endif
   MACRO(_XOPEN_ENH_I18N);
+#if !defined(ANDROID_HOST_MUSL)
   MACRO(_XOPEN_REALTIME);
   MACRO(_XOPEN_REALTIME_THREADS);
   MACRO(_XOPEN_SHM);
+#endif
   MACRO(_XOPEN_UNIX);
 #if defined(_XOPEN_UUCP)
 #if _XOPEN_UUCP != -1 && _XOPEN_UUCP != 0 && _XOPEN_UUCP != 200809L
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 3cc5bbd..63ad99d 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -35,6 +35,7 @@
 
 #include <algorithm>
 #include <atomic>
+#include <functional>
 #include <thread>
 #include <vector>
 
@@ -661,13 +662,13 @@
 }
 
 TEST(malloc, mallopt_smoke) {
-#if !defined(ANDROID_HOST_MUSL)
+#if defined(__BIONIC__)
   errno = 0;
   ASSERT_EQ(0, mallopt(-1000, 1));
   // mallopt doesn't set errno.
   ASSERT_EQ(0, errno);
 #else
-  GTEST_SKIP() << "musl doesn't have mallopt";
+  GTEST_SKIP() << "bionic-only test";
 #endif
 }
 
@@ -1528,3 +1529,157 @@
     }
   }
 }
+
+void VerifyAllocationsAreZero(std::function<void*(size_t)> alloc_func, std::string function_name,
+                              std::vector<size_t>& test_sizes, size_t max_allocations) {
+  // Vector of zero'd data used for comparisons. Make it twice the largest size.
+  std::vector<char> zero(test_sizes.back() * 2, 0);
+
+  SCOPED_TRACE(testing::Message() << function_name << " failed to zero memory");
+
+  for (size_t test_size : test_sizes) {
+    std::vector<void*> ptrs(max_allocations);
+    for (size_t i = 0; i < ptrs.size(); i++) {
+      SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+      ptrs[i] = alloc_func(test_size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+      size_t alloc_size = malloc_usable_size(ptrs[i]);
+      ASSERT_LE(alloc_size, zero.size());
+      ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+
+      // Set the memory to non-zero to make sure if the pointer
+      // is reused it's still zero.
+      memset(ptrs[i], 0xab, alloc_size);
+    }
+    // Free the pointers.
+    for (size_t i = 0; i < ptrs.size(); i++) {
+      free(ptrs[i]);
+    }
+    for (size_t i = 0; i < ptrs.size(); i++) {
+      SCOPED_TRACE(testing::Message() << "size " << test_size << " at iteration " << i);
+      ptrs[i] = malloc(test_size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+      size_t alloc_size = malloc_usable_size(ptrs[i]);
+      ASSERT_LE(alloc_size, zero.size());
+      ASSERT_EQ(0, memcmp(ptrs[i], zero.data(), alloc_size));
+    }
+    // Free all of the pointers later to maximize the chance of reusing from
+    // the first loop.
+    for (size_t i = 0; i < ptrs.size(); i++) {
+      free(ptrs[i]);
+    }
+  }
+}
+
+// Verify that small and medium allocations are always zero.
+TEST(malloc, zeroed_allocations_small_medium_sizes) {
+#if !defined(__BIONIC__)
+  GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+  if (IsLowRamDevice()) {
+    GTEST_SKIP() << "Skipped on low memory devices.";
+  }
+
+  constexpr size_t kMaxAllocations = 1024;
+  std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+  VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+                           kMaxAllocations);
+
+  VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+                           test_sizes, kMaxAllocations);
+
+  VerifyAllocationsAreZero(
+      [](size_t size) -> void* {
+        void* ptr;
+        if (posix_memalign(&ptr, 64, size) == 0) {
+          return ptr;
+        }
+        return nullptr;
+      },
+      "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+// Verify that large allocations are always zero.
+TEST(malloc, zeroed_allocations_large_sizes) {
+#if !defined(__BIONIC__)
+  GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+  if (IsLowRamDevice()) {
+    GTEST_SKIP() << "Skipped on low memory devices.";
+  }
+
+  constexpr size_t kMaxAllocations = 20;
+  std::vector<size_t> test_sizes = {1000000, 2000000, 3000000, 4000000};
+  VerifyAllocationsAreZero([](size_t size) -> void* { return malloc(size); }, "malloc", test_sizes,
+                           kMaxAllocations);
+
+  VerifyAllocationsAreZero([](size_t size) -> void* { return memalign(64, size); }, "memalign",
+                           test_sizes, kMaxAllocations);
+
+  VerifyAllocationsAreZero(
+      [](size_t size) -> void* {
+        void* ptr;
+        if (posix_memalign(&ptr, 64, size) == 0) {
+          return ptr;
+        }
+        return nullptr;
+      },
+      "posix_memalign", test_sizes, kMaxAllocations);
+}
+
+TEST(malloc, zeroed_allocations_realloc) {
+#if !defined(__BIONIC__)
+  GTEST_SKIP() << "Only valid on bionic";
+#endif
+
+  if (IsLowRamDevice()) {
+    GTEST_SKIP() << "Skipped on low memory devices.";
+  }
+
+  // Vector of zero'd data used for comparisons.
+  constexpr size_t kMaxMemorySize = 131072;
+  std::vector<char> zero(kMaxMemorySize, 0);
+
+  constexpr size_t kMaxAllocations = 1024;
+  std::vector<size_t> test_sizes = {16, 48, 128, 1024, 4096, 65536};
+  // Do a number of allocations and set them to non-zero.
+  for (size_t test_size : test_sizes) {
+    std::vector<void*> ptrs(kMaxAllocations);
+    for (size_t i = 0; i < kMaxAllocations; i++) {
+      ptrs[i] = malloc(test_size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+
+      // Set the memory to non-zero to make sure if the pointer
+      // is reused it's still zero.
+      memset(ptrs[i], 0xab, malloc_usable_size(ptrs[i]));
+    }
+    // Free the pointers.
+    for (size_t i = 0; i < kMaxAllocations; i++) {
+      free(ptrs[i]);
+    }
+  }
+
+  // Do the reallocs to a larger size and verify the rest of the allocation
+  // is zero.
+  constexpr size_t kInitialSize = 8;
+  for (size_t test_size : test_sizes) {
+    std::vector<void*> ptrs(kMaxAllocations);
+    for (size_t i = 0; i < kMaxAllocations; i++) {
+      ptrs[i] = malloc(kInitialSize);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+      size_t orig_alloc_size = malloc_usable_size(ptrs[i]);
+
+      ptrs[i] = realloc(ptrs[i], test_size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+      size_t new_alloc_size = malloc_usable_size(ptrs[i]);
+      char* ptr = reinterpret_cast<char*>(ptrs[i]);
+      ASSERT_EQ(0, memcmp(&ptr[orig_alloc_size], zero.data(), new_alloc_size - orig_alloc_size))
+          << "realloc from " << kInitialSize << " to size " << test_size << " at iteration " << i;
+    }
+    for (size_t i = 0; i < kMaxAllocations; i++) {
+      free(ptrs[i]);
+    }
+  }
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 40e5c6d..f0ad937 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -998,6 +998,10 @@
   ASSERT_EQ(-1, ts.tv_sec);
 }
 
+TEST(time, clock_getres_null_resolution) {
+  ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, nullptr));
+}
+
 TEST(time, clock) {
   // clock(3) is hard to test, but a 1s sleep should cost less than 10ms on average.
   static const clock_t N = 5;
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 8258833..92ab145 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -28,6 +28,10 @@
 
 #include "utils.h"
 
+#include <string>
+
+#include <android-base/properties.h>
+
 void RunGwpAsanTest(const char* test_name) {
   ExecTestHelper eh;
   eh.SetEnv({"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1", "GWP_ASAN_MAX_ALLOCS=40000",
@@ -53,3 +57,9 @@
          // |expected_output_regex|, ensure at least one test ran:
          R"(\[  PASSED  \] [1-9]+0? test)");
 }
+
+bool IsLowRamDevice() {
+  return android::base::GetBoolProperty("ro.config.low_ram", false) ||
+         (android::base::GetBoolProperty("ro.debuggable", false) &&
+          android::base::GetBoolProperty("debug.force_low_ram", false));
+}
diff --git a/tests/utils.h b/tests/utils.h
index 81869e3..2e00cc1 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -313,3 +313,5 @@
   return false;
 #endif
 }
+
+bool IsLowRamDevice();
diff --git a/tests/utmp_test.cpp b/tests/utmp_test.cpp
index 6d0d6f1..b024818 100644
--- a/tests/utmp_test.cpp
+++ b/tests/utmp_test.cpp
@@ -29,5 +29,6 @@
   setutent();
   ASSERT_EQ(NULL, getutent());
   endutent();
-  ASSERT_EQ(NULL, pututline(NULL));
+  utmp failure = {.ut_type = EMPTY};
+  ASSERT_EQ(NULL, pututline(&failure));
 }