From 2045373f30bd32e81d2a8430cb9a3d393a71b055 Mon Sep 17 00:00:00 2001
From: Sam Clegg <sbc@chromium.org>
Date: Mon, 24 May 2021 15:06:16 -0700
Subject: [PATCH] Update compiler-rt to llvm-12

---
 src/library_pthread.js                        |  10 +-
 .../include/sanitizer/asan_interface.h        |  16 +-
 .../include/sanitizer/common_interface_defs.h |   9 +-
 .../include/sanitizer/dfsan_interface.h       |   8 +-
 .../include/sanitizer/hwasan_interface.h      |   3 +
 .../include/sanitizer/linux_syscall_hooks.h   |   8 +-
 .../include/sanitizer/memprof_interface.h     |  65 ++
 .../include/sanitizer/msan_interface.h        |   3 +
 .../include/sanitizer/netbsd_syscall_hooks.h  | 213 +++++-
 .../include/sanitizer/tsan_interface.h        |  20 +-
 .../compiler-rt/lib/asan/asan_allocator.cpp   | 468 ++++++++-----
 .../lib/compiler-rt/lib/asan/asan_allocator.h |  11 +-
 .../compiler-rt/lib/asan/asan_emscripten.cpp  |   4 +-
 .../lib/compiler-rt/lib/asan/asan_flags.cpp   |  10 +-
 .../lib/compiler-rt/lib/asan/asan_fuchsia.cpp |  37 +-
 .../lib/asan/asan_interceptors.cpp            |  41 +-
 .../compiler-rt/lib/asan/asan_interceptors.h  |  22 +-
 .../lib/asan/asan_interface_internal.h        |   4 +-
 .../lib/compiler-rt/lib/asan/asan_internal.h  |  12 +-
 .../lib/compiler-rt/lib/asan/asan_linux.cpp   |  45 +-
 system/lib/compiler-rt/lib/asan/asan_mac.cpp  |  48 +-
 .../lib/asan/asan_malloc_linux.cpp            |  10 +-
 .../compiler-rt/lib/asan/asan_malloc_local.h  |   2 +-
 .../lib/compiler-rt/lib/asan/asan_mapping.h   |  21 +
 .../compiler-rt/lib/asan/asan_poisoning.cpp   |   8 -
 .../lib/compiler-rt/lib/asan/asan_posix.cpp   |  32 +
 .../lib/asan/asan_premap_shadow.cpp           |  18 +-
 .../lib/compiler-rt/lib/asan/asan_report.cpp  |   8 +-
 .../lib/compiler-rt/lib/asan/asan_rtems.cpp   |   8 +
 system/lib/compiler-rt/lib/asan/asan_rtl.cpp  |  78 ++-
 .../lib/asan/asan_shadow_setup.cpp            |  45 +-
 system/lib/compiler-rt/lib/asan/asan_stack.h  |   5 -
 .../lib/compiler-rt/lib/asan/asan_thread.cpp  |  29 +-
 system/lib/compiler-rt/lib/asan/asan_thread.h |   7 +-
 system/lib/compiler-rt/lib/asan/asan_win.cpp  |  21 +-
 system/lib/compiler-rt/lib/builtins/absvsi2.c |   2 +-
 system/lib/compiler-rt/lib/builtins/ashldi3.c |   2 +-
 system/lib/compiler-rt/lib/builtins/ashrdi3.c |   2 +-
 .../lib/compiler-rt/lib/builtins/assembly.h   |  93 ++-
 system/lib/compiler-rt/lib/builtins/atomic.c  |  99 +--
 .../compiler-rt/lib/builtins/clear_cache.c    |  22 +-
 system/lib/compiler-rt/lib/builtins/clzdi2.c  |   6 +-
 system/lib/compiler-rt/lib/builtins/clzsi2.c  |   2 +-
 system/lib/compiler-rt/lib/builtins/clzti2.c  |   2 +-
 .../lib/compiler-rt/lib/builtins/cpu_model.c  | 248 ++++---
 system/lib/compiler-rt/lib/builtins/ctzdi2.c  |   6 +-
 system/lib/compiler-rt/lib/builtins/ctzsi2.c  |   2 +-
 system/lib/compiler-rt/lib/builtins/ctzti2.c  |   2 +-
 system/lib/compiler-rt/lib/builtins/divdf3.c  | 189 +-----
 system/lib/compiler-rt/lib/builtins/divdi3.c  |  15 +-
 .../lib/compiler-rt/lib/builtins/divmoddi4.c  |  13 +-
 .../lib/compiler-rt/lib/builtins/divmodsi4.c  |  13 +-
 .../lib/compiler-rt/lib/builtins/divmodti4.c  |  32 +
 system/lib/compiler-rt/lib/builtins/divsf3.c  | 174 +----
 system/lib/compiler-rt/lib/builtins/divsi3.c  |  25 +-
 system/lib/compiler-rt/lib/builtins/divtf3.c  | 203 +-----
 system/lib/compiler-rt/lib/builtins/divti3.c  |  15 +-
 system/lib/compiler-rt/lib/builtins/emutls.c  |   7 +-
 .../compiler-rt/lib/builtins/extendhfsf2.c    |   6 +-
 .../compiler-rt/lib/builtins/extendhftf2.c    |  23 +
 system/lib/compiler-rt/lib/builtins/ffsdi2.c  |   6 +-
 system/lib/compiler-rt/lib/builtins/ffssi2.c  |   4 +-
 system/lib/compiler-rt/lib/builtins/ffsti2.c  |   2 +-
 .../lib/compiler-rt/lib/builtins/floatdidf.c  |   2 +-
 .../lib/compiler-rt/lib/builtins/floatdisf.c  |   2 +-
 .../lib/compiler-rt/lib/builtins/floatsidf.c  |   8 +-
 .../compiler-rt/lib/builtins/floatundidf.c    |   2 +-
 .../compiler-rt/lib/builtins/floatundisf.c    |   2 +-
 .../compiler-rt/lib/builtins/floatunsidf.c    |   6 +-
 .../compiler-rt/lib/builtins/fp_div_impl.inc  | 419 ++++++++++++
 .../lib/compiler-rt/lib/builtins/fp_extend.h  |   6 +-
 system/lib/compiler-rt/lib/builtins/fp_lib.h  |  13 +-
 system/lib/compiler-rt/lib/builtins/fp_mode.h |   4 +-
 .../lib/compiler-rt/lib/builtins/fp_trunc.h   |   4 +
 .../compiler-rt/lib/builtins/int_div_impl.inc |  95 +++
 system/lib/compiler-rt/lib/builtins/int_lib.h |  24 +-
 .../lib/builtins/int_mulo_impl.inc            |  49 ++
 .../lib/builtins/int_mulv_impl.inc            |  47 ++
 .../lib/compiler-rt/lib/builtins/int_types.h  |  26 +-
 .../lib/compiler-rt/lib/builtins/int_util.h   |  16 +
 system/lib/compiler-rt/lib/builtins/lshrdi3.c |   2 +-
 system/lib/compiler-rt/lib/builtins/moddi3.c  |  16 +-
 system/lib/compiler-rt/lib/builtins/modti3.c  |  16 +-
 system/lib/compiler-rt/lib/builtins/mulodi4.c |  33 +-
 system/lib/compiler-rt/lib/builtins/mulosi4.c |  33 +-
 system/lib/compiler-rt/lib/builtins/muloti4.c |  33 +-
 system/lib/compiler-rt/lib/builtins/mulvdi3.c |  33 +-
 system/lib/compiler-rt/lib/builtins/mulvsi3.c |  33 +-
 system/lib/compiler-rt/lib/builtins/mulvti3.c |  33 +-
 .../lib/builtins/os_version_check.c           | 108 ++-
 .../lib/compiler-rt/lib/builtins/paritydi2.c  |   8 +-
 .../lib/compiler-rt/lib/builtins/paritysi2.c  |   2 +-
 .../lib/compiler-rt/lib/builtins/parityti2.c  |  10 +-
 .../compiler-rt/lib/builtins/popcountdi2.c    |   2 +-
 .../compiler-rt/lib/builtins/popcountsi2.c    |   2 +-
 .../compiler-rt/lib/builtins/popcountti2.c    |   2 +-
 system/lib/compiler-rt/lib/builtins/powidf2.c |   2 +-
 system/lib/compiler-rt/lib/builtins/powisf2.c |   2 +-
 system/lib/compiler-rt/lib/builtins/powitf2.c |   7 +-
 system/lib/compiler-rt/lib/builtins/powixf2.c |   2 +-
 .../lib/compiler-rt/lib/builtins/truncdfhf2.c |   4 +-
 .../lib/compiler-rt/lib/builtins/truncsfhf2.c |   6 +-
 .../lib/compiler-rt/lib/builtins/trunctfhf2.c |  23 +
 system/lib/compiler-rt/lib/builtins/udivdi3.c |   6 +-
 .../lib/compiler-rt/lib/builtins/udivmoddi4.c |   6 +-
 .../lib/compiler-rt/lib/builtins/udivmodti4.c | 285 ++++----
 system/lib/compiler-rt/lib/builtins/udivsi3.c |  47 +-
 system/lib/compiler-rt/lib/builtins/umoddi3.c |   8 +-
 system/lib/compiler-rt/lib/builtins/umodsi3.c |   6 +-
 .../lib/interception/interception.h           |   4 +-
 .../lib/interception/interception_linux.cpp   |  10 +-
 .../lib/interception/interception_linux.h     |  11 +-
 .../lib/interception/interception_win.cpp     |   6 +-
 system/lib/compiler-rt/lib/lsan/lsan.cpp      |  21 +-
 system/lib/compiler-rt/lib/lsan/lsan.h        |   6 +
 .../compiler-rt/lib/lsan/lsan_allocator.cpp   |  10 +
 .../lib/compiler-rt/lib/lsan/lsan_allocator.h |  10 +-
 .../lib/compiler-rt/lib/lsan/lsan_common.cpp  | 349 +++++++---
 system/lib/compiler-rt/lib/lsan/lsan_common.h |  39 +-
 .../lib/lsan/lsan_common_emscripten.cpp       |   3 +-
 .../lib/lsan/lsan_common_fuchsia.cpp          | 165 +++++
 .../lib/lsan/lsan_common_linux.cpp            |   8 +-
 .../compiler-rt/lib/lsan/lsan_common_mac.cpp  |   3 +-
 .../lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp | 123 ++++
 .../lib/compiler-rt/lib/lsan/lsan_fuchsia.h   |  35 +
 .../lib/lsan/lsan_interceptors.cpp            |  45 +-
 .../lib/compiler-rt/lib/lsan/lsan_linux.cpp   |   6 +-
 .../lib/compiler-rt/lib/lsan/lsan_posix.cpp   |  96 +++
 system/lib/compiler-rt/lib/lsan/lsan_posix.h  |  49 ++
 .../lib/compiler-rt/lib/lsan/lsan_thread.cpp  | 103 +--
 system/lib/compiler-rt/lib/lsan/lsan_thread.h |  37 +-
 .../lib/sanitizer_common/.clang-tidy          |  16 -
 .../sanitizer_common/sanitizer_allocator.cpp  |  41 +-
 .../sanitizer_common/sanitizer_allocator.h    |   6 +-
 .../sanitizer_allocator_checks.h              |  10 +-
 .../sanitizer_allocator_primary32.h           |   1 +
 .../sanitizer_allocator_primary64.h           |  13 +-
 .../sanitizer_allocator_report.cpp            |   8 +
 .../sanitizer_allocator_report.h              |   1 +
 .../sanitizer_allocator_secondary.h           |   8 +-
 .../lib/sanitizer_common/sanitizer_atomic.h   |   4 +-
 .../sanitizer_common/sanitizer_atomic_clang.h |  14 +-
 .../sanitizer_atomic_clang_mips.h             |  10 +-
 .../sanitizer_atomic_clang_other.h            |  24 +-
 .../sanitizer_atomic_clang_x86.h              |   6 +-
 .../sanitizer_common/sanitizer_atomic_msvc.h  |  36 +-
 .../lib/sanitizer_common/sanitizer_common.cpp |   2 +
 .../lib/sanitizer_common/sanitizer_common.h   | 136 +++-
 .../sanitizer_common_interceptors.inc         | 431 ++++++++++--
 .../sanitizer_common_interceptors_format.inc  |   6 +
 .../sanitizer_common_interceptors_ioctl.inc   |   6 +-
 .../sanitizer_common_interface.inc            |   1 +
 .../sanitizer_common_libcdep.cpp              |  65 +-
 .../sanitizer_common_nolibc.cpp               |   4 +-
 .../sanitizer_common_syscalls.inc             |  31 +-
 .../sanitizer_coverage_fuchsia.cpp            |  25 +-
 .../sanitizer_coverage_interface.inc          |   1 +
 .../sanitizer_coverage_libcdep_new.cpp        |   1 +
 .../sanitizer_deadlock_detector1.cpp          |   2 +-
 .../sanitizer_deadlock_detector2.cpp          |   2 +-
 .../sanitizer_deadlock_detector_interface.h   |   6 +
 .../sanitizer_common/sanitizer_emscripten.cpp |   6 +-
 .../lib/sanitizer_common/sanitizer_errno.h    |   2 +-
 .../sanitizer_common/sanitizer_errno_codes.h  |   7 +-
 .../lib/sanitizer_common/sanitizer_file.cpp   |  37 +-
 .../lib/sanitizer_common/sanitizer_file.h     |   5 +-
 .../sanitizer_common/sanitizer_flag_parser.h  |   2 +-
 .../lib/sanitizer_common/sanitizer_flags.cpp  |   9 +-
 .../lib/sanitizer_common/sanitizer_flags.h    |   4 +
 .../lib/sanitizer_common/sanitizer_flags.inc  |  19 +-
 .../lib/sanitizer_common/sanitizer_freebsd.h  |  23 +-
 .../sanitizer_common/sanitizer_fuchsia.cpp    |  25 +-
 .../lib/sanitizer_common/sanitizer_fuchsia.h  |   6 +
 .../sanitizer_common/sanitizer_getauxval.h    |   5 +-
 .../sanitizer_interceptors_ioctl_netbsd.inc   |   6 +-
 .../sanitizer_interface_internal.h            |  10 +-
 .../sanitizer_internal_defs.h                 |  22 +-
 .../lib/sanitizer_common/sanitizer_libc.h     |   2 +
 .../sanitizer_common/sanitizer_libignore.cpp  |   2 +-
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 389 +++++++----
 .../lib/sanitizer_common/sanitizer_linux.h    |  13 +-
 .../sanitizer_linux_libcdep.cpp               | 221 +++++--
 .../sanitizer_common/sanitizer_linux_s390.cpp |   9 +-
 .../lib/sanitizer_common/sanitizer_mac.cpp    | 312 ++++++---
 .../lib/sanitizer_common/sanitizer_mac.h      |  44 +-
 .../sanitizer_common/sanitizer_malloc_mac.inc |  18 +-
 .../lib/sanitizer_common/sanitizer_netbsd.cpp |  10 +
 .../sanitizer_common/sanitizer_openbsd.cpp    | 115 ----
 .../lib/sanitizer_common/sanitizer_platform.h |  44 +-
 .../sanitizer_platform_interceptors.h         | 360 +++++-----
 .../sanitizer_platform_limits_freebsd.cpp     | 616 +++++++++---------
 .../sanitizer_platform_limits_freebsd.h       |  32 +-
 .../sanitizer_platform_limits_netbsd.cpp      | 284 ++++++++
 .../sanitizer_platform_limits_netbsd.h        |  16 +-
 .../sanitizer_platform_limits_openbsd.cpp     | 278 --------
 .../sanitizer_platform_limits_openbsd.h       | 381 -----------
 .../sanitizer_platform_limits_posix.cpp       | 116 ++--
 .../sanitizer_platform_limits_posix.h         |  15 +-
 .../sanitizer_platform_limits_solaris.cpp     |   4 +-
 .../sanitizer_platform_limits_solaris.h       |   1 +
 .../lib/sanitizer_common/sanitizer_posix.cpp  |  14 +-
 .../lib/sanitizer_common/sanitizer_posix.h    |   4 +-
 .../sanitizer_posix_libcdep.cpp               |  22 +-
 .../lib/sanitizer_common/sanitizer_procmaps.h |   7 +-
 .../sanitizer_procmaps_bsd.cpp                |  31 +-
 .../sanitizer_procmaps_common.cpp             |   2 +-
 .../sanitizer_procmaps_fuchsia.cpp            |  80 +++
 .../sanitizer_procmaps_solaris.cpp            |   7 +-
 .../lib/sanitizer_common/sanitizer_ptrauth.h  |  23 +
 .../lib/sanitizer_common/sanitizer_rtems.cpp  |   6 +-
 .../sanitizer_signal_interceptors.inc         |   5 +-
 .../sanitizer_common/sanitizer_solaris.cpp    |  18 +-
 .../sanitizer_common/sanitizer_stackdepot.cpp |   9 +-
 .../sanitizer_common/sanitizer_stackdepot.h   |   1 +
 .../sanitizer_stackdepotbase.h                |  20 +-
 .../sanitizer_common/sanitizer_stacktrace.cpp |  37 +-
 .../sanitizer_common/sanitizer_stacktrace.h   |  25 +-
 .../sanitizer_stacktrace_libcdep.cpp          |  21 +-
 .../sanitizer_stacktrace_printer.cpp          |  92 ++-
 .../sanitizer_stacktrace_printer.h            |   4 +-
 .../sanitizer_common/sanitizer_stoptheworld.h |  13 +-
 .../sanitizer_stoptheworld_fuchsia.cpp        |  43 ++
 .../sanitizer_stoptheworld_fuchsia.h          |  20 +
 .../sanitizer_stoptheworld_linux_libcdep.cpp  | 106 ++-
 .../sanitizer_stoptheworld_mac.cpp            |  29 +-
 .../sanitizer_stoptheworld_netbsd_libcdep.cpp |  16 +-
 .../sanitizer_common/sanitizer_symbolizer.cpp |   6 +
 .../sanitizer_common/sanitizer_symbolizer.h   |   3 +
 .../sanitizer_symbolizer_internal.h           |  14 +-
 .../sanitizer_symbolizer_libbacktrace.h       |   2 +-
 .../sanitizer_symbolizer_libcdep.cpp          |  98 +--
 .../sanitizer_symbolizer_mac.cpp              |  89 ++-
 .../sanitizer_symbolizer_mac.h                |   5 +-
 .../sanitizer_symbolizer_markup.cpp           |  11 +-
 .../sanitizer_symbolizer_posix_libcdep.cpp    |  41 +-
 .../sanitizer_symbolizer_report.cpp           |  11 +-
 .../sanitizer_symbolizer_win.cpp              |  13 +-
 .../sanitizer_syscall_generic.inc             |   2 +-
 .../sanitizer_syscall_linux_riscv64.inc       | 174 +++++
 .../sanitizer_syscalls_netbsd.inc             | 119 +++-
 .../sanitizer_thread_registry.h               |   5 +-
 .../sanitizer_tls_get_addr.cpp                |  86 ++-
 .../sanitizer_common/sanitizer_tls_get_addr.h |  21 +-
 .../sanitizer_common/sanitizer_unwind_win.cpp |  11 +
 .../lib/sanitizer_common/sanitizer_win.cpp    |  55 +-
 .../compiler-rt/lib/ubsan/ubsan_checks.inc    |   7 +
 .../lib/compiler-rt/lib/ubsan/ubsan_diag.cpp  |   2 +-
 .../lib/ubsan/ubsan_diag_standalone.cpp       |   2 +-
 .../lib/compiler-rt/lib/ubsan/ubsan_flags.cpp |  11 +-
 .../lib/compiler-rt/lib/ubsan/ubsan_flags.h   |   2 -
 .../compiler-rt/lib/ubsan/ubsan_handlers.cpp  |  83 ++-
 .../compiler-rt/lib/ubsan/ubsan_handlers.h    |   8 +
 .../lib/ubsan/ubsan_handlers_cxx.cpp          |   2 +-
 .../lib/compiler-rt/lib/ubsan/ubsan_init.cpp  |   4 +-
 .../lib/ubsan/ubsan_init_standalone.cpp       |   2 +-
 .../ubsan/ubsan_init_standalone_preinit.cpp   |   2 +-
 .../compiler-rt/lib/ubsan/ubsan_interface.inc |   2 +
 .../compiler-rt/lib/ubsan/ubsan_monitor.cpp   |   2 +-
 .../compiler-rt/lib/ubsan/ubsan_platform.h    |   2 +-
 .../lib/ubsan/ubsan_signals_standalone.cpp    |   3 +-
 .../compiler-rt/lib/ubsan/ubsan_type_hash.cpp |   4 +-
 .../lib/ubsan/ubsan_type_hash_itanium.cpp     |   6 +-
 .../lib/ubsan/ubsan_type_hash_win.cpp         |   4 +-
 .../lib/compiler-rt/lib/ubsan/ubsan_value.cpp |  50 +-
 .../lib/compiler-rt/lib/ubsan/ubsan_value.h   |   3 +
 .../lib/ubsan/ubsan_win_dll_thunk.cpp         |   2 +-
 .../ubsan/ubsan_win_dynamic_runtime_thunk.cpp |   2 +-
 .../lib/ubsan/ubsan_win_weak_interception.cpp |   2 +-
 .../ubsan_minimal/ubsan_minimal_handlers.cpp  |   3 +-
 system/lib/compiler-rt/readme.txt             |   8 +-
 system/lib/pthread/library_pthread_stub.c     |   5 +-
 271 files changed, 6966 insertions(+), 4263 deletions(-)
 create mode 100644 system/lib/compiler-rt/include/sanitizer/memprof_interface.h
 create mode 100644 system/lib/compiler-rt/lib/builtins/divmodti4.c
 create mode 100644 system/lib/compiler-rt/lib/builtins/extendhftf2.c
 create mode 100644 system/lib/compiler-rt/lib/builtins/fp_div_impl.inc
 create mode 100644 system/lib/compiler-rt/lib/builtins/int_div_impl.inc
 create mode 100644 system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc
 create mode 100644 system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc
 create mode 100644 system/lib/compiler-rt/lib/builtins/trunctfhf2.c
 create mode 100644 system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
 create mode 100644 system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp
 create mode 100644 system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h
 create mode 100644 system/lib/compiler-rt/lib/lsan/lsan_posix.cpp
 create mode 100644 system/lib/compiler-rt/lib/lsan/lsan_posix.h
 delete mode 100644 system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy
 create mode 100644 system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
 create mode 100644 system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
 create mode 100644 system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
 create mode 100644 system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h
 create mode 100644 system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc

diff --git a/src/library_pthread.js b/src/library_pthread.js
index 4bc001b758b7a..4670ccecc0617 100644
--- a/src/library_pthread.js
+++ b/src/library_pthread.js
@@ -1024,8 +1024,8 @@ var LibraryPThread = {
     return 0;
   },
 
-  pthread_detach__sig: 'vi',
-  pthread_detach: function(thread) {
+  {{{ USE_LSAN ? 'emscripten_builtin_' : '' }}}pthread_detach__sig: 'vi',
+  {{{ USE_LSAN ? 'emscripten_builtin_' : '' }}}pthread_detach: function(thread) {
     if (!thread) {
       err('pthread_detach attempted on a null thread pointer!');
       return ERRNO_CODES.ESRCH;
@@ -1043,9 +1043,13 @@ var LibraryPThread = {
     return wasDetached ? ERRNO_CODES.EINVAL : 0;
   },
 
-  // C11 threads function.
+  // C11 thread version.
   // TODO: remove this in favor or compiling musl/src/thread/pthread_detach.c
+#if USE_LSAN
+  thrd_detach: 'emscripten_builtin_pthread_detach',
+#else
   thrd_detach: 'pthread_detach',
+#endif
 
   pthread_exit__deps: ['exit'],
   pthread_exit: function(status) {
diff --git a/system/lib/compiler-rt/include/sanitizer/asan_interface.h b/system/lib/compiler-rt/include/sanitizer/asan_interface.h
index 6af93aad6512f..792ef9cfaa32b 100644
--- a/system/lib/compiler-rt/include/sanitizer/asan_interface.h
+++ b/system/lib/compiler-rt/include/sanitizer/asan_interface.h
@@ -188,8 +188,8 @@ const char *__asan_get_report_description(void);
 /// \param addr Address to locate.
 /// \param name Buffer to store the variable's name.
 /// \param name_size Size in bytes of the variable's name buffer.
-/// \param region_address [out] Address of the region.
-/// \param region_size [out] Size of the region in bytes.
+/// \param[out] region_address Address of the region.
+/// \param[out] region_size Size of the region in bytes.
 ///
 /// \returns Returns the category of the given pointer as a constant string.
 const char *__asan_locate_address(void *addr, char *name, size_t name_size,
@@ -204,7 +204,7 @@ const char *__asan_locate_address(void *addr, char *name, size_t name_size,
 /// \param addr A heap address.
 /// \param trace A buffer to store the stack trace.
 /// \param size Size in bytes of the trace buffer.
-/// \param thread_id [out] The thread ID of the address.
+/// \param[out] thread_id The thread ID of the address.
 ///
 /// \returns Returns the number of stored frames or 0 on error.
 size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
@@ -219,7 +219,7 @@ size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
 /// \param addr A heap address.
 /// \param trace A buffer to store the stack trace.
 /// \param size Size in bytes of the trace buffer.
-/// \param thread_id [out] The thread ID of the address.
+/// \param[out] thread_id The thread ID of the address.
 ///
 /// \returns Returns the number of stored frames or 0 on error.
 size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
@@ -228,8 +228,8 @@ size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
 /// Gets the current shadow memory mapping (useful for calling from the
 /// debugger).
 ///
-/// \param shadow_scale [out] Shadow scale value.
-/// \param shadow_offset [out] Offset value.
+/// \param[out] shadow_scale Shadow scale value.
+/// \param[out] shadow_offset Offset value.
 void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
 
 /// This is an internal function that is called to report an error. However,
@@ -302,8 +302,8 @@ void *__asan_get_current_fake_stack(void);
 ///
 /// \param fake_stack An opaque handler to a fake stack.
 /// \param addr Address to test.
-/// \param beg [out] Beginning of fake frame.
-/// \param end [out] End of fake frame.
+/// \param[out] beg Beginning of fake frame.
+/// \param[out] end End of fake frame.
 /// \returns Stack address or NULL.
 void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
                                    void **end);
diff --git a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h
index f979c6a8f63b1..cd69285b8d4af 100644
--- a/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h
+++ b/system/lib/compiler-rt/include/sanitizer/common_interface_defs.h
@@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
 // Tell the tools to write their reports to the provided file descriptor
 // (casted to void *).
 void __sanitizer_set_report_fd(void *fd);
+// Get the current full report file path, if a path was specified by
+// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
+const char *__sanitizer_get_report_path();
 
 // Notify the tools that the sandbox is going to be turned on. The reserved
 // parameter will be used in the future to hold a structure with functions
@@ -320,7 +323,7 @@ void __sanitizer_print_memory_profile(size_t top_percent,
 /// signal callback runs during the switch, it will not benefit from stack
 /// use-after-return detection.
 ///
-/// \param fake_stack_save [out] Fake stack save location.
+/// \param[out] fake_stack_save Fake stack save location.
 /// \param bottom Bottom address of stack.
 /// \param size Size of stack in bytes.
 void __sanitizer_start_switch_fiber(void **fake_stack_save,
@@ -335,8 +338,8 @@ void __sanitizer_start_switch_fiber(void **fake_stack_save,
 /// <c>__sanitizer_start_switch_fiber()</c>.
 ///
 /// \param fake_stack_save Fake stack save location.
-/// \param bottom_old [out] Bottom address of old stack.
-/// \param size_old [out] Size of old stack in bytes.
+/// \param[out] bottom_old Bottom address of old stack.
+/// \param[out] size_old Size of old stack in bytes.
 void __sanitizer_finish_switch_fiber(void *fake_stack_save,
                                      const void **bottom_old,
                                      size_t *size_old);
diff --git a/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h b/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h
index 81546e5df71af..18b2c81a6023c 100644
--- a/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h
+++ b/system/lib/compiler-rt/include/sanitizer/dfsan_interface.h
@@ -80,9 +80,11 @@ dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
 size_t dfsan_get_label_count(void);
 
 /// Flushes the DFSan shadow, i.e. forgets about all labels currently associated
-/// with the application memory. Will work only if there are no other
-/// threads executing DFSan-instrumented code concurrently.
-/// Use this call to start over the taint tracking within the same procces.
+/// with the application memory.  Use this call to start over the taint tracking
+/// within the same process.
+///
+/// Note: If another thread is working with tainted data during the flush, that
+/// taint could still be written to shadow after the flush.
 void dfsan_flush(void);
 
 /// Sets a callback to be invoked on calls to write().  The callback is invoked
diff --git a/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h b/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h
index 4c9ad13aa0cb1..14035c05c6353 100644
--- a/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h
+++ b/system/lib/compiler-rt/include/sanitizer/hwasan_interface.h
@@ -73,6 +73,9 @@ extern "C" {
    * accessed through the pointer in x, or -1 if the whole range is good. */
   intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
 
+  /* Sets the callback function to be called during HWASan error reporting. */
+  void __hwasan_set_error_report_callback(void (*callback)(const char *));
+
   int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
   void * __sanitizer_memalign(size_t alignment, size_t size);
   void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
diff --git a/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h
index a1794b71af503..56eae3d40f968 100644
--- a/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h
+++ b/system/lib/compiler-rt/include/sanitizer/linux_syscall_hooks.h
@@ -1845,6 +1845,10 @@
 #define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz)    \
   __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act,     \
                                              (long)oldact, (long)sz)
+#define __sanitizer_syscall_pre_sigaltstack(ss, oss)                           \
+  __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss)
+#define __sanitizer_syscall_post_sigaltstack(res, ss, oss)                     \
+  __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss)
 
 // And now a few syscalls we don't handle yet.
 #define __sanitizer_syscall_pre_afs_syscall(...)
@@ -1912,7 +1916,6 @@
 #define __sanitizer_syscall_pre_setreuid32(...)
 #define __sanitizer_syscall_pre_set_thread_area(...)
 #define __sanitizer_syscall_pre_setuid32(...)
-#define __sanitizer_syscall_pre_sigaltstack(...)
 #define __sanitizer_syscall_pre_sigreturn(...)
 #define __sanitizer_syscall_pre_sigsuspend(...)
 #define __sanitizer_syscall_pre_stty(...)
@@ -1992,7 +1995,6 @@
 #define __sanitizer_syscall_post_setreuid32(res, ...)
 #define __sanitizer_syscall_post_set_thread_area(res, ...)
 #define __sanitizer_syscall_post_setuid32(res, ...)
-#define __sanitizer_syscall_post_sigaltstack(res, ...)
 #define __sanitizer_syscall_post_sigreturn(res, ...)
 #define __sanitizer_syscall_post_sigsuspend(res, ...)
 #define __sanitizer_syscall_post_stty(res, ...)
@@ -3075,6 +3077,8 @@ void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
                                                long oldact, long sz);
 void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
                                                 long oldact, long sz);
+void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss);
+void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss);
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/system/lib/compiler-rt/include/sanitizer/memprof_interface.h b/system/lib/compiler-rt/include/sanitizer/memprof_interface.h
new file mode 100644
index 0000000000000..76031de4014c0
--- /dev/null
+++ b/system/lib/compiler-rt/include/sanitizer/memprof_interface.h
@@ -0,0 +1,65 @@
+//===-- sanitizer/memprof_interface.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of MemProfiler (MemProf).
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_MEMPROF_INTERFACE_H
+#define SANITIZER_MEMPROF_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/// Records access to a memory region (<c>[addr, addr+size)</c>).
+///
+/// This memory must be previously allocated by your program.
+///
+/// \param addr Start of memory region.
+/// \param size Size of memory region.
+void __memprof_record_access_range(void const volatile *addr, size_t size);
+
+/// Records access to a memory address <c><i>addr</i></c>.
+///
+/// This memory must be previously allocated by your program.
+///
+/// \param addr Accessed memory address
+void __memprof_record_access(void const volatile *addr);
+
+/// User-provided callback on MemProf errors.
+///
+/// You can provide a function that would be called immediately when MemProf
+/// detects an error. This is useful in cases when MemProf detects an error but
+/// your program crashes before the MemProf report is printed.
+void __memprof_on_error(void);
+
+/// Prints accumulated statistics to <c>stderr</c> (useful for calling from the
+/// debugger).
+void __memprof_print_accumulated_stats(void);
+
+/// User-provided default option settings.
+///
+/// You can provide your own implementation of this function to return a string
+/// containing MemProf runtime options (for example,
+/// <c>verbosity=1:print_stats=1</c>).
+///
+/// \returns Default options string.
+const char *__memprof_default_options(void);
+
+/// Prints the memory profile to the current profile file.
+///
+/// \returns 0 on success.
+int __memprof_profile_dump(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_MEMPROF_INTERFACE_H
diff --git a/system/lib/compiler-rt/include/sanitizer/msan_interface.h b/system/lib/compiler-rt/include/sanitizer/msan_interface.h
index d40c556a46d93..eeb39fbed8b49 100644
--- a/system/lib/compiler-rt/include/sanitizer/msan_interface.h
+++ b/system/lib/compiler-rt/include/sanitizer/msan_interface.h
@@ -114,6 +114,9 @@ extern "C" {
      call to __msan_scoped_disable_interceptor_checks. */
   void __msan_scoped_enable_interceptor_checks(void);
 
+  void __msan_start_switch_fiber(const void *bottom, size_t size);
+  void __msan_finish_switch_fiber(const void **bottom_old, size_t *size_old);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h b/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h
index 370da0ea72ed8..f661152ccbac7 100644
--- a/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h
+++ b/system/lib/compiler-rt/include/sanitizer/netbsd_syscall_hooks.h
@@ -20,8 +20,8 @@
 // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
 //
 // Generated with: generate_netbsd_syscalls.awk
-// Generated date: 2019-12-24
-// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
+// Generated date: 2020-09-10
+// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp
 //
 //===----------------------------------------------------------------------===//
 #ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H
@@ -474,7 +474,12 @@
   __sanitizer_syscall_pre_impl_dup2((long long)(from), (long long)(to))
 #define __sanitizer_syscall_post_dup2(res, from, to)                           \
   __sanitizer_syscall_post_impl_dup2(res, (long long)(from), (long long)(to))
-/* syscall 91 has been skipped */
+#define __sanitizer_syscall_pre_getrandom(buf, buflen, flags)                  \
+  __sanitizer_syscall_pre_impl_getrandom(                                      \
+      (long long)(buf), (long long)(buflen), (long long)(flags))
+#define __sanitizer_syscall_post_getrandom(res, buf, buflen, flags)            \
+  __sanitizer_syscall_post_impl_getrandom(                                     \
+      res, (long long)(buf), (long long)(buflen), (long long)(flags))
 #define __sanitizer_syscall_pre_fcntl(fd, cmd, arg)                            \
   __sanitizer_syscall_pre_impl_fcntl((long long)(fd), (long long)(cmd),        \
                                      (long long)(arg))
@@ -849,9 +854,31 @@
 #define __sanitizer_syscall_post_sysarch(res, op, parms)                       \
   __sanitizer_syscall_post_impl_sysarch(res, (long long)(op),                  \
                                         (long long)(parms))
-/* syscall 166 has been skipped */
-/* syscall 167 has been skipped */
-/* syscall 168 has been skipped */
+#define __sanitizer_syscall_pre___futex(uaddr, op, val, timeout, uaddr2, val2, \
+                                        val3)                                  \
+  __sanitizer_syscall_pre_impl___futex((long long)(uaddr), (long long)(op),    \
+                                       (long long)(val), (long long)(timeout), \
+                                       (long long)(uaddr2), (long long)(val2), \
+                                       (long long)(val3))
+#define __sanitizer_syscall_post___futex(res, uaddr, op, val, timeout, uaddr2, \
+                                         val2, val3)                           \
+  __sanitizer_syscall_post_impl___futex(                                       \
+      res, (long long)(uaddr), (long long)(op), (long long)(val),              \
+      (long long)(timeout), (long long)(uaddr2), (long long)(val2),            \
+      (long long)(val3))
+#define __sanitizer_syscall_pre___futex_set_robust_list(head, len)             \
+  __sanitizer_syscall_pre_impl___futex_set_robust_list((long long)(head),      \
+                                                       (long long)(len))
+#define __sanitizer_syscall_post___futex_set_robust_list(res, head, len)       \
+  __sanitizer_syscall_post_impl___futex_set_robust_list(                       \
+      res, (long long)(head), (long long)(len))
+#define __sanitizer_syscall_pre___futex_get_robust_list(lwpid, headp, lenp)    \
+  __sanitizer_syscall_pre_impl___futex_get_robust_list(                        \
+      (long long)(lwpid), (long long)(headp), (long long)(lenp))
+#define __sanitizer_syscall_post___futex_get_robust_list(res, lwpid, headp,    \
+                                                         lenp)                 \
+  __sanitizer_syscall_post_impl___futex_get_robust_list(                       \
+      res, (long long)(lwpid), (long long)(headp), (long long)(lenp))
 #if !defined(_LP64)
 #define __sanitizer_syscall_pre_compat_10_osemsys(which, a2, a3, a4, a5)       \
   __sanitizer_syscall_pre_impl_compat_10_osemsys(                              \
@@ -2731,6 +2758,83 @@
   __sanitizer_syscall_post_impl___fhstatvfs190(                                \
       res, (long long)(fhp), (long long)(fh_size), (long long)(buf),           \
       (long long)(flags))
+#define __sanitizer_syscall_pre___acl_get_link(path, type, aclp)               \
+  __sanitizer_syscall_pre_impl___acl_get_link(                                 \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_get_link(res, path, type, aclp)         \
+  __sanitizer_syscall_post_impl___acl_get_link(                                \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_set_link(path, type, aclp)               \
+  __sanitizer_syscall_pre_impl___acl_set_link(                                 \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_set_link(res, path, type, aclp)         \
+  __sanitizer_syscall_post_impl___acl_set_link(                                \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_delete_link(path, type)                  \
+  __sanitizer_syscall_pre_impl___acl_delete_link((long long)(path),            \
+                                                 (long long)(type))
+#define __sanitizer_syscall_post___acl_delete_link(res, path, type)            \
+  __sanitizer_syscall_post_impl___acl_delete_link(res, (long long)(path),      \
+                                                  (long long)(type))
+#define __sanitizer_syscall_pre___acl_aclcheck_link(path, type, aclp)          \
+  __sanitizer_syscall_pre_impl___acl_aclcheck_link(                            \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_aclcheck_link(res, path, type, aclp)    \
+  __sanitizer_syscall_post_impl___acl_aclcheck_link(                           \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_get_file(path, type, aclp)               \
+  __sanitizer_syscall_pre_impl___acl_get_file(                                 \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_get_file(res, path, type, aclp)         \
+  __sanitizer_syscall_post_impl___acl_get_file(                                \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_set_file(path, type, aclp)               \
+  __sanitizer_syscall_pre_impl___acl_set_file(                                 \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_set_file(res, path, type, aclp)         \
+  __sanitizer_syscall_post_impl___acl_set_file(                                \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_get_fd(filedes, type, aclp)              \
+  __sanitizer_syscall_pre_impl___acl_get_fd(                                   \
+      (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_get_fd(res, filedes, type, aclp)        \
+  __sanitizer_syscall_post_impl___acl_get_fd(                                  \
+      res, (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_set_fd(filedes, type, aclp)              \
+  __sanitizer_syscall_pre_impl___acl_set_fd(                                   \
+      (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_set_fd(res, filedes, type, aclp)        \
+  __sanitizer_syscall_post_impl___acl_set_fd(                                  \
+      res, (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_delete_file(path, type)                  \
+  __sanitizer_syscall_pre_impl___acl_delete_file((long long)(path),            \
+                                                 (long long)(type))
+#define __sanitizer_syscall_post___acl_delete_file(res, path, type)            \
+  __sanitizer_syscall_post_impl___acl_delete_file(res, (long long)(path),      \
+                                                  (long long)(type))
+#define __sanitizer_syscall_pre___acl_delete_fd(filedes, type)                 \
+  __sanitizer_syscall_pre_impl___acl_delete_fd((long long)(filedes),           \
+                                               (long long)(type))
+#define __sanitizer_syscall_post___acl_delete_fd(res, filedes, type)           \
+  __sanitizer_syscall_post_impl___acl_delete_fd(res, (long long)(filedes),     \
+                                                (long long)(type))
+#define __sanitizer_syscall_pre___acl_aclcheck_file(path, type, aclp)          \
+  __sanitizer_syscall_pre_impl___acl_aclcheck_file(                            \
+      (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_aclcheck_file(res, path, type, aclp)    \
+  __sanitizer_syscall_post_impl___acl_aclcheck_file(                           \
+      res, (long long)(path), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre___acl_aclcheck_fd(filedes, type, aclp)         \
+  __sanitizer_syscall_pre_impl___acl_aclcheck_fd(                              \
+      (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_post___acl_aclcheck_fd(res, filedes, type, aclp)   \
+  __sanitizer_syscall_post_impl___acl_aclcheck_fd(                             \
+      res, (long long)(filedes), (long long)(type), (long long)(aclp))
+#define __sanitizer_syscall_pre_lpathconf(path, name)                          \
+  __sanitizer_syscall_pre_impl_lpathconf((long long)(path), (long long)(name))
+#define __sanitizer_syscall_post_lpathconf(res, path, name)                    \
+  __sanitizer_syscall_post_impl_lpathconf(res, (long long)(path),              \
+                                          (long long)(name))
 
 /* Compat with older releases */
 #define __sanitizer_syscall_pre_getvfsstat                                     \
@@ -3088,7 +3192,10 @@ void __sanitizer_syscall_post_impl_compat_43_ogetdtablesize(long long res);
 void __sanitizer_syscall_pre_impl_dup2(long long from, long long to);
 void __sanitizer_syscall_post_impl_dup2(long long res, long long from,
                                         long long to);
-/* syscall 91 has been skipped */
+void __sanitizer_syscall_pre_impl_getrandom(long long buf, long long buflen,
+                                            long long flags);
+void __sanitizer_syscall_post_impl_getrandom(long long res, long long buf,
+                                             long long buflen, long long flags);
 void __sanitizer_syscall_pre_impl_fcntl(long long fd, long long cmd,
                                         long long arg);
 void __sanitizer_syscall_post_impl_fcntl(long long res, long long fd,
@@ -3380,9 +3487,26 @@ void __sanitizer_syscall_post_impl_compat_09_ouname(long long res,
 void __sanitizer_syscall_pre_impl_sysarch(long long op, long long parms);
 void __sanitizer_syscall_post_impl_sysarch(long long res, long long op,
                                            long long parms);
-/* syscall 166 has been skipped */
-/* syscall 167 has been skipped */
-/* syscall 168 has been skipped */
+void __sanitizer_syscall_pre_impl___futex(long long uaddr, long long op,
+                                          long long val, long long timeout,
+                                          long long uaddr2, long long val2,
+                                          long long val3);
+void __sanitizer_syscall_post_impl___futex(long long res, long long uaddr,
+                                           long long op, long long val,
+                                           long long timeout, long long uaddr2,
+                                           long long val2, long long val3);
+void __sanitizer_syscall_pre_impl___futex_set_robust_list(long long head,
+                                                          long long len);
+void __sanitizer_syscall_post_impl___futex_set_robust_list(long long res,
+                                                           long long head,
+                                                           long long len);
+void __sanitizer_syscall_pre_impl___futex_get_robust_list(long long lwpid,
+                                                          long long headp,
+                                                          long long lenp);
+void __sanitizer_syscall_post_impl___futex_get_robust_list(long long res,
+                                                           long long lwpid,
+                                                           long long headp,
+                                                           long long lenp);
 #if !defined(_LP64)
 void __sanitizer_syscall_pre_impl_compat_10_osemsys(long long which,
                                                     long long a2, long long a3,
@@ -4802,6 +4926,75 @@ void __sanitizer_syscall_post_impl___fhstatvfs190(long long res, long long fhp,
                                                   long long fh_size,
                                                   long long buf,
                                                   long long flags);
+void __sanitizer_syscall_pre_impl___acl_get_link(long long path, long long type,
+                                                 long long aclp);
+void __sanitizer_syscall_post_impl___acl_get_link(long long res, long long path,
+                                                  long long type,
+                                                  long long aclp);
+void __sanitizer_syscall_pre_impl___acl_set_link(long long path, long long type,
+                                                 long long aclp);
+void __sanitizer_syscall_post_impl___acl_set_link(long long res, long long path,
+                                                  long long type,
+                                                  long long aclp);
+void __sanitizer_syscall_pre_impl___acl_delete_link(long long path,
+                                                    long long type);
+void __sanitizer_syscall_post_impl___acl_delete_link(long long res,
+                                                     long long path,
+                                                     long long type);
+void __sanitizer_syscall_pre_impl___acl_aclcheck_link(long long path,
+                                                      long long type,
+                                                      long long aclp);
+void __sanitizer_syscall_post_impl___acl_aclcheck_link(long long res,
+                                                       long long path,
+                                                       long long type,
+                                                       long long aclp);
+void __sanitizer_syscall_pre_impl___acl_get_file(long long path, long long type,
+                                                 long long aclp);
+void __sanitizer_syscall_post_impl___acl_get_file(long long res, long long path,
+                                                  long long type,
+                                                  long long aclp);
+void __sanitizer_syscall_pre_impl___acl_set_file(long long path, long long type,
+                                                 long long aclp);
+void __sanitizer_syscall_post_impl___acl_set_file(long long res, long long path,
+                                                  long long type,
+                                                  long long aclp);
+void __sanitizer_syscall_pre_impl___acl_get_fd(long long filedes,
+                                               long long type, long long aclp);
+void __sanitizer_syscall_post_impl___acl_get_fd(long long res,
+                                                long long filedes,
+                                                long long type, long long aclp);
+void __sanitizer_syscall_pre_impl___acl_set_fd(long long filedes,
+                                               long long type, long long aclp);
+void __sanitizer_syscall_post_impl___acl_set_fd(long long res,
+                                                long long filedes,
+                                                long long type, long long aclp);
+void __sanitizer_syscall_pre_impl___acl_delete_file(long long path,
+                                                    long long type);
+void __sanitizer_syscall_post_impl___acl_delete_file(long long res,
+                                                     long long path,
+                                                     long long type);
+void __sanitizer_syscall_pre_impl___acl_delete_fd(long long filedes,
+                                                  long long type);
+void __sanitizer_syscall_post_impl___acl_delete_fd(long long res,
+                                                   long long filedes,
+                                                   long long type);
+void __sanitizer_syscall_pre_impl___acl_aclcheck_file(long long path,
+                                                      long long type,
+                                                      long long aclp);
+void __sanitizer_syscall_post_impl___acl_aclcheck_file(long long res,
+                                                       long long path,
+                                                       long long type,
+                                                       long long aclp);
+void __sanitizer_syscall_pre_impl___acl_aclcheck_fd(long long filedes,
+                                                    long long type,
+                                                    long long aclp);
+void __sanitizer_syscall_post_impl___acl_aclcheck_fd(long long res,
+                                                     long long filedes,
+                                                     long long type,
+                                                     long long aclp);
+void __sanitizer_syscall_pre_impl_lpathconf(long long path, long long name);
+void __sanitizer_syscall_post_impl_lpathconf(long long res, long long path,
+                                             long long name);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/system/lib/compiler-rt/include/sanitizer/tsan_interface.h b/system/lib/compiler-rt/include/sanitizer/tsan_interface.h
index 011b23350cac3..96b8ad58541cb 100644
--- a/system/lib/compiler-rt/include/sanitizer/tsan_interface.h
+++ b/system/lib/compiler-rt/include/sanitizer/tsan_interface.h
@@ -38,34 +38,34 @@ void __tsan_release(void *addr);
 
 // Mutex has static storage duration and no-op constructor and destructor.
 // This effectively makes tsan ignore destroy annotation.
-const unsigned __tsan_mutex_linker_init      = 1 << 0;
+static const unsigned __tsan_mutex_linker_init      = 1 << 0;
 // Mutex is write reentrant.
-const unsigned __tsan_mutex_write_reentrant  = 1 << 1;
+static const unsigned __tsan_mutex_write_reentrant  = 1 << 1;
 // Mutex is read reentrant.
-const unsigned __tsan_mutex_read_reentrant   = 1 << 2;
+static const unsigned __tsan_mutex_read_reentrant   = 1 << 2;
 // Mutex does not have static storage duration, and must not be used after
 // its destructor runs.  The opposite of __tsan_mutex_linker_init.
 // If this flag is passed to __tsan_mutex_destroy, then the destruction
 // is ignored unless this flag was previously set on the mutex.
-const unsigned __tsan_mutex_not_static       = 1 << 8;
+static const unsigned __tsan_mutex_not_static       = 1 << 8;
 
 // Mutex operation flags:
 
 // Denotes read lock operation.
-const unsigned __tsan_mutex_read_lock        = 1 << 3;
+static const unsigned __tsan_mutex_read_lock        = 1 << 3;
 // Denotes try lock operation.
-const unsigned __tsan_mutex_try_lock         = 1 << 4;
+static const unsigned __tsan_mutex_try_lock         = 1 << 4;
 // Denotes that a try lock operation has failed to acquire the mutex.
-const unsigned __tsan_mutex_try_lock_failed  = 1 << 5;
+static const unsigned __tsan_mutex_try_lock_failed  = 1 << 5;
 // Denotes that the lock operation acquires multiple recursion levels.
 // Number of levels is passed in recursion parameter.
 // This is useful for annotation of e.g. Java builtin monitors,
 // for which wait operation releases all recursive acquisitions of the mutex.
-const unsigned __tsan_mutex_recursive_lock   = 1 << 6;
+static const unsigned __tsan_mutex_recursive_lock   = 1 << 6;
 // Denotes that the unlock operation releases all recursion levels.
 // Number of released levels is returned and later must be passed to
 // the corresponding __tsan_mutex_post_lock annotation.
-const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
+static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
 
 // Annotate creation of a mutex.
 // Supported flags: mutex creation flags.
@@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
 
 // Flags for __tsan_switch_to_fiber:
 // Do not establish a happens-before relation between fibers
-const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
+static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp
index 65c51fbafdd0c..cd97b37652f8b 100644
--- a/system/lib/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_allocator.cpp
@@ -15,20 +15,21 @@
 //===----------------------------------------------------------------------===//
 
 #include "asan_allocator.h"
+
 #include "asan_mapping.h"
 #include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "asan_thread.h"
+#include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_allocator_checks.h"
 #include "sanitizer_common/sanitizer_allocator_interface.h"
 #include "sanitizer_common/sanitizer_errno.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_list.h"
-#include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_quarantine.h"
-#include "lsan/lsan_common.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
 
 namespace __asan {
 
@@ -50,6 +51,22 @@ static u32 RZSize2Log(u32 rz_size) {
 
 static AsanAllocator &get_allocator();
 
+static void AtomicContextStore(volatile atomic_uint64_t *atomic_context,
+                               u32 tid, u32 stack) {
+  u64 context = tid;
+  context <<= 32;
+  context += stack;
+  atomic_store(atomic_context, context, memory_order_relaxed);
+}
+
+static void AtomicContextLoad(const volatile atomic_uint64_t *atomic_context,
+                              u32 &tid, u32 &stack) {
+  u64 context = atomic_load(atomic_context, memory_order_relaxed);
+  stack = context;
+  context >>= 32;
+  tid = context;
+}
+
 // The memory chunk allocated from the underlying allocator looks like this:
 // L L L L L L H H U U U U U U R R
 //   L -- left redzone words (0 or more bytes)
@@ -67,32 +84,59 @@ static AsanAllocator &get_allocator();
 //   ---------------------|
 //   M -- magic value kAllocBegMagic
 //   B -- address of ChunkHeader pointing to the first 'H'
-static const uptr kAllocBegMagic = 0xCC6E96B9;
-
-struct ChunkHeader {
-  // 1-st 8 bytes.
-  u32 chunk_state       : 8;  // Must be first.
-  u32 alloc_tid         : 24;
-
-  u32 free_tid          : 24;
-  u32 from_memalign     : 1;
-  u32 alloc_type        : 2;
-  u32 rz_log            : 3;
-  u32 lsan_tag          : 2;
-  // 2-nd 8 bytes
-  // This field is used for small sizes. For large sizes it is equal to
-  // SizeClassMap::kMaxSize and the actual size is stored in the
-  // SecondaryAllocator's metadata.
-  u32 user_requested_size : 29;
+
+class ChunkHeader {
+ public:
+  atomic_uint8_t chunk_state;
+  u8 alloc_type : 2;
+  u8 lsan_tag : 2;
+
   // align < 8 -> 0
   // else      -> log2(min(align, 512)) - 2
-  u32 user_requested_alignment_log : 3;
-  u32 alloc_context_id;
+  u8 user_requested_alignment_log : 3;
+
+ private:
+  u16 user_requested_size_hi;
+  u32 user_requested_size_lo;
+  atomic_uint64_t alloc_context_id;
+
+ public:
+  uptr UsedSize() const {
+    uptr R = user_requested_size_lo;
+    if (sizeof(uptr) > sizeof(user_requested_size_lo))
+      R += (uptr)user_requested_size_hi << (8 * sizeof(user_requested_size_lo));
+    return R;
+  }
+
+  void SetUsedSize(uptr size) {
+    user_requested_size_lo = size;
+    if (sizeof(uptr) > sizeof(user_requested_size_lo)) {
+      size >>= (8 * sizeof(user_requested_size_lo));
+      user_requested_size_hi = size;
+      CHECK_EQ(user_requested_size_hi, size);
+    }
+  }
+
+  void SetAllocContext(u32 tid, u32 stack) {
+    AtomicContextStore(&alloc_context_id, tid, stack);
+  }
+
+  void GetAllocContext(u32 &tid, u32 &stack) const {
+    AtomicContextLoad(&alloc_context_id, tid, stack);
+  }
 };
 
-struct ChunkBase : ChunkHeader {
-  // Header2, intersects with user memory.
-  u32 free_context_id;
+class ChunkBase : public ChunkHeader {
+  atomic_uint64_t free_context_id;
+
+ public:
+  void SetFreeContext(u32 tid, u32 stack) {
+    AtomicContextStore(&free_context_id, tid, stack);
+  }
+
+  void GetFreeContext(u32 &tid, u32 &stack) const {
+    AtomicContextLoad(&free_context_id, tid, stack);
+  }
 };
 
 static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
@@ -100,35 +144,50 @@ static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize;
 COMPILER_CHECK(kChunkHeaderSize == 16);
 COMPILER_CHECK(kChunkHeader2Size <= 16);
 
-// Every chunk of memory allocated by this allocator can be in one of 3 states:
-// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
-// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
-// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
 enum {
-  CHUNK_AVAILABLE  = 0,  // 0 is the default value even if we didn't set it.
-  CHUNK_ALLOCATED  = 2,
-  CHUNK_QUARANTINE = 3
+  // Either just allocated by underlying allocator, but AsanChunk is not yet
+  // ready, or almost returned to undelying allocator and AsanChunk is already
+  // meaningless.
+  CHUNK_INVALID = 0,
+  // The chunk is allocated and not yet freed.
+  CHUNK_ALLOCATED = 2,
+  // The chunk was freed and put into quarantine zone.
+  CHUNK_QUARANTINE = 3,
 };
 
-struct AsanChunk: ChunkBase {
+class AsanChunk : public ChunkBase {
+ public:
   uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
-  uptr UsedSize(bool locked_version = false) {
-    if (user_requested_size != SizeClassMap::kMaxSize)
-      return user_requested_size;
-    return *reinterpret_cast<uptr *>(
-               get_allocator().GetMetaData(AllocBeg(locked_version)));
+  bool AddrIsInside(uptr addr) {
+    return (addr >= Beg()) && (addr < Beg() + UsedSize());
   }
-  void *AllocBeg(bool locked_version = false) {
-    if (from_memalign) {
-      if (locked_version)
-        return get_allocator().GetBlockBeginFastLocked(
-            reinterpret_cast<void *>(this));
-      return get_allocator().GetBlockBegin(reinterpret_cast<void *>(this));
-    }
-    return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
+};
+
+class LargeChunkHeader {
+  static constexpr uptr kAllocBegMagic =
+      FIRST_32_SECOND_64(0xCC6E96B9, 0xCC6E96B9CC6E96B9ULL);
+  atomic_uintptr_t magic;
+  AsanChunk *chunk_header;
+
+ public:
+  AsanChunk *Get() const {
+    return atomic_load(&magic, memory_order_acquire) == kAllocBegMagic
+               ? chunk_header
+               : nullptr;
   }
-  bool AddrIsInside(uptr addr, bool locked_version = false) {
-    return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
+
+  void Set(AsanChunk *p) {
+    if (p) {
+      chunk_header = p;
+      atomic_store(&magic, kAllocBegMagic, memory_order_release);
+      return;
+    }
+
+    uptr old = kAllocBegMagic;
+    if (!atomic_compare_exchange_strong(&magic, &old, 0,
+                                        memory_order_release)) {
+      CHECK_EQ(old, kAllocBegMagic);
+    }
   }
 };
 
@@ -139,23 +198,23 @@ struct QuarantineCallback {
   }
 
   void Recycle(AsanChunk *m) {
-    CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
-    atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
-    CHECK_NE(m->alloc_tid, kInvalidTid);
-    CHECK_NE(m->free_tid, kInvalidTid);
-    PoisonShadow(m->Beg(),
-                 RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
-                 kAsanHeapLeftRedzoneMagic);
-    void *p = reinterpret_cast<void *>(m->AllocBeg());
+    void *p = get_allocator().GetBlockBegin(m);
     if (p != m) {
-      uptr *alloc_magic = reinterpret_cast<uptr *>(p);
-      CHECK_EQ(alloc_magic[0], kAllocBegMagic);
       // Clear the magic value, as allocator internals may overwrite the
       // contents of deallocated chunk, confusing GetAsanChunk lookup.
-      alloc_magic[0] = 0;
-      CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m));
+      reinterpret_cast<LargeChunkHeader *>(p)->Set(nullptr);
     }
 
+    u8 old_chunk_state = CHUNK_QUARANTINE;
+    if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state,
+                                        CHUNK_INVALID, memory_order_acquire)) {
+      CHECK_EQ(old_chunk_state, CHUNK_QUARANTINE);
+    }
+
+    PoisonShadow(m->Beg(),
+                 RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
+                 kAsanHeapLeftRedzoneMagic);
+
     // Statistics.
     AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.real_frees++;
@@ -299,23 +358,26 @@ struct Allocator {
     // This could be a user-facing chunk (with redzones), or some internal
     // housekeeping chunk, like TransferBatch. Start by assuming the former.
     AsanChunk *ac = GetAsanChunk((void *)chunk);
-    uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac);
-    uptr beg = ac->Beg();
-    uptr end = ac->Beg() + ac->UsedSize(true);
-    uptr chunk_end = chunk + allocated_size;
-    if (chunk < beg && beg < end && end <= chunk_end &&
-        ac->chunk_state == CHUNK_ALLOCATED) {
-      // Looks like a valid AsanChunk in use, poison redzones only.
-      PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
-      uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
-      FastPoisonShadowPartialRightRedzone(
-          end_aligned_down, end - end_aligned_down,
-          chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
-    } else {
-      // This is either not an AsanChunk or freed or quarantined AsanChunk.
-      // In either case, poison everything.
-      PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
+    uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)chunk);
+    if (ac && atomic_load(&ac->chunk_state, memory_order_acquire) ==
+                  CHUNK_ALLOCATED) {
+      uptr beg = ac->Beg();
+      uptr end = ac->Beg() + ac->UsedSize();
+      uptr chunk_end = chunk + allocated_size;
+      if (chunk < beg && beg < end && end <= chunk_end) {
+        // Looks like a valid AsanChunk in use, poison redzones only.
+        PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
+        uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
+        FastPoisonShadowPartialRightRedzone(
+            end_aligned_down, end - end_aligned_down,
+            chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
+        return;
+      }
     }
+
+    // This is either not an AsanChunk or freed or quarantined AsanChunk.
+    // In either case, poison everything.
+    PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
   }
 
   void ReInitialize(const AllocatorOptions &options) {
@@ -348,17 +410,18 @@ struct Allocator {
 
   // -------------------- Helper methods. -------------------------
   uptr ComputeRZLog(uptr user_requested_size) {
-    u32 rz_log =
-      user_requested_size <= 64        - 16   ? 0 :
-      user_requested_size <= 128       - 32   ? 1 :
-      user_requested_size <= 512       - 64   ? 2 :
-      user_requested_size <= 4096      - 128  ? 3 :
-      user_requested_size <= (1 << 14) - 256  ? 4 :
-      user_requested_size <= (1 << 15) - 512  ? 5 :
-      user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
-    u32 min_rz = atomic_load(&min_redzone, memory_order_acquire);
-    u32 max_rz = atomic_load(&max_redzone, memory_order_acquire);
-    return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
+    u32 rz_log = user_requested_size <= 64 - 16            ? 0
+                 : user_requested_size <= 128 - 32         ? 1
+                 : user_requested_size <= 512 - 64         ? 2
+                 : user_requested_size <= 4096 - 128       ? 3
+                 : user_requested_size <= (1 << 14) - 256  ? 4
+                 : user_requested_size <= (1 << 15) - 512  ? 5
+                 : user_requested_size <= (1 << 16) - 1024 ? 6
+                                                           : 7;
+    u32 hdr_log = RZSize2Log(RoundUpToPowerOfTwo(sizeof(ChunkHeader)));
+    u32 min_log = RZSize2Log(atomic_load(&min_redzone, memory_order_acquire));
+    u32 max_log = RZSize2Log(atomic_load(&max_redzone, memory_order_acquire));
+    return Min(Max(rz_log, Max(min_log, hdr_log)), Max(max_log, hdr_log));
   }
 
   static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) {
@@ -378,16 +441,23 @@ struct Allocator {
   // We have an address between two chunks, and we want to report just one.
   AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
                          AsanChunk *right_chunk) {
+    if (!left_chunk)
+      return right_chunk;
+    if (!right_chunk)
+      return left_chunk;
     // Prefer an allocated chunk over freed chunk and freed chunk
     // over available chunk.
-    if (left_chunk->chunk_state != right_chunk->chunk_state) {
-      if (left_chunk->chunk_state == CHUNK_ALLOCATED)
+    u8 left_state = atomic_load(&left_chunk->chunk_state, memory_order_relaxed);
+    u8 right_state =
+        atomic_load(&right_chunk->chunk_state, memory_order_relaxed);
+    if (left_state != right_state) {
+      if (left_state == CHUNK_ALLOCATED)
         return left_chunk;
-      if (right_chunk->chunk_state == CHUNK_ALLOCATED)
+      if (right_state == CHUNK_ALLOCATED)
         return right_chunk;
-      if (left_chunk->chunk_state == CHUNK_QUARANTINE)
+      if (left_state == CHUNK_QUARANTINE)
         return left_chunk;
-      if (right_chunk->chunk_state == CHUNK_QUARANTINE)
+      if (right_state == CHUNK_QUARANTINE)
         return right_chunk;
     }
     // Same chunk_state: choose based on offset.
@@ -402,10 +472,11 @@ struct Allocator {
   bool UpdateAllocationStack(uptr addr, BufferedStackTrace *stack) {
     AsanChunk *m = GetAsanChunkByAddr(addr);
     if (!m) return false;
-    if (m->chunk_state != CHUNK_ALLOCATED) return false;
+    if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
+      return false;
     if (m->Beg() != addr) return false;
-    atomic_store((atomic_uint32_t *)&m->alloc_context_id, StackDepotPut(*stack),
-                 memory_order_relaxed);
+    AsanThread *t = GetCurrentThread();
+    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
     return true;
   }
 
@@ -442,13 +513,10 @@ struct Allocator {
     uptr needed_size = rounded_size + rz_size;
     if (alignment > min_alignment)
       needed_size += alignment;
-    bool using_primary_allocator = true;
     // If we are allocating from the secondary allocator, there will be no
     // automatic right redzone, so add the right redzone manually.
-    if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) {
+    if (!PrimaryAllocator::CanAllocate(needed_size, alignment))
       needed_size += rz_size;
-      using_primary_allocator = false;
-    }
     CHECK(IsAligned(needed_size, min_alignment));
     if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize ||
         size > max_user_defined_malloc_size) {
@@ -490,8 +558,7 @@ struct Allocator {
 
     uptr alloc_beg = reinterpret_cast<uptr>(allocated);
     uptr alloc_end = alloc_beg + needed_size;
-    uptr beg_plus_redzone = alloc_beg + rz_size;
-    uptr user_beg = beg_plus_redzone;
+    uptr user_beg = alloc_beg + rz_size;
     if (!IsAligned(user_beg, alignment))
       user_beg = RoundUpTo(user_beg, alignment);
     uptr user_end = user_beg + size;
@@ -499,31 +566,11 @@ struct Allocator {
     uptr chunk_beg = user_beg - kChunkHeaderSize;
     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
     m->alloc_type = alloc_type;
-    m->rz_log = rz_log;
-    u32 alloc_tid = t ? t->tid() : 0;
-    m->alloc_tid = alloc_tid;
-    CHECK_EQ(alloc_tid, m->alloc_tid);  // Does alloc_tid fit into the bitfield?
-    m->free_tid = kInvalidTid;
-    m->from_memalign = user_beg != beg_plus_redzone;
-    if (alloc_beg != chunk_beg) {
-      CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg);
-      reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic;
-      reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg;
-    }
-    if (using_primary_allocator) {
-      CHECK(size);
-      m->user_requested_size = size;
-      CHECK(allocator.FromPrimary(allocated));
-    } else {
-      CHECK(!allocator.FromPrimary(allocated));
-      m->user_requested_size = SizeClassMap::kMaxSize;
-      uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
-      meta[0] = size;
-      meta[1] = chunk_beg;
-    }
+    CHECK(size);
+    m->SetUsedSize(size);
     m->user_requested_alignment_log = user_requested_alignment_log;
 
-    m->alloc_context_id = StackDepotPut(*stack);
+    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
 
     uptr size_rounded_down_to_granularity =
         RoundDownTo(size, SHADOW_GRANULARITY);
@@ -556,7 +603,11 @@ struct Allocator {
                                                  : __lsan::kDirectlyLeaked;
 #endif
     // Must be the last mutation of metadata in this function.
-    atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
+    atomic_store(&m->chunk_state, CHUNK_ALLOCATED, memory_order_release);
+    if (alloc_beg != chunk_beg) {
+      CHECK_LE(alloc_beg + sizeof(LargeChunkHeader), chunk_beg);
+      reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Set(m);
+    }
     ASAN_MALLOC_HOOK(res, size);
     return res;
   }
@@ -564,10 +615,10 @@ struct Allocator {
   // Set quarantine flag if chunk is allocated, issue ASan error report on
   // available and quarantined chunks. Return true on success, false otherwise.
   bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr,
-                                   BufferedStackTrace *stack) {
+                                              BufferedStackTrace *stack) {
     u8 old_chunk_state = CHUNK_ALLOCATED;
     // Flip the chunk_state atomically to avoid race on double-free.
-    if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state,
+    if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state,
                                         CHUNK_QUARANTINE,
                                         memory_order_acquire)) {
       ReportInvalidFree(ptr, old_chunk_state, stack);
@@ -575,19 +626,18 @@ struct Allocator {
       return false;
     }
     CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+    // It was a user data.
+    m->SetFreeContext(kInvalidTid, 0);
     return true;
   }
 
   // Expects the chunk to already be marked as quarantined by using
   // AtomicallySetQuarantineFlagIfAllocated.
   void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
-    CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
-    CHECK_GE(m->alloc_tid, 0);
-    if (SANITIZER_WORDSIZE == 64)  // On 32-bits this resides in user area.
-      CHECK_EQ(m->free_tid, kInvalidTid);
+    CHECK_EQ(atomic_load(&m->chunk_state, memory_order_relaxed),
+             CHUNK_QUARANTINE);
     AsanThread *t = GetCurrentThread();
-    m->free_tid = t ? t->tid() : 0;
-    m->free_context_id = StackDepotPut(*stack);
+    m->SetFreeContext(t ? t->tid() : 0, StackDepotPut(*stack));
 
     Flags &fl = *flags();
     if (fl.max_free_fill_size > 0) {
@@ -676,7 +726,7 @@ struct Allocator {
 
     void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
     if (new_ptr) {
-      u8 chunk_state = m->chunk_state;
+      u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire);
       if (chunk_state != CHUNK_ALLOCATED)
         ReportInvalidFree(old_ptr, chunk_state, stack);
       CHECK_NE(REAL(memcpy), nullptr);
@@ -719,17 +769,24 @@ struct Allocator {
   // -------------------------- Chunk lookup ----------------------
 
   // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
+  // Returns nullptr if AsanChunk is not yet initialized just after
+  // get_allocator().Allocate(), or is being destroyed just before
+  // get_allocator().Deallocate().
   AsanChunk *GetAsanChunk(void *alloc_beg) {
-    if (!alloc_beg) return nullptr;
-    if (!allocator.FromPrimary(alloc_beg)) {
-      uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
-      AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
-      return m;
+    if (!alloc_beg)
+      return nullptr;
+    AsanChunk *p = reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Get();
+    if (!p) {
+      if (!allocator.FromPrimary(alloc_beg))
+        return nullptr;
+      p = reinterpret_cast<AsanChunk *>(alloc_beg);
     }
-    uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg);
-    if (alloc_magic[0] == kAllocBegMagic)
-      return reinterpret_cast<AsanChunk *>(alloc_magic[1]);
-    return reinterpret_cast<AsanChunk *>(alloc_beg);
+    u8 state = atomic_load(&p->chunk_state, memory_order_relaxed);
+    // It does not guaranty that Chunk is initialized, but it's
+    // definitely not for any other value.
+    if (state == CHUNK_ALLOCATED || state == CHUNK_QUARANTINE)
+      return p;
+    return nullptr;
   }
 
   AsanChunk *GetAsanChunkByAddr(uptr p) {
@@ -747,16 +804,16 @@ struct Allocator {
   uptr AllocationSize(uptr p) {
     AsanChunk *m = GetAsanChunkByAddr(p);
     if (!m) return 0;
-    if (m->chunk_state != CHUNK_ALLOCATED) return 0;
+    if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
+      return 0;
     if (m->Beg() != p) return 0;
     return m->UsedSize();
   }
 
   AsanChunkView FindHeapChunkByAddress(uptr addr) {
     AsanChunk *m1 = GetAsanChunkByAddr(addr);
-    if (!m1) return AsanChunkView(m1);
     sptr offset = 0;
-    if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
+    if (!m1 || AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
       // The address is in the chunk's left redzone, so maybe it is actually
       // a right buffer overflow from the other chunk to the left.
       // Search a bit to the left to see if there is another chunk.
@@ -813,13 +870,16 @@ static AsanAllocator &get_allocator() {
 }
 
 bool AsanChunkView::IsValid() const {
-  return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
+  return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) !=
+                       CHUNK_INVALID;
 }
 bool AsanChunkView::IsAllocated() const {
-  return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED;
+  return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) ==
+                       CHUNK_ALLOCATED;
 }
 bool AsanChunkView::IsQuarantined() const {
-  return chunk_ && chunk_->chunk_state == CHUNK_QUARANTINE;
+  return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) ==
+                       CHUNK_QUARANTINE;
 }
 uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
 uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
@@ -827,8 +887,23 @@ uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
 u32 AsanChunkView::UserRequestedAlignment() const {
   return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
 }
-uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
-uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; }
+
+uptr AsanChunkView::AllocTid() const {
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetAllocContext(tid, stack);
+  return tid;
+}
+
+uptr AsanChunkView::FreeTid() const {
+  if (!IsQuarantined())
+    return kInvalidTid;
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetFreeContext(tid, stack);
+  return tid;
+}
+
 AllocType AsanChunkView::GetAllocType() const {
   return (AllocType)chunk_->alloc_type;
 }
@@ -840,8 +915,21 @@ static StackTrace GetStackTraceFromId(u32 id) {
   return res;
 }
 
-u32 AsanChunkView::GetAllocStackId() const { return chunk_->alloc_context_id; }
-u32 AsanChunkView::GetFreeStackId() const { return chunk_->free_context_id; }
+u32 AsanChunkView::GetAllocStackId() const {
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetAllocContext(tid, stack);
+  return stack;
+}
+
+u32 AsanChunkView::GetFreeStackId() const {
+  if (!IsQuarantined())
+    return 0;
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetFreeContext(tid, stack);
+  return stack;
+}
 
 StackTrace AsanChunkView::GetAllocStack() const {
   return GetStackTraceFromId(GetAllocStackId());
@@ -1005,7 +1093,7 @@ void AsanSoftRssLimitExceededCallback(bool limit_exceeded) {
   instance.SetRssLimitExceeded(limit_exceeded);
 }
 
-} // namespace __asan
+}  // namespace __asan
 
 // --- Implementation of LSan-specific functions --- {{{1
 namespace __lsan {
@@ -1022,34 +1110,36 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
   *end = *begin + sizeof(__asan::get_allocator());
 }
 
-uptr PointsIntoChunk(void* p) {
+uptr PointsIntoChunk(void *p) {
   uptr addr = reinterpret_cast<uptr>(p);
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr);
-  if (!m) return 0;
-  uptr chunk = m->Beg();
-  if (m->chunk_state != __asan::CHUNK_ALLOCATED)
+  if (!m || atomic_load(&m->chunk_state, memory_order_acquire) !=
+                __asan::CHUNK_ALLOCATED)
     return 0;
-  if (m->AddrIsInside(addr, /*locked_version=*/true))
+  uptr chunk = m->Beg();
+  if (m->AddrIsInside(addr))
     return chunk;
-  if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
-                                  addr))
+  if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(), addr))
     return chunk;
   return 0;
 }
 
 uptr GetUserBegin(uptr chunk) {
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
-  CHECK(m);
-  return m->Beg();
+  return m ? m->Beg() : 0;
 }
 
 LsanMetadata::LsanMetadata(uptr chunk) {
-  metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize);
+  metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
+                    : nullptr;
 }
 
 bool LsanMetadata::allocated() const {
+  if (!metadata_)
+    return false;
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return m->chunk_state == __asan::CHUNK_ALLOCATED;
+  return atomic_load(&m->chunk_state, memory_order_relaxed) ==
+         __asan::CHUNK_ALLOCATED;
 }
 
 ChunkTag LsanMetadata::tag() const {
@@ -1064,12 +1154,15 @@ void LsanMetadata::set_tag(ChunkTag value) {
 
 uptr LsanMetadata::requested_size() const {
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return m->UsedSize(/*locked_version=*/true);
+  return m->UsedSize();
 }
 
 u32 LsanMetadata::stack_trace_id() const {
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return m->alloc_context_id;
+  u32 tid = 0;
+  u32 stack = 0;
+  m->GetAllocContext(tid, stack);
+  return stack;
 }
 
 void ForEachChunk(ForEachChunkCallback callback, void *arg) {
@@ -1079,16 +1172,45 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
 IgnoreObjectResult IgnoreObjectLocked(const void *p) {
   uptr addr = reinterpret_cast<uptr>(p);
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
-  if (!m) return kIgnoreObjectInvalid;
-  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) {
-    if (m->lsan_tag == kIgnored)
-      return kIgnoreObjectAlreadyIgnored;
-    m->lsan_tag = __lsan::kIgnored;
-    return kIgnoreObjectSuccess;
-  } else {
+  if (!m ||
+      (atomic_load(&m->chunk_state, memory_order_acquire) !=
+       __asan::CHUNK_ALLOCATED) ||
+      !m->AddrIsInside(addr)) {
     return kIgnoreObjectInvalid;
   }
+  if (m->lsan_tag == kIgnored)
+    return kIgnoreObjectAlreadyIgnored;
+  m->lsan_tag = __lsan::kIgnored;
+  return kIgnoreObjectSuccess;
+}
+
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
+  // Look for the arg pointer of threads that have been created or are running.
+  // This is necessary to prevent false positive leaks due to the AsanThread
+  // holding the only live reference to a heap object.  This can happen because
+  // the `pthread_create()` interceptor doesn't wait for the child thread to
+  // start before returning and thus loosing the the only live reference to the
+  // heap object on the stack.
+
+  __asan::AsanThreadContext *atctx =
+      reinterpret_cast<__asan::AsanThreadContext *>(tctx);
+  __asan::AsanThread *asan_thread = atctx->thread;
+
+  // Note ThreadStatusRunning is required because there is a small window where
+  // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
+  // still isn't on the stack yet.
+  if (atctx->status != ThreadStatusCreated &&
+      atctx->status != ThreadStatusRunning)
+    return;
+
+  uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
+  if (!thread_arg)
+    return;
+
+  auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
+  ptrsVec->push_back(thread_arg);
 }
+
 }  // namespace __lsan
 
 // ---------------------- Interface ---------------- {{{1
diff --git a/system/lib/compiler-rt/lib/asan/asan_allocator.h b/system/lib/compiler-rt/lib/asan/asan_allocator.h
index b37d8ef4e8d29..2963e979b55c0 100644
--- a/system/lib/compiler-rt/lib/asan/asan_allocator.h
+++ b/system/lib/compiler-rt/lib/asan/asan_allocator.h
@@ -15,10 +15,11 @@
 #define ASAN_ALLOCATOR_H
 
 #include "asan_flags.h"
-#include "asan_internal.h"
 #include "asan_interceptors.h"
+#include "asan_internal.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_list.h"
+#include "sanitizer_common/sanitizer_platform.h"
 
 namespace __asan {
 
@@ -28,7 +29,7 @@ enum AllocType {
   FROM_NEW_BR = 3   // Memory block came from operator new [ ]
 };
 
-struct AsanChunk;
+class AsanChunk;
 
 struct AllocatorOptions {
   u32 quarantine_size_mb;
@@ -132,6 +133,10 @@ typedef DefaultSizeClassMap SizeClassMap;
 const uptr kAllocatorSpace =  ~(uptr)0;
 const uptr kAllocatorSize  =  0x2000000000ULL;  // 128G.
 typedef VeryCompactSizeClassMap SizeClassMap;
+#elif SANITIZER_RISCV64
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize = 0x2000000000ULL;  // 128G.
+typedef VeryDenseSizeClassMap SizeClassMap;
 # elif defined(__aarch64__)
 // AArch64/SANITIZER_CAN_USE_ALLOCATOR64 is only for 42-bit VMA
 // so no need to different values for different VMA.
@@ -171,7 +176,7 @@ template <typename AddressSpaceViewTy>
 struct AP32 {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
-  static const uptr kMetadataSize = 16;
+  static const uptr kMetadataSize = 0;
   typedef __asan::SizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = 20;
   using AddressSpaceView = AddressSpaceViewTy;
diff --git a/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp b/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp
index 5c33e7e3b7f50..cb11a93ac754a 100644
--- a/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_emscripten.cpp
@@ -33,6 +33,8 @@ void *AsanDoesNotSupportStaticLinkage() {
 
 void InitializeAsanInterceptors() {}
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {}
+
 // We can use a plain thread_local variable for TSD.
 static thread_local void *per_thread;
 
@@ -65,7 +67,7 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
     internal_sched_yield();
   emscripten_builtin_free(param);
   SetCurrentThread(t);
-  return t->ThreadStart(GetTid(), nullptr);
+  return t->ThreadStart(GetTid());
 }
 
 INTERCEPTOR(int, pthread_create, void *thread,
diff --git a/system/lib/compiler-rt/lib/asan/asan_flags.cpp b/system/lib/compiler-rt/lib/asan/asan_flags.cpp
index a09535f8269e0..197dfb23661af 100644
--- a/system/lib/compiler-rt/lib/asan/asan_flags.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_flags.cpp
@@ -32,10 +32,6 @@ namespace __asan {
 
 Flags asan_flags_dont_use_directly;  // use via flags().
 
-static const char *MaybeCallAsanDefaultOptions() {
-  return (&__asan_default_options) ? __asan_default_options() : "";
-}
-
 static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
 #ifdef ASAN_DEFAULT_OPTIONS
   return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS);
@@ -118,14 +114,14 @@ void InitializeFlags() {
   asan_parser.ParseString(asan_compile_def);
 
   // Override from user-specified string.
-  const char *asan_default_options = MaybeCallAsanDefaultOptions();
+  const char *asan_default_options = __asan_default_options();
   asan_parser.ParseString(asan_default_options);
 #if CAN_SANITIZE_UB
-  const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+  const char *ubsan_default_options = __ubsan_default_options();
   ubsan_parser.ParseString(ubsan_default_options);
 #endif
 #if CAN_SANITIZE_LEAKS
-  const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions();
+  const char *lsan_default_options = __lsan_default_options();
   lsan_parser.ParseString(lsan_default_options);
 #endif
 
diff --git a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp
index f8b2d5f26979d..6c61344f87cfe 100644
--- a/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_fuchsia.cpp
@@ -62,6 +62,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
   UNIMPLEMENTED();
 }
 
+bool PlatformUnpoisonStacks() { return false; }
+
 // We can use a plain thread_local variable for TSD.
 static thread_local void *per_thread;
 
@@ -89,8 +91,7 @@ struct AsanThread::InitOptions {
 // Shared setup between thread creation and startup for the initial thread.
 static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
                                     uptr user_id, bool detached,
-                                    const char *name, uptr stack_bottom,
-                                    uptr stack_size) {
+                                    const char *name) {
   // In lieu of AsanThread::Create.
   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
 
@@ -99,12 +100,6 @@ static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
       asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
   asanThreadRegistry().SetThreadName(tid, name);
 
-  // On other systems, AsanThread::Init() is called from the new
-  // thread itself.  But on Fuchsia we already know the stack address
-  // range beforehand, so we can do most of the setup right now.
-  const AsanThread::InitOptions options = {stack_bottom, stack_size};
-  thread->Init(&options);
-
   return thread;
 }
 
@@ -133,9 +128,16 @@ AsanThread *CreateMainThread() {
       _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
                               sizeof(name)) == ZX_OK
           ? name
-          : nullptr,
-      __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize);
+          : nullptr);
+  // We need to set the current thread before calling AsanThread::Init() below,
+  // since it reads the thread ID.
   SetCurrentThread(t);
+  DCHECK_EQ(t->tid(), 0);
+
+  const AsanThread::InitOptions options = {__sanitizer::MainThreadStackBase,
+                                           __sanitizer::MainThreadStackSize};
+  t->Init(&options);
+
   return t;
 }
 
@@ -151,8 +153,15 @@ static void *BeforeThreadCreateHook(uptr user_id, bool detached,
   GET_STACK_TRACE_THREAD;
   u32 parent_tid = GetCurrentTidOrInvalid();
 
-  return CreateAsanThread(&stack, parent_tid, user_id, detached, name,
-                          stack_bottom, stack_size);
+  AsanThread *thread =
+      CreateAsanThread(&stack, parent_tid, user_id, detached, name);
+
+  // On other systems, AsanThread::Init() is called from the new
+  // thread itself.  But on Fuchsia we already know the stack address
+  // range beforehand, so we can do most of the setup right now.
+  const AsanThread::InitOptions options = {stack_bottom, stack_size};
+  thread->Init(&options);
+  return thread;
 }
 
 // This is called after creating a new thread (in the creating thread),
@@ -196,6 +205,10 @@ bool HandleDlopenInit() {
   return false;
 }
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+  __sanitizer_fill_shadow(p, size, 0, 0);
+}
+
 }  // namespace __asan
 
 // These are declared (in extern "C") by <zircon/sanitizer.h>.
diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp
index 9002c7fe4dbd9..6f124e9770373 100644
--- a/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -189,20 +189,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
 #include "sanitizer_common/sanitizer_common_syscalls.inc"
 #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
 
-struct ThreadStartParam {
-  atomic_uintptr_t t;
-  atomic_uintptr_t is_registered;
-};
-
 #if ASAN_INTERCEPT_PTHREAD_CREATE
 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
-  ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
-  AsanThread *t = nullptr;
-  while ((t = reinterpret_cast<AsanThread *>(
-              atomic_load(&param->t, memory_order_acquire))) == nullptr)
-    internal_sched_yield();
+  AsanThread *t = (AsanThread *)arg;
   SetCurrentThread(t);
-  return t->ThreadStart(GetTid(), &param->is_registered);
+  return t->ThreadStart(GetTid());
 }
 
 INTERCEPTOR(int, pthread_create, void *thread,
@@ -215,9 +206,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
   int detached = 0;
   if (attr)
     REAL(pthread_attr_getdetachstate)(attr, &detached);
-  ThreadStartParam param;
-  atomic_store(&param.t, 0, memory_order_relaxed);
-  atomic_store(&param.is_registered, 0, memory_order_relaxed);
+
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t =
+      AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+
   int result;
   {
     // Ignore all allocations made by pthread_create: thread stack/TLS may be
@@ -227,21 +220,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
 #if CAN_SANITIZE_LEAKS
     __lsan::ScopedInterceptorDisabler disabler;
 #endif
-    result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+    result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
   }
-  if (result == 0) {
-    u32 current_tid = GetCurrentTidOrInvalid();
-    AsanThread *t =
-        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
-    atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
-    // Wait until the AsanThread object is initialized and the ThreadRegistry
-    // entry is in "started" state. One reason for this is that after this
-    // interceptor exits, the child thread's stack may be the only thing holding
-    // the |arg| pointer. This may cause LSan to report a leak if leak checking
-    // happens at a point when the interceptor has already exited, but the stack
-    // range for the child thread is not yet known.
-    while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
-      internal_sched_yield();
+  if (result != 0) {
+    // If the thread didn't start delete the AsanThread to avoid leaking it.
+    // Note AsanThreadContexts never get destroyed so the AsanThreadContext
+    // that was just created for the AsanThread is wasted.
+    t->Destroy();
   }
   return result;
 }
diff --git a/system/lib/compiler-rt/lib/asan/asan_interceptors.h b/system/lib/compiler-rt/lib/asan/asan_interceptors.h
index 344a64bd83d33..45cdb80b1b640 100644
--- a/system/lib/compiler-rt/lib/asan/asan_interceptors.h
+++ b/system/lib/compiler-rt/lib/asan/asan_interceptors.h
@@ -13,9 +13,10 @@
 #ifndef ASAN_INTERCEPTORS_H
 #define ASAN_INTERCEPTORS_H
 
-#include "asan_internal.h"
 #include "asan_interceptors_memintrinsics.h"
+#include "asan_internal.h"
 #include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform.h"
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 
 namespace __asan {
@@ -59,7 +60,7 @@ void InitializePlatformInterceptors();
 # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
 #endif
 
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
+#if SANITIZER_GLIBC || SANITIZER_SOLARIS
 # define ASAN_INTERCEPT_SWAPCONTEXT 1
 #else
 # define ASAN_INTERCEPT_SWAPCONTEXT 0
@@ -71,7 +72,7 @@ void InitializePlatformInterceptors();
 # define ASAN_INTERCEPT_SIGLONGJMP 0
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
 # define ASAN_INTERCEPT___LONGJMP_CHK 1
 #else
 # define ASAN_INTERCEPT___LONGJMP_CHK 0
@@ -105,14 +106,15 @@ void InitializePlatformInterceptors();
 # define ASAN_INTERCEPT_ATEXIT 0
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
 # define ASAN_INTERCEPT___STRDUP 1
 #else
 # define ASAN_INTERCEPT___STRDUP 0
 #endif
 
-#if SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__) || \
-                        defined(__i386__) || defined(__x86_64__))
+#if SANITIZER_LINUX &&                                                \
+    (defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \
+     defined(__x86_64__) || SANITIZER_RISCV64)
 # define ASAN_INTERCEPT_VFORK 1
 #else
 # define ASAN_INTERCEPT_VFORK 0
@@ -132,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
 DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
 
 #if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name)                                         \
-  do {                                                                    \
-    if (!INTERCEPT_FUNCTION(name))                                        \
-      VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
+#define ASAN_INTERCEPT_FUNC(name)                                        \
+  do {                                                                   \
+    if (!INTERCEPT_FUNCTION(name))                                       \
+      VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
   } while (0)
 #define ASAN_INTERCEPT_FUNC_VER(name, ver)                                  \
   do {                                                                      \
diff --git a/system/lib/compiler-rt/lib/asan/asan_interface_internal.h b/system/lib/compiler-rt/lib/asan/asan_interface_internal.h
index f14cbbcb76a35..3e6e660288746 100644
--- a/system/lib/compiler-rt/lib/asan/asan_interface_internal.h
+++ b/system/lib/compiler-rt/lib/asan/asan_interface_internal.h
@@ -173,8 +173,8 @@ extern "C" {
 
   SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
 
-  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-  const char* __asan_default_options();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char *__asan_default_options();
 
   SANITIZER_INTERFACE_ATTRIBUTE
   extern uptr __asan_shadow_memory_dynamic_address;
diff --git a/system/lib/compiler-rt/lib/asan/asan_internal.h b/system/lib/compiler-rt/lib/asan/asan_internal.h
index 72a4c3f22ff1c..cfb54927c6cf4 100644
--- a/system/lib/compiler-rt/lib/asan/asan_internal.h
+++ b/system/lib/compiler-rt/lib/asan/asan_internal.h
@@ -83,6 +83,16 @@ void *AsanDoesNotSupportStaticLinkage();
 void AsanCheckDynamicRTPrereqs();
 void AsanCheckIncompatibleRT();
 
+// Unpoisons platform-specific stacks.
+// Returns true if all stacks have been unpoisoned.
+bool PlatformUnpoisonStacks();
+
+// asan_rtl.cpp
+// Unpoison a region containing a stack.
+// Performs a sanity check and warns if the bounds don't look right.
+// The warning contains the type string to identify the stack type.
+void UnpoisonStack(uptr bottom, uptr top, const char *type);
+
 // asan_thread.cpp
 AsanThread *CreateMainThread();
 
@@ -108,8 +118,6 @@ void AppendToErrorMessageBuffer(const char *buffer);
 
 void *AsanDlSymNext(const char *sym);
 
-void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
-
 // Returns `true` iff most of ASan init process should be skipped due to the
 // ASan library being loaded via `dlopen()`. Platforms may perform any
 // `dlopen()` specific initialization inside this function.
diff --git a/system/lib/compiler-rt/lib/asan/asan_linux.cpp b/system/lib/compiler-rt/lib/asan/asan_linux.cpp
index ce5e873dc5180..4bcbe5d02e334 100644
--- a/system/lib/compiler-rt/lib/asan/asan_linux.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_linux.cpp
@@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
 #else
 #include <sys/ucontext.h>
 #include <link.h>
+extern ElfW(Dyn) _DYNAMIC[];
 #endif
 
 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
@@ -84,28 +85,15 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
 
 void *AsanDoesNotSupportStaticLinkage() {
   // This will fail to link with -static.
-  return &_DYNAMIC;  // defined in link.h
-}
-
-static void UnmapFromTo(uptr from, uptr to) {
-  CHECK(to >= from);
-  if (to == from) return;
-  uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
-  if (UNLIKELY(internal_iserror(res))) {
-    Report(
-        "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
-        "%p\n",
-        to - from, to - from, from);
-    CHECK("unable to unmap" && 0);
-  }
+  return &_DYNAMIC;
 }
 
 #if ASAN_PREMAP_SHADOW
-uptr FindPremappedShadowStart() {
+uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
   uptr granularity = GetMmapGranularity();
   uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
   uptr premap_shadow_size = PremapShadowSize();
-  uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
+  uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
   // We may have mapped too much. Release extra memory.
   UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
   return shadow_start;
@@ -113,31 +101,26 @@ uptr FindPremappedShadowStart() {
 #endif
 
 uptr FindDynamicShadowStart() {
+  uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
 #if ASAN_PREMAP_SHADOW
   if (!PremapShadowFailed())
-    return FindPremappedShadowStart();
+    return FindPremappedShadowStart(shadow_size_bytes);
 #endif
 
-  uptr granularity = GetMmapGranularity();
-  uptr alignment = granularity * 8;
-  uptr left_padding = granularity;
-  uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
-  uptr map_size = shadow_size + left_padding + alignment;
-
-  uptr map_start = (uptr)MmapNoAccess(map_size);
-  CHECK_NE(map_start, ~(uptr)0);
-
-  uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
-  UnmapFromTo(map_start, shadow_start - left_padding);
-  UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
-
-  return shadow_start;
+  return MapDynamicShadow(shadow_size_bytes, SHADOW_SCALE,
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
 }
 
 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   UNIMPLEMENTED();
 }
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+  // Since asan's mapping is compacting, the shadow chunk may be
+  // not page-aligned, so we only flush the page-aligned portion.
+  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
+}
+
 #if SANITIZER_ANDROID
 // FIXME: should we do anything for Android?
 void AsanCheckDynamicRTPrereqs() {}
diff --git a/system/lib/compiler-rt/lib/asan/asan_mac.cpp b/system/lib/compiler-rt/lib/asan/asan_mac.cpp
index a8d3f5d3473c4..c6950547f089f 100644
--- a/system/lib/compiler-rt/lib/asan/asan_mac.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_mac.cpp
@@ -55,46 +55,8 @@ void *AsanDoesNotSupportStaticLinkage() {
 }
 
 uptr FindDynamicShadowStart() {
-  uptr granularity = GetMmapGranularity();
-  uptr alignment = 8 * granularity;
-  uptr left_padding = granularity;
-  uptr space_size = kHighShadowEnd + left_padding;
-
-  uptr largest_gap_found = 0;
-  uptr max_occupied_addr = 0;
-  VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size);
-  uptr shadow_start =
-      FindAvailableMemoryRange(space_size, alignment, granularity,
-                               &largest_gap_found, &max_occupied_addr);
-  // If the shadow doesn't fit, restrict the address space to make it fit.
-  if (shadow_start == 0) {
-    VReport(
-        2,
-        "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",
-        largest_gap_found, max_occupied_addr);
-    uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment);
-    if (new_max_vm < max_occupied_addr) {
-      Report("Unable to find a memory range for dynamic shadow.\n");
-      Report(
-          "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, "
-          "new_max_vm = %p\n",
-          space_size, largest_gap_found, max_occupied_addr, new_max_vm);
-      CHECK(0 && "cannot place shadow");
-    }
-    RestrictMemoryToMaxAddress(new_max_vm);
-    kHighMemEnd = new_max_vm - 1;
-    space_size = kHighShadowEnd + left_padding;
-    VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size);
-    shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity,
-                                            nullptr, nullptr);
-    if (shadow_start == 0) {
-      Report("Unable to find a memory range after restricting VM.\n");
-      CHECK(0 && "cannot place shadow after restricting vm");
-    }
-  }
-  CHECK_NE((uptr)0, shadow_start);
-  CHECK(IsAligned(shadow_start, alignment));
-  return shadow_start;
+  return MapDynamicShadow(MemToShadowSize(kHighMemEnd), SHADOW_SCALE,
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
 }
 
 // No-op. Mac does not support static linkage anyway.
@@ -127,6 +89,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   op(globals, size / sizeof(__asan_global));
 }
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+  // Since asan's mapping is compacting, the shadow chunk may be
+  // not page-aligned, so we only flush the page-aligned portion.
+  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
+}
+
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
   UNIMPLEMENTED();
 }
diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp
index 20719cd51f959..7d7b3631a187c 100644
--- a/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -35,7 +35,7 @@ static uptr last_dlsym_alloc_size_in_words;
 static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024;
 static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
 
-static INLINE bool IsInDlsymAllocPool(const void *ptr) {
+static inline bool IsInDlsymAllocPool(const void *ptr) {
   uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
   return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
 }
@@ -96,12 +96,12 @@ bool IsFromLocalPool(const void *ptr) {
 }
 #endif
 
-static INLINE bool MaybeInDlsym() {
+static inline bool MaybeInDlsym() {
   // Fuchsia doesn't use dlsym-based interceptors.
   return !SANITIZER_FUCHSIA && asan_init_is_running;
 }
 
-static INLINE bool UseLocalPool() {
+static inline bool UseLocalPool() {
   return EarlyMalloc() || MaybeInDlsym();
 }
 
@@ -121,19 +121,19 @@ static void *ReallocFromLocalPool(void *ptr, uptr size) {
 }
 
 INTERCEPTOR(void, free, void *ptr) {
-  GET_STACK_TRACE_FREE;
   if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
     DeallocateFromLocalPool(ptr);
     return;
   }
+  GET_STACK_TRACE_FREE;
   asan_free(ptr, &stack, FROM_MALLOC);
 }
 
 #if SANITIZER_INTERCEPT_CFREE
 INTERCEPTOR(void, cfree, void *ptr) {
-  GET_STACK_TRACE_FREE;
   if (UNLIKELY(IsInDlsymAllocPool(ptr)))
     return;
+  GET_STACK_TRACE_FREE;
   asan_free(ptr, &stack, FROM_MALLOC);
 }
 #endif // SANITIZER_INTERCEPT_CFREE
diff --git a/system/lib/compiler-rt/lib/asan/asan_malloc_local.h b/system/lib/compiler-rt/lib/asan/asan_malloc_local.h
index 3f784b90c739c..e2c9be0379f2f 100644
--- a/system/lib/compiler-rt/lib/asan/asan_malloc_local.h
+++ b/system/lib/compiler-rt/lib/asan/asan_malloc_local.h
@@ -17,7 +17,7 @@
 #include "sanitizer_common/sanitizer_platform.h"
 #include "asan_internal.h"
 
-static INLINE bool EarlyMalloc() {
+static inline bool EarlyMalloc() {
   return SANITIZER_RTEMS &&
          (!__asan::asan_inited || __asan::asan_init_is_running);
 }
diff --git a/system/lib/compiler-rt/lib/asan/asan_mapping.h b/system/lib/compiler-rt/lib/asan/asan_mapping.h
index 67c5448729a3d..aa499376df64f 100644
--- a/system/lib/compiler-rt/lib/asan/asan_mapping.h
+++ b/system/lib/compiler-rt/lib/asan/asan_mapping.h
@@ -79,6 +79,20 @@
 // || `[0x1000000000, 0x11ffffffff]` || lowshadow  ||
 // || `[0x0000000000, 0x0fffffffff]` || lowmem     ||
 //
+// RISC-V has only 38 bits for task size
+// Low mem size is set with kRiscv64_ShadowOffset64 in
+// compiler-rt/lib/asan/asan_allocator.h and in
+// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
+// kRiscv64_ShadowOffset64, High mem top border is set with
+// GetMaxVirtualAddress() in
+// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+// Default Linux/RISCV64 Sv39/Sv48 mapping:
+// || `[0x000820000000, 0x003fffffffff]` || HighMem    ||
+// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
+// || `[0x000024000000, 0x000123ffffff]` || ShadowGap  ||
+// || `[0x000020000000, 0x000023ffffff]` || LowShadow  ||
+// || `[0x000000000000, 0x00001fffffff]` || LowMem     ||
+//
 // Default Linux/AArch64 (42-bit VMA) mapping:
 // || `[0x10000000000, 0x3ffffffffff]` || highmem    ||
 // || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
@@ -161,6 +175,7 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
 static const u64 kDefaultShort64bitShadowOffset =
     0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale);  // < 2G.
 static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
+static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
 static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
 static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
 static const u64 kPPC64_ShadowOffset64 = 1ULL << 44;
@@ -206,6 +221,10 @@ static const u64 kMyriadCacheBitMask32 = 0x40000000ULL;
 #else
 #  if SANITIZER_IOS
 #    define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
+#  elif SANITIZER_MAC && defined(__aarch64__)
+#    define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
+#elif SANITIZER_RISCV64
+#define SHADOW_OFFSET kRiscv64_ShadowOffset64
 #  elif defined(__aarch64__)
 #    define SHADOW_OFFSET kAArch64_ShadowOffset64
 #  elif defined(__powerpc64__)
@@ -355,6 +374,8 @@ static inline bool AddrIsInShadowGap(uptr a) {
 
 namespace __asan {
 
+static inline uptr MemToShadowSize(uptr size) { return size >> SHADOW_SCALE; }
+
 static inline bool AddrIsInMem(uptr a) {
   PROFILE_ASAN_MAPPING();
   return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) ||
diff --git a/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp b/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp
index a3152eab85409..15be546f62b23 100644
--- a/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_poisoning.cpp
@@ -62,14 +62,6 @@ struct ShadowSegmentEndpoint {
   }
 };
 
-void FlushUnneededASanShadowMemory(uptr p, uptr size) {
-  // Since asan's mapping is compacting, the shadow chunk may be
-  // not page-aligned, so we only flush the page-aligned portion.
-#if !SANITIZER_EMSCRIPTEN
-  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
-#endif
-}
-
 void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
   uptr end = ptr + size;
   if (Verbosity()) {
diff --git a/system/lib/compiler-rt/lib/asan/asan_posix.cpp b/system/lib/compiler-rt/lib/asan/asan_posix.cpp
index 85ebd181ebf2f..6e49520498158 100644
--- a/system/lib/compiler-rt/lib/asan/asan_posix.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_posix.cpp
@@ -17,6 +17,7 @@
 #include "asan_internal.h"
 #include "asan_interceptors.h"
 #include "asan_mapping.h"
+#include "asan_poisoning.h"
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -24,6 +25,7 @@
 #include "sanitizer_common/sanitizer_procmaps.h"
 
 #include <pthread.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -37,6 +39,36 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
   ReportDeadlySignal(sig);
 }
 
+bool PlatformUnpoisonStacks() {
+#if SANITIZER_EMSCRIPTEN
+  return false;
+#else
+  stack_t signal_stack;
+  CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
+  uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
+  uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
+  // If we're executing on the signal alternate stack AND the Linux flag
+  // SS_AUTODISARM was used, then we cannot get the signal alternate stack
+  // bounds from sigaltstack -- sigaltstack's output looks just as if no
+  // alternate stack has ever been set up.
+  // We're always unpoisoning the signal alternate stack to support jumping
+  // between the default stack and signal alternate stack.
+  if (signal_stack.ss_flags != SS_DISABLE)
+    UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
+
+  if (signal_stack.ss_flags != SS_ONSTACK)
+    return false;
+
+  // Since we're on the signal altnerate stack, we cannot find the DEFAULT
+  // stack bottom using a local variable.
+  uptr default_bottom, tls_addr, tls_size, stack_size;
+  GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
+                       &tls_size);
+  UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
+  return true;
+#endif
+}
+
 // ---------------------- TSD ---------------- {{{1
 
 #if SANITIZER_NETBSD && !ASAN_DYNAMIC
diff --git a/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp b/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp
index 7835e99748ffa..666bb9b34bd39 100644
--- a/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_premap_shadow.cpp
@@ -32,22 +32,8 @@ uptr PremapShadowSize() {
 // Returns an address aligned to 8 pages, such that one page on the left and
 // PremapShadowSize() bytes on the right of it are mapped r/o.
 uptr PremapShadow() {
-  uptr granularity = GetMmapGranularity();
-  uptr alignment = granularity * 8;
-  uptr left_padding = granularity;
-  uptr shadow_size = PremapShadowSize();
-  uptr map_size = shadow_size + left_padding + alignment;
-
-  uptr map_start = (uptr)MmapNoAccess(map_size);
-  CHECK_NE(map_start, ~(uptr)0);
-
-  uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
-  uptr shadow_end = shadow_start + shadow_size;
-  internal_munmap(reinterpret_cast<void *>(map_start),
-                  shadow_start - left_padding - map_start);
-  internal_munmap(reinterpret_cast<void *>(shadow_end),
-                  map_start + map_size - shadow_end);
-  return shadow_start;
+  return MapDynamicShadow(PremapShadowSize(), /*mmap_alignment_scale*/ 3,
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
 }
 
 bool PremapShadowFailed() {
diff --git a/system/lib/compiler-rt/lib/asan/asan_report.cpp b/system/lib/compiler-rt/lib/asan/asan_report.cpp
index 2e6ce436d0306..03f1ed2b01866 100644
--- a/system/lib/compiler-rt/lib/asan/asan_report.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_report.cpp
@@ -151,7 +151,8 @@ class ScopedInErrorReport {
     if (common_flags()->print_cmdline)
       PrintCmdline();
 
-    if (common_flags()->print_module_map == 2) PrintModuleMap();
+    if (common_flags()->print_module_map == 2)
+      DumpProcessMap();
 
     // Copy the message buffer so that we could start logging without holding a
     // lock that gets aquired during printing.
@@ -160,6 +161,9 @@ class ScopedInErrorReport {
       BlockingMutexLock l(&error_message_buf_mutex);
       internal_memcpy(buffer_copy.data(),
                       error_message_buffer, kErrorMessageBufferSize);
+      // Clear error_message_buffer so that if we find other errors
+      // we don't re-log this error.
+      error_message_buffer_pos = 0;
     }
 
     LogFullErrorReport(buffer_copy.data());
@@ -408,7 +412,7 @@ static bool IsInvalidPointerPair(uptr a1, uptr a2) {
   return false;
 }
 
-static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
+static inline void CheckForInvalidPointerPair(void *p1, void *p2) {
   switch (flags()->detect_invalid_pointer_pairs) {
     case 0:
       return;
diff --git a/system/lib/compiler-rt/lib/asan/asan_rtems.cpp b/system/lib/compiler-rt/lib/asan/asan_rtems.cpp
index ecd568c5981bb..ea0b4ad9db681 100644
--- a/system/lib/compiler-rt/lib/asan/asan_rtems.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_rtems.cpp
@@ -50,6 +50,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   UNIMPLEMENTED();
 }
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+  // Since asan's mapping is compacting, the shadow chunk may be
+  // not page-aligned, so we only flush the page-aligned portion.
+  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
+}
+
 void AsanCheckDynamicRTPrereqs() {}
 void AsanCheckIncompatibleRT() {}
 void InitializeAsanInterceptors() {}
@@ -64,6 +70,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
   UNIMPLEMENTED();
 }
 
+bool PlatformUnpoisonStacks() { return false; }
+
 void EarlyInit() {
   // Provide early initialization of shadow memory so that
   // instrumented code running before full initialzation will not
diff --git a/system/lib/compiler-rt/lib/asan/asan_rtl.cpp b/system/lib/compiler-rt/lib/asan/asan_rtl.cpp
index 5665654e942fb..3acaa74e3f5ea 100644
--- a/system/lib/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_rtl.cpp
@@ -45,7 +45,8 @@ static void AsanDie() {
     // Don't die twice - run a busy loop.
     while (1) { }
   }
-  if (common_flags()->print_module_map >= 1) PrintModuleMap();
+  if (common_flags()->print_module_map >= 1)
+    DumpProcessMap();
   if (flags()->sleep_before_dying) {
     Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
     SleepForSeconds(flags()->sleep_before_dying);
@@ -321,7 +322,7 @@ static void InitializeHighMemEnd() {
   kHighMemEnd = GetMaxUserVirtualAddress();
   // Increase kHighMemEnd to make sure it's properly
   // aligned together with kHighMemBeg:
-  kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
+  kHighMemEnd |= (GetMmapGranularity() << SHADOW_SCALE) - 1;
 #endif  // !ASAN_FIXED_MAPPING
   CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
 #endif  // !SANITIZER_MYRIAD2
@@ -555,22 +556,33 @@ class AsanInitializer {
 static AsanInitializer asan_initializer;
 #endif  // ASAN_DYNAMIC
 
-} // namespace __asan
-
-// ---------------------- Interface ---------------- {{{1
-using namespace __asan;
-
-void NOINLINE __asan_handle_no_return() {
-  if (asan_init_is_running)
+void UnpoisonStack(uptr bottom, uptr top, const char *type) {
+  static const uptr kMaxExpectedCleanupSize = 64 << 20;  // 64M
+  if (top - bottom > kMaxExpectedCleanupSize) {
+    static bool reported_warning = false;
+    if (reported_warning)
+      return;
+    reported_warning = true;
+    Report(
+        "WARNING: ASan is ignoring requested __asan_handle_no_return: "
+        "stack type: %s top: %p; bottom %p; size: %p (%zd)\n"
+        "False positive error reports may follow\n"
+        "For details see "
+        "https://github.com/google/sanitizers/issues/189\n",
+        type, top, bottom, top - bottom, top - bottom);
     return;
+  }
+  PoisonShadow(bottom, top - bottom, 0);
+}
 
-  int local_stack;
-  AsanThread *curr_thread = GetCurrentThread();
-  uptr PageSize = GetPageSizeCached();
-  uptr top, bottom;
-  if (curr_thread) {
+static void UnpoisonDefaultStack() {
+  uptr bottom, top;
+
+  if (AsanThread *curr_thread = GetCurrentThread()) {
+    int local_stack;
+    const uptr page_size = GetPageSizeCached();
     top = curr_thread->stack_top();
-    bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
+    bottom = ((uptr)&local_stack - page_size) & ~(page_size - 1);
   } else if (SANITIZER_RTEMS) {
     // Give up On RTEMS.
     return;
@@ -582,25 +594,31 @@ void NOINLINE __asan_handle_no_return() {
                          &tls_size);
     top = bottom + stack_size;
   }
-  static const uptr kMaxExpectedCleanupSize = 64 << 20;  // 64M
-  if (top - bottom > kMaxExpectedCleanupSize) {
-    static bool reported_warning = false;
-    if (reported_warning)
-      return;
-    reported_warning = true;
-    Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
-           "stack top: %p; bottom %p; size: %p (%zd)\n"
-           "False positive error reports may follow\n"
-           "For details see "
-           "https://github.com/google/sanitizers/issues/189\n",
-           top, bottom, top - bottom, top - bottom);
-    return;
-  }
-  PoisonShadow(bottom, top - bottom, 0);
+
+  UnpoisonStack(bottom, top, "default");
+}
+
+static void UnpoisonFakeStack() {
+  AsanThread *curr_thread = GetCurrentThread();
   if (curr_thread && curr_thread->has_fake_stack())
     curr_thread->fake_stack()->HandleNoReturn();
 }
 
+}  // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;
+
+void NOINLINE __asan_handle_no_return() {
+  if (asan_init_is_running)
+    return;
+
+  if (!PlatformUnpoisonStacks())
+    UnpoisonDefaultStack();
+
+  UnpoisonFakeStack();
+}
+
 extern "C" void *__asan_extra_spill_area() {
   AsanThread *t = GetCurrentThread();
   CHECK(t);
diff --git a/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp b/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp
index e17da6a3696a9..9b9e7ae3fe15f 100644
--- a/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_shadow_setup.cpp
@@ -22,24 +22,6 @@
 
 namespace __asan {
 
-// ---------------------- mmap -------------------- {{{1
-// Reserve memory range [beg, end].
-// We need to use inclusive range because end+1 may not be representable.
-void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
-  CHECK_EQ((beg % GetMmapGranularity()), 0);
-  CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
-  uptr size = end - beg + 1;
-  DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb.
-  if (!MmapFixedSuperNoReserve(beg, size, name)) {
-    Report(
-        "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
-        "Perhaps you're using ulimit -v\n",
-        size);
-    Abort();
-  }
-  if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
-}
-
 static void ProtectGap(uptr addr, uptr size) {
   if (!flags()->protect_shadow_gap) {
     // The shadow gap is unprotected, so there is a chance that someone
@@ -57,30 +39,13 @@ static void ProtectGap(uptr addr, uptr size) {
                              "unprotected gap shadow");
     return;
   }
-  void *res = MmapFixedNoAccess(addr, size, "shadow gap");
-  if (addr == (uptr)res) return;
-  // A few pages at the start of the address space can not be protected.
-  // But we really want to protect as much as possible, to prevent this memory
-  // being returned as a result of a non-FIXED mmap().
-  if (addr == kZeroBaseShadowStart) {
-    uptr step = GetMmapGranularity();
-    while (size > step && addr < kZeroBaseMaxShadowStart) {
-      addr += step;
-      size -= step;
-      void *res = MmapFixedNoAccess(addr, size, "shadow gap");
-      if (addr == (uptr)res) return;
-    }
-  }
-
-  Report(
-      "ERROR: Failed to protect the shadow gap. "
-      "ASan cannot proceed correctly. ABORTING.\n");
-  DumpProcessMap();
-  Die();
+  __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart,
+                          kZeroBaseMaxShadowStart);
 }
 
 static void MaybeReportLinuxPIEBug() {
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
+#if SANITIZER_LINUX && \
+    (defined(__x86_64__) || defined(__aarch64__) || SANITIZER_RISCV64)
   Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
   Report(
       "See https://github.com/google/sanitizers/issues/856 for possible "
@@ -99,8 +64,6 @@ void InitializeShadowMemory() {
   // |kDefaultShadowSentinel|.
   bool full_shadow_is_available = false;
   if (shadow_start == kDefaultShadowSentinel) {
-    __asan_shadow_memory_dynamic_address = 0;
-    CHECK_EQ(0, kLowShadowBeg);
     shadow_start = FindDynamicShadowStart();
     if (SANITIZER_LINUX) full_shadow_is_available = true;
   }
diff --git a/system/lib/compiler-rt/lib/asan/asan_stack.h b/system/lib/compiler-rt/lib/asan/asan_stack.h
index 4089d3d7340ee..47ca85a164435 100644
--- a/system/lib/compiler-rt/lib/asan/asan_stack.h
+++ b/system/lib/compiler-rt/lib/asan/asan_stack.h
@@ -51,11 +51,6 @@ u32 GetMallocContextSize();
   stack.Unwind(pc, bp, nullptr,                    \
                common_flags()->fast_unwind_on_fatal)
 
-#define GET_STACK_TRACE_SIGNAL(sig)                                        \
-  BufferedStackTrace stack;                                                \
-  stack.Unwind((sig).pc, (sig).bp, (sig).context,                          \
-               common_flags()->fast_unwind_on_fatal)
-
 #define GET_STACK_TRACE_FATAL_HERE                                \
   GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
 
diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.cpp b/system/lib/compiler-rt/lib/asan/asan_thread.cpp
index b573b7f2817b1..a15571b0e4258 100644
--- a/system/lib/compiler-rt/lib/asan/asan_thread.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_thread.cpp
@@ -190,7 +190,7 @@ uptr AsanThread::stack_size() {
   return bounds.top - bounds.bottom;
 }
 
-// We want to create the FakeStack lazyly on the first use, but not eralier
+// We want to create the FakeStack lazily on the first use, but not earlier
 // than the stack size is known and the procedure has to be async-signal safe.
 FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
   uptr stack_size = this->stack_size();
@@ -213,6 +213,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
     stack_size_log =
         Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
     fake_stack_ = FakeStack::Create(stack_size_log);
+    DCHECK_EQ(GetCurrentThread(), this);
     SetTLSFakeStack(fake_stack_);
     return fake_stack_;
   }
@@ -220,6 +221,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
 }
 
 void AsanThread::Init(const InitOptions *options) {
+  DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
   next_stack_top_ = next_stack_bottom_ = 0;
   atomic_store(&stack_switching_, false, memory_order_release);
   CHECK_EQ(this->stack_size(), 0U);
@@ -231,8 +233,17 @@ void AsanThread::Init(const InitOptions *options) {
   }
   ClearShadowForThreadStackAndTLS();
   fake_stack_ = nullptr;
-  if (__asan_option_detect_stack_use_after_return)
+  if (__asan_option_detect_stack_use_after_return &&
+      tid() == GetCurrentTidOrInvalid()) {
+    // AsyncSignalSafeLazyInitFakeStack makes use of threadlocals and must be
+    // called from the context of the thread it is initializing, not its parent.
+    // Most platforms call AsanThread::Init on the newly-spawned thread, but
+    // Fuchsia calls this function from the parent thread.  To support that
+    // approach, we avoid calling AsyncSignalSafeLazyInitFakeStack here; it will
+    // be called by the new thread when it first attempts to access the fake
+    // stack.
     AsyncSignalSafeLazyInitFakeStack();
+  }
   int local = 0;
   VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
           (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
@@ -244,12 +255,9 @@ void AsanThread::Init(const InitOptions *options) {
 // SetThreadStackAndTls.
 #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
 
-thread_return_t AsanThread::ThreadStart(
-    tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
+thread_return_t AsanThread::ThreadStart(tid_t os_id) {
   Init();
   asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
-  if (signal_thread_is_registered)
-    atomic_store(signal_thread_is_registered, 1, memory_order_release);
 
 #if !SANITIZER_EMSCRIPTEN
   if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
@@ -281,8 +289,7 @@ AsanThread *CreateMainThread() {
       /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
       /* stack */ nullptr, /* detached */ true);
   SetCurrentThread(main_thread);
-  main_thread->ThreadStart(internal_getpid(),
-                           /* signal_thread_is_registered */ nullptr);
+  main_thread->ThreadStart(internal_getpid());
   return main_thread;
 }
 
@@ -370,7 +377,9 @@ uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
     bottom = stack_bottom();
   } else if (has_fake_stack()) {
     bottom = fake_stack()->AddrIsInFakeStack(addr);
-    CHECK(bottom);
+    if (bottom == 0) {
+      return 0;
+    }
   } else {
     return 0;
   }
@@ -484,6 +493,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
   return true;
 }
 
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
+
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg) {
   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
diff --git a/system/lib/compiler-rt/lib/asan/asan_thread.h b/system/lib/compiler-rt/lib/asan/asan_thread.h
index c503f507059dd..c33955eee367b 100644
--- a/system/lib/compiler-rt/lib/asan/asan_thread.h
+++ b/system/lib/compiler-rt/lib/asan/asan_thread.h
@@ -35,7 +35,7 @@ class AsanThread;
 
 // These objects are created for every thread and are never deleted,
 // so we can find them by tid even if the thread is long dead.
-class AsanThreadContext : public ThreadContextBase {
+class AsanThreadContext final : public ThreadContextBase {
  public:
   explicit AsanThreadContext(int tid)
       : ThreadContextBase(tid), announced(false),
@@ -69,8 +69,7 @@ class AsanThread {
   struct InitOptions;
   void Init(const InitOptions *options = nullptr);
 
-  thread_return_t ThreadStart(tid_t os_id,
-                              atomic_uintptr_t *signal_thread_is_registered);
+  thread_return_t ThreadStart(tid_t os_id);
 
   uptr stack_top();
   uptr stack_bottom();
@@ -132,6 +131,8 @@ class AsanThread {
 
   void *extra_spill_area() { return &extra_spill_area_; }
 
+  void *get_arg() { return arg_; }
+
  private:
   // NOTE: There is no AsanThread constructor. It is allocated
   // via mmap() and *must* be valid in zero-initialized state.
diff --git a/system/lib/compiler-rt/lib/asan/asan_win.cpp b/system/lib/compiler-rt/lib/asan/asan_win.cpp
index 417892aaedd8e..1577c83cf9941 100644
--- a/system/lib/compiler-rt/lib/asan/asan_win.cpp
+++ b/system/lib/compiler-rt/lib/asan/asan_win.cpp
@@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
   AsanThread *t = (AsanThread *)arg;
   SetCurrentThread(t);
-  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
+  return t->ThreadStart(GetTid());
 }
 
 INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
@@ -191,6 +191,12 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   UNIMPLEMENTED();
 }
 
+void FlushUnneededASanShadowMemory(uptr p, uptr size) {
+  // Since asan's mapping is compacting, the shadow chunk may be
+  // not page-aligned, so we only flush the page-aligned portion.
+  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
+}
+
 // ---------------------- TSD ---------------- {{{
 static bool tsd_key_inited = false;
 
@@ -247,15 +253,8 @@ void *AsanDoesNotSupportStaticLinkage() {
 }
 
 uptr FindDynamicShadowStart() {
-  uptr granularity = GetMmapGranularity();
-  uptr alignment = 8 * granularity;
-  uptr left_padding = granularity;
-  uptr space_size = kHighShadowEnd + left_padding;
-  uptr shadow_start = FindAvailableMemoryRange(space_size, alignment,
-                                               granularity, nullptr, nullptr);
-  CHECK_NE((uptr)0, shadow_start);
-  CHECK(IsAligned(shadow_start, alignment));
-  return shadow_start;
+  return MapDynamicShadow(MemToShadowSize(kHighMemEnd), SHADOW_SCALE,
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
 }
 
 void AsanCheckDynamicRTPrereqs() {}
@@ -268,6 +267,8 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
 
 void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }
 
+bool PlatformUnpoisonStacks() { return false; }
+
 #if SANITIZER_WINDOWS64
 // Exception handler for dealing with shadow memory.
 static LONG CALLBACK
diff --git a/system/lib/compiler-rt/lib/builtins/absvsi2.c b/system/lib/compiler-rt/lib/builtins/absvsi2.c
index 44ada169e7e66..9d5de7e8a3f22 100644
--- a/system/lib/compiler-rt/lib/builtins/absvsi2.c
+++ b/system/lib/compiler-rt/lib/builtins/absvsi2.c
@@ -18,7 +18,7 @@
 
 COMPILER_RT_ABI si_int __absvsi2(si_int a) {
   const int N = (int)(sizeof(si_int) * CHAR_BIT);
-  if (a == (1 << (N - 1)))
+  if (a == ((si_int)1 << (N - 1)))
     compilerrt_abort();
   const si_int t = a >> (N - 1);
   return (a ^ t) - t;
diff --git a/system/lib/compiler-rt/lib/builtins/ashldi3.c b/system/lib/compiler-rt/lib/builtins/ashldi3.c
index 7c81057a22847..04f22228f11db 100644
--- a/system/lib/compiler-rt/lib/builtins/ashldi3.c
+++ b/system/lib/compiler-rt/lib/builtins/ashldi3.c
@@ -16,7 +16,7 @@
 
 // Precondition:  0 <= b < bits_in_dword
 
-COMPILER_RT_ABI di_int __ashldi3(di_int a, si_int b) {
+COMPILER_RT_ABI di_int __ashldi3(di_int a, int b) {
   const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
   dwords input;
   dwords result;
diff --git a/system/lib/compiler-rt/lib/builtins/ashrdi3.c b/system/lib/compiler-rt/lib/builtins/ashrdi3.c
index b9939132205c8..934a5c47fd69b 100644
--- a/system/lib/compiler-rt/lib/builtins/ashrdi3.c
+++ b/system/lib/compiler-rt/lib/builtins/ashrdi3.c
@@ -16,7 +16,7 @@
 
 // Precondition:  0 <= b < bits_in_dword
 
-COMPILER_RT_ABI di_int __ashrdi3(di_int a, si_int b) {
+COMPILER_RT_ABI di_int __ashrdi3(di_int a, int b) {
   const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
   dwords input;
   dwords result;
diff --git a/system/lib/compiler-rt/lib/builtins/assembly.h b/system/lib/compiler-rt/lib/builtins/assembly.h
index f437cb87f60ac..f6ce6a9fccff3 100644
--- a/system/lib/compiler-rt/lib/builtins/assembly.h
+++ b/system/lib/compiler-rt/lib/builtins/assembly.h
@@ -14,8 +14,8 @@
 #ifndef COMPILERRT_ASSEMBLY_H
 #define COMPILERRT_ASSEMBLY_H
 
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
+#if defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR %%
 #else
 #define SEPARATOR ;
 #endif
@@ -35,14 +35,14 @@
 #define HIDDEN(name) .hidden name
 #define LOCAL_LABEL(name) .L_##name
 #define FILE_LEVEL_DIRECTIVE
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
 #define SYMBOL_IS_FUNC(name) .type name,%function
 #else
 #define SYMBOL_IS_FUNC(name) .type name,@function
 #endif
 #define CONST_SECTION .section .rodata
 
-#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) ||        \
     defined(__linux__)
 #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
 #else
@@ -65,6 +65,66 @@
 
 #endif
 
+#if defined(__arm__) || defined(__aarch64__)
+#define FUNC_ALIGN                                                             \
+  .text SEPARATOR                                                              \
+  .balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value)                                              \
+  .pushsection .note.gnu.property, "a" SEPARATOR                               \
+  .p2align 3 SEPARATOR                                                         \
+  .word 4 SEPARATOR                                                            \
+  .word 16 SEPARATOR                                                           \
+  .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR                                       \
+  .asciz "GNU" SEPARATOR                                                       \
+  .word type SEPARATOR                                                         \
+  .word 4 SEPARATOR                                                            \
+  .word value SEPARATOR                                                        \
+  .word 0 SEPARATOR                                                            \
+  .popsection
+
+#if BTI_FLAG != 0
+#define BTI_C bti c
+#else
+#define BTI_C
+#endif
+
+#if (BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC                                                   \
+  GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
+#endif
+
 #if defined(__arm__)
 
 // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
@@ -131,8 +191,14 @@
 #define DEFINE_CODE_STATE
 #endif
 
-#define GLUE2(a, b) a##b
-#define GLUE(a, b) GLUE2(a, b)
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
 #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
 
 #ifdef VISIBILITY_HIDDEN
@@ -177,6 +243,16 @@
   DECLARE_FUNC_ENCODING                                                        \
   name:
 
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name)                     \
+  DEFINE_CODE_STATE                                                            \
+  FUNC_ALIGN                                                                   \
+  .globl name SEPARATOR                                                        \
+  SYMBOL_IS_FUNC(name) SEPARATOR                                               \
+  DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR                                    \
+  CFI_START SEPARATOR                                                          \
+  DECLARE_FUNC_ENCODING                                                        \
+  name: SEPARATOR BTI_C
+
 #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                         \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
   SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
@@ -193,8 +269,13 @@
 #ifdef __ELF__
 #define END_COMPILERRT_FUNCTION(name)                                          \
   .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name)                                  \
+  CFI_END SEPARATOR                                                            \
+  .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
 #else
 #define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name)                                  \
+  CFI_END
 #endif
 
 #endif // COMPILERRT_ASSEMBLY_H
diff --git a/system/lib/compiler-rt/lib/builtins/atomic.c b/system/lib/compiler-rt/lib/builtins/atomic.c
index 32b3a0f9ad239..f48cdc10ccf7a 100644
--- a/system/lib/compiler-rt/lib/builtins/atomic.c
+++ b/system/lib/compiler-rt/lib/builtins/atomic.c
@@ -23,6 +23,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
 
@@ -35,6 +36,8 @@
 #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange)
 #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(              \
     __atomic_compare_exchange)
+#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME(                  \
+    __atomic_is_lock_free)
 
 /// Number of locks.  This allocates one page on 32-bit platforms, two on
 /// 64-bit.  This can be specified externally if a different trade between
@@ -119,56 +122,58 @@ static __inline Lock *lock_for_pointer(void *ptr) {
   return locks + (hash & SPINLOCK_MASK);
 }
 
-/// Macros for determining whether a size is lock free.  Clang can not yet
-/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are
-/// not lock free.
-#define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1)
-#define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2)
-#define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4)
-#define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8)
-#define IS_LOCK_FREE_16 0
+/// Macros for determining whether a size is lock free.
+#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p)                  \
+  (__atomic_always_lock_free(size, p) ||                                       \
+   (__atomic_always_lock_free(size, 0) && ((uintptr_t)p % size) == 0))
+#define IS_LOCK_FREE_1(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(1, p)
+#define IS_LOCK_FREE_2(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(2, p)
+#define IS_LOCK_FREE_4(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(4, p)
+#define IS_LOCK_FREE_8(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(8, p)
+#define IS_LOCK_FREE_16(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(16, p)
 
 /// Macro that calls the compiler-generated lock-free versions of functions
 /// when they exist.
-#define LOCK_FREE_CASES()                                                      \
+#define TRY_LOCK_FREE_CASE(n, type, ptr)                                       \
+  case n:                                                                      \
+    if (IS_LOCK_FREE_##n(ptr)) {                                               \
+      LOCK_FREE_ACTION(type);                                                  \
+    }                                                                          \
+    break;
+#ifdef __SIZEOF_INT128__
+#define TRY_LOCK_FREE_CASE_16(p) TRY_LOCK_FREE_CASE(16, __uint128_t, p)
+#else
+#define TRY_LOCK_FREE_CASE_16(p) /* __uint128_t not available */
+#endif
+
+#define LOCK_FREE_CASES(ptr)                                                   \
   do {                                                                         \
     switch (size) {                                                            \
-    case 1:                                                                    \
-      if (IS_LOCK_FREE_1) {                                                    \
-        LOCK_FREE_ACTION(uint8_t);                                             \
-      }                                                                        \
-      break;                                                                   \
-    case 2:                                                                    \
-      if (IS_LOCK_FREE_2) {                                                    \
-        LOCK_FREE_ACTION(uint16_t);                                            \
-      }                                                                        \
-      break;                                                                   \
-    case 4:                                                                    \
-      if (IS_LOCK_FREE_4) {                                                    \
-        LOCK_FREE_ACTION(uint32_t);                                            \
-      }                                                                        \
-      break;                                                                   \
-    case 8:                                                                    \
-      if (IS_LOCK_FREE_8) {                                                    \
-        LOCK_FREE_ACTION(uint64_t);                                            \
-      }                                                                        \
-      break;                                                                   \
-    case 16:                                                                   \
-      if (IS_LOCK_FREE_16) {                                                   \
-        /* FIXME: __uint128_t isn't available on 32 bit platforms.             \
-        LOCK_FREE_ACTION(__uint128_t);*/                                       \
-      }                                                                        \
+      TRY_LOCK_FREE_CASE(1, uint8_t, ptr)                                      \
+      TRY_LOCK_FREE_CASE(2, uint16_t, ptr)                                     \
+      TRY_LOCK_FREE_CASE(4, uint32_t, ptr)                                     \
+      TRY_LOCK_FREE_CASE(8, uint64_t, ptr)                                     \
+      TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */        \
+    default:                                                                   \
       break;                                                                   \
     }                                                                          \
   } while (0)
 
+/// Whether atomic operations for the given size (and alignment) are lock-free.
+bool __atomic_is_lock_free_c(size_t size, void *ptr) {
+#define LOCK_FREE_ACTION(type) return true;
+  LOCK_FREE_CASES(ptr);
+#undef LOCK_FREE_ACTION
+  return false;
+}
+
 /// An atomic load operation.  This is atomic with respect to the source
 /// pointer only.
 void __atomic_load_c(int size, void *src, void *dest, int model) {
 #define LOCK_FREE_ACTION(type)                                                 \
   *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model);            \
   return;
-  LOCK_FREE_CASES();
+  LOCK_FREE_CASES(src);
 #undef LOCK_FREE_ACTION
   Lock *l = lock_for_pointer(src);
   lock(l);
@@ -182,7 +187,7 @@ void __atomic_store_c(int size, void *dest, void *src, int model) {
 #define LOCK_FREE_ACTION(type)                                                 \
   __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model);              \
   return;
-  LOCK_FREE_CASES();
+  LOCK_FREE_CASES(dest);
 #undef LOCK_FREE_ACTION
   Lock *l = lock_for_pointer(dest);
   lock(l);
@@ -201,7 +206,7 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected,
   return __c11_atomic_compare_exchange_strong(                                 \
       (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success,       \
       failure)
-  LOCK_FREE_CASES();
+  LOCK_FREE_CASES(ptr);
 #undef LOCK_FREE_ACTION
   Lock *l = lock_for_pointer(ptr);
   lock(l);
@@ -222,7 +227,7 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) {
   *(type *)old =                                                               \
       __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model);        \
   return;
-  LOCK_FREE_CASES();
+  LOCK_FREE_CASES(ptr);
 #undef LOCK_FREE_ACTION
   Lock *l = lock_for_pointer(ptr);
   lock(l);
@@ -252,7 +257,7 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) {
 
 #define OPTIMISED_CASE(n, lockfree, type)                                      \
   type __atomic_load_##n(type *src, int model) {                               \
-    if (lockfree)                                                              \
+    if (lockfree(src))                                                         \
       return __c11_atomic_load((_Atomic(type) *)src, model);                   \
     Lock *l = lock_for_pointer(src);                                           \
     lock(l);                                                                   \
@@ -265,7 +270,7 @@ OPTIMISED_CASES
 
 #define OPTIMISED_CASE(n, lockfree, type)                                      \
   void __atomic_store_##n(type *dest, type val, int model) {                   \
-    if (lockfree) {                                                            \
+    if (lockfree(dest)) {                                                      \
       __c11_atomic_store((_Atomic(type) *)dest, val, model);                   \
       return;                                                                  \
     }                                                                          \
@@ -280,7 +285,7 @@ OPTIMISED_CASES
 
 #define OPTIMISED_CASE(n, lockfree, type)                                      \
   type __atomic_exchange_##n(type *dest, type val, int model) {                \
-    if (lockfree)                                                              \
+    if (lockfree(dest))                                                        \
       return __c11_atomic_exchange((_Atomic(type) *)dest, val, model);         \
     Lock *l = lock_for_pointer(dest);                                          \
     lock(l);                                                                   \
@@ -293,9 +298,9 @@ OPTIMISED_CASES
 #undef OPTIMISED_CASE
 
 #define OPTIMISED_CASE(n, lockfree, type)                                      \
-  int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,   \
-                                    int success, int failure) {                \
-    if (lockfree)                                                              \
+  bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,  \
+                                     int success, int failure) {               \
+    if (lockfree(ptr))                                                         \
       return __c11_atomic_compare_exchange_strong(                             \
           (_Atomic(type) *)ptr, expected, desired, success, failure);          \
     Lock *l = lock_for_pointer(ptr);                                           \
@@ -303,11 +308,11 @@ OPTIMISED_CASES
     if (*ptr == *expected) {                                                   \
       *ptr = desired;                                                          \
       unlock(l);                                                               \
-      return 1;                                                                \
+      return true;                                                             \
     }                                                                          \
     *expected = *ptr;                                                          \
     unlock(l);                                                                 \
-    return 0;                                                                  \
+    return false;                                                              \
   }
 OPTIMISED_CASES
 #undef OPTIMISED_CASE
@@ -317,7 +322,7 @@ OPTIMISED_CASES
 ////////////////////////////////////////////////////////////////////////////////
 #define ATOMIC_RMW(n, lockfree, type, opname, op)                              \
   type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {         \
-    if (lockfree)                                                              \
+    if (lockfree(ptr))                                                         \
       return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model);    \
     Lock *l = lock_for_pointer(ptr);                                           \
     lock(l);                                                                   \
diff --git a/system/lib/compiler-rt/lib/builtins/clear_cache.c b/system/lib/compiler-rt/lib/builtins/clear_cache.c
index e83e21254e852..5a443ddd4b03a 100644
--- a/system/lib/compiler-rt/lib/builtins/clear_cache.c
+++ b/system/lib/compiler-rt/lib/builtins/clear_cache.c
@@ -33,7 +33,7 @@ uintptr_t GetCurrentProcess(void);
 #include <machine/sysarch.h>
 #endif
 
-#if defined(__OpenBSD__) && defined(__mips__)
+#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__))
 // clang-format off
 #include <sys/types.h>
 #include <machine/sysarch.h>
@@ -46,6 +46,11 @@ uintptr_t GetCurrentProcess(void);
 #include <unistd.h>
 #endif
 
+#if defined(__linux__) && defined(__riscv)
+// to get platform-specific syscall definitions
+#include <linux/unistd.h>
+#endif
+
 // The compiler generates calls to __clear_cache() when creating
 // trampoline functions on the stack for use with nested functions.
 // It is expected to invalidate the instruction cache for the
@@ -58,7 +63,7 @@ void __clear_cache(void *start, void *end) {
 #elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__))
   FlushInstructionCache(GetCurrentProcess(), start, end - start);
 #elif defined(__arm__) && !defined(__APPLE__)
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
   struct arm_sync_icache_args arg;
 
   arg.addr = (uintptr_t)start;
@@ -147,10 +152,23 @@ void __clear_cache(void *start, void *end) {
 
   for (uintptr_t dword = start_dword; dword < end_dword; dword += dword_size)
     __asm__ volatile("flush %0" : : "r"(dword));
+#elif defined(__riscv) && defined(__linux__)
+  // See: arch/riscv/include/asm/cacheflush.h, arch/riscv/kernel/sys_riscv.c
+  register void *start_reg __asm("a0") = start;
+  const register void *end_reg __asm("a1") = end;
+  // "0" means that we clear cache for all threads (SYS_RISCV_FLUSH_ICACHE_ALL)
+  const register long flags __asm("a2") = 0;
+  const register long syscall_nr __asm("a7") = __NR_riscv_flush_icache;
+  __asm __volatile("ecall"
+                   : "=r"(start_reg)
+                   : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr));
+  assert(start_reg == 0 && "Cache flush syscall failed.");
 #else
 #if __APPLE__
   // On Darwin, sys_icache_invalidate() provides this functionality
   sys_icache_invalidate(start, end - start);
+#elif defined(__ve__)
+  __asm__ volatile("fencec 2");
 #else
   compilerrt_abort();
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/clzdi2.c b/system/lib/compiler-rt/lib/builtins/clzdi2.c
index a0bacb2ae39ea..12c17982a5cb1 100644
--- a/system/lib/compiler-rt/lib/builtins/clzdi2.c
+++ b/system/lib/compiler-rt/lib/builtins/clzdi2.c
@@ -21,15 +21,15 @@
 // ctz instruction, gcc resolves __builtin_clz to __clzdi2 rather than
 // __clzsi2, leading to infinite recursion.
 #define __builtin_clz(a) __clzsi2(a)
-extern si_int __clzsi2(si_int);
+extern int __clzsi2(si_int);
 #endif
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __clzdi2(di_int a) {
+COMPILER_RT_ABI int __clzdi2(di_int a) {
   dwords x;
   x.all = a;
   const si_int f = -(x.s.high == 0);
-  return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) +
+  return clzsi((x.s.high & ~f) | (x.s.low & f)) +
          (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
 }
diff --git a/system/lib/compiler-rt/lib/builtins/clzsi2.c b/system/lib/compiler-rt/lib/builtins/clzsi2.c
index 3f9f27f413315..d75f56d937b07 100644
--- a/system/lib/compiler-rt/lib/builtins/clzsi2.c
+++ b/system/lib/compiler-rt/lib/builtins/clzsi2.c
@@ -16,7 +16,7 @@
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __clzsi2(si_int a) {
+COMPILER_RT_ABI int __clzsi2(si_int a) {
   su_int x = (su_int)a;
   si_int t = ((x & 0xFFFF0000) == 0) << 4; // if (x is small) t = 16 else 0
   x >>= 16 - t;                            // x = [0 - 0xFFFF]
diff --git a/system/lib/compiler-rt/lib/builtins/clzti2.c b/system/lib/compiler-rt/lib/builtins/clzti2.c
index 0c787104caa2a..25d30119f271c 100644
--- a/system/lib/compiler-rt/lib/builtins/clzti2.c
+++ b/system/lib/compiler-rt/lib/builtins/clzti2.c
@@ -18,7 +18,7 @@
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __clzti2(ti_int a) {
+COMPILER_RT_ABI int __clzti2(ti_int a) {
   twords x;
   x.all = a;
   const di_int f = -(x.s.high == 0);
diff --git a/system/lib/compiler-rt/lib/builtins/cpu_model.c b/system/lib/compiler-rt/lib/builtins/cpu_model.c
index fb619037d398c..51bedd98c3d30 100644
--- a/system/lib/compiler-rt/lib/builtins/cpu_model.c
+++ b/system/lib/compiler-rt/lib/builtins/cpu_model.c
@@ -8,10 +8,21 @@
 //
 //  This file is based on LLVM's lib/Support/Host.cpp.
 //  It implements the operating system Host concept and builtin
-//  __cpu_model for the compiler_rt library, for x86 only.
+//  __cpu_model for the compiler_rt library for x86 and
+//  __aarch64_have_lse_atomics for AArch64.
 //
 //===----------------------------------------------------------------------===//
 
+#if defined(HAVE_INIT_PRIORITY)
+#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))
+#elif __has_attribute(__constructor__)
+#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))
+#else
+// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
+// this runs during initialization.
+#define CONSTRUCTOR_ATTRIBUTE
+#endif
+
 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) ||           \
      defined(_M_X64)) &&                                                       \
     (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER))
@@ -57,6 +68,7 @@ enum ProcessorTypes {
   INTEL_GOLDMONT,
   INTEL_GOLDMONT_PLUS,
   INTEL_TREMONT,
+  AMDFAM19H,
   CPU_TYPE_MAX
 };
 
@@ -82,6 +94,11 @@ enum ProcessorSubtypes {
   INTEL_COREI7_ICELAKE_SERVER,
   AMDFAM17H_ZNVER2,
   INTEL_COREI7_CASCADELAKE,
+  INTEL_COREI7_TIGERLAKE,
+  INTEL_COREI7_COOPERLAKE,
+  INTEL_COREI7_SAPPHIRERAPIDS,
+  INTEL_COREI7_ALDERLAKE,
+  AMDFAM19H_ZNVER3,
   CPU_SUBTYPE_MAX
 };
 
@@ -122,7 +139,9 @@ enum ProcessorFeatures {
   FEATURE_VPCLMULQDQ,
   FEATURE_AVX512VNNI,
   FEATURE_AVX512BITALG,
-  FEATURE_AVX512BF16
+  FEATURE_AVX512BF16,
+  FEATURE_AVX512VP2INTERSECT,
+  CPU_FEATURE_MAX
 };
 
 // The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
@@ -268,13 +287,17 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
   }
 }
 
-static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
-                                            unsigned Brand_id,
-                                            unsigned Features,
-                                            unsigned Features2, unsigned *Type,
-                                            unsigned *Subtype) {
-  if (Brand_id != 0)
-    return;
+static const char *
+getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
+                                const unsigned *Features,
+                                unsigned *Type, unsigned *Subtype) {
+#define testFeature(F)                                                         \
+  (Features[F / 32] & (1 << (F % 32))) != 0
+
+  // We select CPU strings to match the code in Host.cpp, but we don't use them
+  // in compiler-rt.
+  const char *CPU = 0;
+
   switch (Family) {
   case 6:
     switch (Model) {
@@ -285,13 +308,17 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
                // 0Fh. All processors are manufactured using the 65 nm process.
     case 0x16: // Intel Celeron processor model 16h. All processors are
                // manufactured using the 65 nm process
+      CPU = "core2";
+      *Type = INTEL_CORE2;
+      break;
     case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
                // 17h. All processors are manufactured using the 45 nm process.
                //
                // 45nm: Penryn , Wolfdale, Yorkfield (XE)
     case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
                // the 45 nm process.
-      *Type = INTEL_CORE2; // "penryn"
+      CPU = "penryn";
+      *Type = INTEL_CORE2;
       break;
     case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
                // processors are manufactured using the 45 nm process.
@@ -299,25 +326,29 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
                // As found in a Summer 2010 model iMac.
     case 0x1f:
     case 0x2e:              // Nehalem EX
-      *Type = INTEL_COREI7; // "nehalem"
+      CPU = "nehalem";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_NEHALEM;
       break;
     case 0x25: // Intel Core i7, laptop version.
     case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
                // processors are manufactured using the 32 nm process.
     case 0x2f: // Westmere EX
-      *Type = INTEL_COREI7; // "westmere"
+      CPU = "westmere";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_WESTMERE;
       break;
     case 0x2a: // Intel Core i7 processor. All processors are manufactured
                // using the 32 nm process.
     case 0x2d:
-      *Type = INTEL_COREI7; //"sandybridge"
+      CPU = "sandybridge";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_SANDYBRIDGE;
       break;
     case 0x3a:
     case 0x3e:              // Ivy Bridge EP
-      *Type = INTEL_COREI7; // "ivybridge"
+      CPU = "ivybridge";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_IVYBRIDGE;
       break;
 
@@ -326,7 +357,8 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     case 0x3f:
     case 0x45:
     case 0x46:
-      *Type = INTEL_COREI7; // "haswell"
+      CPU = "haswell";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_HASWELL;
       break;
 
@@ -335,7 +367,8 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     case 0x47:
     case 0x4f:
     case 0x56:
-      *Type = INTEL_COREI7; // "broadwell"
+      CPU = "broadwell";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_BROADWELL;
       break;
 
@@ -344,37 +377,56 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     case 0x5e:              // Skylake desktop
     case 0x8e:              // Kaby Lake mobile
     case 0x9e:              // Kaby Lake desktop
-      *Type = INTEL_COREI7; // "skylake"
+    case 0xa5:              // Comet Lake-H/S
+    case 0xa6:              // Comet Lake-U
+      CPU = "skylake";
+      *Type = INTEL_COREI7;
       *Subtype = INTEL_COREI7_SKYLAKE;
       break;
 
     // Skylake Xeon:
     case 0x55:
       *Type = INTEL_COREI7;
-      if (Features2 & (1 << (FEATURE_AVX512VNNI - 32)))
-        *Subtype = INTEL_COREI7_CASCADELAKE; // "cascadelake"
-      else
-        *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512"
+      if (testFeature(FEATURE_AVX512BF16)) {
+        CPU = "cooperlake";
+        *Subtype = INTEL_COREI7_COOPERLAKE;
+      } else if (testFeature(FEATURE_AVX512VNNI)) {
+        CPU = "cascadelake";
+        *Subtype = INTEL_COREI7_CASCADELAKE;
+      } else {
+        CPU = "skylake-avx512";
+        *Subtype = INTEL_COREI7_SKYLAKE_AVX512;
+      }
       break;
 
     // Cannonlake:
     case 0x66:
+      CPU = "cannonlake";
       *Type = INTEL_COREI7;
-      *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake"
+      *Subtype = INTEL_COREI7_CANNONLAKE;
       break;
 
     // Icelake:
     case 0x7d:
     case 0x7e:
+      CPU = "icelake-client";
       *Type = INTEL_COREI7;
-      *Subtype = INTEL_COREI7_ICELAKE_CLIENT; // "icelake-client"
+      *Subtype = INTEL_COREI7_ICELAKE_CLIENT;
       break;
 
     // Icelake Xeon:
     case 0x6a:
     case 0x6c:
+      CPU = "icelake-server";
       *Type = INTEL_COREI7;
-      *Subtype = INTEL_COREI7_ICELAKE_SERVER; // "icelake-server"
+      *Subtype = INTEL_COREI7_ICELAKE_SERVER;
+      break;
+
+    // Sapphire Rapids:
+    case 0x8f:
+      CPU = "sapphirerapids";
+      *Type = INTEL_COREI7;
+      *Subtype = INTEL_COREI7_SAPPHIRERAPIDS;
       break;
 
     case 0x1c: // Most 45 nm Intel Atom processors
@@ -382,8 +434,9 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     case 0x27: // 32 nm Atom Medfield
     case 0x35: // 32 nm Atom Midview
     case 0x36: // 32 nm Atom Midview
+      CPU = "bonnell";
       *Type = INTEL_BONNELL;
-      break; // "bonnell"
+      break;
 
     // Atom Silvermont codes from the Intel software optimization guide.
     case 0x37:
@@ -392,26 +445,32 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     case 0x5a:
     case 0x5d:
     case 0x4c: // really airmont
+      CPU = "silvermont";
       *Type = INTEL_SILVERMONT;
-      break; // "silvermont"
+      break;
     // Goldmont:
     case 0x5c: // Apollo Lake
     case 0x5f: // Denverton
+      CPU = "goldmont";
       *Type = INTEL_GOLDMONT;
       break; // "goldmont"
     case 0x7a:
+      CPU = "goldmont-plus";
       *Type = INTEL_GOLDMONT_PLUS;
       break;
     case 0x86:
+      CPU = "tremont";
       *Type = INTEL_TREMONT;
       break;
 
     case 0x57:
-      *Type = INTEL_KNL; // knl
+      CPU = "knl";
+      *Type = INTEL_KNL;
       break;
 
     case 0x85:
-      *Type = INTEL_KNM; // knm
+      CPU = "knm";
+      *Type = INTEL_KNM;
       break;
 
     default: // Unknown family 6 CPU.
@@ -421,17 +480,22 @@ static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
   default:
     break; // Unknown.
   }
+
+  return CPU;
 }
 
-static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
-                                          unsigned Features, unsigned Features2,
-                                          unsigned *Type, unsigned *Subtype) {
-  // FIXME: this poorly matches the generated SubtargetFeatureKV table.  There
-  // appears to be no way to generate the wide variety of AMD-specific targets
-  // from the information returned from CPUID.
+static const char *
+getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
+                              const unsigned *Features,
+                              unsigned *Type, unsigned *Subtype) {
+  // We select CPU strings to match the code in Host.cpp, but we don't use them
+  // in compiler-rt.
+  const char *CPU = 0;
+
   switch (Family) {
   case 16:
-    *Type = AMDFAM10H; // "amdfam10"
+    CPU = "amdfam10";
+    *Type = AMDFAM10H;
     switch (Model) {
     case 2:
       *Subtype = AMDFAM10H_BARCELONA;
@@ -445,60 +509,70 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
     }
     break;
   case 20:
+    CPU = "btver1";
     *Type = AMD_BTVER1;
-    break; // "btver1";
+    break;
   case 21:
+    CPU = "bdver1";
     *Type = AMDFAM15H;
     if (Model >= 0x60 && Model <= 0x7f) {
+      CPU = "bdver4";
       *Subtype = AMDFAM15H_BDVER4;
-      break; // "bdver4"; 60h-7Fh: Excavator
+      break; // 60h-7Fh: Excavator
     }
     if (Model >= 0x30 && Model <= 0x3f) {
+      CPU = "bdver3";
       *Subtype = AMDFAM15H_BDVER3;
-      break; // "bdver3"; 30h-3Fh: Steamroller
+      break; // 30h-3Fh: Steamroller
     }
     if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {
+      CPU = "bdver2";
       *Subtype = AMDFAM15H_BDVER2;
-      break; // "bdver2"; 02h, 10h-1Fh: Piledriver
+      break; // 02h, 10h-1Fh: Piledriver
     }
     if (Model <= 0x0f) {
       *Subtype = AMDFAM15H_BDVER1;
-      break; // "bdver1"; 00h-0Fh: Bulldozer
+      break; // 00h-0Fh: Bulldozer
     }
     break;
   case 22:
+    CPU = "btver2";
     *Type = AMD_BTVER2;
-    break; // "btver2"
+    break;
   case 23:
+    CPU = "znver1";
     *Type = AMDFAM17H;
     if ((Model >= 0x30 && Model <= 0x3f) || Model == 0x71) {
+      CPU = "znver2";
       *Subtype = AMDFAM17H_ZNVER2;
-      break; // "znver2"; 30h-3fh, 71h: Zen2
+      break; // 30h-3fh, 71h: Zen2
     }
     if (Model <= 0x0f) {
       *Subtype = AMDFAM17H_ZNVER1;
-      break; // "znver1"; 00h-0Fh: Zen1
+      break; // 00h-0Fh: Zen1
+    }
+    break;
+  case 25:
+    CPU = "znver3";
+    *Type = AMDFAM19H;
+    if (Model <= 0x0f) {
+      *Subtype = AMDFAM19H_ZNVER3;
+      break; // 00h-0Fh: Zen3
     }
     break;
   default:
-    break; // "generic"
+    break; // Unknown AMD CPU.
   }
+
+  return CPU;
 }
 
 static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
-                                 unsigned *FeaturesOut,
-                                 unsigned *Features2Out) {
-  unsigned Features = 0;
-  unsigned Features2 = 0;
+                                 unsigned *Features) {
   unsigned EAX, EBX;
 
 #define setFeature(F)                                                          \
-  do {                                                                         \
-    if (F < 32)                                                                \
-      Features |= 1U << (F & 0x1f);                                            \
-    else if (F < 64)                                                           \
-      Features2 |= 1U << ((F - 32) & 0x1f);                                    \
-  } while (0)
+  Features[F / 32] |= 1U << (F % 32)
 
   if ((EDX >> 15) & 1)
     setFeature(FEATURE_CMOV);
@@ -590,6 +664,8 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
     setFeature(FEATURE_AVX5124VNNIW);
   if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
     setFeature(FEATURE_AVX5124FMAPS);
+  if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save)
+    setFeature(FEATURE_AVX512VP2INTERSECT);
 
   bool HasLeaf7Subleaf1 =
       MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);
@@ -607,22 +683,9 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
     setFeature(FEATURE_XOP);
   if (HasExtLeaf1 && ((ECX >> 16) & 1))
     setFeature(FEATURE_FMA4);
-
-  *FeaturesOut = Features;
-  *Features2Out = Features2;
 #undef setFeature
 }
 
-#if defined(HAVE_INIT_PRIORITY)
-#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))
-#elif __has_attribute(__constructor__)
-#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))
-#else
-// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
-// this runs during initialization.
-#define CONSTRUCTOR_ATTRIBUTE
-#endif
-
 #ifndef _WIN32
 __attribute__((visibility("hidden")))
 #endif
@@ -641,7 +704,7 @@ struct __processor_model {
 #ifndef _WIN32
 __attribute__((visibility("hidden")))
 #endif
-unsigned int __cpu_features2;
+unsigned int __cpu_features2 = 0;
 
 // A constructor function that is sets __cpu_model and __cpu_features2 with
 // the right values.  This needs to run only once.  This constructor is
@@ -653,40 +716,38 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
   unsigned EAX, EBX, ECX, EDX;
   unsigned MaxLeaf = 5;
   unsigned Vendor;
-  unsigned Model, Family, Brand_id;
-  unsigned Features = 0;
-  unsigned Features2 = 0;
+  unsigned Model, Family;
+  unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0};
 
   // This function needs to run just once.
   if (__cpu_model.__cpu_vendor)
     return 0;
 
-  if (!isCpuIdSupported())
-    return -1;
-
-  // Assume cpuid insn present. Run in level 0 to get vendor id.
-  if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
+  if (!isCpuIdSupported() ||
+      getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
     __cpu_model.__cpu_vendor = VENDOR_OTHER;
     return -1;
   }
+
   getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
   detectX86FamilyModel(EAX, &Family, &Model);
-  Brand_id = EBX & 0xff;
 
   // Find available features.
-  getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2);
-  __cpu_model.__cpu_features[0] = Features;
-  __cpu_features2 = Features2;
+  getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]);
+
+  assert((sizeof(Features)/sizeof(Features[0])) == 2);
+  __cpu_model.__cpu_features[0] = Features[0];
+  __cpu_features2 = Features[1];
 
   if (Vendor == SIG_INTEL) {
     // Get CPU type.
-    getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features,
-                                    Features2, &(__cpu_model.__cpu_type),
+    getIntelProcessorTypeAndSubtype(Family, Model, &Features[0],
+                                    &(__cpu_model.__cpu_type),
                                     &(__cpu_model.__cpu_subtype));
     __cpu_model.__cpu_vendor = VENDOR_INTEL;
   } else if (Vendor == SIG_AMD) {
     // Get CPU type.
-    getAMDProcessorTypeAndSubtype(Family, Model, Features, Features2,
+    getAMDProcessorTypeAndSubtype(Family, Model, &Features[0],
                                   &(__cpu_model.__cpu_type),
                                   &(__cpu_model.__cpu_subtype));
     __cpu_model.__cpu_vendor = VENDOR_AMD;
@@ -699,5 +760,24 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
 
   return 0;
 }
-
+#elif defined(__aarch64__)
+// LSE support detection for out-of-line atomics
+// using HWCAP and Auxiliary vector
+_Bool __aarch64_have_lse_atomics
+    __attribute__((visibility("hidden"), nocommon));
+#if defined(__has_include)
+#if __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#ifndef AT_HWCAP
+#define AT_HWCAP 16
+#endif
+#ifndef HWCAP_ATOMICS
+#define HWCAP_ATOMICS (1 << 8)
 #endif
+static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) {
+  unsigned long hwcap = getauxval(AT_HWCAP);
+  __aarch64_have_lse_atomics = (hwcap & HWCAP_ATOMICS) != 0;
+}
+#endif // defined(__has_include)
+#endif // __has_include(<sys/auxv.h>)
+#endif // defined(__aarch64__)
diff --git a/system/lib/compiler-rt/lib/builtins/ctzdi2.c b/system/lib/compiler-rt/lib/builtins/ctzdi2.c
index 9384aa6055a11..26c908d876ac4 100644
--- a/system/lib/compiler-rt/lib/builtins/ctzdi2.c
+++ b/system/lib/compiler-rt/lib/builtins/ctzdi2.c
@@ -21,15 +21,15 @@
 // ctz instruction, gcc resolves __builtin_ctz to __ctzdi2 rather than
 // __ctzsi2, leading to infinite recursion.
 #define __builtin_ctz(a) __ctzsi2(a)
-extern si_int __ctzsi2(si_int);
+extern int __ctzsi2(si_int);
 #endif
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __ctzdi2(di_int a) {
+COMPILER_RT_ABI int __ctzdi2(di_int a) {
   dwords x;
   x.all = a;
   const si_int f = -(x.s.low == 0);
-  return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) +
+  return ctzsi((x.s.high & f) | (x.s.low & ~f)) +
          (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
 }
diff --git a/system/lib/compiler-rt/lib/builtins/ctzsi2.c b/system/lib/compiler-rt/lib/builtins/ctzsi2.c
index 09c6863b74e3a..ed95c60579339 100644
--- a/system/lib/compiler-rt/lib/builtins/ctzsi2.c
+++ b/system/lib/compiler-rt/lib/builtins/ctzsi2.c
@@ -16,7 +16,7 @@
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __ctzsi2(si_int a) {
+COMPILER_RT_ABI int __ctzsi2(si_int a) {
   su_int x = (su_int)a;
   si_int t = ((x & 0x0000FFFF) == 0)
              << 4; // if (x has no small bits) t = 16 else 0
diff --git a/system/lib/compiler-rt/lib/builtins/ctzti2.c b/system/lib/compiler-rt/lib/builtins/ctzti2.c
index 2a1312c8437de..fb136d0de1c0d 100644
--- a/system/lib/compiler-rt/lib/builtins/ctzti2.c
+++ b/system/lib/compiler-rt/lib/builtins/ctzti2.c
@@ -18,7 +18,7 @@
 
 // Precondition: a != 0
 
-COMPILER_RT_ABI si_int __ctzti2(ti_int a) {
+COMPILER_RT_ABI int __ctzti2(ti_int a) {
   twords x;
   x.all = a;
   const di_int f = -(x.s.low == 0);
diff --git a/system/lib/compiler-rt/lib/builtins/divdf3.c b/system/lib/compiler-rt/lib/builtins/divdf3.c
index 1dea3b534f5ae..4c11759e0c4a7 100644
--- a/system/lib/compiler-rt/lib/builtins/divdf3.c
+++ b/system/lib/compiler-rt/lib/builtins/divdf3.c
@@ -9,197 +9,16 @@
 // This file implements double-precision soft-float division
 // with the IEEE-754 default rounding (to nearest, ties to even).
 //
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
 //===----------------------------------------------------------------------===//
 
 #define DOUBLE_PRECISION
-#include "fp_lib.h"
-
-COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) {
-
-  const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
-  const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
-  const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
-  rep_t aSignificand = toRep(a) & significandMask;
-  rep_t bSignificand = toRep(b) & significandMask;
-  int scale = 0;
-
-  // Detect if a or b is zero, denormal, infinity, or NaN.
-  if (aExponent - 1U >= maxExponent - 1U ||
-      bExponent - 1U >= maxExponent - 1U) {
-
-    const rep_t aAbs = toRep(a) & absMask;
-    const rep_t bAbs = toRep(b) & absMask;
-
-    // NaN / anything = qNaN
-    if (aAbs > infRep)
-      return fromRep(toRep(a) | quietBit);
-    // anything / NaN = qNaN
-    if (bAbs > infRep)
-      return fromRep(toRep(b) | quietBit);
-
-    if (aAbs == infRep) {
-      // infinity / infinity = NaN
-      if (bAbs == infRep)
-        return fromRep(qnanRep);
-      // infinity / anything else = +/- infinity
-      else
-        return fromRep(aAbs | quotientSign);
-    }
-
-    // anything else / infinity = +/- 0
-    if (bAbs == infRep)
-      return fromRep(quotientSign);
-
-    if (!aAbs) {
-      // zero / zero = NaN
-      if (!bAbs)
-        return fromRep(qnanRep);
-      // zero / anything else = +/- zero
-      else
-        return fromRep(quotientSign);
-    }
-    // anything else / zero = +/- infinity
-    if (!bAbs)
-      return fromRep(infRep | quotientSign);
-
-    // One or both of a or b is denormal.  The other (if applicable) is a
-    // normal number.  Renormalize one or both of a and b, and set scale to
-    // include the necessary exponent adjustment.
-    if (aAbs < implicitBit)
-      scale += normalize(&aSignificand);
-    if (bAbs < implicitBit)
-      scale -= normalize(&bSignificand);
-  }
-
-  // Set the implicit significand bit.  If we fell through from the
-  // denormal path it was already set by normalize( ), but setting it twice
-  // won't hurt anything.
-  aSignificand |= implicitBit;
-  bSignificand |= implicitBit;
-  int quotientExponent = aExponent - bExponent + scale;
-
-  // Align the significand of b as a Q31 fixed-point number in the range
-  // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
-  // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2.  This
-  // is accurate to about 3.5 binary digits.
-  const uint32_t q31b = bSignificand >> 21;
-  uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
-  // 0x7504F333 / 2^32 + 1 = 3/4 + 1/sqrt(2)
-
-  // Now refine the reciprocal estimate using a Newton-Raphson iteration:
-  //
-  //     x1 = x0 * (2 - x0 * b)
-  //
-  // This doubles the number of correct binary digits in the approximation
-  // with each iteration.
-  uint32_t correction32;
-  correction32 = -((uint64_t)recip32 * q31b >> 32);
-  recip32 = (uint64_t)recip32 * correction32 >> 31;
-  correction32 = -((uint64_t)recip32 * q31b >> 32);
-  recip32 = (uint64_t)recip32 * correction32 >> 31;
-  correction32 = -((uint64_t)recip32 * q31b >> 32);
-  recip32 = (uint64_t)recip32 * correction32 >> 31;
-
-  // The reciprocal may have overflowed to zero if the upper half of b is
-  // exactly 1.0.  This would sabatoge the full-width final stage of the
-  // computation that follows, so we adjust the reciprocal down by one bit.
-  recip32--;
-
-  // We need to perform one more iteration to get us to 56 binary digits.
-  // The last iteration needs to happen with extra precision.
-  const uint32_t q63blo = bSignificand << 11;
-  uint64_t correction, reciprocal;
-  correction = -((uint64_t)recip32 * q31b + ((uint64_t)recip32 * q63blo >> 32));
-  uint32_t cHi = correction >> 32;
-  uint32_t cLo = correction;
-  reciprocal = (uint64_t)recip32 * cHi + ((uint64_t)recip32 * cLo >> 32);
-
-  // Adjust the final 64-bit reciprocal estimate downward to ensure that it is
-  // strictly smaller than the infinitely precise exact reciprocal.  Because
-  // the computation of the Newton-Raphson step is truncating at every step,
-  // this adjustment is small; most of the work is already done.
-  reciprocal -= 2;
-
-  // The numerical reciprocal is accurate to within 2^-56, lies in the
-  // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
-  // of b.  Multiplying a by this reciprocal thus gives a numerical q = a/b
-  // in Q53 with the following properties:
-  //
-  //    1. q < a/b
-  //    2. q is in the interval [0.5, 2.0)
-  //    3. The error in q is bounded away from 2^-53 (actually, we have a
-  //       couple of bits to spare, but this is all we need).
-
-  // We need a 64 x 64 multiply high to compute q, which isn't a basic
-  // operation in C, so we need to be a little bit fussy.
-  rep_t quotient, quotientLo;
-  wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
-  // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
-  // In either case, we are going to compute a residual of the form
-  //
-  //     r = a - q*b
-  //
-  // We know from the construction of q that r satisfies:
-  //
-  //     0 <= r < ulp(q)*b
-  //
-  // If r is greater than 1/2 ulp(q)*b, then q rounds up.  Otherwise, we
-  // already have the correct result.  The exact halfway case cannot occur.
-  // We also take this time to right shift quotient if it falls in the [1,2)
-  // range and adjust the exponent accordingly.
-  rep_t residual;
-  if (quotient < (implicitBit << 1)) {
-    residual = (aSignificand << 53) - quotient * bSignificand;
-    quotientExponent--;
-  } else {
-    quotient >>= 1;
-    residual = (aSignificand << 52) - quotient * bSignificand;
-  }
-
-  const int writtenExponent = quotientExponent + exponentBias;
 
-  if (writtenExponent >= maxExponent) {
-    // If we have overflowed the exponent, return infinity.
-    return fromRep(infRep | quotientSign);
-  }
+#define NUMBER_OF_HALF_ITERATIONS 3
+#define NUMBER_OF_FULL_ITERATIONS 1
 
-  else if (writtenExponent < 1) {
-    if (writtenExponent == 0) {
-      // Check whether the rounded result is normal.
-      const bool round = (residual << 1) > bSignificand;
-      // Clear the implicit bit.
-      rep_t absResult = quotient & significandMask;
-      // Round.
-      absResult += round;
-      if (absResult & ~significandMask) {
-        // The rounded result is normal; return it.
-        return fromRep(absResult | quotientSign);
-      }
-    }
-    // Flush denormals to zero.  In the future, it would be nice to add
-    // code to round them correctly.
-    return fromRep(quotientSign);
-  }
+#include "fp_div_impl.inc"
 
-  else {
-    const bool round = (residual << 1) > bSignificand;
-    // Clear the implicit bit.
-    rep_t absResult = quotient & significandMask;
-    // Insert the exponent.
-    absResult |= (rep_t)writtenExponent << significandBits;
-    // Round.
-    absResult += round;
-    // Insert the sign and return.
-    const double result = fromRep(absResult | quotientSign);
-    return result;
-  }
-}
+COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
diff --git a/system/lib/compiler-rt/lib/builtins/divdi3.c b/system/lib/compiler-rt/lib/builtins/divdi3.c
index ee08d6557783c..d71e138d995c7 100644
--- a/system/lib/compiler-rt/lib/builtins/divdi3.c
+++ b/system/lib/compiler-rt/lib/builtins/divdi3.c
@@ -14,12 +14,9 @@
 
 // Returns: a / b
 
-COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) {
-  const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
-  di_int s_a = a >> bits_in_dword_m1;                   // s_a = a < 0 ? -1 : 0
-  di_int s_b = b >> bits_in_dword_m1;                   // s_b = b < 0 ? -1 : 0
-  a = (a ^ s_a) - s_a;                                  // negate if s_a == -1
-  b = (b ^ s_b) - s_b;                                  // negate if s_b == -1
-  s_a ^= s_b;                                           // sign of quotient
-  return (__udivmoddi4(a, b, (du_int *)0) ^ s_a) - s_a; // negate if s_a == -1
-}
+#define fixint_t di_int
+#define fixuint_t du_int
+#define COMPUTE_UDIV(a, b) __udivmoddi4((a), (b), (du_int *)0)
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { return __divXi3(a, b); }
diff --git a/system/lib/compiler-rt/lib/builtins/divmoddi4.c b/system/lib/compiler-rt/lib/builtins/divmoddi4.c
index 7f333510c0034..e7cbbb1aaa304 100644
--- a/system/lib/compiler-rt/lib/builtins/divmoddi4.c
+++ b/system/lib/compiler-rt/lib/builtins/divmoddi4.c
@@ -15,7 +15,14 @@
 // Returns: a / b, *rem = a % b
 
 COMPILER_RT_ABI di_int __divmoddi4(di_int a, di_int b, di_int *rem) {
-  di_int d = __divdi3(a, b);
-  *rem = a - (d * b);
-  return d;
+  const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+  di_int s_a = a >> bits_in_dword_m1;                   // s_a = a < 0 ? -1 : 0
+  di_int s_b = b >> bits_in_dword_m1;                   // s_b = b < 0 ? -1 : 0
+  a = (a ^ s_a) - s_a;                                  // negate if s_a == -1
+  b = (b ^ s_b) - s_b;                                  // negate if s_b == -1
+  s_b ^= s_a;                                           // sign of quotient
+  du_int r;
+  di_int q = (__udivmoddi4(a, b, &r) ^ s_b) - s_b;      // negate if s_b == -1
+  *rem = (r ^ s_a) - s_a;                               // negate if s_a == -1
+  return q;
 }
diff --git a/system/lib/compiler-rt/lib/builtins/divmodsi4.c b/system/lib/compiler-rt/lib/builtins/divmodsi4.c
index 402eed22fe7a0..a85e2993b4e9b 100644
--- a/system/lib/compiler-rt/lib/builtins/divmodsi4.c
+++ b/system/lib/compiler-rt/lib/builtins/divmodsi4.c
@@ -16,7 +16,14 @@
 // Returns: a / b, *rem = a % b
 
 COMPILER_RT_ABI si_int __divmodsi4(si_int a, si_int b, si_int *rem) {
-  si_int d = __divsi3(a, b);
-  *rem = a - (d * b);
-  return d;
+  const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
+  si_int s_a = a >> bits_in_word_m1;                    // s_a = a < 0 ? -1 : 0
+  si_int s_b = b >> bits_in_word_m1;                    // s_b = b < 0 ? -1 : 0
+  a = (a ^ s_a) - s_a;                                  // negate if s_a == -1
+  b = (b ^ s_b) - s_b;                                  // negate if s_b == -1
+  s_b ^= s_a;                                           // sign of quotient
+  su_int r;
+  si_int q = (__udivmodsi4(a, b, &r) ^ s_b) - s_b;      // negate if s_b == -1
+  *rem = (r ^ s_a) - s_a;                               // negate if s_a == -1
+  return q;
 }
diff --git a/system/lib/compiler-rt/lib/builtins/divmodti4.c b/system/lib/compiler-rt/lib/builtins/divmodti4.c
new file mode 100644
index 0000000000000..b243ba4ef8537
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/divmodti4.c
@@ -0,0 +1,32 @@
+//===-- divmodti4.c - Implement __divmodti4 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divmodti4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+// Returns: a / b, *rem = a % b
+
+COMPILER_RT_ABI ti_int __divmodti4(ti_int a, ti_int b, ti_int *rem) {
+  const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+  ti_int s_a = a >> bits_in_tword_m1;                   // s_a = a < 0 ? -1 : 0
+  ti_int s_b = b >> bits_in_tword_m1;                   // s_b = b < 0 ? -1 : 0
+  a = (a ^ s_a) - s_a;                                  // negate if s_a == -1
+  b = (b ^ s_b) - s_b;                                  // negate if s_b == -1
+  s_b ^= s_a;                                           // sign of quotient
+  tu_int r;
+  ti_int q = (__udivmodti4(a, b, &r) ^ s_b) - s_b;      // negate if s_b == -1
+  *rem = (r ^ s_a) - s_a;                               // negate if s_a == -1
+  return q;
+}
+
+#endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/divsf3.c b/system/lib/compiler-rt/lib/builtins/divsf3.c
index 593f93b45ac24..5744c015240b6 100644
--- a/system/lib/compiler-rt/lib/builtins/divsf3.c
+++ b/system/lib/compiler-rt/lib/builtins/divsf3.c
@@ -9,181 +9,17 @@
 // This file implements single-precision soft-float division
 // with the IEEE-754 default rounding (to nearest, ties to even).
 //
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
 //===----------------------------------------------------------------------===//
 
 #define SINGLE_PRECISION
-#include "fp_lib.h"
-
-COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) {
-
-  const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
-  const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
-  const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
-  rep_t aSignificand = toRep(a) & significandMask;
-  rep_t bSignificand = toRep(b) & significandMask;
-  int scale = 0;
-
-  // Detect if a or b is zero, denormal, infinity, or NaN.
-  if (aExponent - 1U >= maxExponent - 1U ||
-      bExponent - 1U >= maxExponent - 1U) {
-
-    const rep_t aAbs = toRep(a) & absMask;
-    const rep_t bAbs = toRep(b) & absMask;
-
-    // NaN / anything = qNaN
-    if (aAbs > infRep)
-      return fromRep(toRep(a) | quietBit);
-    // anything / NaN = qNaN
-    if (bAbs > infRep)
-      return fromRep(toRep(b) | quietBit);
-
-    if (aAbs == infRep) {
-      // infinity / infinity = NaN
-      if (bAbs == infRep)
-        return fromRep(qnanRep);
-      // infinity / anything else = +/- infinity
-      else
-        return fromRep(aAbs | quotientSign);
-    }
-
-    // anything else / infinity = +/- 0
-    if (bAbs == infRep)
-      return fromRep(quotientSign);
-
-    if (!aAbs) {
-      // zero / zero = NaN
-      if (!bAbs)
-        return fromRep(qnanRep);
-      // zero / anything else = +/- zero
-      else
-        return fromRep(quotientSign);
-    }
-    // anything else / zero = +/- infinity
-    if (!bAbs)
-      return fromRep(infRep | quotientSign);
-
-    // One or both of a or b is denormal.  The other (if applicable) is a
-    // normal number.  Renormalize one or both of a and b, and set scale to
-    // include the necessary exponent adjustment.
-    if (aAbs < implicitBit)
-      scale += normalize(&aSignificand);
-    if (bAbs < implicitBit)
-      scale -= normalize(&bSignificand);
-  }
-
-  // Set the implicit significand bit.  If we fell through from the
-  // denormal path it was already set by normalize( ), but setting it twice
-  // won't hurt anything.
-  aSignificand |= implicitBit;
-  bSignificand |= implicitBit;
-  int quotientExponent = aExponent - bExponent + scale;
-  // 0x7504F333 / 2^32 + 1 = 3/4 + 1/sqrt(2)
-
-  // Align the significand of b as a Q31 fixed-point number in the range
-  // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
-  // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2.  This
-  // is accurate to about 3.5 binary digits.
-  uint32_t q31b = bSignificand << 8;
-  uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
-
-  // Now refine the reciprocal estimate using a Newton-Raphson iteration:
-  //
-  //     x1 = x0 * (2 - x0 * b)
-  //
-  // This doubles the number of correct binary digits in the approximation
-  // with each iteration.
-  uint32_t correction;
-  correction = -((uint64_t)reciprocal * q31b >> 32);
-  reciprocal = (uint64_t)reciprocal * correction >> 31;
-  correction = -((uint64_t)reciprocal * q31b >> 32);
-  reciprocal = (uint64_t)reciprocal * correction >> 31;
-  correction = -((uint64_t)reciprocal * q31b >> 32);
-  reciprocal = (uint64_t)reciprocal * correction >> 31;
-
-  // Adust the final 32-bit reciprocal estimate downward to ensure that it is
-  // strictly smaller than the infinitely precise exact reciprocal.  Because
-  // the computation of the Newton-Raphson step is truncating at every step,
-  // this adjustment is small; most of the work is already done.
-  reciprocal -= 2;
-
-  // The numerical reciprocal is accurate to within 2^-28, lies in the
-  // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
-  // than the true reciprocal of b.  Multiplying a by this reciprocal thus
-  // gives a numerical q = a/b in Q24 with the following properties:
-  //
-  //    1. q < a/b
-  //    2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0)
-  //    3. The error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes
-  //       from the fact that we truncate the product, and the 2^27 term
-  //       is the error in the reciprocal of b scaled by the maximum
-  //       possible value of a.  As a consequence of this error bound,
-  //       either q or nextafter(q) is the correctly rounded.
-  rep_t quotient = (uint64_t)reciprocal * (aSignificand << 1) >> 32;
-
-  // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
-  // In either case, we are going to compute a residual of the form
-  //
-  //     r = a - q*b
-  //
-  // We know from the construction of q that r satisfies:
-  //
-  //     0 <= r < ulp(q)*b
-  //
-  // If r is greater than 1/2 ulp(q)*b, then q rounds up.  Otherwise, we
-  // already have the correct result.  The exact halfway case cannot occur.
-  // We also take this time to right shift quotient if it falls in the [1,2)
-  // range and adjust the exponent accordingly.
-  rep_t residual;
-  if (quotient < (implicitBit << 1)) {
-    residual = (aSignificand << 24) - quotient * bSignificand;
-    quotientExponent--;
-  } else {
-    quotient >>= 1;
-    residual = (aSignificand << 23) - quotient * bSignificand;
-  }
-
-  const int writtenExponent = quotientExponent + exponentBias;
 
-  if (writtenExponent >= maxExponent) {
-    // If we have overflowed the exponent, return infinity.
-    return fromRep(infRep | quotientSign);
-  }
+#define NUMBER_OF_HALF_ITERATIONS 0
+#define NUMBER_OF_FULL_ITERATIONS 3
+#define USE_NATIVE_FULL_ITERATIONS
 
-  else if (writtenExponent < 1) {
-    if (writtenExponent == 0) {
-      // Check whether the rounded result is normal.
-      const bool round = (residual << 1) > bSignificand;
-      // Clear the implicit bit.
-      rep_t absResult = quotient & significandMask;
-      // Round.
-      absResult += round;
-      if (absResult & ~significandMask) {
-        // The rounded result is normal; return it.
-        return fromRep(absResult | quotientSign);
-      }
-    }
-    // Flush denormals to zero.  In the future, it would be nice to add
-    // code to round them correctly.
-    return fromRep(quotientSign);
-  }
+#include "fp_div_impl.inc"
 
-  else {
-    const bool round = (residual << 1) > bSignificand;
-    // Clear the implicit bit.
-    rep_t absResult = quotient & significandMask;
-    // Insert the exponent.
-    absResult |= (rep_t)writtenExponent << significandBits;
-    // Round.
-    absResult += round;
-    // Insert the sign and return.
-    return fromRep(absResult | quotientSign);
-  }
-}
+COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
diff --git a/system/lib/compiler-rt/lib/builtins/divsi3.c b/system/lib/compiler-rt/lib/builtins/divsi3.c
index b97e11119f0eb..f514407477f33 100644
--- a/system/lib/compiler-rt/lib/builtins/divsi3.c
+++ b/system/lib/compiler-rt/lib/builtins/divsi3.c
@@ -14,21 +14,16 @@
 
 // Returns: a / b
 
-COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) {
-  const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
-  si_int s_a = a >> bits_in_word_m1; // s_a = a < 0 ? -1 : 0
-  si_int s_b = b >> bits_in_word_m1; // s_b = b < 0 ? -1 : 0
-  a = (a ^ s_a) - s_a;               // negate if s_a == -1
-  b = (b ^ s_b) - s_b;               // negate if s_b == -1
-  s_a ^= s_b;                        // sign of quotient
-  //
-  // On CPUs without unsigned hardware division support,
-  //  this calls __udivsi3 (notice the cast to su_int).
-  // On CPUs with unsigned hardware division support,
-  //  this uses the unsigned division instruction.
-  //
-  return ((su_int)a / (su_int)b ^ s_a) - s_a; // negate if s_a == -1
-}
+#define fixint_t si_int
+#define fixuint_t su_int
+// On CPUs without unsigned hardware division support,
+//  this calls __udivsi3 (notice the cast to su_int).
+// On CPUs with unsigned hardware division support,
+//  this uses the unsigned division instruction.
+#define COMPUTE_UDIV(a, b) ((su_int)(a) / (su_int)(b))
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { return __divXi3(a, b); }
 
 #if defined(__ARM_EABI__)
 COMPILER_RT_ALIAS(__divsi3, __aeabi_idiv)
diff --git a/system/lib/compiler-rt/lib/builtins/divtf3.c b/system/lib/compiler-rt/lib/builtins/divtf3.c
index ce462d4d46c12..5bcc9a8e4aa18 100644
--- a/system/lib/compiler-rt/lib/builtins/divtf3.c
+++ b/system/lib/compiler-rt/lib/builtins/divtf3.c
@@ -9,213 +9,18 @@
 // This file implements quad-precision soft-float division
 // with the IEEE-754 default rounding (to nearest, ties to even).
 //
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
 //===----------------------------------------------------------------------===//
 
 #define QUAD_PRECISION
 #include "fp_lib.h"
 
 #if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
-
-  const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
-  const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
-  const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
-  rep_t aSignificand = toRep(a) & significandMask;
-  rep_t bSignificand = toRep(b) & significandMask;
-  int scale = 0;
-
-  // Detect if a or b is zero, denormal, infinity, or NaN.
-  if (aExponent - 1U >= maxExponent - 1U ||
-      bExponent - 1U >= maxExponent - 1U) {
-
-    const rep_t aAbs = toRep(a) & absMask;
-    const rep_t bAbs = toRep(b) & absMask;
-
-    // NaN / anything = qNaN
-    if (aAbs > infRep)
-      return fromRep(toRep(a) | quietBit);
-    // anything / NaN = qNaN
-    if (bAbs > infRep)
-      return fromRep(toRep(b) | quietBit);
-
-    if (aAbs == infRep) {
-      // infinity / infinity = NaN
-      if (bAbs == infRep)
-        return fromRep(qnanRep);
-      // infinity / anything else = +/- infinity
-      else
-        return fromRep(aAbs | quotientSign);
-    }
-
-    // anything else / infinity = +/- 0
-    if (bAbs == infRep)
-      return fromRep(quotientSign);
-
-    if (!aAbs) {
-      // zero / zero = NaN
-      if (!bAbs)
-        return fromRep(qnanRep);
-      // zero / anything else = +/- zero
-      else
-        return fromRep(quotientSign);
-    }
-    // anything else / zero = +/- infinity
-    if (!bAbs)
-      return fromRep(infRep | quotientSign);
-
-    // One or both of a or b is denormal.  The other (if applicable) is a
-    // normal number.  Renormalize one or both of a and b, and set scale to
-    // include the necessary exponent adjustment.
-    if (aAbs < implicitBit)
-      scale += normalize(&aSignificand);
-    if (bAbs < implicitBit)
-      scale -= normalize(&bSignificand);
-  }
-
-  // Set the implicit significand bit.  If we fell through from the
-  // denormal path it was already set by normalize( ), but setting it twice
-  // won't hurt anything.
-  aSignificand |= implicitBit;
-  bSignificand |= implicitBit;
-  int quotientExponent = aExponent - bExponent + scale;
-
-  // Align the significand of b as a Q63 fixed-point number in the range
-  // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
-  // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2.  This
-  // is accurate to about 3.5 binary digits.
-  const uint64_t q63b = bSignificand >> 49;
-  uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b;
-  // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
-
-  // Now refine the reciprocal estimate using a Newton-Raphson iteration:
-  //
-  //     x1 = x0 * (2 - x0 * b)
-  //
-  // This doubles the number of correct binary digits in the approximation
-  // with each iteration.
-  uint64_t correction64;
-  correction64 = -((rep_t)recip64 * q63b >> 64);
-  recip64 = (rep_t)recip64 * correction64 >> 63;
-  correction64 = -((rep_t)recip64 * q63b >> 64);
-  recip64 = (rep_t)recip64 * correction64 >> 63;
-  correction64 = -((rep_t)recip64 * q63b >> 64);
-  recip64 = (rep_t)recip64 * correction64 >> 63;
-  correction64 = -((rep_t)recip64 * q63b >> 64);
-  recip64 = (rep_t)recip64 * correction64 >> 63;
-  correction64 = -((rep_t)recip64 * q63b >> 64);
-  recip64 = (rep_t)recip64 * correction64 >> 63;
-
-  // The reciprocal may have overflowed to zero if the upper half of b is
-  // exactly 1.0.  This would sabatoge the full-width final stage of the
-  // computation that follows, so we adjust the reciprocal down by one bit.
-  recip64--;
-
-  // We need to perform one more iteration to get us to 112 binary digits;
-  // The last iteration needs to happen with extra precision.
-  const uint64_t q127blo = bSignificand << 15;
-  rep_t correction, reciprocal;
-
-  // NOTE: This operation is equivalent to __multi3, which is not implemented
-  //       in some architechure
-  rep_t r64q63, r64q127, r64cH, r64cL, dummy;
-  wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63);
-  wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127);
-
-  correction = -(r64q63 + (r64q127 >> 64));
-
-  uint64_t cHi = correction >> 64;
-  uint64_t cLo = correction;
-
-  wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH);
-  wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL);
-
-  reciprocal = r64cH + (r64cL >> 64);
-
-  // Adjust the final 128-bit reciprocal estimate downward to ensure that it
-  // is strictly smaller than the infinitely precise exact reciprocal. Because
-  // the computation of the Newton-Raphson step is truncating at every step,
-  // this adjustment is small; most of the work is already done.
-  reciprocal -= 2;
-
-  // The numerical reciprocal is accurate to within 2^-112, lies in the
-  // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
-  // of b.  Multiplying a by this reciprocal thus gives a numerical q = a/b
-  // in Q127 with the following properties:
-  //
-  //    1. q < a/b
-  //    2. q is in the interval [0.5, 2.0)
-  //    3. The error in q is bounded away from 2^-113 (actually, we have a
-  //       couple of bits to spare, but this is all we need).
-
-  // We need a 128 x 128 multiply high to compute q, which isn't a basic
-  // operation in C, so we need to be a little bit fussy.
-  rep_t quotient, quotientLo;
-  wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
-  // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
-  // In either case, we are going to compute a residual of the form
-  //
-  //     r = a - q*b
-  //
-  // We know from the construction of q that r satisfies:
-  //
-  //     0 <= r < ulp(q)*b
-  //
-  // If r is greater than 1/2 ulp(q)*b, then q rounds up.  Otherwise, we
-  // already have the correct result.  The exact halfway case cannot occur.
-  // We also take this time to right shift quotient if it falls in the [1,2)
-  // range and adjust the exponent accordingly.
-  rep_t residual;
-  rep_t qb;
 
-  if (quotient < (implicitBit << 1)) {
-    wideMultiply(quotient, bSignificand, &dummy, &qb);
-    residual = (aSignificand << 113) - qb;
-    quotientExponent--;
-  } else {
-    quotient >>= 1;
-    wideMultiply(quotient, bSignificand, &dummy, &qb);
-    residual = (aSignificand << 112) - qb;
-  }
+#define NUMBER_OF_HALF_ITERATIONS 4
+#define NUMBER_OF_FULL_ITERATIONS 1
 
-  const int writtenExponent = quotientExponent + exponentBias;
+#include "fp_div_impl.inc"
 
-  if (writtenExponent >= maxExponent) {
-    // If we have overflowed the exponent, return infinity.
-    return fromRep(infRep | quotientSign);
-  } else if (writtenExponent < 1) {
-    if (writtenExponent == 0) {
-      // Check whether the rounded result is normal.
-      const bool round = (residual << 1) > bSignificand;
-      // Clear the implicit bit.
-      rep_t absResult = quotient & significandMask;
-      // Round.
-      absResult += round;
-      if (absResult & ~significandMask) {
-        // The rounded result is normal; return it.
-        return fromRep(absResult | quotientSign);
-      }
-    }
-    // Flush denormals to zero.  In the future, it would be nice to add
-    // code to round them correctly.
-    return fromRep(quotientSign);
-  } else {
-    const bool round = (residual << 1) >= bSignificand;
-    // Clear the implicit bit.
-    rep_t absResult = quotient & significandMask;
-    // Insert the exponent.
-    absResult |= (rep_t)writtenExponent << significandBits;
-    // Round.
-    absResult += round;
-    // Insert the sign and return.
-    const fp_t result = fromRep(absResult | quotientSign);
-    return result;
-  }
-}
+COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
 
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/divti3.c b/system/lib/compiler-rt/lib/builtins/divti3.c
index 6d007fe346546..80f2130b590e2 100644
--- a/system/lib/compiler-rt/lib/builtins/divti3.c
+++ b/system/lib/compiler-rt/lib/builtins/divti3.c
@@ -16,14 +16,11 @@
 
 // Returns: a / b
 
-COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) {
-  const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
-  ti_int s_a = a >> bits_in_tword_m1;                   // s_a = a < 0 ? -1 : 0
-  ti_int s_b = b >> bits_in_tword_m1;                   // s_b = b < 0 ? -1 : 0
-  a = (a ^ s_a) - s_a;                                  // negate if s_a == -1
-  b = (b ^ s_b) - s_b;                                  // negate if s_b == -1
-  s_a ^= s_b;                                           // sign of quotient
-  return (__udivmodti4(a, b, (tu_int *)0) ^ s_a) - s_a; // negate if s_a == -1
-}
+#define fixint_t ti_int
+#define fixuint_t tu_int
+#define COMPUTE_UDIV(a, b) __udivmodti4((a), (b), (tu_int *)0)
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) { return __divXi3(a, b); }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/emutls.c b/system/lib/compiler-rt/lib/builtins/emutls.c
index e0aa19155f7d3..98cabd917d6ce 100644
--- a/system/lib/compiler-rt/lib/builtins/emutls.c
+++ b/system/lib/compiler-rt/lib/builtins/emutls.c
@@ -182,9 +182,10 @@ static void emutls_exit(void) {
   }
 }
 
-#pragma warning(push)
-#pragma warning(disable : 4100)
 static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) {
+  (void)p0;
+  (void)p1;
+  (void)p2;
   emutls_mutex =
       (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16);
   if (!emutls_mutex) {
@@ -251,8 +252,6 @@ static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {
 
 #endif // __ATOMIC_RELEASE
 
-#pragma warning(pop)
-
 #endif // _WIN32
 
 static size_t emutls_num_object = 0; // number of allocated TLS objects
diff --git a/system/lib/compiler-rt/lib/builtins/extendhfsf2.c b/system/lib/compiler-rt/lib/builtins/extendhfsf2.c
index 7c1a76eb58517..0159ab09d3ebb 100644
--- a/system/lib/compiler-rt/lib/builtins/extendhfsf2.c
+++ b/system/lib/compiler-rt/lib/builtins/extendhfsf2.c
@@ -12,15 +12,15 @@
 
 // Use a forwarding definition and noinline to implement a poor man's alias,
 // as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) {
+COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) {
   return __extendXfYf2__(a);
 }
 
-COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) { return __extendhfsf2(a); }
+COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI float __aeabi_h2f(uint16_t a) { return __extendhfsf2(a); }
+AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); }
 #else
 COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f)
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/extendhftf2.c b/system/lib/compiler-rt/lib/builtins/extendhftf2.c
new file mode 100644
index 0000000000000..aefe9737d34f9
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/extendhftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extendhftf2.c - half -> quad conversion ---------------*- C -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) &&                     \
+    defined(COMPILER_RT_HAS_FLOAT16)
+#define SRC_HALF
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extendhftf2(_Float16 a) {
+  return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/system/lib/compiler-rt/lib/builtins/ffsdi2.c b/system/lib/compiler-rt/lib/builtins/ffsdi2.c
index 9c1a242609567..beae5530430ed 100644
--- a/system/lib/compiler-rt/lib/builtins/ffsdi2.c
+++ b/system/lib/compiler-rt/lib/builtins/ffsdi2.c
@@ -15,13 +15,13 @@
 // Returns: the index of the least significant 1-bit in a, or
 // the value zero if a is zero. The least significant bit is index one.
 
-COMPILER_RT_ABI si_int __ffsdi2(di_int a) {
+COMPILER_RT_ABI int __ffsdi2(di_int a) {
   dwords x;
   x.all = a;
   if (x.s.low == 0) {
     if (x.s.high == 0)
       return 0;
-    return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT);
+    return ctzsi(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT);
   }
-  return __builtin_ctz(x.s.low) + 1;
+  return ctzsi(x.s.low) + 1;
 }
diff --git a/system/lib/compiler-rt/lib/builtins/ffssi2.c b/system/lib/compiler-rt/lib/builtins/ffssi2.c
index cba1f72fdc61a..ddb52927f8db9 100644
--- a/system/lib/compiler-rt/lib/builtins/ffssi2.c
+++ b/system/lib/compiler-rt/lib/builtins/ffssi2.c
@@ -15,9 +15,9 @@
 // Returns: the index of the least significant 1-bit in a, or
 // the value zero if a is zero. The least significant bit is index one.
 
-COMPILER_RT_ABI si_int __ffssi2(si_int a) {
+COMPILER_RT_ABI int __ffssi2(si_int a) {
   if (a == 0) {
     return 0;
   }
-  return __builtin_ctz(a) + 1;
+  return ctzsi(a) + 1;
 }
diff --git a/system/lib/compiler-rt/lib/builtins/ffsti2.c b/system/lib/compiler-rt/lib/builtins/ffsti2.c
index a2d7ce08ada13..a2177d148a099 100644
--- a/system/lib/compiler-rt/lib/builtins/ffsti2.c
+++ b/system/lib/compiler-rt/lib/builtins/ffsti2.c
@@ -17,7 +17,7 @@
 // Returns: the index of the least significant 1-bit in a, or
 // the value zero if a is zero. The least significant bit is index one.
 
-COMPILER_RT_ABI si_int __ffsti2(ti_int a) {
+COMPILER_RT_ABI int __ffsti2(ti_int a) {
   twords x;
   x.all = a;
   if (x.s.low == 0) {
diff --git a/system/lib/compiler-rt/lib/builtins/floatdidf.c b/system/lib/compiler-rt/lib/builtins/floatdidf.c
index 8f887314b9e1b..b2d8f2b44b6d3 100644
--- a/system/lib/compiler-rt/lib/builtins/floatdidf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatdidf.c
@@ -87,7 +87,7 @@ COMPILER_RT_ABI double __floatdidf(di_int a) {
   }
   double_bits fb;
   fb.u.s.high = ((su_int)s & 0x80000000) |        // sign
-                ((e + 1023) << 20) |              // exponent
+                ((su_int)(e + 1023) << 20) |      // exponent
                 ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
   fb.u.s.low = (su_int)a;                         // mantissa-low
   return fb.f;
diff --git a/system/lib/compiler-rt/lib/builtins/floatdisf.c b/system/lib/compiler-rt/lib/builtins/floatdisf.c
index cd9e0a3b78a50..faaa1bcb3c8ed 100644
--- a/system/lib/compiler-rt/lib/builtins/floatdisf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatdisf.c
@@ -26,7 +26,7 @@ COMPILER_RT_ABI float __floatdisf(di_int a) {
   const di_int s = a >> (N - 1);
   a = (a ^ s) - s;
   int sd = N - __builtin_clzll(a); // number of significant digits
-  int e = sd - 1;                  // exponent
+  si_int e = sd - 1;               // exponent
   if (sd > FLT_MANT_DIG) {
     //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
     //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
diff --git a/system/lib/compiler-rt/lib/builtins/floatsidf.c b/system/lib/compiler-rt/lib/builtins/floatsidf.c
index 2c66167d794dc..28cf32f6388b5 100644
--- a/system/lib/compiler-rt/lib/builtins/floatsidf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatsidf.c
@@ -17,7 +17,7 @@
 
 #include "int_lib.h"
 
-COMPILER_RT_ABI fp_t __floatsidf(int a) {
+COMPILER_RT_ABI fp_t __floatsidf(si_int a) {
 
   const int aWidth = sizeof a * CHAR_BIT;
 
@@ -33,14 +33,14 @@ COMPILER_RT_ABI fp_t __floatsidf(int a) {
   }
 
   // Exponent of (fp_t)a is the width of abs(a).
-  const int exponent = (aWidth - 1) - __builtin_clz(a);
+  const int exponent = (aWidth - 1) - clzsi(a);
   rep_t result;
 
   // Shift a into the significand field and clear the implicit bit.  Extra
   // cast to unsigned int is necessary to get the correct behavior for
   // the input INT_MIN.
   const int shift = significandBits - exponent;
-  result = (rep_t)(unsigned int)a << shift ^ implicitBit;
+  result = (rep_t)(su_int)a << shift ^ implicitBit;
 
   // Insert the exponent
   result += (rep_t)(exponent + exponentBias) << significandBits;
@@ -50,7 +50,7 @@ COMPILER_RT_ABI fp_t __floatsidf(int a) {
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI fp_t __aeabi_i2d(int a) { return __floatsidf(a); }
+AEABI_RTABI fp_t __aeabi_i2d(si_int a) { return __floatsidf(a); }
 #else
 COMPILER_RT_ALIAS(__floatsidf, __aeabi_i2d)
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/floatundidf.c b/system/lib/compiler-rt/lib/builtins/floatundidf.c
index e7c6aae5ce382..4c445b118080b 100644
--- a/system/lib/compiler-rt/lib/builtins/floatundidf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatundidf.c
@@ -90,7 +90,7 @@ COMPILER_RT_ABI double __floatundidf(du_int a) {
     // a is now rounded to DBL_MANT_DIG bits
   }
   double_bits fb;
-  fb.u.s.high = ((e + 1023) << 20) |              // exponent
+  fb.u.s.high = ((su_int)(e + 1023) << 20) |      // exponent
                 ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
   fb.u.s.low = (su_int)a;                         // mantissa-low
   return fb.f;
diff --git a/system/lib/compiler-rt/lib/builtins/floatundisf.c b/system/lib/compiler-rt/lib/builtins/floatundisf.c
index 87841b761ded5..00d61b0c63107 100644
--- a/system/lib/compiler-rt/lib/builtins/floatundisf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatundisf.c
@@ -24,7 +24,7 @@ COMPILER_RT_ABI float __floatundisf(du_int a) {
     return 0.0F;
   const unsigned N = sizeof(du_int) * CHAR_BIT;
   int sd = N - __builtin_clzll(a); // number of significant digits
-  int e = sd - 1;                  // 8 exponent
+  si_int e = sd - 1;               // 8 exponent
   if (sd > FLT_MANT_DIG) {
     //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
     //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
diff --git a/system/lib/compiler-rt/lib/builtins/floatunsidf.c b/system/lib/compiler-rt/lib/builtins/floatunsidf.c
index 2c01c3041434d..9b3e5fea0e45b 100644
--- a/system/lib/compiler-rt/lib/builtins/floatunsidf.c
+++ b/system/lib/compiler-rt/lib/builtins/floatunsidf.c
@@ -17,7 +17,7 @@
 
 #include "int_lib.h"
 
-COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) {
+COMPILER_RT_ABI fp_t __floatunsidf(su_int a) {
 
   const int aWidth = sizeof a * CHAR_BIT;
 
@@ -26,7 +26,7 @@ COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) {
     return fromRep(0);
 
   // Exponent of (fp_t)a is the width of abs(a).
-  const int exponent = (aWidth - 1) - __builtin_clz(a);
+  const int exponent = (aWidth - 1) - clzsi(a);
   rep_t result;
 
   // Shift a into the significand field and clear the implicit bit.
@@ -40,7 +40,7 @@ COMPILER_RT_ABI fp_t __floatunsidf(unsigned int a) {
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI fp_t __aeabi_ui2d(unsigned int a) { return __floatunsidf(a); }
+AEABI_RTABI fp_t __aeabi_ui2d(su_int a) { return __floatunsidf(a); }
 #else
 COMPILER_RT_ALIAS(__floatunsidf, __aeabi_ui2d)
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc b/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc
new file mode 100644
index 0000000000000..29bcd1920edfb
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/fp_div_impl.inc
@@ -0,0 +1,419 @@
+//===-- fp_div_impl.inc - Floating point division -----------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements soft-float division with the IEEE-754 default
+// rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+// The __divXf3__ function implements Newton-Raphson floating point division.
+// It uses 3 iterations for float32, 4 for float64 and 5 for float128,
+// respectively. Due to number of significant bits being roughly doubled
+// every iteration, the two modes are supported: N full-width iterations (as
+// it is done for float32 by default) and (N-1) half-width iteration plus one
+// final full-width iteration. It is expected that half-width integer
+// operations (w.r.t rep_t size) can be performed faster for some hardware but
+// they require error estimations to be computed separately due to larger
+// computational errors caused by truncating intermediate results.
+
+// Half the bit-size of rep_t
+#define HW (typeWidth / 2)
+// rep_t-sized bitmask with lower half of bits set to ones
+#define loMask (REP_C(-1) >> HW)
+
+#if NUMBER_OF_FULL_ITERATIONS < 1
+#error At least one full iteration is required
+#endif
+
+static __inline fp_t __divXf3__(fp_t a, fp_t b) {
+
+  const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+  const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+  const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+  rep_t aSignificand = toRep(a) & significandMask;
+  rep_t bSignificand = toRep(b) & significandMask;
+  int scale = 0;
+
+  // Detect if a or b is zero, denormal, infinity, or NaN.
+  if (aExponent - 1U >= maxExponent - 1U ||
+      bExponent - 1U >= maxExponent - 1U) {
+
+    const rep_t aAbs = toRep(a) & absMask;
+    const rep_t bAbs = toRep(b) & absMask;
+
+    // NaN / anything = qNaN
+    if (aAbs > infRep)
+      return fromRep(toRep(a) | quietBit);
+    // anything / NaN = qNaN
+    if (bAbs > infRep)
+      return fromRep(toRep(b) | quietBit);
+
+    if (aAbs == infRep) {
+      // infinity / infinity = NaN
+      if (bAbs == infRep)
+        return fromRep(qnanRep);
+      // infinity / anything else = +/- infinity
+      else
+        return fromRep(aAbs | quotientSign);
+    }
+
+    // anything else / infinity = +/- 0
+    if (bAbs == infRep)
+      return fromRep(quotientSign);
+
+    if (!aAbs) {
+      // zero / zero = NaN
+      if (!bAbs)
+        return fromRep(qnanRep);
+      // zero / anything else = +/- zero
+      else
+        return fromRep(quotientSign);
+    }
+    // anything else / zero = +/- infinity
+    if (!bAbs)
+      return fromRep(infRep | quotientSign);
+
+    // One or both of a or b is denormal.  The other (if applicable) is a
+    // normal number.  Renormalize one or both of a and b, and set scale to
+    // include the necessary exponent adjustment.
+    if (aAbs < implicitBit)
+      scale += normalize(&aSignificand);
+    if (bAbs < implicitBit)
+      scale -= normalize(&bSignificand);
+  }
+
+  // Set the implicit significand bit.  If we fell through from the
+  // denormal path it was already set by normalize( ), but setting it twice
+  // won't hurt anything.
+  aSignificand |= implicitBit;
+  bSignificand |= implicitBit;
+
+  int writtenExponent = (aExponent - bExponent + scale) + exponentBias;
+
+  const rep_t b_UQ1 = bSignificand << (typeWidth - significandBits - 1);
+
+  // Align the significand of b as a UQ1.(n-1) fixed-point number in the range
+  // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax
+  // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2.
+  // The max error for this approximation is achieved at endpoints, so
+  //   abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289...,
+  // which is about 4.5 bits.
+  // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571...
+
+  // Then, refine the reciprocal estimate using a quadratically converging
+  // Newton-Raphson iteration:
+  //     x_{n+1} = x_n * (2 - x_n * b)
+  //
+  // Let b be the original divisor considered "in infinite precision" and
+  // obtained from IEEE754 representation of function argument (with the
+  // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in
+  // UQ1.(W-1).
+  //
+  // Let b_hw be an infinitely precise number obtained from the highest (HW-1)
+  // bits of divisor significand (with the implicit bit set). Corresponds to
+  // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated**
+  // version of b_UQ1.
+  //
+  // Let e_n := x_n - 1/b_hw
+  //     E_n := x_n - 1/b
+  // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b)
+  //           = abs(e_n) + (b - b_hw) / (b*b_hw)
+  //          <= abs(e_n) + 2 * 2^-HW
+
+  // rep_t-sized iterations may be slower than the corresponding half-width
+  // variant depending on the handware and whether single/double/quad precision
+  // is selected.
+  // NB: Using half-width iterations increases computation errors due to
+  // rounding, so error estimations have to be computed taking the selected
+  // mode into account!
+#if NUMBER_OF_HALF_ITERATIONS > 0
+  // Starting with (n-1) half-width iterations
+  const half_rep_t b_UQ1_hw = bSignificand >> (significandBits + 1 - HW);
+
+  // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW
+  // with W0 being either 16 or 32 and W0 <= HW.
+  // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which
+  // b/2 is subtracted to obtain x0) wrapped to [0, 1) range.
+#if defined(SINGLE_PRECISION)
+  // Use 16-bit initial estimation in case we are using half-width iterations
+  // for float32 division. This is expected to be useful for some 16-bit
+  // targets. Not used by default as it requires performing more work during
+  // rounding and would hardly help on regular 32- or 64-bit targets.
+  const half_rep_t C_hw = HALF_REP_C(0x7504);
+#else
+  // HW is at least 32. Shifting into the highest bits if needed.
+  const half_rep_t C_hw = HALF_REP_C(0x7504F333) << (HW - 32);
+#endif
+
+  // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572,
+  // so x0 fits to UQ0.HW without wrapping.
+  half_rep_t x_UQ0_hw = C_hw - (b_UQ1_hw /* exact b_hw/2 as UQ0.HW */);
+  // An e_0 error is comprised of errors due to
+  // * x0 being an inherently imprecise first approximation of 1/b_hw
+  // * C_hw being some (irrational) number **truncated** to W0 bits
+  // Please note that e_0 is calculated against the infinitely precise
+  // reciprocal of b_hw (that is, **truncated** version of b).
+  //
+  // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0
+
+  // By construction, 1 <= b < 2
+  // f(x)  = x * (2 - b*x) = 2*x - b*x^2
+  // f'(x) = 2 * (1 - b*x)
+  //
+  // On the [0, 1] interval, f(0)   = 0,
+  // then it increses until  f(1/b) = 1 / b, maximum on (0, 1),
+  // then it decreses to     f(1)   = 2 - b
+  //
+  // Let g(x) = x - f(x) = b*x^2 - x.
+  // On (0, 1/b), g(x) < 0 <=> f(x) > x
+  // On (1/b, 1], g(x) > 0 <=> f(x) < x
+  //
+  // For half-width iterations, b_hw is used instead of b.
+  REPEAT_N_TIMES(NUMBER_OF_HALF_ITERATIONS, {
+    // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp
+    // of corr_UQ1_hw.
+    // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1).
+    // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided
+    // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is
+    // expected to be strictly positive because b_UQ1_hw has its highest bit set
+    // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1).
+    half_rep_t corr_UQ1_hw = 0 - ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW);
+
+    // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally
+    // obtaining an UQ1.(HW-1) number and proving its highest bit could be
+    // considered to be 0 to be able to represent it in UQ0.HW.
+    // From the above analysis of f(x), if corr_UQ1_hw would be represented
+    // without any intermediate loss of precision (that is, in twice_rep_t)
+    // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly
+    // less otherwise. On the other hand, to obtain [1.]000..., one have to pass
+    // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due
+    // to 1.0 being not representable as UQ0.HW).
+    // The fact corr_UQ1_hw was virtually round up (due to result of
+    // multiplication being **first** truncated, then negated - to improve
+    // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw.
+    x_UQ0_hw = (rep_t)x_UQ0_hw * corr_UQ1_hw >> (HW - 1);
+    // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t
+    // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after
+    // any number of iterations, so just subtract 2 from the reciprocal
+    // approximation after last iteration.
+
+    // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW:
+    // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1
+    //             = 1 - e_n * b_hw + 2*eps1
+    // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2
+    //          = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2
+    //          = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2
+    // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2
+    //         = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw
+    //                        \------ >0 -------/   \-- >0 ---/
+    // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U)
+  })
+  // For initial half-width iterations, U = 2^-HW
+  // Let  abs(e_n)     <= u_n * U,
+  // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U)
+  // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2)
+
+  // Account for possible overflow (see above). For an overflow to occur for the
+  // first time, for "ideal" corr_UQ1_hw (that is, without intermediate
+  // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum
+  // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to
+  // be not below that value (see g(x) above), so it is safe to decrement just
+  // once after the final iteration. On the other hand, an effective value of
+  // divisor changes after this point (from b_hw to b), so adjust here.
+  x_UQ0_hw -= 1U;
+  rep_t x_UQ0 = (rep_t)x_UQ0_hw << HW;
+  x_UQ0 -= 1U;
+
+#else
+  // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n
+  const rep_t C = REP_C(0x7504F333) << (typeWidth - 32);
+  rep_t x_UQ0 = C - b_UQ1;
+  // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32
+#endif
+
+  // Error estimations for full-precision iterations are calculated just
+  // as above, but with U := 2^-W and taking extra decrementing into account.
+  // We need at least one such iteration.
+
+#ifdef USE_NATIVE_FULL_ITERATIONS
+  REPEAT_N_TIMES(NUMBER_OF_FULL_ITERATIONS, {
+    rep_t corr_UQ1 = 0 - ((twice_rep_t)x_UQ0 * b_UQ1 >> typeWidth);
+    x_UQ0 = (twice_rep_t)x_UQ0 * corr_UQ1 >> (typeWidth - 1);
+  })
+#else
+#if NUMBER_OF_FULL_ITERATIONS != 1
+#error Only a single emulated full iteration is supported
+#endif
+#if !(NUMBER_OF_HALF_ITERATIONS > 0)
+  // Cannot normally reach here: only one full-width iteration is requested and
+  // the total number of iterations should be at least 3 even for float32.
+#error Check NUMBER_OF_HALF_ITERATIONS, NUMBER_OF_FULL_ITERATIONS and USE_NATIVE_FULL_ITERATIONS.
+#endif
+  // Simulating operations on a twice_rep_t to perform a single final full-width
+  // iteration. Using ad-hoc multiplication implementations to take advantage
+  // of particular structure of operands.
+  rep_t blo = b_UQ1 & loMask;
+  // x_UQ0 = x_UQ0_hw * 2^HW - 1
+  // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1
+  //
+  //   <--- higher half ---><--- lower half --->
+  //   [x_UQ0_hw * b_UQ1_hw]
+  // +            [  x_UQ0_hw *  blo  ]
+  // -                      [      b_UQ1       ]
+  // = [      result       ][.... discarded ...]
+  rep_t corr_UQ1 = 0U - (   (rep_t)x_UQ0_hw * b_UQ1_hw
+                         + ((rep_t)x_UQ0_hw * blo >> HW)
+                         - REP_C(1)); // account for *possible* carry
+  rep_t lo_corr = corr_UQ1 & loMask;
+  rep_t hi_corr = corr_UQ1 >> HW;
+  // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1
+  x_UQ0 =   ((rep_t)x_UQ0_hw * hi_corr << 1)
+          + ((rep_t)x_UQ0_hw * lo_corr >> (HW - 1))
+          - REP_C(2); // 1 to account for the highest bit of corr_UQ1 can be 1
+                      // 1 to account for possible carry
+  // Just like the case of half-width iterations but with possibility
+  // of overflowing by one extra Ulp of x_UQ0.
+  x_UQ0 -= 1U;
+  // ... and then traditional fixup by 2 should work
+
+  // On error estimation:
+  // abs(E_{N-1}) <=   (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW
+  //                 + (2^-HW + 2^-W))
+  // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW
+
+  // Then like for the half-width iterations:
+  // With 0 <= eps1, eps2 < 2^-W
+  // E_N  = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b
+  // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ]
+  // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ]
+#endif
+
+  // Finally, account for possible overflow, as explained above.
+  x_UQ0 -= 2U;
+
+  // u_n for different precisions (with N-1 half-width iterations):
+  // W0 is the precision of C
+  //   u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW
+
+  // Estimated with bc:
+  //   define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; }
+  //   define half2(un) { return 2.0 * un / 2.0^hw + 2.0; }
+  //   define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; }
+  //   define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; }
+
+  //             | f32 (0 + 3) | f32 (2 + 1)  | f64 (3 + 1)  | f128 (4 + 1)
+  // u_0         | < 184224974 | < 2812.1     | < 184224974  | < 791240234244348797
+  // u_1         | < 15804007  | < 242.7      | < 15804007   | < 67877681371350440
+  // u_2         | < 116308    | < 2.81       | < 116308     | < 499533100252317
+  // u_3         | < 7.31      |              | < 7.31       | < 27054456580
+  // u_4         |             |              |              | < 80.4
+  // Final (U_N) | same as u_3 | < 72         | < 218        | < 13920
+
+  // Add 2 to U_N due to final decrement.
+
+#if defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 2 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(74)
+#elif defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 0 && NUMBER_OF_FULL_ITERATIONS == 3
+#define RECIPROCAL_PRECISION REP_C(10)
+#elif defined(DOUBLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 3 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(220)
+#elif defined(QUAD_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 4 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(13922)
+#else
+#error Invalid number of iterations
+#endif
+
+  // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W
+  x_UQ0 -= RECIPROCAL_PRECISION;
+  // Now 1/b - (2*P) * 2^-W < x < 1/b
+  // FIXME Is x_UQ0 still >= 0.5?
+
+  rep_t quotient_UQ1, dummy;
+  wideMultiply(x_UQ0, aSignificand << 1, &quotient_UQ1, &dummy);
+  // Now, a/b - 4*P * 2^-W < q < a/b for q=<quotient_UQ1:dummy> in UQ1.(SB+1+W).
+
+  // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1),
+  // adjust it to be in [1.0, 2.0) as UQ1.SB.
+  rep_t residualLo;
+  if (quotient_UQ1 < (implicitBit << 1)) {
+    // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB,
+    // effectively doubling its value as well as its error estimation.
+    residualLo = (aSignificand << (significandBits + 1)) - quotient_UQ1 * bSignificand;
+    writtenExponent -= 1;
+    aSignificand <<= 1;
+  } else {
+    // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it
+    // to UQ1.SB by right shifting by 1. Least significant bit is omitted.
+    quotient_UQ1 >>= 1;
+    residualLo = (aSignificand << significandBits) - quotient_UQ1 * bSignificand;
+  }
+  // NB: residualLo is calculated above for the normal result case.
+  //     It is re-computed on denormal path that is expected to be not so
+  //     performance-sensitive.
+
+  // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB
+  // Each NextAfter() increments the floating point value by at least 2^-SB
+  // (more, if exponent was incremented).
+  // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint):
+  //   q
+  //   |   | * |   |   |       |       |
+  //       <--->      2^t
+  //   |   |   |   |   |   *   |       |
+  //               q
+  // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB.
+  //   (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB
+  //   (8*P) * 2^-W         < 0.5 * 2^-SB
+  //   P < 2^(W-4-SB)
+  // Generally, for at most R NextAfter() to be enough,
+  //   P < (2*R - 1) * 2^(W-4-SB)
+  // For f32 (0+3): 10 < 32 (OK)
+  // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required
+  // For f64: 220 < 256 (OK)
+  // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required)
+
+  // If we have overflowed the exponent, return infinity
+  if (writtenExponent >= maxExponent)
+    return fromRep(infRep | quotientSign);
+
+  // Now, quotient_UQ1_SB <= the correctly-rounded result
+  // and may need taking NextAfter() up to 3 times (see error estimates above)
+  // r = a - b * q
+  rep_t absResult;
+  if (writtenExponent > 0) {
+    // Clear the implicit bit
+    absResult = quotient_UQ1 & significandMask;
+    // Insert the exponent
+    absResult |= (rep_t)writtenExponent << significandBits;
+    residualLo <<= 1;
+  } else {
+    // Prevent shift amount from being negative
+    if (significandBits + writtenExponent < 0)
+      return fromRep(quotientSign);
+
+    absResult = quotient_UQ1 >> (-writtenExponent + 1);
+
+    // multiplied by two to prevent shift amount to be negative
+    residualLo = (aSignificand << (significandBits + writtenExponent)) - (absResult * bSignificand << 1);
+  }
+
+  // Round
+  residualLo += absResult & 1; // tie to even
+  // The above line conditionally turns the below LT comparison into LTE
+  absResult += residualLo > bSignificand;
+#if defined(QUAD_PRECISION) || (defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS > 0)
+  // Do not round Infinity to NaN
+  absResult += absResult < infRep && residualLo > (2 + 1) * bSignificand;
+#endif
+#if defined(QUAD_PRECISION)
+  absResult += absResult < infRep && residualLo > (4 + 1) * bSignificand;
+#endif
+  return fromRep(absResult | quotientSign);
+}
diff --git a/system/lib/compiler-rt/lib/builtins/fp_extend.h b/system/lib/compiler-rt/lib/builtins/fp_extend.h
index d2083c4267225..aad4436730dd4 100644
--- a/system/lib/compiler-rt/lib/builtins/fp_extend.h
+++ b/system/lib/compiler-rt/lib/builtins/fp_extend.h
@@ -21,7 +21,7 @@ typedef float src_t;
 typedef uint32_t src_rep_t;
 #define SRC_REP_C UINT32_C
 static const int srcSigBits = 23;
-#define src_rep_t_clz __builtin_clz
+#define src_rep_t_clz clzsi
 
 #elif defined SRC_DOUBLE
 typedef double src_t;
@@ -40,7 +40,11 @@ static __inline int src_rep_t_clz(src_rep_t a) {
 }
 
 #elif defined SRC_HALF
+#ifdef COMPILER_RT_HAS_FLOAT16
+typedef _Float16 src_t;
+#else
 typedef uint16_t src_t;
+#endif
 typedef uint16_t src_rep_t;
 #define SRC_REP_C UINT16_C
 static const int srcSigBits = 10;
diff --git a/system/lib/compiler-rt/lib/builtins/fp_lib.h b/system/lib/compiler-rt/lib/builtins/fp_lib.h
index e2a906681c46d..f22feafa4e694 100644
--- a/system/lib/compiler-rt/lib/builtins/fp_lib.h
+++ b/system/lib/compiler-rt/lib/builtins/fp_lib.h
@@ -40,13 +40,16 @@
 
 #if defined SINGLE_PRECISION
 
+typedef uint16_t half_rep_t;
 typedef uint32_t rep_t;
+typedef uint64_t twice_rep_t;
 typedef int32_t srep_t;
 typedef float fp_t;
+#define HALF_REP_C UINT16_C
 #define REP_C UINT32_C
 #define significandBits 23
 
-static __inline int rep_clz(rep_t a) { return __builtin_clz(a); }
+static __inline int rep_clz(rep_t a) { return clzsi(a); }
 
 // 32x32 --> 64 bit multiply
 static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
@@ -58,9 +61,11 @@ COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
 
 #elif defined DOUBLE_PRECISION
 
+typedef uint32_t half_rep_t;
 typedef uint64_t rep_t;
 typedef int64_t srep_t;
 typedef double fp_t;
+#define HALF_REP_C UINT32_C
 #define REP_C UINT64_C
 #define significandBits 52
 
@@ -69,9 +74,9 @@ static __inline int rep_clz(rep_t a) {
   return __builtin_clzl(a);
 #else
   if (a & REP_C(0xffffffff00000000))
-    return __builtin_clz(a >> 32);
+    return clzsi(a >> 32);
   else
-    return 32 + __builtin_clz(a & REP_C(0xffffffff));
+    return 32 + clzsi(a & REP_C(0xffffffff));
 #endif
 }
 
@@ -102,9 +107,11 @@ COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
 #elif defined QUAD_PRECISION
 #if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__)
 #define CRT_LDBL_128BIT
+typedef uint64_t half_rep_t;
 typedef __uint128_t rep_t;
 typedef __int128_t srep_t;
 typedef long double fp_t;
+#define HALF_REP_C UINT64_C
 #define REP_C (__uint128_t)
 // Note: Since there is no explicit way to tell compiler the constant is a
 // 128-bit integer, we let the constant be casted to 128-bit integer
diff --git a/system/lib/compiler-rt/lib/builtins/fp_mode.h b/system/lib/compiler-rt/lib/builtins/fp_mode.h
index 51bec0431a402..4ba682c384f2d 100644
--- a/system/lib/compiler-rt/lib/builtins/fp_mode.h
+++ b/system/lib/compiler-rt/lib/builtins/fp_mode.h
@@ -23,7 +23,7 @@ typedef enum {
   FE_TOWARDZERO
 } FE_ROUND_MODE;
 
-FE_ROUND_MODE __fe_getround();
-int __fe_raise_inexact();
+FE_ROUND_MODE __fe_getround(void);
+int __fe_raise_inexact(void);
 
 #endif // FP_MODE_H
diff --git a/system/lib/compiler-rt/lib/builtins/fp_trunc.h b/system/lib/compiler-rt/lib/builtins/fp_trunc.h
index aca4c9b6e6777..00595edd5e018 100644
--- a/system/lib/compiler-rt/lib/builtins/fp_trunc.h
+++ b/system/lib/compiler-rt/lib/builtins/fp_trunc.h
@@ -50,7 +50,11 @@ typedef uint32_t dst_rep_t;
 static const int dstSigBits = 23;
 
 #elif defined DST_HALF
+#ifdef COMPILER_RT_HAS_FLOAT16
+typedef _Float16 dst_t;
+#else
 typedef uint16_t dst_t;
+#endif
 typedef uint16_t dst_rep_t;
 #define DST_REP_C UINT16_C
 static const int dstSigBits = 10;
diff --git a/system/lib/compiler-rt/lib/builtins/int_div_impl.inc b/system/lib/compiler-rt/lib/builtins/int_div_impl.inc
new file mode 100644
index 0000000000000..dc1f97cbeae53
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/int_div_impl.inc
@@ -0,0 +1,95 @@
+//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3.
+//
+//===----------------------------------------------------------------------===//
+
+#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a))
+
+// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide
+static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) {
+  const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+  // d == 0 cases are unspecified.
+  unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+  // 0 <= sr <= N - 1 or sr is very large.
+  if (sr > N - 1) // n < d
+    return 0;
+  if (sr == N - 1) // d == 1
+    return n;
+  ++sr;
+  // 1 <= sr <= N - 1. Shifts do not trigger UB.
+  fixuint_t r = n >> sr;
+  n <<= N - sr;
+  fixuint_t carry = 0;
+  for (; sr > 0; --sr) {
+    r = (r << 1) | (n >> (N - 1));
+    n = (n << 1) | carry;
+    // Branch-less version of:
+    // carry = 0;
+    // if (r >= d) r -= d, carry = 1;
+    const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+    carry = s & 1;
+    r -= d & s;
+  }
+  n = (n << 1) | carry;
+  return n;
+}
+
+// Mostly identical to __udivXi3 but the return values are different.
+static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) {
+  const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+  // d == 0 cases are unspecified.
+  unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+  // 0 <= sr <= N - 1 or sr is very large.
+  if (sr > N - 1) // n < d
+    return n;
+  if (sr == N - 1) // d == 1
+    return 0;
+  ++sr;
+  // 1 <= sr <= N - 1. Shifts do not trigger UB.
+  fixuint_t r = n >> sr;
+  n <<= N - sr;
+  fixuint_t carry = 0;
+  for (; sr > 0; --sr) {
+    r = (r << 1) | (n >> (N - 1));
+    n = (n << 1) | carry;
+    // Branch-less version of:
+    // carry = 0;
+    // if (r >= d) r -= d, carry = 1;
+    const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+    carry = s & 1;
+    r -= d & s;
+  }
+  return r;
+}
+
+#ifdef COMPUTE_UDIV
+static __inline fixint_t __divXi3(fixint_t a, fixint_t b) {
+  const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+  fixint_t s_a = a >> N;                            // s_a = a < 0 ? -1 : 0
+  fixint_t s_b = b >> N;                            // s_b = b < 0 ? -1 : 0
+  fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a);    // negate if s_a == -1
+  fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b);    // negate if s_b == -1
+  s_a ^= s_b;                                       // sign of quotient
+  return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a);   // negate if s_a == -1
+}
+#endif // COMPUTE_UDIV
+
+#ifdef ASSIGN_UMOD
+static __inline fixint_t __modXi3(fixint_t a, fixint_t b) {
+  const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+  fixint_t s = b >> N;                              // s = b < 0 ? -1 : 0
+  fixuint_t b_u = (fixuint_t)(b ^ s) + (-s);        // negate if s == -1
+  s = a >> N;                                       // s = a < 0 ? -1 : 0
+  fixuint_t a_u = (fixuint_t)(a ^ s) + (-s);        // negate if s == -1
+  fixuint_t res;
+  ASSIGN_UMOD(res, a_u, b_u);
+  return (res ^ s) + (-s);                          // negate if s == -1
+}
+#endif // ASSIGN_UMOD
diff --git a/system/lib/compiler-rt/lib/builtins/int_lib.h b/system/lib/compiler-rt/lib/builtins/int_lib.h
index 3092f68c084a6..991c4a99ea6e2 100644
--- a/system/lib/compiler-rt/lib/builtins/int_lib.h
+++ b/system/lib/compiler-rt/lib/builtins/int_lib.h
@@ -48,12 +48,20 @@
 #define XSTR(a) STR(a)
 #define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
 
-#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__)
+#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) ||           \
+    defined(_AIX)
 #define COMPILER_RT_ALIAS(name, aliasname) \
   COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name)));
 #elif defined(__APPLE__)
+#if defined(VISIBILITY_HIDDEN)
+#define COMPILER_RT_ALIAS_VISIBILITY(name) \
+  __asm__(".private_extern " SYMBOL_NAME(name));
+#else
+#define COMPILER_RT_ALIAS_VISIBILITY(name)
+#endif
 #define COMPILER_RT_ALIAS(name, aliasname) \
   __asm__(".globl " SYMBOL_NAME(aliasname)); \
+  COMPILER_RT_ALIAS_VISIBILITY(aliasname) \
   __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
   COMPILER_RT_ABI __typeof(name) aliasname;
 #elif defined(_WIN32)
@@ -84,8 +92,8 @@
 // Include internal utility function declarations.
 #include "int_util.h"
 
-COMPILER_RT_ABI si_int __paritysi2(si_int a);
-COMPILER_RT_ABI si_int __paritydi2(di_int a);
+COMPILER_RT_ABI int __paritysi2(si_int a);
+COMPILER_RT_ABI int __paritydi2(di_int a);
 
 COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
 COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
@@ -94,7 +102,7 @@ COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
 COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem);
 COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem);
 #ifdef CRT_HAS_128BIT
-COMPILER_RT_ABI si_int __clzti2(ti_int a);
+COMPILER_RT_ABI int __clzti2(ti_int a);
 COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem);
 #endif
 
@@ -102,14 +110,14 @@ COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem);
 #if defined(_MSC_VER) && !defined(__clang__)
 #include <intrin.h>
 
-uint32_t __inline __builtin_ctz(uint32_t value) {
+int __inline __builtin_ctz(uint32_t value) {
   unsigned long trailing_zero = 0;
   if (_BitScanForward(&trailing_zero, value))
     return trailing_zero;
   return 32;
 }
 
-uint32_t __inline __builtin_clz(uint32_t value) {
+int __inline __builtin_clz(uint32_t value) {
   unsigned long leading_zero = 0;
   if (_BitScanReverse(&leading_zero, value))
     return 31 - leading_zero;
@@ -117,14 +125,14 @@ uint32_t __inline __builtin_clz(uint32_t value) {
 }
 
 #if defined(_M_ARM) || defined(_M_X64)
-uint32_t __inline __builtin_clzll(uint64_t value) {
+int __inline __builtin_clzll(uint64_t value) {
   unsigned long leading_zero = 0;
   if (_BitScanReverse64(&leading_zero, value))
     return 63 - leading_zero;
   return 64;
 }
 #else
-uint32_t __inline __builtin_clzll(uint64_t value) {
+int __inline __builtin_clzll(uint64_t value) {
   if (value == 0)
     return 64;
   uint32_t msh = (uint32_t)(value >> 32);
diff --git a/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc b/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc
new file mode 100644
index 0000000000000..567d8b9e6e603
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/int_mulo_impl.inc
@@ -0,0 +1,49 @@
+//===-- int_mulo_impl.inc - Implement __mulo[sdt]i4 ---------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper used by __mulosi4, __mulodi4 and __muloti4.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a * b
+
+// Effects: sets *overflow to 1  if a * b overflows
+
+static __inline fixint_t __muloXi4(fixint_t a, fixint_t b, int *overflow) {
+  const int N = (int)(sizeof(fixint_t) * CHAR_BIT);
+  const fixint_t MIN = (fixint_t)1 << (N - 1);
+  const fixint_t MAX = ~MIN;
+  *overflow = 0;
+  fixint_t result = a * b;
+  if (a == MIN) {
+    if (b != 0 && b != 1)
+      *overflow = 1;
+    return result;
+  }
+  if (b == MIN) {
+    if (a != 0 && a != 1)
+      *overflow = 1;
+    return result;
+  }
+  fixint_t sa = a >> (N - 1);
+  fixint_t abs_a = (a ^ sa) - sa;
+  fixint_t sb = b >> (N - 1);
+  fixint_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+    return result;
+  if (sa == sb) {
+    if (abs_a > MAX / abs_b)
+      *overflow = 1;
+  } else {
+    if (abs_a > MIN / -abs_b)
+      *overflow = 1;
+  }
+  return result;
+}
diff --git a/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc b/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc
new file mode 100644
index 0000000000000..1e920716ec499
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/int_mulv_impl.inc
@@ -0,0 +1,47 @@
+//===-- int_mulv_impl.inc - Implement __mulv[sdt]i3 ---------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper used by __mulvsi3, __mulvdi3 and __mulvti3.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a * b
+
+// Effects: aborts if a * b overflows
+
+static __inline fixint_t __mulvXi3(fixint_t a, fixint_t b) {
+  const int N = (int)(sizeof(fixint_t) * CHAR_BIT);
+  const fixint_t MIN = (fixint_t)1 << (N - 1);
+  const fixint_t MAX = ~MIN;
+  if (a == MIN) {
+    if (b == 0 || b == 1)
+      return a * b;
+    compilerrt_abort();
+  }
+  if (b == MIN) {
+    if (a == 0 || a == 1)
+      return a * b;
+    compilerrt_abort();
+  }
+  fixint_t sa = a >> (N - 1);
+  fixint_t abs_a = (a ^ sa) - sa;
+  fixint_t sb = b >> (N - 1);
+  fixint_t abs_b = (b ^ sb) - sb;
+  if (abs_a < 2 || abs_b < 2)
+    return a * b;
+  if (sa == sb) {
+    if (abs_a > MAX / abs_b)
+      compilerrt_abort();
+  } else {
+    if (abs_a > MIN / -abs_b)
+      compilerrt_abort();
+  }
+  return a * b;
+}
diff --git a/system/lib/compiler-rt/lib/builtins/int_types.h b/system/lib/compiler-rt/lib/builtins/int_types.h
index f89220d543509..705355a4840d4 100644
--- a/system/lib/compiler-rt/lib/builtins/int_types.h
+++ b/system/lib/compiler-rt/lib/builtins/int_types.h
@@ -22,11 +22,20 @@
 #ifdef si_int
 #undef si_int
 #endif
-typedef int si_int;
-typedef unsigned su_int;
+typedef int32_t si_int;
+typedef uint32_t su_int;
+#if UINT_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clz
+#define ctzsi __builtin_ctz
+#elif ULONG_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clzl
+#define ctzsi __builtin_ctzl
+#else
+#error could not determine appropriate clzsi macro for this system
+#endif
 
-typedef long long di_int;
-typedef unsigned long long du_int;
+typedef int64_t di_int;
+typedef uint64_t du_int;
 
 typedef union {
   di_int all;
@@ -135,9 +144,12 @@ typedef struct {
 // Check if the target supports 80 bit extended precision long doubles.
 // Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
 // still makes it 80 bits. Clang will match whatever compiler it is trying to
-// be compatible with.
-#if ((defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)) ||      \
-    defined(__m68k__) || defined(__ia64__)
+// be compatible with. On 32-bit x86 Android, long double is 64 bits, while on
+// x86_64 Android, long double is 128 bits.
+#if (defined(__i386__) || defined(__x86_64__)) &&                              \
+    !(defined(_MSC_VER) || defined(__ANDROID__))
+#define HAS_80_BIT_LONG_DOUBLE 1
+#elif defined(__m68k__) || defined(__ia64__)
 #define HAS_80_BIT_LONG_DOUBLE 1
 #else
 #define HAS_80_BIT_LONG_DOUBLE 0
diff --git a/system/lib/compiler-rt/lib/builtins/int_util.h b/system/lib/compiler-rt/lib/builtins/int_util.h
index 5fbdfb57c1e74..c372c2edc6371 100644
--- a/system/lib/compiler-rt/lib/builtins/int_util.h
+++ b/system/lib/compiler-rt/lib/builtins/int_util.h
@@ -28,4 +28,20 @@ NORETURN void __compilerrt_abort_impl(const char *file, int line,
 #define COMPILE_TIME_ASSERT2(expr, cnt)                                        \
   typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
 
+// Force unrolling the code specified to be repeated N times.
+#define REPEAT_0_TIMES(code_to_repeat) /* do nothing */
+#define REPEAT_1_TIMES(code_to_repeat) code_to_repeat
+#define REPEAT_2_TIMES(code_to_repeat)                                         \
+  REPEAT_1_TIMES(code_to_repeat)                                               \
+  code_to_repeat
+#define REPEAT_3_TIMES(code_to_repeat)                                         \
+  REPEAT_2_TIMES(code_to_repeat)                                               \
+  code_to_repeat
+#define REPEAT_4_TIMES(code_to_repeat)                                         \
+  REPEAT_3_TIMES(code_to_repeat)                                               \
+  code_to_repeat
+
+#define REPEAT_N_TIMES_(N, code_to_repeat) REPEAT_##N##_TIMES(code_to_repeat)
+#define REPEAT_N_TIMES(N, code_to_repeat) REPEAT_N_TIMES_(N, code_to_repeat)
+
 #endif // INT_UTIL_H
diff --git a/system/lib/compiler-rt/lib/builtins/lshrdi3.c b/system/lib/compiler-rt/lib/builtins/lshrdi3.c
index 97e08e1e9ba0b..6072152583ac5 100644
--- a/system/lib/compiler-rt/lib/builtins/lshrdi3.c
+++ b/system/lib/compiler-rt/lib/builtins/lshrdi3.c
@@ -16,7 +16,7 @@
 
 // Precondition:  0 <= b < bits_in_dword
 
-COMPILER_RT_ABI di_int __lshrdi3(di_int a, si_int b) {
+COMPILER_RT_ABI di_int __lshrdi3(di_int a, int b) {
   const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
   udwords input;
   udwords result;
diff --git a/system/lib/compiler-rt/lib/builtins/moddi3.c b/system/lib/compiler-rt/lib/builtins/moddi3.c
index 92b0996077c64..15cf80b995557 100644
--- a/system/lib/compiler-rt/lib/builtins/moddi3.c
+++ b/system/lib/compiler-rt/lib/builtins/moddi3.c
@@ -14,13 +14,9 @@
 
 // Returns: a % b
 
-COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) {
-  const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
-  di_int s = b >> bits_in_dword_m1; // s = b < 0 ? -1 : 0
-  b = (b ^ s) - s;                  // negate if s == -1
-  s = a >> bits_in_dword_m1;        // s = a < 0 ? -1 : 0
-  a = (a ^ s) - s;                  // negate if s == -1
-  du_int r;
-  __udivmoddi4(a, b, &r);
-  return ((di_int)r ^ s) - s; // negate if s == -1
-}
+#define fixint_t di_int
+#define fixuint_t du_int
+#define ASSIGN_UMOD(res, a, b) __udivmoddi4((a), (b), &(res))
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) { return __modXi3(a, b); }
diff --git a/system/lib/compiler-rt/lib/builtins/modti3.c b/system/lib/compiler-rt/lib/builtins/modti3.c
index d11fe220b7691..7c10cfd39027b 100644
--- a/system/lib/compiler-rt/lib/builtins/modti3.c
+++ b/system/lib/compiler-rt/lib/builtins/modti3.c
@@ -16,15 +16,11 @@
 
 // Returns: a % b
 
-COMPILER_RT_ABI ti_int __modti3(ti_int a, ti_int b) {
-  const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
-  ti_int s = b >> bits_in_tword_m1; // s = b < 0 ? -1 : 0
-  b = (b ^ s) - s;                  // negate if s == -1
-  s = a >> bits_in_tword_m1;        // s = a < 0 ? -1 : 0
-  a = (a ^ s) - s;                  // negate if s == -1
-  tu_int r;
-  __udivmodti4(a, b, &r);
-  return ((ti_int)r ^ s) - s; // negate if s == -1
-}
+#define fixint_t ti_int
+#define fixuint_t tu_int
+#define ASSIGN_UMOD(res, a, b) __udivmodti4((a), (b), &(res))
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI ti_int __modti3(ti_int a, ti_int b) { return __modXi3(a, b); }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/mulodi4.c b/system/lib/compiler-rt/lib/builtins/mulodi4.c
index 23f5571ac4689..7209676a327e4 100644
--- a/system/lib/compiler-rt/lib/builtins/mulodi4.c
+++ b/system/lib/compiler-rt/lib/builtins/mulodi4.c
@@ -10,40 +10,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "int_lib.h"
+#define fixint_t di_int
+#include "int_mulo_impl.inc"
 
 // Returns: a * b
 
 // Effects: sets *overflow to 1  if a * b overflows
 
 COMPILER_RT_ABI di_int __mulodi4(di_int a, di_int b, int *overflow) {
-  const int N = (int)(sizeof(di_int) * CHAR_BIT);
-  const di_int MIN = (di_int)1 << (N - 1);
-  const di_int MAX = ~MIN;
-  *overflow = 0;
-  di_int result = a * b;
-  if (a == MIN) {
-    if (b != 0 && b != 1)
-      *overflow = 1;
-    return result;
-  }
-  if (b == MIN) {
-    if (a != 0 && a != 1)
-      *overflow = 1;
-    return result;
-  }
-  di_int sa = a >> (N - 1);
-  di_int abs_a = (a ^ sa) - sa;
-  di_int sb = b >> (N - 1);
-  di_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return result;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      *overflow = 1;
-  } else {
-    if (abs_a > MIN / -abs_b)
-      *overflow = 1;
-  }
-  return result;
+  return __muloXi4(a, b, overflow);
 }
diff --git a/system/lib/compiler-rt/lib/builtins/mulosi4.c b/system/lib/compiler-rt/lib/builtins/mulosi4.c
index fea4311296f8b..4e03c24455d67 100644
--- a/system/lib/compiler-rt/lib/builtins/mulosi4.c
+++ b/system/lib/compiler-rt/lib/builtins/mulosi4.c
@@ -10,40 +10,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "int_lib.h"
+#define fixint_t si_int
+#include "int_mulo_impl.inc"
 
 // Returns: a * b
 
 // Effects: sets *overflow to 1  if a * b overflows
 
 COMPILER_RT_ABI si_int __mulosi4(si_int a, si_int b, int *overflow) {
-  const int N = (int)(sizeof(si_int) * CHAR_BIT);
-  const si_int MIN = (si_int)1 << (N - 1);
-  const si_int MAX = ~MIN;
-  *overflow = 0;
-  si_int result = a * b;
-  if (a == MIN) {
-    if (b != 0 && b != 1)
-      *overflow = 1;
-    return result;
-  }
-  if (b == MIN) {
-    if (a != 0 && a != 1)
-      *overflow = 1;
-    return result;
-  }
-  si_int sa = a >> (N - 1);
-  si_int abs_a = (a ^ sa) - sa;
-  si_int sb = b >> (N - 1);
-  si_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return result;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      *overflow = 1;
-  } else {
-    if (abs_a > MIN / -abs_b)
-      *overflow = 1;
-  }
-  return result;
+  return __muloXi4(a, b, overflow);
 }
diff --git a/system/lib/compiler-rt/lib/builtins/muloti4.c b/system/lib/compiler-rt/lib/builtins/muloti4.c
index 9bdd5b649908b..9a7aa85b022bf 100644
--- a/system/lib/compiler-rt/lib/builtins/muloti4.c
+++ b/system/lib/compiler-rt/lib/builtins/muloti4.c
@@ -18,36 +18,11 @@
 
 // Effects: sets *overflow to 1  if a * b overflows
 
+#define fixint_t ti_int
+#include "int_mulo_impl.inc"
+
 COMPILER_RT_ABI ti_int __muloti4(ti_int a, ti_int b, int *overflow) {
-  const int N = (int)(sizeof(ti_int) * CHAR_BIT);
-  const ti_int MIN = (ti_int)1 << (N - 1);
-  const ti_int MAX = ~MIN;
-  *overflow = 0;
-  ti_int result = a * b;
-  if (a == MIN) {
-    if (b != 0 && b != 1)
-      *overflow = 1;
-    return result;
-  }
-  if (b == MIN) {
-    if (a != 0 && a != 1)
-      *overflow = 1;
-    return result;
-  }
-  ti_int sa = a >> (N - 1);
-  ti_int abs_a = (a ^ sa) - sa;
-  ti_int sb = b >> (N - 1);
-  ti_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return result;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      *overflow = 1;
-  } else {
-    if (abs_a > MIN / -abs_b)
-      *overflow = 1;
-  }
-  return result;
+  return __muloXi4(a, b, overflow);
 }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/mulvdi3.c b/system/lib/compiler-rt/lib/builtins/mulvdi3.c
index cecc97ccf22ec..1d672c6dc155d 100644
--- a/system/lib/compiler-rt/lib/builtins/mulvdi3.c
+++ b/system/lib/compiler-rt/lib/builtins/mulvdi3.c
@@ -10,38 +10,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "int_lib.h"
+#define fixint_t di_int
+#include "int_mulv_impl.inc"
 
 // Returns: a * b
 
 // Effects: aborts if a * b overflows
 
-COMPILER_RT_ABI di_int __mulvdi3(di_int a, di_int b) {
-  const int N = (int)(sizeof(di_int) * CHAR_BIT);
-  const di_int MIN = (di_int)1 << (N - 1);
-  const di_int MAX = ~MIN;
-  if (a == MIN) {
-    if (b == 0 || b == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  if (b == MIN) {
-    if (a == 0 || a == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  di_int sa = a >> (N - 1);
-  di_int abs_a = (a ^ sa) - sa;
-  di_int sb = b >> (N - 1);
-  di_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return a * b;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      compilerrt_abort();
-  } else {
-    if (abs_a > MIN / -abs_b)
-      compilerrt_abort();
-  }
-  return a * b;
-}
+COMPILER_RT_ABI di_int __mulvdi3(di_int a, di_int b) { return __mulvXi3(a, b); }
diff --git a/system/lib/compiler-rt/lib/builtins/mulvsi3.c b/system/lib/compiler-rt/lib/builtins/mulvsi3.c
index 0d6b18ad01a40..00b2e50eeca91 100644
--- a/system/lib/compiler-rt/lib/builtins/mulvsi3.c
+++ b/system/lib/compiler-rt/lib/builtins/mulvsi3.c
@@ -10,38 +10,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "int_lib.h"
+#define fixint_t si_int
+#include "int_mulv_impl.inc"
 
 // Returns: a * b
 
 // Effects: aborts if a * b overflows
 
-COMPILER_RT_ABI si_int __mulvsi3(si_int a, si_int b) {
-  const int N = (int)(sizeof(si_int) * CHAR_BIT);
-  const si_int MIN = (si_int)1 << (N - 1);
-  const si_int MAX = ~MIN;
-  if (a == MIN) {
-    if (b == 0 || b == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  if (b == MIN) {
-    if (a == 0 || a == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  si_int sa = a >> (N - 1);
-  si_int abs_a = (a ^ sa) - sa;
-  si_int sb = b >> (N - 1);
-  si_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return a * b;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      compilerrt_abort();
-  } else {
-    if (abs_a > MIN / -abs_b)
-      compilerrt_abort();
-  }
-  return a * b;
-}
+COMPILER_RT_ABI si_int __mulvsi3(si_int a, si_int b) { return __mulvXi3(a, b); }
diff --git a/system/lib/compiler-rt/lib/builtins/mulvti3.c b/system/lib/compiler-rt/lib/builtins/mulvti3.c
index 03963a0ca694f..ba355149f9a76 100644
--- a/system/lib/compiler-rt/lib/builtins/mulvti3.c
+++ b/system/lib/compiler-rt/lib/builtins/mulvti3.c
@@ -18,34 +18,9 @@
 
 // Effects: aborts if a * b overflows
 
-COMPILER_RT_ABI ti_int __mulvti3(ti_int a, ti_int b) {
-  const int N = (int)(sizeof(ti_int) * CHAR_BIT);
-  const ti_int MIN = (ti_int)1 << (N - 1);
-  const ti_int MAX = ~MIN;
-  if (a == MIN) {
-    if (b == 0 || b == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  if (b == MIN) {
-    if (a == 0 || a == 1)
-      return a * b;
-    compilerrt_abort();
-  }
-  ti_int sa = a >> (N - 1);
-  ti_int abs_a = (a ^ sa) - sa;
-  ti_int sb = b >> (N - 1);
-  ti_int abs_b = (b ^ sb) - sb;
-  if (abs_a < 2 || abs_b < 2)
-    return a * b;
-  if (sa == sb) {
-    if (abs_a > MAX / abs_b)
-      compilerrt_abort();
-  } else {
-    if (abs_a > MIN / -abs_b)
-      compilerrt_abort();
-  }
-  return a * b;
-}
+#define fixint_t ti_int
+#include "int_mulv_impl.inc"
+
+COMPILER_RT_ABI ti_int __mulvti3(ti_int a, ti_int b) { return __mulvXi3(a, b); }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/os_version_check.c b/system/lib/compiler-rt/lib/builtins/os_version_check.c
index 3794b979434cc..d7194b99ae54c 100644
--- a/system/lib/compiler-rt/lib/builtins/os_version_check.c
+++ b/system/lib/compiler-rt/lib/builtins/os_version_check.c
@@ -24,6 +24,20 @@
 // These three variables hold the host's OS version.
 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
 static dispatch_once_t DispatchOnceCounter;
+static dispatch_once_t CompatibilityDispatchOnceCounter;
+
+// _availability_version_check darwin API support.
+typedef uint32_t dyld_platform_t;
+
+typedef struct {
+  dyld_platform_t platform;
+  uint32_t version;
+} dyld_build_version_t;
+
+typedef bool (*AvailabilityVersionCheckFuncTy)(uint32_t count,
+                                               dyld_build_version_t versions[]);
+
+static AvailabilityVersionCheckFuncTy AvailabilityVersionCheck;
 
 // We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
 // just forward declare everything that we need from it.
@@ -72,9 +86,25 @@ typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
                                             CFStringEncoding);
 typedef void (*CFReleaseFuncTy)(CFTypeRef);
 
-// Find and parse the SystemVersion.plist file.
-static void parseSystemVersionPList(void *Unused) {
-  (void)Unused;
+static void _initializeAvailabilityCheck(bool LoadPlist) {
+  if (AvailabilityVersionCheck && !LoadPlist) {
+    // New API is supported and we're not being asked to load the plist,
+    // exit early!
+    return;
+  }
+
+  // Use the new API if it's is available.
+  AvailabilityVersionCheck = (AvailabilityVersionCheckFuncTy)dlsym(
+      RTLD_DEFAULT, "_availability_version_check");
+
+  if (AvailabilityVersionCheck && !LoadPlist) {
+    // New API is supported and we're not being asked to load the plist,
+    // exit early!
+    return;
+  }
+  // Still load the PLIST to ensure that the existing calls to
+  // __isOSVersionAtLeast still work even with new compiler-rt and old OSes.
+
   // Load CoreFoundation dynamically
   const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
   if (!NullAllocator)
@@ -201,9 +231,24 @@ static void parseSystemVersionPList(void *Unused) {
   fclose(PropertyList);
 }
 
+// Find and parse the SystemVersion.plist file.
+static void compatibilityInitializeAvailabilityCheck(void *Unused) {
+  (void)Unused;
+  _initializeAvailabilityCheck(/*LoadPlist=*/true);
+}
+
+static void initializeAvailabilityCheck(void *Unused) {
+  (void)Unused;
+  _initializeAvailabilityCheck(/*LoadPlist=*/false);
+}
+
+// This old API entry point is no longer used by Clang for Darwin. We still need
+// to keep it around to ensure that object files that reference it are still
+// usable when linked with new compiler-rt.
 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
   // Populate the global version variables, if they haven't already.
-  dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
+  dispatch_once_f(&CompatibilityDispatchOnceCounter, NULL,
+                  compatibilityInitializeAvailabilityCheck);
 
   if (Major < GlobalMajor)
     return 1;
@@ -216,6 +261,61 @@ int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
   return Subminor <= GlobalSubminor;
 }
 
+static inline uint32_t ConstructVersion(uint32_t Major, uint32_t Minor,
+                                        uint32_t Subminor) {
+  return ((Major & 0xffff) << 16) | ((Minor & 0xff) << 8) | (Subminor & 0xff);
+}
+
+int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major,
+                                   uint32_t Minor, uint32_t Subminor) {
+  dispatch_once_f(&DispatchOnceCounter, NULL, initializeAvailabilityCheck);
+
+  if (!AvailabilityVersionCheck) {
+    return __isOSVersionAtLeast(Major, Minor, Subminor);
+  }
+  dyld_build_version_t Versions[] = {
+      {Platform, ConstructVersion(Major, Minor, Subminor)}};
+  return AvailabilityVersionCheck(1, Versions);
+}
+
+#elif __ANDROID__
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/system_properties.h>
+
+static int SdkVersion;
+static int IsPreRelease;
+
+static void readSystemProperties(void) {
+  char buf[PROP_VALUE_MAX];
+
+  if (__system_property_get("ro.build.version.sdk", buf) == 0) {
+    // When the system property doesn't exist, defaults to future API level.
+    SdkVersion = __ANDROID_API_FUTURE__;
+  } else {
+    SdkVersion = atoi(buf);
+  }
+
+  if (__system_property_get("ro.build.version.codename", buf) == 0) {
+    IsPreRelease = 1;
+  } else {
+    IsPreRelease = strcmp(buf, "REL") != 0;
+  }
+  return;
+}
+
+int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
+  (int32_t) Minor;
+  (int32_t) Subminor;
+  static pthread_once_t once = PTHREAD_ONCE_INIT;
+  pthread_once(&once, readSystemProperties);
+
+  return SdkVersion >= Major ||
+         (IsPreRelease && Major == __ANDROID_API_FUTURE__);
+}
+
 #else
 
 // Silence an empty translation unit warning.
diff --git a/system/lib/compiler-rt/lib/builtins/paritydi2.c b/system/lib/compiler-rt/lib/builtins/paritydi2.c
index dd9d45e63ea47..350dceb8cef59 100644
--- a/system/lib/compiler-rt/lib/builtins/paritydi2.c
+++ b/system/lib/compiler-rt/lib/builtins/paritydi2.c
@@ -14,8 +14,12 @@
 
 // Returns: 1 if number of bits is odd else returns 0
 
-COMPILER_RT_ABI si_int __paritydi2(di_int a) {
+COMPILER_RT_ABI int __paritydi2(di_int a) {
   dwords x;
   x.all = a;
-  return __paritysi2(x.s.high ^ x.s.low);
+  su_int x2 = x.s.high ^ x.s.low;
+  x2 ^= x2 >> 16;
+  x2 ^= x2 >> 8;
+  x2 ^= x2 >> 4;
+  return (0x6996 >> (x2 & 0xF)) & 1;
 }
diff --git a/system/lib/compiler-rt/lib/builtins/paritysi2.c b/system/lib/compiler-rt/lib/builtins/paritysi2.c
index 3efa961f2f85f..a4b84e0806328 100644
--- a/system/lib/compiler-rt/lib/builtins/paritysi2.c
+++ b/system/lib/compiler-rt/lib/builtins/paritysi2.c
@@ -14,7 +14,7 @@
 
 // Returns: 1 if number of bits is odd else returns 0
 
-COMPILER_RT_ABI si_int __paritysi2(si_int a) {
+COMPILER_RT_ABI int __paritysi2(si_int a) {
   su_int x = (su_int)a;
   x ^= x >> 16;
   x ^= x >> 8;
diff --git a/system/lib/compiler-rt/lib/builtins/parityti2.c b/system/lib/compiler-rt/lib/builtins/parityti2.c
index f3942ba8378c7..011c8dd455620 100644
--- a/system/lib/compiler-rt/lib/builtins/parityti2.c
+++ b/system/lib/compiler-rt/lib/builtins/parityti2.c
@@ -16,10 +16,16 @@
 
 // Returns: 1 if number of bits is odd else returns 0
 
-COMPILER_RT_ABI si_int __parityti2(ti_int a) {
+COMPILER_RT_ABI int __parityti2(ti_int a) {
   twords x;
+  dwords x2;
   x.all = a;
-  return __paritydi2(x.s.high ^ x.s.low);
+  x2.all = x.s.high ^ x.s.low;
+  su_int x3 = x2.s.high ^ x2.s.low;
+  x3 ^= x3 >> 16;
+  x3 ^= x3 >> 8;
+  x3 ^= x3 >> 4;
+  return (0x6996 >> (x3 & 0xF)) & 1;
 }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/popcountdi2.c b/system/lib/compiler-rt/lib/builtins/popcountdi2.c
index 9bbc39c6608a1..20dd0b0239efc 100644
--- a/system/lib/compiler-rt/lib/builtins/popcountdi2.c
+++ b/system/lib/compiler-rt/lib/builtins/popcountdi2.c
@@ -14,7 +14,7 @@
 
 // Returns: count of 1 bits
 
-COMPILER_RT_ABI si_int __popcountdi2(di_int a) {
+COMPILER_RT_ABI int __popcountdi2(di_int a) {
   du_int x2 = (du_int)a;
   x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
   // Every 2 bits holds the sum of every pair of bits (32)
diff --git a/system/lib/compiler-rt/lib/builtins/popcountsi2.c b/system/lib/compiler-rt/lib/builtins/popcountsi2.c
index 75e592a778d98..4d346c45d9cee 100644
--- a/system/lib/compiler-rt/lib/builtins/popcountsi2.c
+++ b/system/lib/compiler-rt/lib/builtins/popcountsi2.c
@@ -14,7 +14,7 @@
 
 // Returns: count of 1 bits
 
-COMPILER_RT_ABI si_int __popcountsi2(si_int a) {
+COMPILER_RT_ABI int __popcountsi2(si_int a) {
   su_int x = (su_int)a;
   x = x - ((x >> 1) & 0x55555555);
   // Every 2 bits holds the sum of every pair of bits
diff --git a/system/lib/compiler-rt/lib/builtins/popcountti2.c b/system/lib/compiler-rt/lib/builtins/popcountti2.c
index 853fd722309ee..79cbb2fb34c00 100644
--- a/system/lib/compiler-rt/lib/builtins/popcountti2.c
+++ b/system/lib/compiler-rt/lib/builtins/popcountti2.c
@@ -17,7 +17,7 @@
 
 // Returns: count of 1 bits
 
-COMPILER_RT_ABI si_int __popcountti2(ti_int a) {
+COMPILER_RT_ABI int __popcountti2(ti_int a) {
   tu_int x3 = (tu_int)a;
   x3 = x3 - ((x3 >> 1) &
              (((tu_int)0x5555555555555555uLL << 64) | 0x5555555555555555uLL));
diff --git a/system/lib/compiler-rt/lib/builtins/powidf2.c b/system/lib/compiler-rt/lib/builtins/powidf2.c
index 9697588484e74..81058af508297 100644
--- a/system/lib/compiler-rt/lib/builtins/powidf2.c
+++ b/system/lib/compiler-rt/lib/builtins/powidf2.c
@@ -14,7 +14,7 @@
 
 // Returns: a ^ b
 
-COMPILER_RT_ABI double __powidf2(double a, si_int b) {
+COMPILER_RT_ABI double __powidf2(double a, int b) {
   const int recip = b < 0;
   double r = 1;
   while (1) {
diff --git a/system/lib/compiler-rt/lib/builtins/powisf2.c b/system/lib/compiler-rt/lib/builtins/powisf2.c
index 469402348825c..d0ab26167bbd2 100644
--- a/system/lib/compiler-rt/lib/builtins/powisf2.c
+++ b/system/lib/compiler-rt/lib/builtins/powisf2.c
@@ -14,7 +14,7 @@
 
 // Returns: a ^ b
 
-COMPILER_RT_ABI float __powisf2(float a, si_int b) {
+COMPILER_RT_ABI float __powisf2(float a, int b) {
   const int recip = b < 0;
   float r = 1;
   while (1) {
diff --git a/system/lib/compiler-rt/lib/builtins/powitf2.c b/system/lib/compiler-rt/lib/builtins/powitf2.c
index 443da04b29b19..8e639a03a3c4b 100644
--- a/system/lib/compiler-rt/lib/builtins/powitf2.c
+++ b/system/lib/compiler-rt/lib/builtins/powitf2.c
@@ -10,13 +10,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "int_lib.h"
+#define QUAD_PRECISION
+#include "fp_lib.h"
 
-#if defined _ARCH_PPC || defined __wasm__
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
 
 // Returns: a ^ b
 
-COMPILER_RT_ABI long double __powitf2(long double a, si_int b) {
+COMPILER_RT_ABI long double __powitf2(long double a, int b) {
   const int recip = b < 0;
   long double r = 1;
   while (1) {
diff --git a/system/lib/compiler-rt/lib/builtins/powixf2.c b/system/lib/compiler-rt/lib/builtins/powixf2.c
index b7b52095afa17..3edfe9fd7af59 100644
--- a/system/lib/compiler-rt/lib/builtins/powixf2.c
+++ b/system/lib/compiler-rt/lib/builtins/powixf2.c
@@ -16,7 +16,7 @@
 
 // Returns: a ^ b
 
-COMPILER_RT_ABI long double __powixf2(long double a, si_int b) {
+COMPILER_RT_ABI long double __powixf2(long double a, int b) {
   const int recip = b < 0;
   long double r = 1;
   while (1) {
diff --git a/system/lib/compiler-rt/lib/builtins/truncdfhf2.c b/system/lib/compiler-rt/lib/builtins/truncdfhf2.c
index 90c418a4387ff..24c6e62f715f5 100644
--- a/system/lib/compiler-rt/lib/builtins/truncdfhf2.c
+++ b/system/lib/compiler-rt/lib/builtins/truncdfhf2.c
@@ -10,11 +10,11 @@
 #define DST_HALF
 #include "fp_trunc_impl.inc"
 
-COMPILER_RT_ABI uint16_t __truncdfhf2(double a) { return __truncXfYf2__(a); }
+COMPILER_RT_ABI dst_t __truncdfhf2(double a) { return __truncXfYf2__(a); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI uint16_t __aeabi_d2h(double a) { return __truncdfhf2(a); }
+AEABI_RTABI dst_t __aeabi_d2h(double a) { return __truncdfhf2(a); }
 #else
 COMPILER_RT_ALIAS(__truncdfhf2, __aeabi_d2h)
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/truncsfhf2.c b/system/lib/compiler-rt/lib/builtins/truncsfhf2.c
index 1f17194c38e59..379e7cb6f7845 100644
--- a/system/lib/compiler-rt/lib/builtins/truncsfhf2.c
+++ b/system/lib/compiler-rt/lib/builtins/truncsfhf2.c
@@ -12,15 +12,15 @@
 
 // Use a forwarding definition and noinline to implement a poor man's alias,
 // as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) {
+COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) {
   return __truncXfYf2__(a);
 }
 
-COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); }
+COMPILER_RT_ABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); }
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI uint16_t __aeabi_f2h(float a) { return __truncsfhf2(a); }
+AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); }
 #else
 COMPILER_RT_ALIAS(__truncsfhf2, __aeabi_f2h)
 #endif
diff --git a/system/lib/compiler-rt/lib/builtins/trunctfhf2.c b/system/lib/compiler-rt/lib/builtins/trunctfhf2.c
new file mode 100644
index 0000000000000..e3a2309d954bc
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/trunctfhf2.c
@@ -0,0 +1,23 @@
+//===-- lib/trunctfhf2.c - quad -> half conversion ----------------*- C -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) &&                     \
+    defined(COMPILER_RT_HAS_FLOAT16)
+#define SRC_QUAD
+#define DST_HALF
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI _Float16 __trunctfhf2(long double a) {
+  return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/system/lib/compiler-rt/lib/builtins/udivdi3.c b/system/lib/compiler-rt/lib/builtins/udivdi3.c
index a23139ec947f6..74319cbe71c3b 100644
--- a/system/lib/compiler-rt/lib/builtins/udivdi3.c
+++ b/system/lib/compiler-rt/lib/builtins/udivdi3.c
@@ -12,8 +12,12 @@
 
 #include "int_lib.h"
 
+typedef du_int fixuint_t;
+typedef di_int fixint_t;
+#include "int_div_impl.inc"
+
 // Returns: a / b
 
 COMPILER_RT_ABI du_int __udivdi3(du_int a, du_int b) {
-  return __udivmoddi4(a, b, 0);
+  return __udivXi3(a, b);
 }
diff --git a/system/lib/compiler-rt/lib/builtins/udivmoddi4.c b/system/lib/compiler-rt/lib/builtins/udivmoddi4.c
index 5b297c32d7901..10b41df28f840 100644
--- a/system/lib/compiler-rt/lib/builtins/udivmoddi4.c
+++ b/system/lib/compiler-rt/lib/builtins/udivmoddi4.c
@@ -87,7 +87,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
     // K K
     // ---
     // K 0
-    sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+    sr = clzsi(d.s.high) - clzsi(n.s.high);
     // 0 <= sr <= n_uword_bits - 2 or sr large
     if (sr > n_uword_bits - 2) {
       if (rem)
@@ -120,7 +120,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
       // K X
       // ---
       // 0 K
-      sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
+      sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high);
       // 2 <= sr <= n_udword_bits - 1
       // q.all = n.all << (n_udword_bits - sr);
       // r.all = n.all >> sr;
@@ -145,7 +145,7 @@ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
       // K X
       // ---
       // K K
-      sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
+      sr = clzsi(d.s.high) - clzsi(n.s.high);
       // 0 <= sr <= n_uword_bits - 1 or sr large
       if (sr > n_uword_bits - 1) {
         if (rem)
diff --git a/system/lib/compiler-rt/lib/builtins/udivmodti4.c b/system/lib/compiler-rt/lib/builtins/udivmodti4.c
index dd14a8b579ca5..55def37c9e1fe 100644
--- a/system/lib/compiler-rt/lib/builtins/udivmodti4.c
+++ b/system/lib/compiler-rt/lib/builtins/udivmodti4.c
@@ -14,182 +14,145 @@
 
 #ifdef CRT_HAS_128BIT
 
+// Returns the 128 bit division result by 64 bit. Result must fit in 64 bits.
+// Remainder stored in r.
+// Taken and adjusted from libdivide libdivide_128_div_64_to_64 division
+// fallback. For a correctness proof see the reference for this algorithm
+// in Knuth, Volume 2, section 4.3.1, Algorithm D.
+UNUSED
+static inline du_int udiv128by64to64default(du_int u1, du_int u0, du_int v,
+                                            du_int *r) {
+  const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+  const du_int b = (1ULL << (n_udword_bits / 2)); // Number base (32 bits)
+  du_int un1, un0;                                // Norm. dividend LSD's
+  du_int vn1, vn0;                                // Norm. divisor digits
+  du_int q1, q0;                                  // Quotient digits
+  du_int un64, un21, un10;                        // Dividend digit pairs
+  du_int rhat;                                    // A remainder
+  si_int s;                                       // Shift amount for normalization
+
+  s = __builtin_clzll(v);
+  if (s > 0) {
+    // Normalize the divisor.
+    v = v << s;
+    un64 = (u1 << s) | (u0 >> (n_udword_bits - s));
+    un10 = u0 << s; // Shift dividend left
+  } else {
+    // Avoid undefined behavior of (u0 >> 64).
+    un64 = u1;
+    un10 = u0;
+  }
+
+  // Break divisor up into two 32-bit digits.
+  vn1 = v >> (n_udword_bits / 2);
+  vn0 = v & 0xFFFFFFFF;
+
+  // Break right half of dividend into two digits.
+  un1 = un10 >> (n_udword_bits / 2);
+  un0 = un10 & 0xFFFFFFFF;
+
+  // Compute the first quotient digit, q1.
+  q1 = un64 / vn1;
+  rhat = un64 - q1 * vn1;
+
+  // q1 has at most error 2. No more than 2 iterations.
+  while (q1 >= b || q1 * vn0 > b * rhat + un1) {
+    q1 = q1 - 1;
+    rhat = rhat + vn1;
+    if (rhat >= b)
+      break;
+  }
+
+  un21 = un64 * b + un1 - q1 * v;
+
+  // Compute the second quotient digit.
+  q0 = un21 / vn1;
+  rhat = un21 - q0 * vn1;
+
+  // q0 has at most error 2. No more than 2 iterations.
+  while (q0 >= b || q0 * vn0 > b * rhat + un0) {
+    q0 = q0 - 1;
+    rhat = rhat + vn1;
+    if (rhat >= b)
+      break;
+  }
+
+  *r = (un21 * b + un0 - q0 * v) >> s;
+  return q1 * b + q0;
+}
+
+static inline du_int udiv128by64to64(du_int u1, du_int u0, du_int v,
+                                     du_int *r) {
+#if defined(__x86_64__)
+  du_int result;
+  __asm__("divq %[v]"
+          : "=a"(result), "=d"(*r)
+          : [ v ] "r"(v), "a"(u0), "d"(u1));
+  return result;
+#else
+  return udiv128by64to64default(u1, u0, v, r);
+#endif
+}
+
 // Effects: if rem != 0, *rem = a % b
 // Returns: a / b
 
-// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
-
 COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
-  const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
   const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
-  utwords n;
-  n.all = a;
-  utwords d;
-  d.all = b;
-  utwords q;
-  utwords r;
-  unsigned sr;
-  // special cases, X is unknown, K != 0
-  if (n.s.high == 0) {
-    if (d.s.high == 0) {
-      // 0 X
-      // ---
-      // 0 X
-      if (rem)
-        *rem = n.s.low % d.s.low;
-      return n.s.low / d.s.low;
-    }
-    // 0 X
-    // ---
-    // K X
+  utwords dividend;
+  dividend.all = a;
+  utwords divisor;
+  divisor.all = b;
+  utwords quotient;
+  utwords remainder;
+  if (divisor.all > dividend.all) {
     if (rem)
-      *rem = n.s.low;
+      *rem = dividend.all;
     return 0;
   }
-  // n.s.high != 0
-  if (d.s.low == 0) {
-    if (d.s.high == 0) {
-      // K X
-      // ---
-      // 0 0
-      if (rem)
-        *rem = n.s.high % d.s.low;
-      return n.s.high / d.s.low;
-    }
-    // d.s.high != 0
-    if (n.s.low == 0) {
-      // K 0
-      // ---
-      // K 0
-      if (rem) {
-        r.s.high = n.s.high % d.s.high;
-        r.s.low = 0;
-        *rem = r.all;
-      }
-      return n.s.high / d.s.high;
-    }
-    // K K
-    // ---
-    // K 0
-    if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ {
-      if (rem) {
-        r.s.low = n.s.low;
-        r.s.high = n.s.high & (d.s.high - 1);
-        *rem = r.all;
-      }
-      return n.s.high >> __builtin_ctzll(d.s.high);
-    }
-    // K K
-    // ---
-    // K 0
-    sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
-    // 0 <= sr <= n_udword_bits - 2 or sr large
-    if (sr > n_udword_bits - 2) {
-      if (rem)
-        *rem = n.all;
-      return 0;
-    }
-    ++sr;
-    // 1 <= sr <= n_udword_bits - 1
-    // q.all = n.all << (n_utword_bits - sr);
-    q.s.low = 0;
-    q.s.high = n.s.low << (n_udword_bits - sr);
-    // r.all = n.all >> sr;
-    r.s.high = n.s.high >> sr;
-    r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
-  } else /* d.s.low != 0 */ {
-    if (d.s.high == 0) {
-      // K X
-      // ---
-      // 0 K
-      if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ {
-        if (rem)
-          *rem = n.s.low & (d.s.low - 1);
-        if (d.s.low == 1)
-          return n.all;
-        sr = __builtin_ctzll(d.s.low);
-        q.s.high = n.s.high >> sr;
-        q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
-        return q.all;
-      }
-      // K X
-      // ---
-      // 0 K
-      sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) -
-           __builtin_clzll(n.s.high);
-      // 2 <= sr <= n_utword_bits - 1
-      // q.all = n.all << (n_utword_bits - sr);
-      // r.all = n.all >> sr;
-      if (sr == n_udword_bits) {
-        q.s.low = 0;
-        q.s.high = n.s.low;
-        r.s.high = 0;
-        r.s.low = n.s.high;
-      } else if (sr < n_udword_bits) /* 2 <= sr <= n_udword_bits - 1 */ {
-        q.s.low = 0;
-        q.s.high = n.s.low << (n_udword_bits - sr);
-        r.s.high = n.s.high >> sr;
-        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
-      } else /* n_udword_bits + 1 <= sr <= n_utword_bits - 1 */ {
-        q.s.low = n.s.low << (n_utword_bits - sr);
-        q.s.high = (n.s.high << (n_utword_bits - sr)) |
-                   (n.s.low >> (sr - n_udword_bits));
-        r.s.high = 0;
-        r.s.low = n.s.high >> (sr - n_udword_bits);
-      }
+  // When the divisor fits in 64 bits, we can use an optimized path.
+  if (divisor.s.high == 0) {
+    remainder.s.high = 0;
+    if (dividend.s.high < divisor.s.low) {
+      // The result fits in 64 bits.
+      quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low,
+                                       divisor.s.low, &remainder.s.low);
+      quotient.s.high = 0;
     } else {
-      // K X
-      // ---
-      // K K
-      sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
-      // 0 <= sr <= n_udword_bits - 1 or sr large
-      if (sr > n_udword_bits - 1) {
-        if (rem)
-          *rem = n.all;
-        return 0;
-      }
-      ++sr;
-      // 1 <= sr <= n_udword_bits
-      // q.all = n.all << (n_utword_bits - sr);
-      // r.all = n.all >> sr;
-      q.s.low = 0;
-      if (sr == n_udword_bits) {
-        q.s.high = n.s.low;
-        r.s.high = 0;
-        r.s.low = n.s.high;
-      } else {
-        r.s.high = n.s.high >> sr;
-        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
-        q.s.high = n.s.low << (n_udword_bits - sr);
-      }
+      // First, divide with the high part to get the remainder in dividend.s.high.
+      // After that dividend.s.high < divisor.s.low.
+      quotient.s.high = dividend.s.high / divisor.s.low;
+      dividend.s.high = dividend.s.high % divisor.s.low;
+      quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low,
+                                       divisor.s.low, &remainder.s.low);
     }
+    if (rem)
+      *rem = remainder.all;
+    return quotient.all;
   }
-  // Not a special case
-  // q and r are initialized with:
-  // q.all = n.all << (n_utword_bits - sr);
-  // r.all = n.all >> sr;
-  // 1 <= sr <= n_utword_bits - 1
-  su_int carry = 0;
-  for (; sr > 0; --sr) {
-    // r:q = ((r:q)  << 1) | carry
-    r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
-    r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
-    q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
-    q.s.low = (q.s.low << 1) | carry;
-    // carry = 0;
-    // if (r.all >= d.all)
+  // 0 <= shift <= 63.
+  si_int shift =
+      __builtin_clzll(divisor.s.high) - __builtin_clzll(dividend.s.high);
+  divisor.all <<= shift;
+  quotient.s.high = 0;
+  quotient.s.low = 0;
+  for (; shift >= 0; --shift) {
+    quotient.s.low <<= 1;
+    // Branch free version of.
+    // if (dividend.all >= divisor.all)
     // {
-    //     r.all -= d.all;
-    //      carry = 1;
+    //    dividend.all -= divisor.all;
+    //    carry = 1;
     // }
-    const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
-    carry = s & 1;
-    r.all -= d.all & s;
+    const ti_int s =
+        (ti_int)(divisor.all - dividend.all - 1) >> (n_utword_bits - 1);
+    quotient.s.low |= s & 1;
+    dividend.all -= divisor.all & s;
+    divisor.all >>= 1;
   }
-  q.all = (q.all << 1) | carry;
   if (rem)
-    *rem = r.all;
-  return q.all;
+    *rem = dividend.all;
+  return quotient.all;
 }
 
 #endif // CRT_HAS_128BIT
diff --git a/system/lib/compiler-rt/lib/builtins/udivsi3.c b/system/lib/compiler-rt/lib/builtins/udivsi3.c
index 18cc96c1b2e08..3894e1597552f 100644
--- a/system/lib/compiler-rt/lib/builtins/udivsi3.c
+++ b/system/lib/compiler-rt/lib/builtins/udivsi3.c
@@ -12,49 +12,14 @@
 
 #include "int_lib.h"
 
-// Returns: a / b
+typedef su_int fixuint_t;
+typedef si_int fixint_t;
+#include "int_div_impl.inc"
 
-// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
+// Returns: a / b
 
-// This function should not call __divsi3!
-COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d) {
-  const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
-  su_int q;
-  su_int r;
-  unsigned sr;
-  // special cases
-  if (d == 0)
-    return 0; // ?!
-  if (n == 0)
-    return 0;
-  sr = __builtin_clz(d) - __builtin_clz(n);
-  // 0 <= sr <= n_uword_bits - 1 or sr large
-  if (sr > n_uword_bits - 1) // d > r
-    return 0;
-  if (sr == n_uword_bits - 1) // d == 1
-    return n;
-  ++sr;
-  // 1 <= sr <= n_uword_bits - 1
-  // Not a special case
-  q = n << (n_uword_bits - sr);
-  r = n >> sr;
-  su_int carry = 0;
-  for (; sr > 0; --sr) {
-    // r:q = ((r:q)  << 1) | carry
-    r = (r << 1) | (q >> (n_uword_bits - 1));
-    q = (q << 1) | carry;
-    // carry = 0;
-    // if (r.all >= d.all)
-    // {
-    //      r.all -= d.all;
-    //      carry = 1;
-    // }
-    const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1);
-    carry = s & 1;
-    r -= d & s;
-  }
-  q = (q << 1) | carry;
-  return q;
+COMPILER_RT_ABI su_int __udivsi3(su_int a, su_int b) {
+  return __udivXi3(a, b);
 }
 
 #if defined(__ARM_EABI__)
diff --git a/system/lib/compiler-rt/lib/builtins/umoddi3.c b/system/lib/compiler-rt/lib/builtins/umoddi3.c
index 965cf8fc01bd2..e672da96ef629 100644
--- a/system/lib/compiler-rt/lib/builtins/umoddi3.c
+++ b/system/lib/compiler-rt/lib/builtins/umoddi3.c
@@ -12,10 +12,12 @@
 
 #include "int_lib.h"
 
+typedef du_int fixuint_t;
+typedef di_int fixint_t;
+#include "int_div_impl.inc"
+
 // Returns: a % b
 
 COMPILER_RT_ABI du_int __umoddi3(du_int a, du_int b) {
-  du_int r;
-  __udivmoddi4(a, b, &r);
-  return r;
+  return __umodXi3(a, b);
 }
diff --git a/system/lib/compiler-rt/lib/builtins/umodsi3.c b/system/lib/compiler-rt/lib/builtins/umodsi3.c
index ce9abcd94ef77..5383aea656a99 100644
--- a/system/lib/compiler-rt/lib/builtins/umodsi3.c
+++ b/system/lib/compiler-rt/lib/builtins/umodsi3.c
@@ -12,8 +12,12 @@
 
 #include "int_lib.h"
 
+typedef su_int fixuint_t;
+typedef si_int fixint_t;
+#include "int_div_impl.inc"
+
 // Returns: a % b
 
 COMPILER_RT_ABI su_int __umodsi3(su_int a, su_int b) {
-  return a - __udivsi3(a, b) * b;
+  return __umodXi3(a, b);
 }
diff --git a/system/lib/compiler-rt/lib/interception/interception.h b/system/lib/compiler-rt/lib/interception/interception.h
index aa2986b1c92fa..c69a63963798d 100644
--- a/system/lib/compiler-rt/lib/interception/interception.h
+++ b/system/lib/compiler-rt/lib/interception/interception.h
@@ -17,7 +17,7 @@
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
 #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \
-    !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \
+    !SANITIZER_NETBSD && !SANITIZER_WINDOWS && \
     !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS && \
     !SANITIZER_EMSCRIPTEN
 # error "Interception doesn't work on this operating system."
@@ -290,7 +290,7 @@ typedef unsigned long uptr;  // NOLINT
 #define INCLUDED_FROM_INTERCEPTION_LIB
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 # include "interception_linux.h"
 # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
diff --git a/system/lib/compiler-rt/lib/interception/interception_linux.cpp b/system/lib/compiler-rt/lib/interception/interception_linux.cpp
index 950cd5126538b..5111a87f0a6c9 100644
--- a/system/lib/compiler-rt/lib/interception/interception_linux.cpp
+++ b/system/lib/compiler-rt/lib/interception/interception_linux.cpp
@@ -14,7 +14,7 @@
 #include "interception.h"
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_SOLARIS
 
 #include <dlfcn.h>   // for dlsym() and dlvsym()
 
@@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
   return addr && (func == wrapper);
 }
 
-// Android and Solaris do not have dlvsym
-#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD
+// dlvsym is a GNU extension supported by some other platforms.
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
 static void *GetFuncAddr(const char *name, const char *ver) {
   return dlvsym(RTLD_NEXT, name, ver);
 }
@@ -75,9 +75,9 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
   *ptr_to_real = (uptr)addr;
   return addr && (func == wrapper);
 }
-#endif  // !SANITIZER_ANDROID
+#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
 
 }  // namespace __interception
 
 #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
-        // SANITIZER_OPENBSD || SANITIZER_SOLARIS
+        // SANITIZER_SOLARIS
diff --git a/system/lib/compiler-rt/lib/interception/interception_linux.h b/system/lib/compiler-rt/lib/interception/interception_linux.h
index 5a98b57d01d7b..6d3957e570267 100644
--- a/system/lib/compiler-rt/lib/interception/interception_linux.h
+++ b/system/lib/compiler-rt/lib/interception/interception_linux.h
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 #if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
 # error "interception_linux.h should be included from interception library only"
@@ -35,9 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
       (::__interception::uptr) & (func),          \
       (::__interception::uptr) & WRAP(func))
 
-// Android,  Solaris, OpenBSD and emscripten do not have dlvsym
-#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD && \
-    !SANITIZER_EMSCRIPTEN
+// dlvsym is a GNU extension supported by some other platforms.
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
   ::__interception::InterceptFunction(                        \
       #func, symver,                                          \
@@ -47,8 +46,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
 #else
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
   INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
-#endif  // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
+#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
 
 #endif  // INTERCEPTION_LINUX_H
 #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
-        // SANITIZER_OPENBSD || SANITIZER_SOLARIS
+        // SANITIZER_SOLARIS
diff --git a/system/lib/compiler-rt/lib/interception/interception_win.cpp b/system/lib/compiler-rt/lib/interception/interception_win.cpp
index 1a1c327e61240..98bc756ae53aa 100644
--- a/system/lib/compiler-rt/lib/interception/interception_win.cpp
+++ b/system/lib/compiler-rt/lib/interception/interception_win.cpp
@@ -136,7 +136,7 @@ namespace __interception {
 static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
 static const int kJumpInstructionLength = 5;
 static const int kShortJumpInstructionLength = 2;
-static const int kIndirectJumpInstructionLength = 6;
+UNUSED static const int kIndirectJumpInstructionLength = 6;
 static const int kBranchLength =
     FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
 static const int kDirectBranchLength = kBranchLength + kAddressLength;
@@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
   return si.dwAllocationGranularity;
 }
 
-static uptr RoundUpTo(uptr size, uptr boundary) {
+UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
   return (size + boundary - 1) & ~(boundary - 1);
 }
 
@@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
   uptr max_size;
 };
 
-static const uptr kTrampolineScanLimitRange = 1 << 31;  // 2 gig
+UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31;  // 2 gig
 static const int kMaxTrampolineRegion = 1024;
 static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
 
diff --git a/system/lib/compiler-rt/lib/lsan/lsan.cpp b/system/lib/compiler-rt/lib/lsan/lsan.cpp
index 8e3f0294eea04..e1e33c068e1fe 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan.cpp
@@ -15,7 +15,6 @@
 
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
-#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "lsan_allocator.h"
 #include "lsan_common.h"
 #include "lsan_thread.h"
@@ -83,7 +82,7 @@ static void InitializeFlags() {
   RegisterCommonFlags(&parser);
 
   // Override from user-specified string.
-  const char *lsan_default_options = MaybeCallLsanDefaultOptions();
+  const char *lsan_default_options = __lsan_default_options();
   parser.ParseString(lsan_default_options);
 #if SANITIZER_EMSCRIPTEN
   char *options = (char*) EM_ASM_INT({
@@ -102,7 +101,7 @@ static void InitializeFlags() {
     StackTrace::snapshot_stack = false;
 #endif // SANITIZER_EMSCRIPTEN
 
-  SetVerbosity(common_flags()->verbosity);
+  InitializeCommonFlags();
 
   if (Verbosity()) ReportUnrecognizedFlags();
 
@@ -111,17 +110,6 @@ static void InitializeFlags() {
   __sanitizer_set_report_path(common_flags()->log_path);
 }
 
-static void OnStackUnwind(const SignalContext &sig, const void *,
-                          BufferedStackTrace *stack) {
-  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
-                common_flags()->fast_unwind_on_fatal);
-}
-
-static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
-  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
-                     nullptr);
-}
-
 extern "C" void __lsan_init() {
   CHECK(!lsan_init_is_running);
   if (lsan_inited)
@@ -141,10 +129,7 @@ extern "C" void __lsan_init() {
   // Emscripten does not have signals
   InstallDeadlySignalHandlers(LsanOnDeadlySignal);
 #endif
-  u32 tid = ThreadCreate(0, 0, true);
-  CHECK_EQ(tid, 0);
-  ThreadStart(tid, GetTid());
-  SetCurrentThread(tid);
+  InitializeMainThread();
 
   if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
     Atexit(DoLeakCheck);
diff --git a/system/lib/compiler-rt/lib/lsan/lsan.h b/system/lib/compiler-rt/lib/lsan/lsan.h
index 9904ada4bb3bd..1e82ad72f0058 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan.h
+++ b/system/lib/compiler-rt/lib/lsan/lsan.h
@@ -12,6 +12,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "lsan_thread.h"
+#if SANITIZER_POSIX
+#include "lsan_posix.h"
+#elif SANITIZER_FUCHSIA
+#include "lsan_fuchsia.h"
+#endif
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 
@@ -33,6 +38,7 @@ namespace __lsan {
 
 void InitializeInterceptors();
 void ReplaceSystemMalloc();
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
 
 #define ENSURE_LSAN_INITED do {   \
   CHECK(!lsan_init_is_running);   \
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp b/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp
index 845526a8771a1..5dff571e4a059 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_allocator.cpp
@@ -309,6 +309,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
     return kIgnoreObjectInvalid;
   }
 }
+
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
+  // This function can be used to treat memory reachable from `tctx` as live.
+  // This is useful for threads that have been created but not yet started.
+
+  // This is currently a no-op because the LSan `pthread_create()` interceptor
+  // blocks until the child thread starts which keeps the thread's `arg` pointer
+  // live.
+}
+
 } // namespace __lsan
 
 using namespace __lsan;
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h
index 3df5f77bd3bcf..050a9143bc014 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_allocator.h
+++ b/system/lib/compiler-rt/lib/lsan/lsan_allocator.h
@@ -72,10 +72,16 @@ struct AP32 {
 template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
-#elif defined(__x86_64__) || defined(__powerpc64__)
-# if defined(__powerpc64__)
+#elif defined(__x86_64__) || defined(__powerpc64__) || defined(__s390x__)
+# if SANITIZER_FUCHSIA
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
+# elif defined(__powerpc64__)
 const uptr kAllocatorSpace = 0xa0000000000ULL;
 const uptr kAllocatorSize  = 0x20000000000ULL;  // 2T.
+#elif defined(__s390x__)
+const uptr kAllocatorSpace = 0x40000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
 # else
 const uptr kAllocatorSpace = 0x600000000000ULL;
 const uptr kAllocatorSize  = 0x40000000000ULL;  // 4T.
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp
index fdd53733241b5..50a2e1952ecd6 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common.cpp
@@ -1,4 +1,4 @@
-//=-- lsan_common.cc ------------------------------------------------------===//
+//=-- lsan_common.cpp -----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -38,6 +38,7 @@ BlockingMutex global_mutex(LINKER_INITIALIZED);
 
 Flags lsan_flags;
 
+
 void DisableCounterUnderflow() {
   if (common_flags()->detect_leaks) {
     Report("Unmatched call to __lsan_enable().\n");
@@ -68,35 +69,67 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
     if (flags()->log_threads) Report(__VA_ARGS__); \
   } while (0)
 
-ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
-static SuppressionContext *suppression_ctx = nullptr;
+class LeakSuppressionContext {
+  bool parsed = false;
+  SuppressionContext context;
+  bool suppressed_stacks_sorted = true;
+  InternalMmapVector<u32> suppressed_stacks;
+
+  Suppression *GetSuppressionForAddr(uptr addr);
+  void LazyInit();
+
+ public:
+  LeakSuppressionContext(const char *supprression_types[],
+                         int suppression_types_num)
+      : context(supprression_types, suppression_types_num) {}
+
+  Suppression *GetSuppressionForStack(u32 stack_trace_id);
+
+  const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
+    if (!suppressed_stacks_sorted) {
+      suppressed_stacks_sorted = true;
+      SortAndDedup(suppressed_stacks);
+    }
+    return suppressed_stacks;
+  }
+  void PrintMatchedSuppressions();
+};
+
+ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
+static LeakSuppressionContext *suppression_ctx = nullptr;
 static const char kSuppressionLeak[] = "leak";
 static const char *kSuppressionTypes[] = { kSuppressionLeak };
 static const char kStdSuppressions[] =
 #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
-  // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
-  // definition.
-  "leak:*pthread_exit*\n"
+    // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+    // definition.
+    "leak:*pthread_exit*\n"
 #endif  // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
 #if SANITIZER_MAC
-  // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173
-  "leak:*_os_trace*\n"
+    // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173
+    "leak:*_os_trace*\n"
 #endif
-  // TLS leak in some glibc versions, described in
-  // https://sourceware.org/bugzilla/show_bug.cgi?id=12650.
-  "leak:*tls_get_addr*\n";
+    // TLS leak in some glibc versions, described in
+    // https://sourceware.org/bugzilla/show_bug.cgi?id=12650.
+    "leak:*tls_get_addr*\n";
 
 void InitializeSuppressions() {
   CHECK_EQ(nullptr, suppression_ctx);
   suppression_ctx = new (suppression_placeholder) // NOLINT
-      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
-  suppression_ctx->ParseFromFile(flags()->suppressions);
-  if (&__lsan_default_suppressions)
-    suppression_ctx->Parse(__lsan_default_suppressions());
-  suppression_ctx->Parse(kStdSuppressions);
+      LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
 }
 
-static SuppressionContext *GetSuppressionContext() {
+void LeakSuppressionContext::LazyInit() {
+  if (!parsed) {
+    parsed = true;
+    context.ParseFromFile(flags()->suppressions);
+    if (&__lsan_default_suppressions)
+      context.Parse(__lsan_default_suppressions());
+    context.Parse(kStdSuppressions);
+  }
+}
+
+static LeakSuppressionContext *GetSuppressionContext() {
   CHECK(suppression_ctx);
   return suppression_ctx;
 }
@@ -111,10 +144,6 @@ void InitializeRootRegions() {
   root_regions = new (placeholder) InternalMmapVector<RootRegion>();
 }
 
-const char *MaybeCallLsanDefaultOptions() {
-  return (&__lsan_default_options) ? __lsan_default_options() : "";
-}
-
 void InitCommonLsan() {
   InitializeRootRegions();
   if (common_flags()->detect_leaks) {
@@ -232,14 +261,45 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
   ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
 }
 
+#if SANITIZER_FUCHSIA
+
+// Fuchsia handles all threads together with its own callback.
+static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
+
+#else
+
+#if SANITIZER_ANDROID
+// FIXME: Move this out into *libcdep.cpp
+extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
+    pid_t, void (*cb)(void *, void *, uptr, void *), void *);
+#endif
+
+static void ProcessThreadRegistry(Frontier *frontier) {
+  InternalMmapVector<uptr> ptrs;
+  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      GetAdditionalThreadContextPtrs, &ptrs);
+
+  for (uptr i = 0; i < ptrs.size(); ++i) {
+    void *ptr = reinterpret_cast<void *>(ptrs[i]);
+    uptr chunk = PointsIntoChunk(ptr);
+    if (!chunk)
+      continue;
+    LsanMetadata m(chunk);
+    if (!m.allocated())
+      continue;
+
+    // Mark as reachable and add to frontier.
+    LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
+    m.set_tag(kReachable);
+    frontier->push_back(chunk);
+  }
+}
+
 #if !SANITIZER_EMSCRIPTEN
 // Scans thread data (stacks and TLS) for heap pointers.
-void ProcessThreads(SuspendedThreadsList const &suspended_threads,
-                    Frontier *frontier) {
-  InternalMmapVector<uptr> registers(suspended_threads.RegisterCount());
-  uptr registers_begin = reinterpret_cast<uptr>(registers.data());
-  uptr registers_end =
-      reinterpret_cast<uptr>(registers.data() + registers.size());
+static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
+                           Frontier *frontier) {
+  InternalMmapVector<uptr> registers;
   for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
     tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
     LOG_THREADS("Processing thread %d.\n", os_id);
@@ -256,7 +316,7 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads,
     }
     uptr sp;
     PtraceRegistersStatus have_registers =
-        suspended_threads.GetRegistersAndSP(i, registers.data(), &sp);
+        suspended_threads.GetRegistersAndSP(i, &registers, &sp);
     if (have_registers != REGISTERS_AVAILABLE) {
       Report("Unable to get registers from thread %d.\n", os_id);
       // If unable to get SP, consider the entire stack to be reachable unless
@@ -265,9 +325,13 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads,
       sp = stack_begin;
     }
 
-    if (flags()->use_registers && have_registers)
+    if (flags()->use_registers && have_registers) {
+      uptr registers_begin = reinterpret_cast<uptr>(registers.data());
+      uptr registers_end =
+          reinterpret_cast<uptr>(registers.data() + registers.size());
       ScanRangeForPointers(registers_begin, registers_end, frontier,
                            "REGISTERS", kReachable);
+    }
 
     if (flags()->use_stacks) {
       LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp);
@@ -311,26 +375,46 @@ void ProcessThreads(SuspendedThreadsList const &suspended_threads,
                                  kReachable);
         }
       }
+#if SANITIZER_ANDROID
+      auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
+                     void *arg) -> void {
+        ScanRangeForPointers(reinterpret_cast<uptr>(dtls_begin),
+                             reinterpret_cast<uptr>(dtls_end),
+                             reinterpret_cast<Frontier *>(arg), "DTLS",
+                             kReachable);
+      };
+
+      // FIXME: There might be a race-condition here (and in Bionic) if the
+      // thread is suspended in the middle of updating its DTLS. IOWs, we
+      // could scan already freed memory. (probably fine for now)
+      __libc_iterate_dynamic_tls(os_id, cb, frontier);
+#else
       if (dtls && !DTLSInDestruction(dtls)) {
-        for (uptr j = 0; j < dtls->dtv_size; ++j) {
-          uptr dtls_beg = dtls->dtv[j].beg;
-          uptr dtls_end = dtls_beg + dtls->dtv[j].size;
+        ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
+          uptr dtls_beg = dtv.beg;
+          uptr dtls_end = dtls_beg + dtv.size;
           if (dtls_beg < dtls_end) {
-            LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
+            LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
             ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
                                  kReachable);
           }
-        }
+        });
       } else {
         // We are handling a thread with DTLS under destruction. Log about
         // this and continue.
         LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id);
       }
+#endif
     }
   }
+
+  // Add pointers reachable from ThreadContexts
+  ProcessThreadRegistry(frontier);
 }
 #endif // !SANITIZER_EMSCRIPTEN
 
+#endif  // SANITIZER_FUCHSIA
+
 void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
                     uptr region_begin, uptr region_end, bool is_readable) {
   uptr intersection_begin = Max(root_region.begin, region_begin);
@@ -393,6 +477,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
   }
 }
 
+static void IgnoredSuppressedCb(uptr chunk, void *arg) {
+  CHECK(arg);
+  chunk = GetUserBegin(chunk);
+  LsanMetadata m(chunk);
+  if (!m.allocated() || m.tag() == kIgnored)
+    return;
+
+  const InternalMmapVector<u32> &suppressed =
+      *static_cast<const InternalMmapVector<u32> *>(arg);
+  uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
+  if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
+    return;
+
+  LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
+               chunk + m.requested_size(), m.requested_size());
+  m.set_tag(kIgnored);
+}
+
 // ForEachChunk callback. If chunk is marked as ignored, adds its address to
 // frontier.
 static void CollectIgnoredCb(uptr chunk, void *arg) {
@@ -476,25 +578,29 @@ void ProcessPC(Frontier *frontier) {
 }
 
 // Sets the appropriate tag on each chunk.
-static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
-  // Holds the flood fill frontier.
-  Frontier frontier;
-
-  ForEachChunk(CollectIgnoredCb, &frontier);
-  ProcessGlobalRegions(&frontier);
-  ProcessThreads(suspended_threads, &frontier);
-  ProcessRootRegions(&frontier);
-  FloodFillTag(&frontier, kReachable);
+static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
+                              Frontier *frontier) {
+  const InternalMmapVector<u32> &suppressed_stacks =
+      GetSuppressionContext()->GetSortedSuppressedStacks();
+  if (!suppressed_stacks.empty()) {
+    ForEachChunk(IgnoredSuppressedCb,
+                 const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
+  }
+  ForEachChunk(CollectIgnoredCb, frontier);
+  ProcessGlobalRegions(frontier);
+  ProcessThreads(suspended_threads, frontier);
+  ProcessRootRegions(frontier);
+  FloodFillTag(frontier, kReachable);
 
-  CHECK_EQ(0, frontier.size());
-  ProcessPC(&frontier);
+  CHECK_EQ(0, frontier->size());
+  ProcessPC(frontier);
 
   // The check here is relatively expensive, so we do this in a separate flood
   // fill. That way we can skip the check for chunks that are reachable
   // otherwise.
   LOG_POINTERS("Processing platform-specific allocations.\n");
-  ProcessPlatformSpecificAllocations(&frontier);
-  FloodFillTag(&frontier, kReachable);
+  ProcessPlatformSpecificAllocations(frontier);
+  FloodFillTag(frontier, kReachable);
 
   // Iterate over leaked chunks and mark those that are reachable from other
   // leaked chunks.
@@ -539,38 +645,42 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
   }
 }
 
-static void PrintMatchedSuppressions() {
+void LeakSuppressionContext::PrintMatchedSuppressions() {
   InternalMmapVector<Suppression *> matched;
-  GetSuppressionContext()->GetMatched(&matched);
+  context.GetMatched(&matched);
   if (!matched.size())
     return;
   const char *line = "-----------------------------------------------------";
   Printf("%s\n", line);
   Printf("Suppressions used:\n");
   Printf("  count      bytes template\n");
-  for (uptr i = 0; i < matched.size(); i++)
-    Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
-        &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
+  for (uptr i = 0; i < matched.size(); i++) {
+    Printf("%7zu %10zu %s\n",
+           static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
+           matched[i]->weight, matched[i]->templ);
+  }
   Printf("%s\n\n", line);
 }
 
-struct CheckForLeaksParam {
-  bool success;
-  LeakReport leak_report;
-};
-
 static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
   const InternalMmapVector<tid_t> &suspended_threads =
       *(const InternalMmapVector<tid_t> *)arg;
   if (tctx->status == ThreadStatusRunning) {
-    uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
-                                tctx->os_id, CompareLess<int>());
+    uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
     if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
       Report("Running thread %d was not suspended. False leaks are possible.\n",
              tctx->os_id);
   }
 }
 
+#if SANITIZER_FUCHSIA
+
+// Fuchsia provides a libc interface that guarantees all threads are
+// covered, and SuspendedThreadList is never really used.
+static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
+
+#else  // !SANITIZER_FUCHSIA
+
 static void ReportUnsuspendedThreads(
     const SuspendedThreadsList &suspended_threads) {
   InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
@@ -583,6 +693,8 @@ static void ReportUnsuspendedThreads(
       &ReportIfNotSuspended, &threads);
 }
 
+#endif  // !SANITIZER_FUCHSIA
+
 static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
                                   void *arg) {
   CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
@@ -591,7 +703,7 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
 #if !SANITIZER_EMSCRIPTEN
   ReportUnsuspendedThreads(suspended_threads);
 #endif
-  ClassifyAllChunks(suspended_threads);
+  ClassifyAllChunks(suspended_threads, &param->frontier);
   ForEachChunk(CollectLeaksCb, &param->leak_report);
   // Clean up for subsequent leak checks. This assumes we did not overwrite any
   // kIgnored tags.
@@ -599,44 +711,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
   param->success = true;
 }
 
-static bool CheckForLeaks() {
-  if (&__lsan_is_turned_off && __lsan_is_turned_off())
-      return false;
-  EnsureMainThreadIDIsCorrect();
-  CheckForLeaksParam param;
-  param.success = false;
-  LockStuffAndStopTheWorld(CheckForLeaksCallback, &param);
-
-  if (!param.success) {
-    Report("LeakSanitizer has encountered a fatal error.\n");
-    Report(
-        "HINT: For debugging, try setting environment variable "
-        "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
-    Report(
-        "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
-    Die();
-  }
-  param.leak_report.ApplySuppressions();
-  uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
-  if (unsuppressed_count > 0) {
+static bool PrintResults(LeakReport &report) {
+  uptr unsuppressed_count = report.UnsuppressedLeakCount();
+  if (unsuppressed_count) {
     Decorator d;
-    Printf("\n"
-           "================================================================="
-           "\n");
+    Printf(
+        "\n"
+        "================================================================="
+        "\n");
     Printf("%s", d.Error());
     Report("ERROR: LeakSanitizer: detected memory leaks\n");
     Printf("%s", d.Default());
-    param.leak_report.ReportTopLeaks(flags()->max_leaks);
+    report.ReportTopLeaks(flags()->max_leaks);
   }
   if (common_flags()->print_suppressions)
-    PrintMatchedSuppressions();
+    GetSuppressionContext()->PrintMatchedSuppressions();
   if (unsuppressed_count > 0) {
-    param.leak_report.PrintSummary();
+    report.PrintSummary();
     return true;
   }
   return false;
 }
 
+static bool CheckForLeaks() {
+  if (&__lsan_is_turned_off && __lsan_is_turned_off())
+    return false;
+  // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
+  // suppressions. However if a stack id was previously suppressed, it should be
+  // suppressed in future checks as well.
+  for (int i = 0;; ++i) {
+    EnsureMainThreadIDIsCorrect();
+    CheckForLeaksParam param;
+    LockStuffAndStopTheWorld(CheckForLeaksCallback, &param);
+    if (!param.success) {
+      Report("LeakSanitizer has encountered a fatal error.\n");
+      Report(
+          "HINT: For debugging, try setting environment variable "
+          "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
+      Report(
+          "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
+          "etc)\n");
+      Die();
+    }
+    // No new suppressions stacks, so rerun will not help and we can report.
+    if (!param.leak_report.ApplySuppressions())
+      return PrintResults(param.leak_report);
+
+    // No indirect leaks to report, so we are done here.
+    if (!param.leak_report.IndirectUnsuppressedLeakCount())
+      return PrintResults(param.leak_report);
+
+    if (i >= 8) {
+      Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
+      return PrintResults(param.leak_report);
+    }
+
+    // We found a new previously unseen suppressed call stack. Rerun to make
+    // sure it does not hold indirect leaks.
+    VReport(1, "Rerun with %zu suppressed stacks.",
+            GetSuppressionContext()->GetSortedSuppressedStacks().size());
+  }
+}
+
 static bool has_reported_leaks = false;
 bool HasReportedLeaks() { return has_reported_leaks; }
 
@@ -657,21 +793,20 @@ static int DoRecoverableLeakCheck() {
 
 void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
 
-static Suppression *GetSuppressionForAddr(uptr addr) {
+Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
   Suppression *s = nullptr;
 
   // Suppress by module name.
-  SuppressionContext *suppressions = GetSuppressionContext();
   if (const char *module_name =
           Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
-    if (suppressions->Match(module_name, kSuppressionLeak, &s))
+    if (context.Match(module_name, kSuppressionLeak, &s))
       return s;
 
   // Suppress by file or function name.
   SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
   for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
-    if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
-        suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
+    if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
+        context.Match(cur->info.file, kSuppressionLeak, &s)) {
       break;
     }
   }
@@ -679,7 +814,9 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
   return s;
 }
 
-static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
+Suppression *LeakSuppressionContext::GetSuppressionForStack(
+    u32 stack_trace_id) {
+  LazyInit();
   StackTrace stack = StackDepotGet(stack_trace_id);
   for (uptr i = 0; i < stack.size; i++) {
 #if SANITIZER_EMSCRIPTEN
@@ -691,7 +828,11 @@ static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
     Suppression *s = GetSuppressionForAddr(
         StackTrace::GetPreviousInstructionPc(stack.trace[i]));
 #endif
-    if (s) return s;
+    if (s) {
+      suppressed_stacks_sorted = false;
+      suppressed_stacks.push_back(stack_trace_id);
+      return s;
+    }
   }
   return nullptr;
 }
@@ -802,16 +943,21 @@ void LeakReport::PrintSummary() {
   ReportErrorSummary(summary.data());
 }
 
-void LeakReport::ApplySuppressions() {
+uptr LeakReport::ApplySuppressions() {
+  LeakSuppressionContext *suppressions = GetSuppressionContext();
+  uptr new_suppressions = false;
   for (uptr i = 0; i < leaks_.size(); i++) {
-    Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
+    Suppression *s =
+        suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
     if (s) {
       s->weight += leaks_[i].total_size;
       atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
           leaks_[i].hit_count);
       leaks_[i].is_suppressed = true;
+      ++new_suppressions;
     }
   }
+  return new_suppressions;
 }
 
 uptr LeakReport::UnsuppressedLeakCount() {
@@ -821,6 +967,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
   return result;
 }
 
+uptr LeakReport::IndirectUnsuppressedLeakCount() {
+  uptr result = 0;
+  for (uptr i = 0; i < leaks_.size(); i++)
+    if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
+      result++;
+  return result;
+}
+
 } // namespace __lsan
 #else // CAN_SANITIZE_LEAKS
 namespace __lsan {
@@ -923,12 +1077,11 @@ int __lsan_do_recoverable_leak_check() {
   return 0;
 }
 
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char * __lsan_default_options() {
+SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_options, void) {
   return "";
 }
 
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 int __lsan_is_turned_off() {
   return 0;
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common.h b/system/lib/compiler-rt/lib/lsan/lsan_common.h
index 6901e18829aeb..809e7e57a9f19 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_common.h
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common.h
@@ -29,18 +29,19 @@
 // To enable LeakSanitizer on a new architecture, one needs to implement the
 // internal_clone function as well as (probably) adjust the TLS machinery for
 // the new architecture inside the sanitizer library.
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \
-    (SANITIZER_WORDSIZE == 64) &&                               \
-    (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \
-     defined(__powerpc64__))
+// Exclude leak-detection on arm32 for Android because `__aeabi_read_tp`
+// is missing. This caused a link error.
+#if SANITIZER_ANDROID && (__ANDROID_API__ < 28 || defined(__arm__))
+#define CAN_SANITIZE_LEAKS 0
+#elif (SANITIZER_LINUX || SANITIZER_MAC) && (SANITIZER_WORDSIZE == 64) && \
+    (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) ||  \
+     defined(__powerpc64__) || defined(__s390x__))
 #define CAN_SANITIZE_LEAKS 1
-#elif defined(__i386__) && \
-    (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC)
+#elif defined(__i386__) && (SANITIZER_LINUX || SANITIZER_MAC)
 #define CAN_SANITIZE_LEAKS 1
-#elif defined(__arm__) && \
-    SANITIZER_LINUX && !SANITIZER_ANDROID
+#elif defined(__arm__) && SANITIZER_LINUX
 #define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_EMSCRIPTEN
+#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
 #define CAN_SANITIZE_LEAKS 1
 #else
 #define CAN_SANITIZE_LEAKS 0
@@ -49,6 +50,7 @@
 namespace __sanitizer {
 class FlagParser;
 class ThreadRegistry;
+class ThreadContextBase;
 struct DTLS;
 }
 
@@ -102,8 +104,9 @@ class LeakReport {
                       ChunkTag tag);
   void ReportTopLeaks(uptr max_leaks);
   void PrintSummary();
-  void ApplySuppressions();
+  uptr ApplySuppressions();
   uptr UnsuppressedLeakCount();
+  uptr IndirectUnsuppressedLeakCount();
 
  private:
   void PrintReportForLeak(uptr index);
@@ -126,12 +129,25 @@ struct RootRegion {
   uptr size;
 };
 
+// LockStuffAndStopTheWorld can start to use Scan* calls to collect into
+// this Frontier vector before the StopTheWorldCallback actually runs.
+// This is used when the OS has a unified callback API for suspending
+// threads and enumerating roots.
+struct CheckForLeaksParam {
+  Frontier frontier;
+  LeakReport leak_report;
+  bool success = false;
+};
+
 InternalMmapVector<RootRegion> const *GetRootRegions();
 void ScanRootRegion(Frontier *frontier, RootRegion const &region,
                     uptr region_begin, uptr region_end, bool is_readable);
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
+void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
 // Run stoptheworld while holding any platform-specific locks, as well as the
 // allocator and thread registry locks.
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument);
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam* argument);
 
 void ScanRangeForPointers(uptr begin, uptr end,
                           Frontier *frontier,
@@ -211,6 +227,7 @@ ThreadRegistry *GetThreadRegistryLocked();
 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
                            uptr *cache_end, DTLS **dtls);
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg);
 // Scans thread data (stacks and TLS) for heap pointers.
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp
index de1efe6bc264f..a60dea00e88c8 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common_emscripten.cpp
@@ -102,7 +102,8 @@ void HandleLeaks() {
   if (common_flags()->exitcode) Die();
 }
 
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
   // Currently, on Emscripten this does nothing and just calls the callback.
   // This works fine on a single-threaded environment.
   LockThreadRegistry();
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
new file mode 100644
index 0000000000000..2d35fa5b1cffd
--- /dev/null
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common_fuchsia.cpp
@@ -0,0 +1,165 @@
+//=-- lsan_common_fuchsia.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality. Fuchsia-specific code.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
+#include <zircon/sanitizer.h>
+
+#include "lsan_allocator.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+
+// Ensure that the Zircon system ABI is linked in.
+#pragma comment(lib, "zircon")
+
+namespace __lsan {
+
+void InitializePlatformSpecificModules() {}
+
+LoadedModule *GetLinker() { return nullptr; }
+
+__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+  if (disable_counter == 0) {
+    DisableCounterUnderflow();
+  }
+  disable_counter--;
+}
+
+// There is nothing left to do after the globals callbacks.
+void ProcessGlobalRegions(Frontier *frontier) {}
+
+// Nothing to do here.
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
+
+// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
+// code if required at that point.  Calling Die() here is undefined
+// behavior and causes rare race conditions.
+void HandleLeaks() {}
+
+int ExitHook(int status) {
+  return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
+}
+
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
+  LockThreadRegistry();
+  LockAllocator();
+
+  struct Params {
+    InternalMmapVector<uptr> allocator_caches;
+    StopTheWorldCallback callback;
+    CheckForLeaksParam *argument;
+  } params = {{}, callback, argument};
+
+  // Callback from libc for globals (data/bss modulo relro), when enabled.
+  auto globals = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanGlobalRange(begin, end, &params->argument->frontier);
+  };
+
+  // Callback from libc for thread stacks.
+  auto stacks = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",
+                         kReachable);
+  };
+
+  // Callback from libc for thread registers.
+  auto registers = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->argument->frontier, "REGISTERS",
+                         kReachable);
+  };
+
+  if (flags()->use_tls) {
+    // Collect the allocator cache range from each thread so these
+    // can all be excluded from the reported TLS ranges.
+    GetAllThreadAllocatorCachesLocked(&params.allocator_caches);
+    __sanitizer::Sort(params.allocator_caches.data(),
+                      params.allocator_caches.size());
+  }
+
+  // Callback from libc for TLS regions.  This includes thread_local
+  // variables as well as C11 tss_set and POSIX pthread_setspecific.
+  auto tls = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
+    if (i < params->allocator_caches.size() &&
+        params->allocator_caches[i] >= begin &&
+        end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
+      // Split the range in two and omit the allocator cache within.
+      ScanRangeForPointers(begin, params->allocator_caches[i],
+                           &params->argument->frontier, "TLS", kReachable);
+      uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
+      ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",
+                           kReachable);
+    } else {
+      ScanRangeForPointers(begin, end, &params->argument->frontier, "TLS",
+                           kReachable);
+    }
+  };
+
+  // This stops the world and then makes callbacks for various memory regions.
+  // The final callback is the last thing before the world starts up again.
+  __sanitizer_memory_snapshot(
+      flags()->use_globals ? globals : nullptr,
+      flags()->use_stacks ? stacks : nullptr,
+      flags()->use_registers ? registers : nullptr,
+      flags()->use_tls ? tls : nullptr,
+      [](zx_status_t, void *data) {
+        auto params = static_cast<const Params *>(data);
+
+        // We don't use the thread registry at all for enumerating the threads
+        // and their stacks, registers, and TLS regions.  So use it separately
+        // just for the allocator cache, and to call ForEachExtraStackRange,
+        // which ASan needs.
+        if (flags()->use_stacks) {
+          GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+              [](ThreadContextBase *tctx, void *arg) {
+                ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
+                                       arg);
+              },
+              &params->argument->frontier);
+        }
+
+        params->callback(SuspendedThreadsListFuchsia(), params->argument);
+      },
+      &params);
+
+  UnlockAllocator();
+  UnlockThreadRegistry();
+}
+
+}  // namespace __lsan
+
+// This is declared (in extern "C") by <zircon/sanitizer.h>.
+// _Exit calls this directly to intercept and change the status value.
+int __sanitizer_process_exit_hook(int status) {
+  return __lsan::ExitHook(status);
+}
+
+#endif
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp
index a9693e02edd1c..896f0479cb0a8 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common_linux.cpp
@@ -93,6 +93,11 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
   return 0;
 }
 
+#if SANITIZER_ANDROID && __ANDROID_API__ < 21
+extern "C" __attribute__((weak)) int dl_iterate_phdr(
+    int (*)(struct dl_phdr_info *, size_t, void *), void *);
+#endif
+
 // Scans global variables for heap pointers.
 void ProcessGlobalRegions(Frontier *frontier) {
   if (!flags()->use_globals) return;
@@ -134,7 +139,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
 // while holding the libdl lock in the parent thread, we can safely reenter it
 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
 // callback in the parent thread.
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
   DoStopTheWorldParam param = {callback, argument};
   dl_iterate_phdr(LockStuffAndStopTheWorldCallback, &param);
 }
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp b/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp
index c1804e93c11db..8516a176eb467 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_common_mac.cpp
@@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {
 // causes rare race conditions.
 void HandleLeaks() {}
 
-void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
   LockThreadRegistry();
   LockAllocator();
   StopTheWorld(callback, argument);
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp
new file mode 100644
index 0000000000000..40e65c6fb7293
--- /dev/null
+++ b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.cpp
@@ -0,0 +1,123 @@
+//=-- lsan_fuchsia.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code specific to Fuchsia.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_FUCHSIA
+#include <zircon/sanitizer.h>
+
+#include "lsan.h"
+#include "lsan_allocator.h"
+
+using namespace __lsan;
+
+namespace __lsan {
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {}
+
+ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
+
+struct OnCreatedArgs {
+  uptr stack_begin, stack_end;
+};
+
+// On Fuchsia, the stack bounds of a new thread are available before
+// the thread itself has started running.
+void ThreadContext::OnCreated(void *arg) {
+  // Stack bounds passed through from __sanitizer_before_thread_create_hook
+  // or InitializeMainThread.
+  auto args = reinterpret_cast<const OnCreatedArgs *>(arg);
+  stack_begin_ = args->stack_begin;
+  stack_end_ = args->stack_end;
+}
+
+struct OnStartedArgs {
+  uptr cache_begin, cache_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+  auto args = reinterpret_cast<const OnStartedArgs *>(arg);
+  cache_begin_ = args->cache_begin;
+  cache_end_ = args->cache_end;
+}
+
+void ThreadStart(u32 tid) {
+  OnStartedArgs args;
+  GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+  CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache));
+  ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args);
+}
+
+void InitializeMainThread() {
+  OnCreatedArgs args;
+  __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end,
+                                          &args.stack_begin);
+  u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args);
+  CHECK_EQ(tid, 0);
+  ThreadStart(tid);
+}
+
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
+  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *arg) {
+        auto ctx = static_cast<ThreadContext *>(tctx);
+        static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
+      },
+      caches);
+}
+
+}  // namespace __lsan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// The system runtime will call our definitions directly.
+
+// This is called before each thread creation is attempted.  So, in
+// its first call, the calling thread is the initial and sole thread.
+void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
+                                            const char *name, void *stack_base,
+                                            size_t stack_size) {
+  uptr user_id = reinterpret_cast<uptr>(thread);
+  ENSURE_LSAN_INITED;
+  EnsureMainThreadIDIsCorrect();
+  OnCreatedArgs args;
+  args.stack_begin = reinterpret_cast<uptr>(stack_base);
+  args.stack_end = args.stack_begin + stack_size;
+  u32 parent_tid = GetCurrentThread();
+  u32 tid = ThreadCreate(parent_tid, user_id, detached, &args);
+  return reinterpret_cast<void *>(static_cast<uptr>(tid));
+}
+
+// This is called after creating a new thread (in the creating thread),
+// with the pointer returned by __sanitizer_before_thread_create_hook (above).
+void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
+  u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
+  // On success, there is nothing to do here.
+  if (error != thrd_success) {
+    // Clean up the thread registry for the thread creation that didn't happen.
+    GetThreadRegistryLocked()->FinishThread(tid);
+  }
+}
+
+// This is called in the newly-created thread before it runs anything else,
+// with the pointer returned by __sanitizer_before_thread_create_hook (above).
+void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
+  u32 tid = static_cast<u32>(reinterpret_cast<uptr>(hook));
+  ThreadStart(tid);
+}
+
+// Each thread runs this just before it exits,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// All per-thread destructors have already been called.
+void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); }
+
+#endif  // SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h
new file mode 100644
index 0000000000000..e730d8f25f21e
--- /dev/null
+++ b/system/lib/compiler-rt/lib/lsan/lsan_fuchsia.h
@@ -0,0 +1,35 @@
+//=-- lsan_fuchsia.h ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code specific to Fuchsia.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_FUCHSIA_H
+#define LSAN_FUCHSIA_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_FUCHSIA
+#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)"
+#endif
+
+namespace __lsan {
+
+class ThreadContext final : public ThreadContextLsanBase {
+ public:
+  explicit ThreadContext(int tid);
+  void OnCreated(void *arg) override;
+  void OnStarted(void *arg) override;
+};
+
+}  // namespace __lsan
+
+#endif  // LSAN_FUCHSIA_H
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp
index b27f324bc558f..e90bcb50d0f3a 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -22,7 +22,9 @@
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#if SANITIZER_POSIX
 #include "sanitizer_common/sanitizer_posix.h"
+#endif
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 #include "lsan.h"
 #include "lsan_allocator.h"
@@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) {
 }
 
 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+  // This hack is not required for Fuchsia because there are no dlsym calls
+  // involved in setting up interceptors.
+#if !SANITIZER_FUCHSIA
   if (lsan_init_is_running) {
     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
     const uptr kCallocPoolSize = 1024;
@@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
     CHECK(allocated < kCallocPoolSize);
     return mem;
   }
+#endif  // !SANITIZER_FUCHSIA
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
   return lsan_calloc(nmemb, size, stack);
@@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
   GET_STACK_TRACE_MALLOC;
   return lsan_valloc(size, stack);
 }
-#endif
+#endif  // !SANITIZER_MAC
 
 #if SANITIZER_INTERCEPT_MEMALIGN
 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
@@ -109,7 +115,11 @@ INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
   return lsan_memalign(alignment, size, stack);
 }
 #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define LSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif  // SANITIZER_INTERCEPT_MEMALIGN
 
+#if SANITIZER_INTERCEPT___LIBC_MEMALIGN
 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
@@ -119,9 +129,8 @@ INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
 }
 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
 #else
-#define LSAN_MAYBE_INTERCEPT_MEMALIGN
 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
-#endif // SANITIZER_INTERCEPT_MEMALIGN
+#endif  // SANITIZER_INTERCEPT___LIBC_MEMALIGN
 
 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
 INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
@@ -307,7 +316,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
 
 ///// Thread initialization and finalization. /////
 
-#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
+#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
 static unsigned g_thread_finalize_key;
 
 static void thread_finalize(void *v) {
@@ -389,6 +398,7 @@ extern "C" {
   int emscripten_builtin_pthread_create(void *thread, void *attr,
                                         void *(*callback)(void *), void *arg);
   int emscripten_builtin_pthread_join(void *th, void **ret);
+  int emscripten_builtin_pthread_detach(void *th);
   void *emscripten_builtin_malloc(size_t size);
   void emscripten_builtin_free(void *);
 }
@@ -404,6 +414,8 @@ INTERCEPTOR(char *, strerror, int errnum) {
 #define LSAN_MAYBE_INTERCEPT_STRERROR
 #endif
 
+#if SANITIZER_POSIX
+
 struct ThreadParam {
   void *(*callback)(void *arg);
   void *param;
@@ -426,7 +438,6 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
   int tid = 0;
   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
     internal_sched_yield();
-  SetCurrentThread(tid);
   ThreadStart(tid, GetTid());
 #if SANITIZER_EMSCRIPTEN
   emscripten_builtin_free(p);
@@ -498,27 +509,30 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) {
   return res;
 }
 
+INTERCEPTOR(int, pthread_detach, void *th) {
+  ENSURE_LSAN_INITED;
+  int tid = ThreadTid((uptr)th);
+  int res = REAL(pthread_detach)(th);
+  if (res == 0)
+    ThreadDetach(tid);
+  return res;
+}
+
 #if !SANITIZER_EMSCRIPTEN
 INTERCEPTOR(void, _exit, int status) {
   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
   REAL(_exit)(status);
 }
-#endif
-
-#if SANITIZER_EMSCRIPTEN
-namespace __lsan {
 
-void InitializeInterceptors() {}
-
-} // namespace __lsan
-
-#else
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
+#endif
 
 namespace __lsan {
 
 void InitializeInterceptors() {
+  // Fuchsia doesn't use interceptors that require any setup.
+#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN
   InitializeSignalInterceptors();
 
   INTERCEPT_FUNCTION(malloc);
@@ -536,6 +550,7 @@ void InitializeInterceptors() {
   LSAN_MAYBE_INTERCEPT_MALLINFO;
   LSAN_MAYBE_INTERCEPT_MALLOPT;
   INTERCEPT_FUNCTION(pthread_create);
+  INTERCEPT_FUNCTION(pthread_detach);
   INTERCEPT_FUNCTION(pthread_join);
   INTERCEPT_FUNCTION(_exit);
 
@@ -554,6 +569,8 @@ void InitializeInterceptors() {
     Die();
   }
 #endif
+
+#endif  // !SANITIZER_FUCHSIA
 }
 
 } // namespace __lsan
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp b/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp
index 691ce42313687..63ae2c1a945b8 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_linux.cpp
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is a part of LeakSanitizer. Linux/NetBSD-specific code.
+// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code.
 //
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common/sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN
+#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
 
 #include "lsan_allocator.h"
 
@@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {}
 
 } // namespace __lsan
 
-#endif // SANITIZER_LINUX
+#endif  // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp
new file mode 100644
index 0000000000000..8e05915dd1b99
--- /dev/null
+++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.cpp
@@ -0,0 +1,96 @@
+//=-- lsan_posix.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to POSIX-like systems.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_POSIX
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __lsan {
+
+ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
+
+struct OnStartedArgs {
+  uptr stack_begin;
+  uptr stack_end;
+  uptr cache_begin;
+  uptr cache_end;
+  uptr tls_begin;
+  uptr tls_end;
+  DTLS *dtls;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+  auto args = reinterpret_cast<const OnStartedArgs *>(arg);
+  stack_begin_ = args->stack_begin;
+  stack_end_ = args->stack_end;
+  tls_begin_ = args->tls_begin;
+  tls_end_ = args->tls_end;
+  cache_begin_ = args->cache_begin;
+  cache_end_ = args->cache_end;
+  dtls_ = args->dtls;
+}
+
+void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
+  OnStartedArgs args;
+  uptr stack_size = 0;
+  uptr tls_size = 0;
+  GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+                       &args.tls_begin, &tls_size);
+  args.stack_end = args.stack_begin + stack_size;
+  args.tls_end = args.tls_begin + tls_size;
+  GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+  args.dtls = DTLS_Get();
+  ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
+}
+
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+                           uptr *cache_end, DTLS **dtls) {
+  ThreadContext *context = static_cast<ThreadContext *>(
+      GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
+  if (!context)
+    return false;
+  *stack_begin = context->stack_begin();
+  *stack_end = context->stack_end();
+  *tls_begin = context->tls_begin();
+  *tls_end = context->tls_end();
+  *cache_begin = context->cache_begin();
+  *cache_end = context->cache_end();
+  *dtls = context->dtls();
+  return true;
+}
+
+void InitializeMainThread() {
+  u32 tid = ThreadCreate(0, 0, true);
+  CHECK_EQ(tid, 0);
+  ThreadStart(tid, GetTid());
+}
+
+static void OnStackUnwind(const SignalContext &sig, const void *,
+                          BufferedStackTrace *stack) {
+  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
+}
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+                     nullptr);
+}
+
+}  // namespace __lsan
+
+#endif  // SANITIZER_POSIX
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_posix.h b/system/lib/compiler-rt/lib/lsan/lsan_posix.h
new file mode 100644
index 0000000000000..b1265f233f363
--- /dev/null
+++ b/system/lib/compiler-rt/lib/lsan/lsan_posix.h
@@ -0,0 +1,49 @@
+//=-- lsan_posix.h -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to POSIX-like systems.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_POSIX_H
+#define LSAN_POSIX_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_POSIX
+#error "lsan_posix.h is used only on POSIX-like systems (SANITIZER_POSIX)"
+#endif
+
+namespace __sanitizer {
+struct DTLS;
+}
+
+namespace __lsan {
+
+class ThreadContext final : public ThreadContextLsanBase {
+ public:
+  explicit ThreadContext(int tid);
+  void OnStarted(void *arg) override;
+  uptr tls_begin() { return tls_begin_; }
+  uptr tls_end() { return tls_end_; }
+  DTLS *dtls() { return dtls_; }
+
+ private:
+  uptr tls_begin_ = 0;
+  uptr tls_end_ = 0;
+  DTLS *dtls_ = nullptr;
+};
+
+void ThreadStart(u32 tid, tid_t os_id,
+                 ThreadType thread_type = ThreadType::Regular);
+
+}  // namespace __lsan
+
+#endif  // LSAN_POSIX_H
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp
index 84e7ce61b9756..371a1f29dfe0b 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp
+++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.cpp
@@ -13,12 +13,13 @@
 
 #include "lsan_thread.h"
 
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
-#include "lsan_allocator.h"
-#include "lsan_common.h"
 
 namespace __lsan {
 
@@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry;
 
 static ThreadContextBase *CreateThreadContext(u32 tid) {
   void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
-  return new(mem) ThreadContext(tid);
+  return new (mem) ThreadContext(tid);
 }
 
 static const uptr kMaxThreads = 1 << 13;
@@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64;
 
 void InitializeThreadRegistry() {
   static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)];
-  thread_registry = new(thread_registry_placeholder)
-    ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+  thread_registry = new (thread_registry_placeholder)
+      ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
 }
 
-ThreadContext::ThreadContext(int tid)
-    : ThreadContextBase(tid),
-      stack_begin_(0),
-      stack_end_(0),
-      cache_begin_(0),
-      cache_end_(0),
-      tls_begin_(0),
-      tls_end_(0),
-      dtls_(nullptr) {}
-
-struct OnStartedArgs {
-  uptr stack_begin, stack_end,
-       cache_begin, cache_end,
-       tls_begin, tls_end;
-  DTLS *dtls;
-};
-
-void ThreadContext::OnStarted(void *arg) {
-  OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
-  stack_begin_ = args->stack_begin;
-  stack_end_ = args->stack_end;
-  tls_begin_ = args->tls_begin;
-  tls_end_ = args->tls_end;
-  cache_begin_ = args->cache_begin;
-  cache_end_ = args->cache_end;
-  dtls_ = args->dtls;
-}
+ThreadContextLsanBase::ThreadContextLsanBase(int tid)
+    : ThreadContextBase(tid) {}
 
-void ThreadContext::OnFinished() {
+void ThreadContextLsanBase::OnFinished() {
   AllocatorThreadFinish();
   DTLS_Destroy();
 }
 
-u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
-  return thread_registry->CreateThread(user_id, detached, parent_tid,
-                                       /* arg */ nullptr);
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) {
+  return thread_registry->CreateThread(user_id, detached, parent_tid, arg);
 }
 
-void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
-  OnStartedArgs args;
-  uptr stack_size = 0;
-  uptr tls_size = 0;
-  GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
-                       &args.tls_begin, &tls_size);
-  args.stack_end = args.stack_begin + stack_size;
-  args.tls_end = args.tls_begin + tls_size;
-  GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
-  args.dtls = DTLS_Get();
-  thread_registry->StartThread(tid, os_id, thread_type, &args);
+void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id,
+                                        ThreadType thread_type, void *arg) {
+  thread_registry->StartThread(tid, os_id, thread_type, arg);
+  SetCurrentThread(tid);
 }
 
 void ThreadFinish() {
@@ -95,7 +63,8 @@ void ThreadFinish() {
 }
 
 ThreadContext *CurrentThreadContext() {
-  if (!thread_registry) return nullptr;
+  if (!thread_registry)
+    return nullptr;
   if (GetCurrentThread() == kInvalidTid)
     return nullptr;
   // No lock needed when getting current thread.
@@ -111,12 +80,17 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
 }
 
 u32 ThreadTid(uptr uid) {
-  return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+  return thread_registry->FindThread(FindThreadByUid, (void *)uid);
+}
+
+void ThreadDetach(u32 tid) {
+  CHECK_NE(tid, kInvalidTid);
+  thread_registry->DetachThread(tid, /* arg */ nullptr);
 }
 
 void ThreadJoin(u32 tid) {
   CHECK_NE(tid, kInvalidTid);
-  thread_registry->JoinThread(tid, /* arg */nullptr);
+  thread_registry->JoinThread(tid, /* arg */ nullptr);
 }
 
 void EnsureMainThreadIDIsCorrect() {
@@ -126,37 +100,16 @@ void EnsureMainThreadIDIsCorrect() {
 
 ///// Interface to the common LSan module. /////
 
-bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
-                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
-                           uptr *cache_end, DTLS **dtls) {
-  ThreadContext *context = static_cast<ThreadContext *>(
-      thread_registry->FindThreadContextByOsIDLocked(os_id));
-  if (!context) return false;
-  *stack_begin = context->stack_begin();
-  *stack_end = context->stack_end();
-  *tls_begin = context->tls_begin();
-  *tls_end = context->tls_end();
-  *cache_begin = context->cache_begin();
-  *cache_end = context->cache_end();
-  *dtls = context->dtls();
-  return true;
-}
-
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
-                            void *arg) {
-}
+                            void *arg) {}
 
-void LockThreadRegistry() {
-  thread_registry->Lock();
-}
+void LockThreadRegistry() { thread_registry->Lock(); }
 
-void UnlockThreadRegistry() {
-  thread_registry->Unlock();
-}
+void UnlockThreadRegistry() { thread_registry->Unlock(); }
 
 ThreadRegistry *GetThreadRegistryLocked() {
   thread_registry->CheckLocked();
   return thread_registry;
 }
 
-} // namespace __lsan
+}  // namespace __lsan
diff --git a/system/lib/compiler-rt/lib/lsan/lsan_thread.h b/system/lib/compiler-rt/lib/lsan/lsan_thread.h
index b869d066d9d8b..36643753d0190 100644
--- a/system/lib/compiler-rt/lib/lsan/lsan_thread.h
+++ b/system/lib/compiler-rt/lib/lsan/lsan_thread.h
@@ -16,38 +16,38 @@
 
 #include "sanitizer_common/sanitizer_thread_registry.h"
 
-namespace __sanitizer {
-struct DTLS;
-}
-
 namespace __lsan {
 
-class ThreadContext : public ThreadContextBase {
+class ThreadContextLsanBase : public ThreadContextBase {
  public:
-  explicit ThreadContext(int tid);
-  void OnStarted(void *arg) override;
+  explicit ThreadContextLsanBase(int tid);
   void OnFinished() override;
   uptr stack_begin() { return stack_begin_; }
   uptr stack_end() { return stack_end_; }
-  uptr tls_begin() { return tls_begin_; }
-  uptr tls_end() { return tls_end_; }
   uptr cache_begin() { return cache_begin_; }
   uptr cache_end() { return cache_end_; }
-  DTLS *dtls() { return dtls_; }
 
- private:
-  uptr stack_begin_, stack_end_,
-       cache_begin_, cache_end_,
-       tls_begin_, tls_end_;
-  DTLS *dtls_;
+  // The argument is passed on to the subclass's OnStarted member function.
+  static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type,
+                          void *onstarted_arg);
+
+ protected:
+  ~ThreadContextLsanBase() {}
+  uptr stack_begin_ = 0;
+  uptr stack_end_ = 0;
+  uptr cache_begin_ = 0;
+  uptr cache_end_ = 0;
 };
 
+// This subclass of ThreadContextLsanBase is declared in an OS-specific header.
+class ThreadContext;
+
 void InitializeThreadRegistry();
+void InitializeMainThread();
 
-void ThreadStart(u32 tid, tid_t os_id,
-                 ThreadType thread_type = ThreadType::Regular);
+u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr);
 void ThreadFinish();
-u32 ThreadCreate(u32 tid, uptr uid, bool detached);
+void ThreadDetach(u32 tid);
 void ThreadJoin(u32 tid);
 u32 ThreadTid(uptr uid);
 
@@ -55,6 +55,7 @@ u32 GetCurrentThread();
 void SetCurrentThread(u32 tid);
 ThreadContext *CurrentThreadContext();
 void EnsureMainThreadIDIsCorrect();
+
 }  // namespace __lsan
 
 #endif  // LSAN_THREAD_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy b/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy
deleted file mode 100644
index 6c71abff0d382..0000000000000
--- a/system/lib/compiler-rt/lib/sanitizer_common/.clang-tidy
+++ /dev/null
@@ -1,16 +0,0 @@
-Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,readability-identifier-naming'
-CheckOptions:
-  - key:             readability-identifier-naming.ClassCase
-    value:           CamelCase
-  - key:             readability-identifier-naming.EnumCase
-    value:           CamelCase
-  - key:             readability-identifier-naming.FunctionCase
-    value:           CamelCase
-  - key:             readability-identifier-naming.UnionCase
-    value:           CamelCase
-  - key:             readability-identifier-naming.GlobalConstantCase
-    value:           CamelCase
-  - key:             readability-identifier-naming.GlobalConstantPrefix
-    value:           "k"
-  - key:             readability-identifier-naming.VariableCase
-    value:           lower_case
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp
index 906d4af7f5eed..3157b35ffaf80 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp
@@ -25,7 +25,7 @@ const char *PrimaryAllocatorName = "SizeClassAllocator";
 const char *SecondaryAllocatorName = "LargeMmapAllocator";
 
 // ThreadSanitizer for Go uses libc malloc/free.
-#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
+#if defined(SANITIZER_USE_MALLOC)
 # if SANITIZER_LINUX && !SANITIZER_ANDROID
 extern "C" void *__libc_malloc(uptr size);
 #  if !SANITIZER_GO
@@ -137,8 +137,14 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
 
 #endif  // SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
 
+namespace {
 const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
 
+struct BlockHeader {
+  u64 magic;
+};
+}  // namespace
+
 static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
   SetAllocatorOutOfMemory();
   Report("FATAL: %s: internal allocator is out of memory trying to allocate "
@@ -147,27 +153,28 @@ static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
 }
 
 void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
-  if (size + sizeof(u64) < size)
+  uptr s = size + sizeof(BlockHeader);
+  if (s < size)
     return nullptr;
-  void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment);
+  BlockHeader *p = (BlockHeader *)RawInternalAlloc(s, cache, alignment);
   if (UNLIKELY(!p))
-    ReportInternalAllocatorOutOfMemory(size + sizeof(u64));
-  ((u64*)p)[0] = kBlockMagic;
-  return (char*)p + sizeof(u64);
+    ReportInternalAllocatorOutOfMemory(s);
+  p->magic = kBlockMagic;
+  return p + 1;
 }
 
 void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
   if (!addr)
     return InternalAlloc(size, cache);
-  if (size + sizeof(u64) < size)
+  uptr s = size + sizeof(BlockHeader);
+  if (s < size)
     return nullptr;
-  addr = (char*)addr - sizeof(u64);
-  size = size + sizeof(u64);
-  CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
-  void *p = RawInternalRealloc(addr, size, cache);
+  BlockHeader *p = (BlockHeader *)addr - 1;
+  CHECK_EQ(kBlockMagic, p->magic);
+  p = (BlockHeader *)RawInternalRealloc(p, s, cache);
   if (UNLIKELY(!p))
-    ReportInternalAllocatorOutOfMemory(size);
-  return (char*)p + sizeof(u64);
+    ReportInternalAllocatorOutOfMemory(s);
+  return p + 1;
 }
 
 void *InternalReallocArray(void *addr, uptr count, uptr size,
@@ -198,10 +205,10 @@ void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
 void InternalFree(void *addr, InternalAllocatorCache *cache) {
   if (!addr)
     return;
-  addr = (char*)addr - sizeof(u64);
-  CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
-  ((u64*)addr)[0] = 0;
-  RawInternalFree(addr, cache);
+  BlockHeader *p = (BlockHeader *)addr - 1;
+  CHECK_EQ(kBlockMagic, p->magic);
+  p->magic = 0;
+  RawInternalFree(p, cache);
 }
 
 // LowLevelAllocator
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
index 23d589888d3b6..5ec47416fe0c9 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h
@@ -52,14 +52,14 @@ struct NoOpMapUnmapCallback {
 // Callback type for iterating over chunks.
 typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
 
-INLINE u32 Rand(u32 *state) {  // ANSI C linear congruential PRNG.
+inline u32 Rand(u32 *state) {  // ANSI C linear congruential PRNG.
   return (*state = *state * 1103515245 + 12345) >> 16;
 }
 
-INLINE u32 RandN(u32 *state, u32 n) { return Rand(state) % n; }  // [0, n)
+inline u32 RandN(u32 *state, u32 n) { return Rand(state) % n; }  // [0, n)
 
 template<typename T>
-INLINE void RandomShuffle(T *a, u32 n, u32 *rand_state) {
+inline void RandomShuffle(T *a, u32 n, u32 *rand_state) {
   if (n <= 1) return;
   u32 state = *rand_state;
   for (u32 i = n - 1; i > 0; i--)
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h
index fc426f0e74f48..1cc3992c4c9fa 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_checks.h
@@ -27,7 +27,7 @@ namespace __sanitizer {
 void SetErrnoToENOMEM();
 
 // A common errno setting logic shared by almost all sanitizer allocator APIs.
-INLINE void *SetErrnoOnNull(void *ptr) {
+inline void *SetErrnoOnNull(void *ptr) {
   if (UNLIKELY(!ptr))
     SetErrnoToENOMEM();
   return ptr;
@@ -41,7 +41,7 @@ INLINE void *SetErrnoOnNull(void *ptr) {
 // two and that the size is a multiple of alignment for POSIX implementation,
 // and a bit relaxed requirement for non-POSIX ones, that the size is a multiple
 // of alignment.
-INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) {
+inline bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) {
 #if SANITIZER_POSIX
   return alignment != 0 && IsPowerOfTwo(alignment) &&
          (size & (alignment - 1)) == 0;
@@ -52,13 +52,13 @@ INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) {
 
 // Checks posix_memalign() parameters, verifies that alignment is a power of two
 // and a multiple of sizeof(void *).
-INLINE bool CheckPosixMemalignAlignment(uptr alignment) {
+inline bool CheckPosixMemalignAlignment(uptr alignment) {
   return alignment != 0 && IsPowerOfTwo(alignment) &&
          (alignment % sizeof(void *)) == 0;
 }
 
 // Returns true if calloc(size, n) call overflows on size*n calculation.
-INLINE bool CheckForCallocOverflow(uptr size, uptr n) {
+inline bool CheckForCallocOverflow(uptr size, uptr n) {
   if (!size)
     return false;
   uptr max = (uptr)-1L;
@@ -67,7 +67,7 @@ INLINE bool CheckForCallocOverflow(uptr size, uptr n) {
 
 // Returns true if the size passed to pvalloc overflows when rounded to the next
 // multiple of page_size.
-INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) {
+inline bool CheckForPvallocOverflow(uptr size, uptr page_size) {
   return RoundUpTo(size, page_size) < size;
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h
index 3b1838b3985ac..b90dabbf77692 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h
@@ -153,6 +153,7 @@ class SizeClassAllocator32 {
   }
 
   void *GetMetaData(const void *p) {
+    CHECK(kMetadataSize);
     CHECK(PointerIsMine(p));
     uptr mem = reinterpret_cast<uptr>(p);
     uptr beg = ComputeRegionBeg(mem);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
index 90603280e7c95..0a18b0c58ef79 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h
@@ -72,11 +72,15 @@ class SizeClassAllocator64 {
   void Init(s32 release_to_os_interval_ms) {
     uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
     if (kUsingConstantSpaceBeg) {
+      CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
       CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
                                              PrimaryAllocatorName, kSpaceBeg));
     } else {
-      NonConstSpaceBeg = address_range.Init(TotalSpaceSize,
-                                            PrimaryAllocatorName);
+      // Combined allocator expects that an 2^N allocation is always aligned to
+      // 2^N. For this to work, the start of the space needs to be aligned as
+      // high as the largest size class (which also needs to be a power of 2).
+      NonConstSpaceBeg = address_range.InitAligned(
+          TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName);
       CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
     }
     SetReleaseToOSIntervalMs(release_to_os_interval_ms);
@@ -182,13 +186,13 @@ class SizeClassAllocator64 {
 
   void *GetBlockBegin(const void *p) {
     uptr class_id = GetSizeClass(p);
+    if (class_id >= kNumClasses) return nullptr;
     uptr size = ClassIdToSize(class_id);
     if (!size) return nullptr;
     uptr chunk_idx = GetChunkIdx((uptr)p, size);
     uptr reg_beg = GetRegionBegin(p);
     uptr beg = chunk_idx * size;
     uptr next_beg = beg + size;
-    if (class_id >= kNumClasses) return nullptr;
     const RegionInfo *region = AddressSpaceView::Load(GetRegionInfo(class_id));
     if (region->mapped_user >= next_beg)
       return reinterpret_cast<void*>(reg_beg + beg);
@@ -203,6 +207,7 @@ class SizeClassAllocator64 {
   static uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
 
   void *GetMetaData(const void *p) {
+    CHECK(kMetadataSize);
     uptr class_id = GetSizeClass(p);
     uptr size = ClassIdToSize(class_id);
     uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
@@ -220,7 +225,7 @@ class SizeClassAllocator64 {
 
   // Test-only.
   void TestOnlyUnmap() {
-    UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
+    UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size());
   }
 
   static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp
index d74e08010d5de..1c6520819ef93 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cpp
@@ -134,4 +134,12 @@ void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack) {
   Die();
 }
 
+void NORETURN ReportRssLimitExceeded(const StackTrace *stack) {
+  {
+    ScopedAllocatorErrorReport report("rss-limit-exceeded", stack);
+    Report("ERROR: %s: allocator exceeded the RSS limit\n", SanitizerToolName);
+  }
+  Die();
+}
+
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h
index 0653c365c1cd4..6e4e6b1354916 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.h
@@ -33,6 +33,7 @@ void NORETURN ReportInvalidPosixMemalignAlignment(uptr alignment,
 void NORETURN ReportAllocationSizeTooBig(uptr user_size, uptr max_size,
                                          const StackTrace *stack);
 void NORETURN ReportOutOfMemory(uptr requested_size, const StackTrace *stack);
+void NORETURN ReportRssLimitExceeded(const StackTrace *stack);
 
 }  // namespace __sanitizer
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h
index 1d128f55de05a..61fb98742373a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h
@@ -18,8 +18,8 @@
 // (currently, 32 bits and internal allocator).
 class LargeMmapAllocatorPtrArrayStatic {
  public:
-  INLINE void *Init() { return &p_[0]; }
-  INLINE void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); }
+  inline void *Init() { return &p_[0]; }
+  inline void EnsureSpace(uptr n) { CHECK_LT(n, kMaxNumChunks); }
  private:
   static const int kMaxNumChunks = 1 << 15;
   uptr p_[kMaxNumChunks];
@@ -31,14 +31,14 @@ class LargeMmapAllocatorPtrArrayStatic {
 // same functionality in Fuchsia case, which does not support MAP_NORESERVE.
 class LargeMmapAllocatorPtrArrayDynamic {
  public:
-  INLINE void *Init() {
+  inline void *Init() {
     uptr p = address_range_.Init(kMaxNumChunks * sizeof(uptr),
                                  SecondaryAllocatorName);
     CHECK(p);
     return reinterpret_cast<void*>(p);
   }
 
-  INLINE void EnsureSpace(uptr n) {
+  inline void EnsureSpace(uptr n) {
     CHECK_LT(n, kMaxNumChunks);
     DCHECK(n <= n_reserved_);
     if (UNLIKELY(n == n_reserved_)) {
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
index a798a0cf25d9c..46f06957228c9 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic.h
@@ -72,12 +72,12 @@ namespace __sanitizer {
 // Clutter-reducing helpers.
 
 template<typename T>
-INLINE typename T::Type atomic_load_relaxed(const volatile T *a) {
+inline typename T::Type atomic_load_relaxed(const volatile T *a) {
   return atomic_load(a, memory_order_relaxed);
 }
 
 template<typename T>
-INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) {
+inline void atomic_store_relaxed(volatile T *a, typename T::Type v) {
   atomic_store(a, v, memory_order_relaxed);
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
index c40461ebc3bf6..fc13ca52dda74 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -34,16 +34,16 @@ namespace __sanitizer {
 // See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
 // for mappings of the memory model to different processors.
 
-INLINE void atomic_signal_fence(memory_order) {
+inline void atomic_signal_fence(memory_order) {
   __asm__ __volatile__("" ::: "memory");
 }
 
-INLINE void atomic_thread_fence(memory_order) {
+inline void atomic_thread_fence(memory_order) {
   __sync_synchronize();
 }
 
 template<typename T>
-INLINE typename T::Type atomic_fetch_add(volatile T *a,
+inline typename T::Type atomic_fetch_add(volatile T *a,
     typename T::Type v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -51,7 +51,7 @@ INLINE typename T::Type atomic_fetch_add(volatile T *a,
 }
 
 template<typename T>
-INLINE typename T::Type atomic_fetch_sub(volatile T *a,
+inline typename T::Type atomic_fetch_sub(volatile T *a,
     typename T::Type v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -59,7 +59,7 @@ INLINE typename T::Type atomic_fetch_sub(volatile T *a,
 }
 
 template<typename T>
-INLINE typename T::Type atomic_exchange(volatile T *a,
+inline typename T::Type atomic_exchange(volatile T *a,
     typename T::Type v, memory_order mo) {
   DCHECK(!((uptr)a % sizeof(*a)));
   if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
@@ -71,7 +71,7 @@ INLINE typename T::Type atomic_exchange(volatile T *a,
 }
 
 template <typename T>
-INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
+inline bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
                                            typename T::Type xchg,
                                            memory_order mo) {
   typedef typename T::Type Type;
@@ -84,7 +84,7 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
 }
 
 template<typename T>
-INLINE bool atomic_compare_exchange_weak(volatile T *a,
+inline bool atomic_compare_exchange_weak(volatile T *a,
                                          typename T::Type *cmp,
                                          typename T::Type xchg,
                                          memory_order mo) {
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h
index d369aeb9935c6..59155e9883ebe 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_mips.h
@@ -37,7 +37,7 @@ static struct {
 } __attribute__((aligned(32))) lock = {0, {0}};
 
 template <>
-INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
+inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
                                               atomic_uint64_t::Type val,
                                               memory_order mo) {
   DCHECK(mo &
@@ -55,14 +55,14 @@ INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
 }
 
 template <>
-INLINE atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr,
+inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr,
                                               atomic_uint64_t::Type val,
                                               memory_order mo) {
   return atomic_fetch_add(ptr, -val, mo);
 }
 
 template <>
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
+inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
                                            atomic_uint64_t::Type *cmp,
                                            atomic_uint64_t::Type xchg,
                                            memory_order mo) {
@@ -87,7 +87,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
 }
 
 template <>
-INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
+inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
                                          memory_order mo) {
   DCHECK(mo &
          (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
@@ -100,7 +100,7 @@ INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
 }
 
 template <>
-INLINE void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
+inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
                          memory_order mo) {
   DCHECK(mo &
          (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
index b8685a8542676..4a39889e534a0 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -17,12 +17,12 @@
 namespace __sanitizer {
 
 
-INLINE void proc_yield(int cnt) {
+inline void proc_yield(int cnt) {
   __asm__ __volatile__("" ::: "memory");
 }
 
 template<typename T>
-INLINE typename T::Type atomic_load(
+inline typename T::Type atomic_load(
     const volatile T *a, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_consume
       | memory_order_acquire | memory_order_seq_cst));
@@ -50,17 +50,14 @@ INLINE typename T::Type atomic_load(
       __sync_synchronize();
     }
   } else {
-    // 64-bit load on 32-bit platform.
-    // Gross, but simple and reliable.
-    // Assume that it is not in read-only memory.
-    v = __sync_fetch_and_add(
-        const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+    __atomic_load(const_cast<typename T::Type volatile *>(&a->val_dont_use), &v,
+                  __ATOMIC_SEQ_CST);
   }
   return v;
 }
 
 template<typename T>
-INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_release
       | memory_order_seq_cst));
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -79,16 +76,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
       __sync_synchronize();
     }
   } else {
-    // 64-bit store on 32-bit platform.
-    // Gross, but simple and reliable.
-    typename T::Type cmp = a->val_dont_use;
-    typename T::Type cur;
-    for (;;) {
-      cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
-      if (cur == cmp || cur == v)
-        break;
-      cmp = cur;
-    }
+    __atomic_store(&a->val_dont_use, &v, __ATOMIC_SEQ_CST);
   }
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
index f2ce553baa7a1..51597b4927412 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -16,7 +16,7 @@
 
 namespace __sanitizer {
 
-INLINE void proc_yield(int cnt) {
+inline void proc_yield(int cnt) {
   __asm__ __volatile__("" ::: "memory");
   for (int i = 0; i < cnt; i++)
     __asm__ __volatile__("pause");
@@ -24,7 +24,7 @@ INLINE void proc_yield(int cnt) {
 }
 
 template<typename T>
-INLINE typename T::Type atomic_load(
+inline typename T::Type atomic_load(
     const volatile T *a, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_consume
       | memory_order_acquire | memory_order_seq_cst));
@@ -70,7 +70,7 @@ INLINE typename T::Type atomic_load(
 }
 
 template<typename T>
-INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_release
       | memory_order_seq_cst));
   DCHECK(!((uptr)a % sizeof(*a)));
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
index 6a7c5465dcbbc..31317adcdfc99 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -54,21 +54,21 @@ extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend,
 
 namespace __sanitizer {
 
-INLINE void atomic_signal_fence(memory_order) {
+inline void atomic_signal_fence(memory_order) {
   _ReadWriteBarrier();
 }
 
-INLINE void atomic_thread_fence(memory_order) {
+inline void atomic_thread_fence(memory_order) {
   _mm_mfence();
 }
 
-INLINE void proc_yield(int cnt) {
+inline void proc_yield(int cnt) {
   for (int i = 0; i < cnt; i++)
     _mm_pause();
 }
 
 template<typename T>
-INLINE typename T::Type atomic_load(
+inline typename T::Type atomic_load(
     const volatile T *a, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_consume
       | memory_order_acquire | memory_order_seq_cst));
@@ -86,7 +86,7 @@ INLINE typename T::Type atomic_load(
 }
 
 template<typename T>
-INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
   DCHECK(mo & (memory_order_relaxed | memory_order_release
       | memory_order_seq_cst));
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -102,7 +102,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
     atomic_thread_fence(memory_order_seq_cst);
 }
 
-INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
+inline u32 atomic_fetch_add(volatile atomic_uint32_t *a,
     u32 v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -110,7 +110,7 @@ INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
                                       (long)v);
 }
 
-INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
+inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
     uptr v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -123,7 +123,7 @@ INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
 #endif
 }
 
-INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
+inline u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
     u32 v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -131,7 +131,7 @@ INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
                                       -(long)v);
 }
 
-INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
+inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
     uptr v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
@@ -144,28 +144,28 @@ INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
 #endif
 }
 
-INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
+inline u8 atomic_exchange(volatile atomic_uint8_t *a,
     u8 v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
   return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v);
 }
 
-INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
+inline u16 atomic_exchange(volatile atomic_uint16_t *a,
     u16 v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
   return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v);
 }
 
-INLINE u32 atomic_exchange(volatile atomic_uint32_t *a,
+inline u32 atomic_exchange(volatile atomic_uint32_t *a,
     u32 v, memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
   return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v);
 }
 
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
+inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
                                            u8 *cmp,
                                            u8 xchgv,
                                            memory_order mo) {
@@ -191,7 +191,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
   return false;
 }
 
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
+inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
                                            uptr *cmp,
                                            uptr xchg,
                                            memory_order mo) {
@@ -204,7 +204,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
   return false;
 }
 
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
+inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
                                            u16 *cmp,
                                            u16 xchg,
                                            memory_order mo) {
@@ -217,7 +217,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
   return false;
 }
 
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
+inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
                                            u32 *cmp,
                                            u32 xchg,
                                            memory_order mo) {
@@ -230,7 +230,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
   return false;
 }
 
-INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
+inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
                                            u64 *cmp,
                                            u64 xchg,
                                            memory_order mo) {
@@ -244,7 +244,7 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
 }
 
 template<typename T>
-INLINE bool atomic_compare_exchange_weak(volatile T *a,
+inline bool atomic_compare_exchange_weak(volatile T *a,
                                          typename T::Type *cmp,
                                          typename T::Type xchg,
                                          memory_order mo) {
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
index f5f9f49d8cffc..87efda5bd3721 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
@@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
   return name_len;
 }
 
+#if !SANITIZER_GO
 void PrintCmdline() {
   char **argv = GetArgv();
   if (!argv) return;
@@ -282,6 +283,7 @@ void PrintCmdline() {
     Printf("%s ", argv[i]);
   Printf("\n\n");
 }
+#endif
 
 // Malloc hooks.
 static const int kMaxMallocFreeHooks = 5;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 3b52172c483c7..a6532eee164d8 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -53,25 +53,25 @@ const u64 kExternalPCBit = 1ULL << 60;
 extern const char *SanitizerToolName;  // Can be changed by the tool.
 
 extern atomic_uint32_t current_verbosity;
-INLINE void SetVerbosity(int verbosity) {
+inline void SetVerbosity(int verbosity) {
   atomic_store(&current_verbosity, verbosity, memory_order_relaxed);
 }
-INLINE int Verbosity() {
+inline int Verbosity() {
   return atomic_load(&current_verbosity, memory_order_relaxed);
 }
 
 #if SANITIZER_ANDROID
-INLINE uptr GetPageSize() {
+inline uptr GetPageSize() {
 // Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
   return 4096;
 }
-INLINE uptr GetPageSizeCached() {
+inline uptr GetPageSizeCached() {
   return 4096;
 }
 #else
 uptr GetPageSize();
 extern uptr PageSizeCached;
-INLINE uptr GetPageSizeCached() {
+inline uptr GetPageSizeCached() {
   if (!PageSizeCached)
     PageSizeCached = GetPageSize();
   return PageSizeCached;
@@ -91,7 +91,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
 
 // Memory management
 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
-INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
+inline void *MmapOrDieQuietly(uptr size, const char *mem_type) {
   return MmapOrDie(size, mem_type, /*raw_report*/ true);
 }
 void UnmapOrDie(void *addr, uptr size);
@@ -121,6 +121,31 @@ bool MprotectReadOnly(uptr addr, uptr size);
 
 void MprotectMallocZones(void *addr, int prot);
 
+#if SANITIZER_LINUX
+// Unmap memory. Currently only used on Linux.
+void UnmapFromTo(uptr from, uptr to);
+#endif
+
+// Maps shadow_size_bytes of shadow memory and returns shadow address. It will
+// be aligned to the mmap granularity * 2^shadow_scale, or to
+// 2^min_shadow_base_alignment if that is larger. The returned address will
+// have max(2^min_shadow_base_alignment, mmap granularity) on the left, and
+// shadow_size_bytes bytes on the right, which on linux is mapped no access.
+// The high_mem_end may be updated if the original shadow size doesn't fit.
+uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
+                      uptr min_shadow_base_alignment, uptr &high_mem_end);
+
+// Reserve memory range [beg, end]. If madvise_shadow is true then apply
+// madvise (e.g. hugepages, core dumping) requested by options.
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
+                              bool madvise_shadow = true);
+
+// Protect size bytes of memory starting at addr. Also try to protect
+// several pages at the start of the address space as specified by
+// zero_base_shadow_start, at most up to the size or zero_base_max_shadow_start.
+void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start,
+                uptr zero_base_max_shadow_start);
+
 // Find an available address space.
 uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
                               uptr *largest_gap_found, uptr *max_occupied_addr);
@@ -143,6 +168,7 @@ void RunFreeHooks(const void *ptr);
 class ReservedAddressRange {
  public:
   uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0);
+  uptr InitAligned(uptr size, uptr align, const char *name = nullptr);
   uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr);
   uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr);
   void Unmap(uptr addr, uptr size);
@@ -228,7 +254,6 @@ void UpdateProcessName();
 void CacheBinaryName();
 void DisableCoreDumperIfNecessary();
 void DumpProcessMap();
-void PrintModuleMap();
 const char *GetEnv(const char *name);
 bool SetEnv(const char *name, const char *value);
 
@@ -348,7 +373,7 @@ unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);
 }
 #endif
 
-INLINE uptr MostSignificantSetBitIndex(uptr x) {
+inline uptr MostSignificantSetBitIndex(uptr x) {
   CHECK_NE(x, 0U);
   unsigned long up;
 #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
@@ -365,7 +390,7 @@ INLINE uptr MostSignificantSetBitIndex(uptr x) {
   return up;
 }
 
-INLINE uptr LeastSignificantSetBitIndex(uptr x) {
+inline uptr LeastSignificantSetBitIndex(uptr x) {
   CHECK_NE(x, 0U);
   unsigned long up;
 #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
@@ -382,11 +407,11 @@ INLINE uptr LeastSignificantSetBitIndex(uptr x) {
   return up;
 }
 
-INLINE bool IsPowerOfTwo(uptr x) {
+inline bool IsPowerOfTwo(uptr x) {
   return (x & (x - 1)) == 0;
 }
 
-INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+inline uptr RoundUpToPowerOfTwo(uptr size) {
   CHECK(size);
   if (IsPowerOfTwo(size)) return size;
 
@@ -396,20 +421,20 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) {
   return 1ULL << (up + 1);
 }
 
-INLINE uptr RoundUpTo(uptr size, uptr boundary) {
+inline uptr RoundUpTo(uptr size, uptr boundary) {
   RAW_CHECK(IsPowerOfTwo(boundary));
   return (size + boundary - 1) & ~(boundary - 1);
 }
 
-INLINE uptr RoundDownTo(uptr x, uptr boundary) {
+inline uptr RoundDownTo(uptr x, uptr boundary) {
   return x & ~(boundary - 1);
 }
 
-INLINE bool IsAligned(uptr a, uptr alignment) {
+inline bool IsAligned(uptr a, uptr alignment) {
   return (a & (alignment - 1)) == 0;
 }
 
-INLINE uptr Log2(uptr x) {
+inline uptr Log2(uptr x) {
   CHECK(IsPowerOfTwo(x));
   return LeastSignificantSetBitIndex(x);
 }
@@ -425,14 +450,14 @@ template<class T> void Swap(T& a, T& b) {
 }
 
 // Char handling
-INLINE bool IsSpace(int c) {
+inline bool IsSpace(int c) {
   return (c == ' ') || (c == '\n') || (c == '\t') ||
          (c == '\f') || (c == '\r') || (c == '\v');
 }
-INLINE bool IsDigit(int c) {
+inline bool IsDigit(int c) {
   return (c >= '0') && (c <= '9');
 }
-INLINE int ToLower(int c) {
+inline int ToLower(int c) {
   return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
 }
 
@@ -442,6 +467,7 @@ INLINE int ToLower(int c) {
 template<typename T>
 class InternalMmapVectorNoCtor {
  public:
+  using value_type = T;
   void Initialize(uptr initial_capacity) {
     capacity_bytes_ = 0;
     size_ = 0;
@@ -626,9 +652,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
 
 // Works like std::lower_bound: finds the first element that is not less
 // than the val.
-template <class Container, class Value, class Compare>
-uptr InternalLowerBound(const Container &v, uptr first, uptr last,
-                        const Value &val, Compare comp) {
+template <class Container,
+          class Compare = CompareLess<typename Container::value_type>>
+uptr InternalLowerBound(const Container &v,
+                        const typename Container::value_type &val,
+                        Compare comp = {}) {
+  uptr first = 0;
+  uptr last = v.size();
   while (last > first) {
     uptr mid = (first + last) / 2;
     if (comp(v[mid], val))
@@ -648,9 +678,31 @@ enum ModuleArch {
   kModuleArchARMV7,
   kModuleArchARMV7S,
   kModuleArchARMV7K,
-  kModuleArchARM64
+  kModuleArchARM64,
+  kModuleArchRISCV64
 };
 
+// Sorts and removes duplicates from the container.
+template <class Container,
+          class Compare = CompareLess<typename Container::value_type>>
+void SortAndDedup(Container &v, Compare comp = {}) {
+  Sort(v.data(), v.size(), comp);
+  uptr size = v.size();
+  if (size < 2)
+    return;
+  uptr last = 0;
+  for (uptr i = 1; i < size; ++i) {
+    if (comp(v[last], v[i])) {
+      ++last;
+      if (last != i)
+        v[last] = v[i];
+    } else {
+      CHECK(!comp(v[i], v[last]));
+    }
+  }
+  v.resize(last + 1);
+}
+
 // Opens the file 'file_name" and reads up to 'max_len' bytes.
 // The resulting buffer is mmaped and stored in '*buff'.
 // Returns true if file was successfully opened and read.
@@ -692,6 +744,8 @@ inline const char *ModuleArchToString(ModuleArch arch) {
       return "armv7k";
     case kModuleArchARM64:
       return "arm64";
+    case kModuleArchRISCV64:
+      return "riscv64";
   }
   CHECK(0 && "Invalid module arch");
   return "";
@@ -814,15 +868,15 @@ void WriteToSyslog(const char *buffer);
 #if SANITIZER_MAC || SANITIZER_WIN_TRACE
 void LogFullErrorReport(const char *buffer);
 #else
-INLINE void LogFullErrorReport(const char *buffer) {}
+inline void LogFullErrorReport(const char *buffer) {}
 #endif
 
 #if SANITIZER_LINUX || SANITIZER_MAC
 void WriteOneLineToSyslog(const char *s);
 void LogMessageOnPrintf(const char *str);
 #else
-INLINE void WriteOneLineToSyslog(const char *s) {}
-INLINE void LogMessageOnPrintf(const char *str) {}
+inline void WriteOneLineToSyslog(const char *s) {}
+inline void LogMessageOnPrintf(const char *str) {}
 #endif
 
 #if SANITIZER_LINUX || SANITIZER_WIN_TRACE
@@ -830,21 +884,21 @@ INLINE void LogMessageOnPrintf(const char *str) {}
 void AndroidLogInit();
 void SetAbortMessage(const char *);
 #else
-INLINE void AndroidLogInit() {}
+inline void AndroidLogInit() {}
 // FIXME: MacOS implementation could use CRSetCrashLogMessage.
-INLINE void SetAbortMessage(const char *) {}
+inline void SetAbortMessage(const char *) {}
 #endif
 
 #if SANITIZER_ANDROID
 void SanitizerInitializeUnwinder();
 AndroidApiLevel AndroidGetApiLevel();
 #else
-INLINE void AndroidLogWrite(const char *buffer_unused) {}
-INLINE void SanitizerInitializeUnwinder() {}
-INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
+inline void AndroidLogWrite(const char *buffer_unused) {}
+inline void SanitizerInitializeUnwinder() {}
+inline AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
 #endif
 
-INLINE uptr GetPthreadDestructorIterations() {
+inline uptr GetPthreadDestructorIterations() {
 #if SANITIZER_ANDROID
   return (AndroidGetApiLevel() == ANDROID_LOLLIPOP_MR1) ? 8 : 4;
 #elif SANITIZER_POSIX
@@ -855,7 +909,7 @@ INLINE uptr GetPthreadDestructorIterations() {
 #endif
 }
 
-void *internal_start_thread(void(*func)(void*), void *arg);
+void *internal_start_thread(void *(*func)(void*), void *arg);
 void internal_join_thread(void *th);
 void MaybeStartBackgroudThread();
 
@@ -950,7 +1004,7 @@ RunOnDestruction<Fn> at_scope_exit(Fn fn) {
 #if SANITIZER_LINUX && SANITIZER_S390_64
 void AvoidCVE_2016_2143();
 #else
-INLINE void AvoidCVE_2016_2143() {}
+inline void AvoidCVE_2016_2143() {}
 #endif
 
 struct StackDepotStats {
@@ -971,12 +1025,26 @@ bool GetRandom(void *buffer, uptr length, bool blocking = true);
 // Returns the number of logical processors on the system.
 u32 GetNumberOfCPUs();
 extern u32 NumberOfCPUsCached;
-INLINE u32 GetNumberOfCPUsCached() {
+inline u32 GetNumberOfCPUsCached() {
   if (!NumberOfCPUsCached)
     NumberOfCPUsCached = GetNumberOfCPUs();
   return NumberOfCPUsCached;
 }
 
+template <typename T>
+class ArrayRef {
+ public:
+  ArrayRef() {}
+  ArrayRef(T *begin, T *end) : begin_(begin), end_(end) {}
+
+  T *begin() { return begin_; }
+  T *end() { return end_; }
+
+ private:
+  T *begin_ = nullptr;
+  T *end_ = nullptr;
+};
+
 }  // namespace __sanitizer
 
 inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 2a4ab7e67a5ce..d4b9ea5f7f067 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -113,6 +113,7 @@
 #define setitimer __setitimer50
 #define setlocale __setlocale50
 #define shmctl __shmctl50
+#define sigaltstack __sigaltstack14
 #define sigemptyset __sigemptyset14
 #define sigfillset __sigfillset14
 #define sigpending __sigpending14
@@ -133,11 +134,7 @@ extern const short *_tolower_tab_;
 
 // Platform-specific options.
 #if SANITIZER_MAC
-namespace __sanitizer {
-bool PlatformHasDifferentMemcpyAndMemmove();
-}
-#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
-  (__sanitizer::PlatformHasDifferentMemcpyAndMemmove())
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
 #elif SANITIZER_WINDOWS64
 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
 #else
@@ -448,8 +445,10 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
     c2 = (unsigned char)s2[i];
     if (c1 != c2 || c1 == '\0') break;
   }
-  COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
-  COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
+  if (common_flags()->intercept_strcmp) {
+    COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
+    COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
+  }
   int result = CharCmpX(c1, c2);
   CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
                              s2, result);
@@ -1865,7 +1864,7 @@ UNUSED static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_gecos,
                                      REAL(strlen)(pwd->pw_gecos) + 1);
 #endif
-#if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD
+#if SANITIZER_MAC || SANITIZER_FREEBSD || SANITIZER_NETBSD
     if (pwd->pw_class)
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd->pw_class,
                                      REAL(strlen)(pwd->pw_class) + 1);
@@ -2202,6 +2201,24 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
 #define INIT_CLOCK_GETTIME
 #endif
 
+#if SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID
+INTERCEPTOR(int, clock_getcpuclockid, pid_t pid,
+            __sanitizer_clockid_t *clockid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, clock_getcpuclockid, pid, clockid);
+  int res = REAL(clock_getcpuclockid)(pid, clockid);
+  if (!res && clockid) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, clockid, sizeof *clockid);
+  }
+  return res;
+}
+
+#define INIT_CLOCK_GETCPUCLOCKID                  \
+  COMMON_INTERCEPT_FUNCTION(clock_getcpuclockid);
+#else
+#define INIT_CLOCK_GETCPUCLOCKID
+#endif
+
 #if SANITIZER_INTERCEPT_GETITIMER
 INTERCEPTOR(int, getitimer, int which, void *curr_value) {
   void *ctx;
@@ -3095,6 +3112,34 @@ INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec,
 #define INIT_SENDMMSG
 #endif
 
+#if SANITIZER_INTERCEPT_SYSMSG
+INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz,
+            int msgflg) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg);
+  if (msgp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz);
+  int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg);
+  return res;
+}
+
+INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz,
+            long msgtyp, int msgflg) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg);
+  SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg);
+  if (len != -1)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len);
+  return len;
+}
+
+#define INIT_SYSMSG                  \
+  COMMON_INTERCEPT_FUNCTION(msgsnd); \
+  COMMON_INTERCEPT_FUNCTION(msgrcv);
+#else
+#define INIT_SYSMSG
+#endif
+
 #if SANITIZER_INTERCEPT_GETPEERNAME
 INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
   void *ctx;
@@ -3705,7 +3750,7 @@ INTERCEPTOR(char *, strerror, int errnum) {
 //    static storage.
 #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \
     SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD ||                 \
-    SANITIZER_FREEBSD || SANITIZER_OPENBSD
+    SANITIZER_FREEBSD
 // POSIX version. Spec is not clear on whether buf is NULL-terminated.
 // At least on OSX, buf contents are valid even when the call fails.
 INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) {
@@ -4042,6 +4087,41 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
 #define INIT_SIGSETOPS
 #endif
 
+#if SANITIZER_INTERCEPT_SIGSET_LOGICOPS
+INTERCEPTOR(int, sigandset, __sanitizer_sigset_t *dst,
+            __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigandset, dst, src1, src2);
+  if (src1)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1));
+  if (src2)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2));
+  int res = REAL(sigandset)(dst, src1, src2);
+  if (!res && dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+  return res;
+}
+
+INTERCEPTOR(int, sigorset, __sanitizer_sigset_t *dst,
+            __sanitizer_sigset_t *src1, __sanitizer_sigset_t *src2) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigorset, dst, src1, src2);
+  if (src1)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src1, sizeof(*src1));
+  if (src2)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src2, sizeof(*src2));
+  int res = REAL(sigorset)(dst, src1, src2);
+  if (!res && dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+  return res;
+}
+#define INIT_SIGSET_LOGICOPS                    \
+  COMMON_INTERCEPT_FUNCTION(sigandset);   \
+  COMMON_INTERCEPT_FUNCTION(sigorset);
+#else
+#define INIT_SIGSET_LOGICOPS
+#endif
+
 #if SANITIZER_INTERCEPT_SIGPENDING
 INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
   void *ctx;
@@ -4795,6 +4875,34 @@ INTERCEPTOR(char *, tmpnam_r, char *s) {
 #define INIT_TMPNAM_R
 #endif
 
+#if SANITIZER_INTERCEPT_PTSNAME
+INTERCEPTOR(char *, ptsname, int fd) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ptsname, fd);
+  char *res = REAL(ptsname)(fd);
+  if (res != nullptr)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT_PTSNAME COMMON_INTERCEPT_FUNCTION(ptsname);
+#else
+#define INIT_PTSNAME
+#endif
+
+#if SANITIZER_INTERCEPT_PTSNAME_R
+INTERCEPTOR(int, ptsname_r, int fd, char *name, SIZE_T namesize) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ptsname_r, fd, name, namesize);
+  int res = REAL(ptsname_r)(fd, name, namesize);
+  if (res == 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  return res;
+}
+#define INIT_PTSNAME_R COMMON_INTERCEPT_FUNCTION(ptsname_r);
+#else
+#define INIT_PTSNAME_R
+#endif
+
 #if SANITIZER_INTERCEPT_TTYNAME
 INTERCEPTOR(char *, ttyname, int fd) {
   void *ctx;
@@ -5766,6 +5874,79 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
 #define INIT_XDR
 #endif  // SANITIZER_INTERCEPT_XDR
 
+#if SANITIZER_INTERCEPT_XDRREC
+typedef int (*xdrrec_cb)(char*, char*, int);
+struct XdrRecWrapper {
+  char *handle;
+  xdrrec_cb rd, wr;
+};
+typedef AddrHashMap<XdrRecWrapper *, 11> XdrRecWrapMap;
+static XdrRecWrapMap *xdrrec_wrap_map;
+
+static int xdrrec_wr_wrap(char *handle, char *buf, int count) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count);
+  XdrRecWrapper *wrap = (XdrRecWrapper *)handle;
+  return wrap->wr(wrap->handle, buf, count);
+}
+
+static int xdrrec_rd_wrap(char *handle, char *buf, int count) {
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
+  XdrRecWrapper *wrap = (XdrRecWrapper *)handle;
+  return wrap->rd(wrap->handle, buf, count);
+}
+
+// This doesn't apply to the solaris version as it has a different function
+// signature.
+INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize,
+            unsigned rcvsize, char *handle, int (*rd)(char*, char*, int),
+            int (*wr)(char*, char*, int)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize,
+                           handle, rd, wr);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op);
+
+  // We can't allocate a wrapper on the stack, as the handle is used outside
+  // this stack frame. So we put it on the heap, and keep track of it with
+  // the HashMap (keyed by x_private). When we later need to xdr_destroy,
+  // we can index the map, free the wrapper, and then clean the map entry.
+  XdrRecWrapper *wrap_data =
+      (XdrRecWrapper *)InternalAlloc(sizeof(XdrRecWrapper));
+  wrap_data->handle = handle;
+  wrap_data->rd = rd;
+  wrap_data->wr = wr;
+  if (wr)
+    wr = xdrrec_wr_wrap;
+  if (rd)
+    rd = xdrrec_rd_wrap;
+  handle = (char *)wrap_data;
+
+  REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr);
+
+  XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, false, true);
+  *wrap = wrap_data;
+}
+
+// We have to intercept this to be able to free wrapper memory;
+// otherwise it's not necessary.
+INTERCEPTOR(void, xdr_destroy, __sanitizer_XDR *xdr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdr_destroy, xdr);
+
+  XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, true);
+  InternalFree(*wrap);
+  REAL(xdr_destroy)(xdr);
+}
+#define INIT_XDRREC_LINUX \
+  static u64 xdrrec_wrap_mem[sizeof(XdrRecWrapMap) / sizeof(u64) + 1]; \
+  xdrrec_wrap_map = new ((void *)&xdrrec_wrap_mem) XdrRecWrapMap(); \
+  COMMON_INTERCEPT_FUNCTION(xdrrec_create); \
+  COMMON_INTERCEPT_FUNCTION(xdr_destroy);
+#else
+#define INIT_XDRREC_LINUX
+#endif
+
 #if SANITIZER_INTERCEPT_TSEARCH
 INTERCEPTOR(void *, tsearch, void *key, void **rootp,
             int (*compar)(const void *, const void *)) {
@@ -5797,6 +5978,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
   if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
     COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
                                         fp->_IO_read_end - fp->_IO_read_base);
+  if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
+                                        fp->_IO_write_end - fp->_IO_write_base);
 #endif
 #endif  // SANITIZER_HAS_STRUCT_FILE
 }
@@ -6023,6 +6207,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
 INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
+  if (fp)
+    unpoison_file(fp);
   int res = REAL(fflush)(fp);
   // FIXME: handle fp == NULL
   if (fp) {
@@ -6042,6 +6228,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
   COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
   COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
   const FileMetadata *m = GetInterceptorMetadata(fp);
+  if (fp)
+    unpoison_file(fp);
   int res = REAL(fclose)(fp);
   if (m) {
     COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
@@ -6432,12 +6620,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
   if (srcaddr) srcaddr_sz = *addrlen;
   (void)srcaddr_sz;  // prevent "set but not used" warning
   SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
-  if (res > 0) {
+  if (res > 0)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
-    if (srcaddr)
-      COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
-                                          Min((SIZE_T)*addrlen, srcaddr_sz));
-  }
+  if (res >= 0 && srcaddr)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
+                                        Min((SIZE_T)*addrlen, srcaddr_sz));
   return res;
 }
 #define INIT_RECV_RECVFROM          \
@@ -7275,23 +7462,26 @@ INTERCEPTOR(int, setttyentpath, char *path) {
 #endif
 
 #if SANITIZER_INTERCEPT_PROTOENT
-INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent);
-  struct __sanitizer_protoent *p = REAL(getprotoent)();
-  if (p) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+static void write_protoent(void *ctx, struct __sanitizer_protoent *p) {
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
 
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1);
 
-    SIZE_T pp_size = 1; // One handles the trailing \0
+  SIZE_T pp_size = 1; // One handles the trailing \0
 
-    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size)
-       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1);
+  for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1);
 
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases,
-                                   pp_size * sizeof(char **));
-  }
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases,
+                                  pp_size * sizeof(char **));
+}
+
+INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent);
+  struct __sanitizer_protoent *p = REAL(getprotoent)();
+  if (p)
+    write_protoent(ctx, p);
   return p;
 }
 
@@ -7301,19 +7491,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobyname, const char *name) {
   if (name)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
   struct __sanitizer_protoent *p = REAL(getprotobyname)(name);
-  if (p) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
-
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1);
-
-    SIZE_T pp_size = 1; // One handles the trailing \0
-
-    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size)
-       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1);
-
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases,
-                                   pp_size * sizeof(char **));
-  }
+  if (p)
+    write_protoent(ctx, p);
   return p;
 }
 
@@ -7321,19 +7500,8 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber, proto);
   struct __sanitizer_protoent *p = REAL(getprotobynumber)(proto);
-  if (p) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
-
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_name, REAL(strlen)(p->p_name) + 1);
-
-    SIZE_T pp_size = 1; // One handles the trailing \0
-
-    for (char **pp = p->p_aliases; *pp; ++pp, ++pp_size)
-       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *pp, REAL(strlen)(*pp) + 1);
-
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases,
-                                   pp_size * sizeof(char **));
-  }
+  if (p)
+    write_protoent(ctx, p);
   return p;
 }
 #define INIT_PROTOENT \
@@ -7344,6 +7512,58 @@ INTERCEPTOR(struct __sanitizer_protoent *, getprotobynumber, int proto) {
 #define INIT_PROTOENT
 #endif
 
+#if SANITIZER_INTERCEPT_PROTOENT_R
+INTERCEPTOR(int, getprotoent_r, struct __sanitizer_protoent *result_buf,
+            char *buf, SIZE_T buflen, struct __sanitizer_protoent **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent_r, result_buf, buf, buflen,
+                           result);
+  int res = REAL(getprotoent_r)(result_buf, buf, buflen, result);
+
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result);
+  if (!res && *result)
+    write_protoent(ctx, *result);
+  return res;
+}
+
+INTERCEPTOR(int, getprotobyname_r, const char *name,
+            struct __sanitizer_protoent *result_buf, char *buf, SIZE_T buflen,
+            struct __sanitizer_protoent **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getprotobyname_r, name, result_buf, buf,
+                           buflen, result);
+  if (name)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  int res = REAL(getprotobyname_r)(name, result_buf, buf, buflen, result);
+
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result);
+  if (!res && *result)
+    write_protoent(ctx, *result);
+  return res;
+}
+
+INTERCEPTOR(int, getprotobynumber_r, int num,
+            struct __sanitizer_protoent *result_buf, char *buf,
+            SIZE_T buflen, struct __sanitizer_protoent **result) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getprotobynumber_r, num, result_buf, buf,
+                           buflen, result);
+  int res = REAL(getprotobynumber_r)(num, result_buf, buf, buflen, result);
+
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof *result);
+  if (!res && *result)
+    write_protoent(ctx, *result);
+  return res;
+}
+
+#define INIT_PROTOENT_R \
+  COMMON_INTERCEPT_FUNCTION(getprotoent_r); \
+  COMMON_INTERCEPT_FUNCTION(getprotobyname_r); \
+  COMMON_INTERCEPT_FUNCTION(getprotobynumber_r);
+#else
+#define INIT_PROTOENT_R
+#endif
+
 #if SANITIZER_INTERCEPT_NETENT
 INTERCEPTOR(struct __sanitizer_netent *, getnetent) {
   void *ctx;
@@ -9680,12 +9900,25 @@ INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size,
     }
   }
   qsort_compar_f old_compar = qsort_compar;
-  qsort_compar = compar;
   SIZE_T old_size = qsort_size;
-  qsort_size = size;
+  // Handle qsort() implementations that recurse using an
+  // interposable function call:
+  bool already_wrapped = compar == wrapped_qsort_compar;
+  if (already_wrapped) {
+    // This case should only happen if the qsort() implementation calls itself
+    // using a preemptible function call (e.g. the FreeBSD libc version).
+    // Check that the size and comparator arguments are as expected.
+    CHECK_NE(compar, qsort_compar);
+    CHECK_EQ(qsort_size, size);
+  } else {
+    qsort_compar = compar;
+    qsort_size = size;
+  }
   REAL(qsort)(base, nmemb, size, wrapped_qsort_compar);
-  qsort_compar = old_compar;
-  qsort_size = old_size;
+  if (!already_wrapped) {
+    qsort_compar = old_compar;
+    qsort_size = old_size;
+  }
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
 }
 #define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort)
@@ -9718,12 +9951,25 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
     }
   }
   qsort_r_compar_f old_compar = qsort_r_compar;
-  qsort_r_compar = compar;
   SIZE_T old_size = qsort_r_size;
-  qsort_r_size = size;
+  // Handle qsort_r() implementations that recurse using an
+  // interposable function call:
+  bool already_wrapped = compar == wrapped_qsort_r_compar;
+  if (already_wrapped) {
+    // This case should only happen if the qsort() implementation calls itself
+    // using a preemptible function call (e.g. the FreeBSD libc version).
+    // Check that the size and comparator arguments are as expected.
+    CHECK_NE(compar, qsort_r_compar);
+    CHECK_EQ(qsort_r_size, size);
+  } else {
+    qsort_r_compar = compar;
+    qsort_r_size = size;
+  }
   REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg);
-  qsort_r_compar = old_compar;
-  qsort_r_size = old_size;
+  if (!already_wrapped) {
+    qsort_r_compar = old_compar;
+    qsort_r_size = old_size;
+  }
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size);
 }
 #define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r)
@@ -9731,6 +9977,59 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size,
 #define INIT_QSORT_R
 #endif
 
+#if SANITIZER_INTERCEPT_SIGALTSTACK
+INTERCEPTOR(int, sigaltstack, void *ss, void *oss) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss);
+  int r = REAL(sigaltstack)(ss, oss);
+  if (r == 0 && oss != nullptr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz);
+  }
+  return r;
+}
+#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack)
+#else
+#define INIT_SIGALTSTACK
+#endif
+
+#if SANITIZER_INTERCEPT_UNAME
+INTERCEPTOR(int, uname, struct utsname *utsname) {
+#if SANITIZER_LINUX
+  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+    return internal_uname(utsname);
+#endif
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname);
+  int res = REAL(uname)(utsname);
+  if (!res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
+                                   __sanitizer::struct_utsname_sz);
+  return res;
+}
+#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname)
+#else
+#define INIT_UNAME
+#endif
+
+#if SANITIZER_INTERCEPT___XUNAME
+// FreeBSD's <sys/utsname.h> define uname() as
+// static __inline int uname(struct utsname *name) {
+//   return __xuname(SYS_NMLN, (void*)name);
+// }
+INTERCEPTOR(int, __xuname, int size, void *utsname) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname);
+  int res = REAL(__xuname)(size, utsname);
+  if (!res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname,
+                                   __sanitizer::struct_utsname_sz);
+  return res;
+}
+#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname)
+#else
+#define INIT___XUNAME
+#endif
+
 #include "sanitizer_common_interceptors_netbsd_compat.inc"
 
 static void InitializeCommonInterceptors() {
@@ -9804,6 +10103,7 @@ static void InitializeCommonInterceptors() {
   INIT_FGETGRENT_R;
   INIT_SETPWENT;
   INIT_CLOCK_GETTIME;
+  INIT_CLOCK_GETCPUCLOCKID;
   INIT_GETITIMER;
   INIT_TIME;
   INIT_GLOB;
@@ -9830,6 +10130,7 @@ static void InitializeCommonInterceptors() {
   INIT_SENDMSG;
   INIT_RECVMMSG;
   INIT_SENDMMSG;
+  INIT_SYSMSG;
   INIT_GETPEERNAME;
   INIT_IOCTL;
   INIT_INET_ATON;
@@ -9866,6 +10167,7 @@ static void InitializeCommonInterceptors() {
   INIT_SIGWAITINFO;
   INIT_SIGTIMEDWAIT;
   INIT_SIGSETOPS;
+  INIT_SIGSET_LOGICOPS;
   INIT_SIGPENDING;
   INIT_SIGPROCMASK;
   INIT_PTHREAD_SIGMASK;
@@ -9907,6 +10209,8 @@ static void InitializeCommonInterceptors() {
   INIT_PTHREAD_BARRIERATTR_GETPSHARED;
   INIT_TMPNAM;
   INIT_TMPNAM_R;
+  INIT_PTSNAME;
+  INIT_PTSNAME_R;
   INIT_TTYNAME;
   INIT_TTYNAME_R;
   INIT_TEMPNAM;
@@ -9936,6 +10240,7 @@ static void InitializeCommonInterceptors() {
   INIT_BZERO;
   INIT_FTIME;
   INIT_XDR;
+  INIT_XDRREC_LINUX;
   INIT_TSEARCH;
   INIT_LIBIO_INTERNALS;
   INIT_FOPEN;
@@ -9993,6 +10298,7 @@ static void InitializeCommonInterceptors() {
   INIT_STRMODE;
   INIT_TTYENT;
   INIT_PROTOENT;
+  INIT_PROTOENT_R;
   INIT_NETENT;
   INIT_GETMNTINFO;
   INIT_MI_VECTOR_HASH;
@@ -10036,6 +10342,9 @@ static void InitializeCommonInterceptors() {
   INIT_GETENTROPY;
   INIT_QSORT;
   INIT_QSORT_R;
+  INIT_SIGALTSTACK;
+  INIT_UNAME;
+  INIT___XUNAME;
 
   INIT___PRINTF_CHK;
 }
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
index bbbedda8fbe21..082398ba960af 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -340,6 +340,12 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
       size = 0;
     }
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+    // For %ms/%mc, write the allocated output buffer as well.
+    if (dir.allocate) {
+      char *buf = *(char **)argp;
+      if (buf)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1);
+    }
   }
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 490a04b2181b0..7f181258eab52 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -330,13 +330,17 @@ static void ioctl_table_fill() {
   _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
   _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
   _(TCFLSH, NONE, 0);
+#if SANITIZER_GLIBC
   _(TCGETA, WRITE, struct_termio_sz);
+#endif
   _(TCGETS, WRITE, struct_termios_sz);
   _(TCSBRK, NONE, 0);
   _(TCSBRKP, NONE, 0);
+#if SANITIZER_GLIBC
   _(TCSETA, READ, struct_termio_sz);
   _(TCSETAF, READ, struct_termio_sz);
   _(TCSETAW, READ, struct_termio_sz);
+#endif
   _(TCSETS, READ, struct_termios_sz);
   _(TCSETSF, READ, struct_termios_sz);
   _(TCSETSW, READ, struct_termios_sz);
@@ -364,7 +368,7 @@ static void ioctl_table_fill() {
   _(VT_WAITACTIVE, NONE, 0);
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
   // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
   _(CYGETDEFTHRESH, WRITE, sizeof(int));
   _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
index c78b6e10b6895..932e5478616d5 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
@@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
 INTERFACE_FUNCTION(__sanitizer_set_death_callback)
 INTERFACE_FUNCTION(__sanitizer_set_report_path)
 INTERFACE_FUNCTION(__sanitizer_set_report_fd)
+INTERFACE_FUNCTION(__sanitizer_get_report_path)
 INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
 INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
 INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
index 27d6a177760e4..047c5a17ea6e7 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp
@@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
   return nullptr;
 }
 
-void BackgroundThread(void *arg) {
+void *BackgroundThread(void *arg) {
   const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
   const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
   const bool heap_profile = common_flags()->heap_profile;
@@ -129,6 +129,69 @@ void SetSandboxingCallback(void (*f)()) {
   sandboxing_callback = f;
 }
 
+uptr ReservedAddressRange::InitAligned(uptr size, uptr align,
+                                       const char *name) {
+  CHECK(IsPowerOfTwo(align));
+  if (align <= GetPageSizeCached())
+    return Init(size, name);
+  uptr start = Init(size + align, name);
+  start += align - (start & (align - 1));
+  return start;
+}
+
+#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
+
+// Reserve memory range [beg, end].
+// We need to use inclusive range because end+1 may not be representable.
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
+                              bool madvise_shadow) {
+  CHECK_EQ((beg % GetMmapGranularity()), 0);
+  CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
+  uptr size = end - beg + 1;
+  DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb.
+  if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name)
+                     : !MmapFixedNoReserve(beg, size, name)) {
+    Report(
+        "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
+        "Perhaps you're using ulimit -v\n",
+        size);
+    Abort();
+  }
+  if (madvise_shadow && common_flags()->use_madv_dontdump)
+    DontDumpShadowMemory(beg, size);
+}
+
+void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start,
+                uptr zero_base_max_shadow_start) {
+  if (!size)
+    return;
+  void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+  if (addr == (uptr)res)
+    return;
+  // A few pages at the start of the address space can not be protected.
+  // But we really want to protect as much as possible, to prevent this memory
+  // being returned as a result of a non-FIXED mmap().
+  if (addr == zero_base_shadow_start) {
+    uptr step = GetMmapGranularity();
+    while (size > step && addr < zero_base_max_shadow_start) {
+      addr += step;
+      size -= step;
+      void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+      if (addr == (uptr)res)
+        return;
+    }
+  }
+
+  Report(
+      "ERROR: Failed to protect the shadow gap. "
+      "%s cannot proceed correctly. ABORTING.\n",
+      SanitizerToolName);
+  DumpProcessMap();
+  Die();
+}
+
+#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
+
 }  // namespace __sanitizer
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
index 3b278e017eb7c..487a634a16523 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
@@ -10,9 +10,10 @@
 // libc in no-libcdep sources.
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_platform.h"
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_platform.h"
 
 namespace __sanitizer {
 
@@ -29,6 +30,7 @@ void SleepForSeconds(int seconds) { internal_sleep(seconds); }
 
 #if !SANITIZER_WINDOWS && !SANITIZER_MAC
 void ListOfModules::init() {}
+void InitializePlatformCommonFlags(CommonFlags *cf) {}
 #endif
 
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 31ff48cfd2cfc..1b89d6e176840 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -2294,9 +2294,10 @@ PRE_SYSCALL(ni_syscall)() {}
 POST_SYSCALL(ni_syscall)(long res) {}
 
 PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
-#if !SANITIZER_ANDROID && \
-    (defined(__i386) || defined(__x86_64) || defined(__mips64) || \
-     defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__))
+#if !SANITIZER_ANDROID &&                                                   \
+    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||           \
+     defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
+     SANITIZER_RISCV64)
   if (data) {
     if (request == ptrace_setregs) {
       PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2315,9 +2316,10 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
 }
 
 POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
-#if !SANITIZER_ANDROID && \
-    (defined(__i386) || defined(__x86_64) || defined(__mips64) || \
-     defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__))
+#if !SANITIZER_ANDROID &&                                                   \
+    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||           \
+     defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
+     SANITIZER_RISCV64)
   if (res >= 0 && data) {
     // Note that this is different from the interceptor in
     // sanitizer_common_interceptors.inc.
@@ -2885,6 +2887,23 @@ POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) {
     POST_WRITE(buf, res);
   }
 }
+
+PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) {
+  if (ss != nullptr) {
+    PRE_READ(ss, struct_stack_t_sz);
+  }
+  if (oss != nullptr) {
+    PRE_WRITE(oss, struct_stack_t_sz);
+  }
+}
+
+POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) {
+  if (res == 0) {
+    if (oss != nullptr) {
+      POST_WRITE(oss, struct_stack_t_sz);
+    }
+  }
+}
 }  // extern "C"
 
 #undef PRE_SYSCALL
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp
index f18cee66b8431..a52db08433e3b 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp
@@ -27,15 +27,15 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+
 #include "sanitizer_atomic.h"
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_symbolizer_fuchsia.h"
 
-#include <zircon/process.h>
-#include <zircon/sanitizer.h>
-#include <zircon/syscalls.h>
-
 using namespace __sanitizer;
 
 namespace __sancov {
@@ -82,7 +82,8 @@ class TracePcGuardController final {
   void TracePcGuard(u32 *guard, uptr pc) {
     atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard);
     u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
-    if (idx > 0) array_[idx] = pc;
+    if (idx > 0)
+      array_[idx] = pc;
   }
 
   void Dump() {
@@ -140,6 +141,10 @@ class TracePcGuardController final {
                         internal_getpid());
       _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
                               internal_strlen(vmo_name_));
+      uint64_t size = DataSize();
+      status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
+                                       sizeof(size));
+      CHECK_EQ(status, ZX_OK);
 
       // Map the largest possible view we might need into the VMO.  Later
       // we might need to increase the VMO's size before we can use larger
@@ -172,6 +177,10 @@ class TracePcGuardController final {
 
       zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
       CHECK_EQ(status, ZX_OK);
+      uint64_t size = DataSize();
+      status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
+                                       sizeof(size));
+      CHECK_EQ(status, ZX_OK);
 
       return first_index;
     }
@@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs,
 }
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) {
-  if (!*guard) return;
+  if (!*guard)
+    return;
   __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
 }
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
                              u32 *start, u32 *end) {
-  if (start == end || *start) return;
+  if (start == end || *start)
+    return;
   __sancov::pc_guard_controller.InitTracePcGuard(start, end);
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc
index 7beeff7e8af80..d7ab0c3d98c15 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc
@@ -29,4 +29,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
 INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir)
 INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch)
 INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init)
 INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init)
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
index 6a75792f92624..73ebeb5fa14ad 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
@@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {}
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
 }  // extern "C"
 // Weak definition for code instrumented with -fsanitize-coverage=stack-depth
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp
index d4a325bea4b2d..2c924f5d39639 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cpp
@@ -32,7 +32,7 @@ struct DDLogicalThread {
   bool report_pending;
 };
 
-struct DD : public DDetector {
+struct DD final : public DDetector {
   SpinMutex mtx;
   DeadlockDetector<DDBV> dd;
   DDFlags flags;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp
index 4026739d4e515..e3f8e1b127623 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector2.cpp
@@ -80,7 +80,7 @@ struct Mutex {
   Link link[kMaxLink];
 };
 
-struct DD : public DDetector {
+struct DD final : public DDetector {
   explicit DD(const DDFlags *flags);
 
   DDPhysicalThread* CreatePhysicalThread();
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
index a4722b080ebd1..7f461c98bade4 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -66,6 +66,9 @@ struct DDCallback {
 
   virtual u32 Unwind() { return 0; }
   virtual int UniqueTid() { return 0; }
+
+ protected:
+  ~DDCallback() {}
 };
 
 struct DDetector {
@@ -85,6 +88,9 @@ struct DDetector {
   virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
 
   virtual DDReport *GetReport(DDCallback *cb) { return nullptr; }
+
+ protected:
+  ~DDetector() {}
 };
 
 } // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp
index 6cdfa28a95afd..785ebf97169d8 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp
@@ -124,12 +124,16 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
 #endif
 }
 
+class SuspendedThreadsListEmscripten final : public SuspendedThreadsList {};
+
 void StopTheWorld(StopTheWorldCallback callback, void *argument) {
   // TODO: have some workable alternative, since we can't just fork and suspend
   // the parent process. This does not matter when single thread.
-  callback(SuspendedThreadsList(), argument);
+  callback(SuspendedThreadsListEmscripten(), argument);
 }
 
+void InitializePlatformCommonFlags(CommonFlags *cf) {}
+
 } // namespace __sanitizer
 
 #endif
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h
index 584e66e4a861a..94f16b6e87358 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno.h
@@ -23,7 +23,7 @@
 
 #if SANITIZER_FREEBSD || SANITIZER_MAC
 #  define __errno_location __error
-#elif SANITIZER_ANDROID || SANITIZER_NETBSD || SANITIZER_OPENBSD || \
+#elif SANITIZER_ANDROID || SANITIZER_NETBSD || \
   SANITIZER_RTEMS
 #  define __errno_location __errno
 #elif SANITIZER_SOLARIS
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
index 7f797c2c4c15c..650cf99128d78 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h
@@ -24,9 +24,10 @@
 
 namespace __sanitizer {
 
-#define errno_ENOMEM __WASI_ERRNO_NOMEM
-#define errno_EBUSY  __WASI_ERRNO_BUSY
-#define errno_EINVAL __WASI_ERRNO_INVAL
+#define errno_ENOMEM       __WASI_ERRNO_NOMEM
+#define errno_EBUSY        __WASI_ERRNO_BUSY
+#define errno_EINVAL       __WASI_ERRNO_INVAL
+#define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG
 
 // Those might not present or their value differ on different platforms.
 extern const int errno_EOWNERDEAD;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
index 79930d7942501..7c64b53e9b11d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
@@ -58,40 +58,49 @@ void ReportFile::ReopenIfNecessary() {
   } else {
     internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
   }
-  fd = OpenFile(full_path, WrOnly);
+  error_t err;
+  fd = OpenFile(full_path, WrOnly, &err);
   if (fd == kInvalidFd) {
     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
     WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
     WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
+    char errmsg[100];
+    internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err);
+    WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg));
     Die();
   }
   fd_pid = pid;
 }
 
 void ReportFile::SetReportPath(const char *path) {
-  if (!path)
-    return;
-  uptr len = internal_strlen(path);
-  if (len > sizeof(path_prefix) - 100) {
-    Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
-           path[0], path[1], path[2], path[3],
-           path[4], path[5], path[6], path[7]);
-    Die();
+  if (path) {
+    uptr len = internal_strlen(path);
+    if (len > sizeof(path_prefix) - 100) {
+      Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1],
+             path[2], path[3], path[4], path[5], path[6], path[7]);
+      Die();
+    }
   }
 
   SpinMutexLock l(mu);
   if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
     CloseFile(fd);
   fd = kInvalidFd;
-  if (internal_strcmp(path, "stdout") == 0) {
-    fd = kStdoutFd;
-  } else if (internal_strcmp(path, "stderr") == 0) {
+  if (!path || internal_strcmp(path, "stderr") == 0) {
     fd = kStderrFd;
+  } else if (internal_strcmp(path, "stdout") == 0) {
+    fd = kStdoutFd;
   } else {
     internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
   }
 }
 
+const char *ReportFile::GetReportPath() {
+  SpinMutexLock l(mu);
+  ReopenIfNecessary();
+  return full_path;
+}
+
 bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
                       uptr *read_len, uptr max_len, error_t *errno_p) {
   *buff = nullptr;
@@ -210,6 +219,10 @@ void __sanitizer_set_report_fd(void *fd) {
   report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
   report_file.fd_pid = internal_getpid();
 }
+
+const char *__sanitizer_get_report_path() {
+  return report_file.GetReportPath();
+}
 } // extern "C"
 
 #endif  // !SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h
index 4a78a0e0ac881..08671ab67d0f5 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_file.h
@@ -26,6 +26,7 @@ struct ReportFile {
   void Write(const char *buffer, uptr length);
   bool SupportsColors();
   void SetReportPath(const char *path);
+  const char *GetReportPath();
 
   // Don't use fields directly. They are only declared public to allow
   // aggregate initialization.
@@ -87,8 +88,8 @@ bool IsAbsolutePath(const char *path);
 // The child process will close all fds after STDERR_FILENO
 // before passing control to a program.
 pid_t StartSubprocess(const char *filename, const char *const argv[],
-                      fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
-                      fd_t stderr_fd = kInvalidFd);
+                      const char *const envp[], fd_t stdin_fd = kInvalidFd,
+                      fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd);
 // Checks if specified process is still running
 bool IsProcessRunning(pid_t pid);
 // Waits for the process to finish and returns its exit code.
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
index fac5dff346333..acc71ccd89eea 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h
@@ -42,7 +42,7 @@ class FlagHandlerBase {
 };
 
 template <typename T>
-class FlagHandler : public FlagHandlerBase {
+class FlagHandler final : public FlagHandlerBase {
   T *t_;
 
  public:
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp
index 684ee1e0b9995..21048be730416 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp
@@ -13,9 +13,10 @@
 #include "sanitizer_flags.h"
 
 #include "sanitizer_common.h"
+#include "sanitizer_flag_parser.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
 #include "sanitizer_list.h"
-#include "sanitizer_flag_parser.h"
 
 namespace __sanitizer {
 
@@ -72,7 +73,7 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
   *out = '\0';
 }
 
-class FlagHandlerInclude : public FlagHandlerBase {
+class FlagHandlerInclude final : public FlagHandlerBase {
   FlagParser *parser_;
   bool ignore_missing_;
   const char *original_path_;
@@ -91,7 +92,7 @@ class FlagHandlerInclude : public FlagHandlerBase {
     }
     return parser_->ParseFile(value, ignore_missing_);
   }
-  bool Format(char *buffer, uptr size) {
+  bool Format(char *buffer, uptr size) override {
     // Note `original_path_` isn't actually what's parsed due to `%`
     // substitutions. Printing the substituted path would require holding onto
     // mmap'ed memory.
@@ -124,6 +125,8 @@ void InitializeCommonFlags(CommonFlags *cf) {
   // need to record coverage to generate coverage report.
   cf->coverage |= cf->html_cov_report;
   SetVerbosity(cf->verbosity);
+
+  InitializePlatformCommonFlags(cf);
 }
 
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
index 8f5e987da3ffd..5b59e5801bf91 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.h
@@ -62,6 +62,10 @@ void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf);
 // and perform initializations common to all sanitizers (e.g. setting
 // verbosity).
 void InitializeCommonFlags(CommonFlags *cf = &common_flags_dont_use);
+
+// Platform specific flags initialization.
+void InitializePlatformCommonFlags(CommonFlags *cf);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FLAGS_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
index 065258a5a6e13..cfb5822645f13 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
@@ -40,16 +40,21 @@ COMMON_FLAG(bool, fast_unwind_on_check, false,
 COMMON_FLAG(bool, fast_unwind_on_fatal, false,
             "If available, use the fast frame-pointer-based unwinder on fatal "
             "errors.")
-COMMON_FLAG(bool, fast_unwind_on_malloc, true,
+// ARM thumb/thumb2 frame pointer is inconsistent on GCC and Clang [1]
+// and fast-unwider is also unreliable with mixing arm and thumb code [2].
+// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92172
+// [2] https://bugs.llvm.org/show_bug.cgi?id=44158
+COMMON_FLAG(bool, fast_unwind_on_malloc,
+            !(SANITIZER_LINUX && !SANITIZER_ANDROID && SANITIZER_ARM),
             "If available, use the fast frame-pointer-based unwinder on "
             "malloc/free.")
 COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.")
 COMMON_FLAG(int, malloc_context_size, 1,
             "Max number of stack frames kept for each allocation/deallocation.")
 COMMON_FLAG(
-    const char *, log_path, "stderr",
+    const char *, log_path, nullptr,
     "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
-    "\"stderr\". The default is \"stderr\".")
+    "\"stderr\". If unspecified, defaults to \"stderr\".")
 COMMON_FLAG(
     bool, log_exe_name, false,
     "Mention name of executable when reporting error and "
@@ -77,8 +82,9 @@ COMMON_FLAG(bool, print_summary, true,
             "If false, disable printing error summaries in addition to error "
             "reports.")
 COMMON_FLAG(int, print_module_map, 0,
-            "OS X only (0 - don't print, 1 - print only once before process "
-            "exits, 2 - print after each report).")
+            "Print the process module map where supported (0 - don't print, "
+            "1 - print only once before process exits, 2 - print after each "
+            "report).")
 COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
 #define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \
     "Controls custom tool's " #signal " handler (0 - do not registers the " \
@@ -195,6 +201,9 @@ COMMON_FLAG(bool, intercept_strtok, true,
 COMMON_FLAG(bool, intercept_strpbrk, true,
             "If set, uses custom wrappers for strpbrk function "
             "to find more errors.")
+COMMON_FLAG(
+    bool, intercept_strcmp, true,
+    "If set, uses custom wrappers for strcmp functions to find more errors.")
 COMMON_FLAG(bool, intercept_strlen, true,
             "If set, uses custom wrappers for strlen and strnlen functions "
             "to find more errors.")
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h
index 64cb21f1c3d2b..82b227eab6dab 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_freebsd.h
@@ -19,11 +19,11 @@
 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
 // 32-bit mode.
 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-# include <osreldate.h>
-# if __FreeBSD_version <= 902001  // v9.2
-#  include <link.h>
-#  include <sys/param.h>
-#  include <ucontext.h>
+#include <osreldate.h>
+#if __FreeBSD_version <= 902001  // v9.2
+#include <link.h>
+#include <sys/param.h>
+#include <ucontext.h>
 
 namespace __sanitizer {
 
@@ -68,8 +68,8 @@ typedef struct __xmcontext {
 } xmcontext_t;
 
 typedef struct __xucontext {
-  sigset_t  uc_sigmask;
-  xmcontext_t  uc_mcontext;
+  sigset_t uc_sigmask;
+  xmcontext_t uc_mcontext;
 
   struct __ucontext *uc_link;
   stack_t uc_stack;
@@ -122,15 +122,16 @@ struct xdl_phdr_info {
   void *dlpi_tls_data;
 };
 
-typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
-typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
+typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t,
+                                          void *);
+typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *);
 
 #define xdl_iterate_phdr(callback, param) \
-  (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
+  (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param)))
 
 }  // namespace __sanitizer
 
-# endif  // __FreeBSD_version <= 902001
+#endif  // __FreeBSD_version <= 902001
 #endif  // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
 
 #endif  // SANITIZER_FREEBSD_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
index 6e2c6137f0ce7..5ad20d0d7da62 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
@@ -14,10 +14,6 @@
 #include "sanitizer_fuchsia.h"
 #if SANITIZER_FUCHSIA
 
-#include "sanitizer_common.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_mutex.h"
-
 #include <limits.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -25,6 +21,11 @@
 #include <zircon/errors.h>
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
+#include <zircon/utc.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
 
 namespace __sanitizer {
 
@@ -47,8 +48,10 @@ unsigned int internal_sleep(unsigned int seconds) {
 }
 
 u64 NanoTime() {
+  zx_handle_t utc_clock = _zx_utc_reference_get();
+  CHECK_NE(utc_clock, ZX_HANDLE_INVALID);
   zx_time_t time;
-  zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time);
+  zx_status_t status = _zx_clock_read(utc_clock, &time);
   CHECK_EQ(status, ZX_OK);
   return time;
 }
@@ -66,6 +69,10 @@ uptr internal_getpid() {
   return pid;
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  UNIMPLEMENTED();
+}
+
 uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
 
 tid_t GetTid() { return GetThreadSelf(); }
@@ -101,8 +108,6 @@ void SetAlternateSignalStack() {}
 void UnsetAlternateSignalStack() {}
 void InitTlsSize() {}
 
-void PrintModuleMap() {}
-
 bool SignalContext::IsStackOverflow() const { return false; }
 void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
 const char *SignalContext::Describe() const { UNIMPLEMENTED(); }
@@ -500,6 +505,8 @@ u32 GetNumberOfCPUs() {
 
 uptr GetRSS() { UNIMPLEMENTED(); }
 
+void InitializePlatformCommonFlags(CommonFlags *cf) {}
+
 }  // namespace __sanitizer
 
 using namespace __sanitizer;
@@ -522,6 +529,10 @@ void __sanitizer_set_report_path(const char *path) {
 void __sanitizer_set_report_fd(void *fd) {
   UNREACHABLE("not available on Fuchsia");
 }
+
+const char *__sanitizer_get_report_path() {
+  UNREACHABLE("not available on Fuchsia");
+}
 }  // extern "C"
 
 #endif  // SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h
index 5a2ad32b4113b..96f9cde7ef191 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.h
@@ -18,12 +18,18 @@
 #include "sanitizer_common.h"
 
 #include <zircon/sanitizer.h>
+#include <zircon/syscalls/object.h>
 
 namespace __sanitizer {
 
 extern uptr MainThreadStackBase, MainThreadStackSize;
 extern sanitizer_shadow_bounds_t ShadowBounds;
 
+struct MemoryMappingLayoutData {
+  InternalMmapVector<zx_info_maps_t> data;
+  size_t current;  // Current index into the vector.
+};
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h
index 86ad3a5e2c2aa..38439e44f611e 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h
@@ -21,8 +21,9 @@
 
 #if SANITIZER_LINUX || SANITIZER_FUCHSIA
 
-# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \
-     SANITIZER_FUCHSIA
+# if (__GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) || \
+      SANITIZER_FUCHSIA) &&                                                    \
+     !SANITIZER_GO
 #  define SANITIZER_USE_GETAUXVAL 1
 # else
 #  define SANITIZER_USE_GETAUXVAL 0
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
index d0cc4da9755f4..576807ea3a6a1 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
@@ -446,9 +446,6 @@ static void ioctl_table_fill() {
   _(STICIO_STOPQ, NONE, 0);
   /* Entries from file: dev/usb/ukyopon.h */
   _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz);
-  /* Entries from file: dev/usb/urio.h */
-  _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
-  _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
   /* Entries from file: dev/usb/usb.h */
   _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz);
   _(USB_SETDEBUG, READ, sizeof(int));
@@ -1405,6 +1402,9 @@ static void ioctl_table_fill() {
   /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */
   _(FILEMON_SET_FD, READWRITE, sizeof(int));
   _(FILEMON_SET_PID, READWRITE, sizeof(int));
+  /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */
+  _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz);
+  _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz);
 #undef _
 } // NOLINT
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
index c110eff130f24..0b001c1c48300 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
@@ -28,6 +28,10 @@ extern "C" {
   // (casted to void *).
   SANITIZER_INTERFACE_ATTRIBUTE
   void __sanitizer_set_report_fd(void *fd);
+  // Get the current full report file path, if a path was specified by
+  // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char *__sanitizer_get_report_path();
 
   typedef struct {
       int coverage_sandboxed;
@@ -109,8 +113,10 @@ extern "C" {
                                            __sanitizer::u32*);
   SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
   void __sanitizer_cov_8bit_counters_init();
-  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-  void __sanitizer_cov_pcs_init();
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+  __sanitizer_cov_bool_flag_init();
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+  __sanitizer_cov_pcs_init();
 } // extern "C"
 
 #endif  // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
index 4e4609c27cb66..9e6f406029e0d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -39,7 +39,7 @@
 
 // TLS is handled differently on different platforms
 #if SANITIZER_LINUX || SANITIZER_NETBSD || \
-  SANITIZER_FREEBSD || SANITIZER_OPENBSD
+  SANITIZER_FREEBSD
 # define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \
     __attribute__((tls_model("initial-exec"))) thread_local
 #else
@@ -104,8 +104,7 @@
 //
 // FIXME: do we have anything like this on Mac?
 #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY
-#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \
-     SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC)
+#if (SANITIZER_LINUX || SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC)
 #define SANITIZER_CAN_USE_PREINIT_ARRAY 1
 // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.
 // FIXME: Check for those conditions.
@@ -170,7 +169,7 @@ typedef int pid_t;
 #endif
 
 #if SANITIZER_FREEBSD || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_MAC || \
+    SANITIZER_MAC || \
     (SANITIZER_SOLARIS && (defined(_LP64) || _FILE_OFFSET_BITS == 64)) || \
     (SANITIZER_LINUX && defined(__x86_64__))
 typedef u64 OFF_T;
@@ -182,8 +181,7 @@ typedef u64  OFF64_T;
 #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
 typedef uptr operator_new_size_type;
 #else
-# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) || \
-     SANITIZER_EMSCRIPTEN
+# if defined(__s390__) && !defined(__s390x__) || SANITIZER_EMSCRIPTEN
 // Special case: 31-bit s390 has unsigned long as size_t.
 typedef unsigned long operator_new_size_type;
 # else
@@ -197,9 +195,6 @@ typedef u64 tid_t;
 // This header should NOT include any other headers to avoid portability issues.
 
 // Common defs.
-#ifndef INLINE
-#define INLINE inline
-#endif
 #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 #define SANITIZER_WEAK_DEFAULT_IMPL \
   extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
@@ -334,14 +329,10 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
 
 #define UNIMPLEMENTED() UNREACHABLE("unimplemented")
 
-#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
+#define COMPILER_CHECK(pred) static_assert(pred, "")
 
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
 
-#define IMPL_PASTE(a, b) a##b
-#define IMPL_COMPILER_ASSERT(pred, line) \
-    typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1]
-
 // Limits for integral types. We have to redefine it in case we don't
 // have stdint.h (like in Visual Studio 9).
 #undef __INT64_C
@@ -456,5 +447,8 @@ using namespace __sanitizer;
 namespace __hwasan {
 using namespace __sanitizer;
 }
+namespace __memprof {
+using namespace __sanitizer;
+}
 
 #endif  // SANITIZER_DEFS_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
index 3d5db35d68ba5..ec0a6ded009b0 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
@@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds);
 uptr internal_getpid();
 uptr internal_getppid();
 
+int internal_dlinfo(void *handle, int request, void *p);
+
 // Threading
 uptr internal_sched_yield();
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
index eb9bb765013da..9ea19bc21fa3c 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
@@ -9,7 +9,7 @@
 #include "sanitizer_platform.h"
 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \
-    SANITIZER_NETBSD || SANITIZER_OPENBSD
+    SANITIZER_NETBSD
 
 #include "sanitizer_libignore.h"
 #include "sanitizer_flags.h"
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index dc5bbb6bc6cc6..d1738e0c2aecf 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -14,7 +14,7 @@
 #include "sanitizer_platform.h"
 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
@@ -26,7 +26,7 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_GO
 #include <asm/param.h>
 #endif
 
@@ -38,6 +38,14 @@
 #include <asm/unistd.h>
 #include <sys/types.h>
 #define stat kernel_stat
+#if SANITIZER_GO
+#undef st_atime
+#undef st_mtime
+#undef st_ctime
+#define st_atime st_atim
+#define st_mtime st_mtim
+#define st_ctime st_ctim
+#endif
 #include <asm/stat.h>
 #undef stat
 #endif
@@ -59,13 +67,7 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#if !SANITIZER_OPENBSD
 #include <ucontext.h>
-#endif
-#if SANITIZER_OPENBSD
-#include <sys/futex.h>
-#include <sys/sysctl.h>
-#endif
 #include <unistd.h>
 
 #if SANITIZER_LINUX
@@ -137,7 +139,7 @@ const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
 #endif
 
 // Note : FreeBSD had implemented both
-// Linux and OpenBSD apis, available from
+// Linux apis, available from
 // future 12.x version most likely
 #if SANITIZER_LINUX && defined(__NR_getrandom)
 # if !defined(GRND_NONBLOCK)
@@ -148,20 +150,18 @@ const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
 # define SANITIZER_USE_GETRANDOM 0
 #endif  // SANITIZER_LINUX && defined(__NR_getrandom)
 
-#if SANITIZER_OPENBSD
-# define SANITIZER_USE_GETENTROPY 1
+#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
+#  define SANITIZER_USE_GETENTROPY 1
 #else
-# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
-#   define SANITIZER_USE_GETENTROPY 1
-# else
-#   define SANITIZER_USE_GETENTROPY 0
-# endif
-#endif // SANITIZER_USE_GETENTROPY
+#  define SANITIZER_USE_GETENTROPY 0
+#endif
 
 namespace __sanitizer {
 
 #if SANITIZER_LINUX && defined(__x86_64__)
 #include "sanitizer_syscall_linux_x86_64.inc"
+#elif SANITIZER_LINUX && SANITIZER_RISCV64
+#include "sanitizer_syscall_linux_riscv64.inc"
 #elif SANITIZER_LINUX && defined(__aarch64__)
 #include "sanitizer_syscall_linux_aarch64.inc"
 #elif SANITIZER_LINUX && defined(__arm__)
@@ -172,7 +172,7 @@ namespace __sanitizer {
 
 // --------------- sanitizer_libc.h
 #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
-#if !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
+#if !SANITIZER_S390 && !SANITIZER_EMSCRIPTEN
 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                    u64 offset) {
 #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
@@ -185,20 +185,22 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                           offset / 4096);
 #endif
 }
-#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_NETBSD
+#endif // !SANITIZER_S390 && !SANITIZER_NETBSD
 
-#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
+#if !SANITIZER_EMSCRIPTEN
 uptr internal_munmap(void *addr, uptr length) {
   return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
 }
-#endif
 
-#if !SANITIZER_OPENBSD
 int internal_mprotect(void *addr, uptr length, int prot) {
   return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
 }
 #endif
 
+int internal_madvise(uptr addr, uptr length, int advice) {
+  return internal_syscall(SYSCALL(madvise), addr, length, advice);
+}
+
 uptr internal_close(fd_t fd) {
 #if SANITIZER_EMSCRIPTEN
   return __wasi_fd_close(fd);
@@ -291,9 +293,11 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
 // Undefine compatibility macros from <sys/stat.h>
 // so that they would not clash with the kernel_stat
 // st_[a|m|c]time fields
+#if !SANITIZER_GO
 #undef st_atime
 #undef st_mtime
 #undef st_ctime
+#endif
 #if defined(SANITIZER_ANDROID)
 // Bionic sys/stat.h defines additional macros
 // for compatibility with the old NDKs and
@@ -336,7 +340,7 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
 #endif
 
 uptr internal_stat(const char *path, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0);
 #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
@@ -360,7 +364,7 @@ uptr internal_stat(const char *path, void *buf) {
 }
 
 uptr internal_lstat(const char *path, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           AT_SYMLINK_NOFOLLOW);
 #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
@@ -385,9 +389,8 @@ uptr internal_lstat(const char *path, void *buf) {
 }
 
 uptr internal_fstat(fd_t fd, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \
-    SANITIZER_LINUX_USES_64BIT_SYSCALLS
-#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#if SANITIZER_MIPS64
   // For mips64, fstat syscall fills buffer in the format of kernel_stat
   struct kernel_stat kbuf;
   int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
@@ -427,16 +430,13 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
 #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
                           bufsize);
-#elif SANITIZER_OPENBSD
-  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
-                          bufsize);
 #else
   return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
 #endif
 }
 
 uptr internal_unlink(const char *path) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
 #else
   return internal_syscall(SYSCALL(unlink), (uptr)path);
@@ -447,7 +447,7 @@ uptr internal_rename(const char *oldpath, const char *newpath) {
 #if defined(__riscv)
   return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                           (uptr)newpath, 0);
-#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                           (uptr)newpath);
 #else
@@ -463,16 +463,6 @@ uptr internal_sched_yield() {
 #endif
 }
 
-void internal__exit(int exitcode) {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
-  internal_syscall(SYSCALL(exit), exitcode);
-#else
-  internal_syscall(SYSCALL(exit_group), exitcode);
-#endif
-  Die();  // Unreachable.
-}
-
-
 #if !SANITIZER_EMSCRIPTEN
 unsigned int internal_sleep(unsigned int seconds) {
   struct timespec ts;
@@ -491,6 +481,17 @@ uptr internal_execve(const char *filename, char *const argv[],
 #endif  // !SANITIZER_EMSCRIPTEN
 #endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 
+#if !SANITIZER_NETBSD
+void internal__exit(int exitcode) {
+#if SANITIZER_FREEBSD || SANITIZER_SOLARIS
+  internal_syscall(SYSCALL(exit), exitcode);
+#else
+  internal_syscall(SYSCALL(exit_group), exitcode);
+#endif
+  Die();  // Unreachable.
+}
+#endif  // !SANITIZER_NETBSD
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
   if (ShouldMockFailureToOpen(filename))
@@ -512,8 +513,6 @@ tid_t GetTid() {
   long Tid;
   thr_self(&Tid);
   return Tid;
-#elif SANITIZER_OPENBSD
-  return internal_syscall(SYSCALL(getthrid));
 #elif SANITIZER_SOLARIS
   return thr_self();
 #elif SANITIZER_EMSCRIPTEN
@@ -529,9 +528,6 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
   return internal_syscall(SYSCALL(tgkill), pid, tid, sig);
 #elif SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig);
-#elif SANITIZER_OPENBSD
-  (void)pid;
-  return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr);
 #elif SANITIZER_SOLARIS
   (void)pid;
   return thr_kill(tid, sig);
@@ -542,7 +538,7 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
 
 #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN
 u64 NanoTime() {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD
   timeval tv;
 #else
   kernel_timeval tv;
@@ -569,8 +565,7 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
 // 'environ' array (on some others) and does not use libc. This function
 // should be called first inside __asan_init.
 const char *GetEnv(const char *name) {
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \
-    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
   if (::environ != 0) {
     uptr NameLen = internal_strlen(name);
     for (char **Env = ::environ; *Env != 0; Env++) {
@@ -608,14 +603,13 @@ const char *GetEnv(const char *name) {
 #endif
 }
 
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
 extern "C" {
 SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
 }
 #endif
 
-#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD &&                \
-    !SANITIZER_OPENBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
 static void ReadNullSepFileToArray(const char *path, char ***arr,
                                    int arr_size) {
   char *buff;
@@ -640,7 +634,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
 }
 #endif
 
-#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
+#if !SANITIZER_EMSCRIPTEN
 static void GetArgsAndEnv(char ***argv, char ***envp) {
 #if SANITIZER_FREEBSD
   // On FreeBSD, retrieving the argument and environment arrays is done via the
@@ -660,16 +654,21 @@ static void GetArgsAndEnv(char ***argv, char ***envp) {
 #else // SANITIZER_FREEBSD
 #if !SANITIZER_GO
   if (&__libc_stack_end) {
-#endif // !SANITIZER_GO
     uptr* stack_end = (uptr*)__libc_stack_end;
-    int argc = *stack_end;
+    // Normally argc can be obtained from *stack_end, however, on ARM glibc's
+    // _start clobbers it:
+    // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
+    // Do not special-case ARM and infer argc from argv everywhere.
+    int argc = 0;
+    while (stack_end[argc + 1]) argc++;
     *argv = (char**)(stack_end + 1);
     *envp = (char**)(stack_end + argc + 2);
-#if !SANITIZER_GO
   } else {
+#endif // !SANITIZER_GO
     static const int kMaxArgv = 2000, kMaxEnvp = 2000;
     ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
     ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
+#if !SANITIZER_GO
   }
 #endif // !SANITIZER_GO
 #endif // SANITIZER_FREEBSD
@@ -687,7 +686,7 @@ char **GetEnviron() {
   return envp;
 }
 
-#endif  // !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN
+#endif // !SANITIZER_EMSCRIPTEN
 
 #if !SANITIZER_SOLARIS
 enum MutexState {
@@ -748,19 +747,9 @@ void BlockingMutex::CheckLocked() {
 // 32-bit syscall here.
 #if SANITIZER_NETBSD
 // Not used
-#elif SANITIZER_OPENBSD
-// struct dirent is different for Linux and us. At this moment, we use only
-// d_fileno (Linux call this d_ino), d_reclen, and d_name.
-struct linux_dirent {
-  u64 d_ino;  // d_fileno
-  u16 d_reclen;
-  u16 d_namlen;  // not used
-  u8 d_type;     // not used
-  char d_name[NAME_MAX + 1];
-};
 #else
 struct linux_dirent {
-#if SANITIZER_X32 || defined(__aarch64__)
+#if SANITIZER_X32 || defined(__aarch64__) || SANITIZER_RISCV64
   u64 d_ino;
   u64 d_off;
 #else
@@ -768,7 +757,7 @@ struct linux_dirent {
   unsigned long      d_off;
 #endif
   unsigned short     d_reclen;
-#ifdef __aarch64__
+#if defined(__aarch64__) || SANITIZER_RISCV64
   unsigned char      d_type;
 #endif
   char               d_name[256];
@@ -797,6 +786,14 @@ uptr internal_getppid() {
   return internal_syscall(SYSCALL(getppid));
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+#if SANITIZER_FREEBSD
+  return dlinfo(handle, request, p);
+#else
+  UNIMPLEMENTED();
+#endif
+}
+
 uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
 #if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
@@ -839,28 +836,39 @@ int internal_fork() {
 #endif
 }
 
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD
 int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
                     uptr *oldlenp, const void *newp, uptr newlen) {
-#if SANITIZER_OPENBSD
-  return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp,
-                (size_t)newlen);
-#else
   return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp,
                           (size_t *)oldlenp, newp, (size_t)newlen);
-#endif
 }
 
-#if SANITIZER_FREEBSD
 int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
                           const void *newp, uptr newlen) {
-  static decltype(sysctlbyname) *real = nullptr;
-  if (!real)
-    real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname");
-  CHECK(real);
-  return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen);
-}
+  // Note: this function can be called during startup, so we need to avoid
+  // calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname()
+  // is a real syscall, but for older versions it calls sysctlnametomib()
+  // followed by sysctl(). To avoid calling the intercepted version and
+  // asserting if this happens during startup, call the real sysctlnametomib()
+  // followed by internal_sysctl() if the syscall is not available.
+#ifdef SYS___sysctlbyname
+  return internal_syscall(SYSCALL(__sysctlbyname), sname,
+                          internal_strlen(sname), oldp, (size_t *)oldlenp, newp,
+                          (size_t)newlen);
+#else
+  static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr;
+  if (!real_sysctlnametomib)
+    real_sysctlnametomib =
+        (decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib");
+  CHECK(real_sysctlnametomib);
+
+  int oid[CTL_MAXNAME];
+  size_t len = CTL_MAXNAME;
+  if (real_sysctlnametomib(sname, oid, &len) == -1)
+    return (-1);
+  return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen);
 #endif
+}
 #endif
 
 #if SANITIZER_LINUX
@@ -914,16 +922,15 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
 
 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
                           __sanitizer_sigset_t *oldset) {
-#if SANITIZER_FREEBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
 #elif SANITIZER_EMSCRIPTEN
   return NULL;
 #else
   __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
   __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
-  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
-                          (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
-                          sizeof(__sanitizer_kernel_sigset_t));
+  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set,
+                          (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t));
 #endif
 }
 
@@ -1080,9 +1087,8 @@ static uptr GetKernelAreaSize() {
   // is modified (e.g. under schroot) so check this as well.
   struct utsname uname_info;
   int pers = personality(0xffffffffUL);
-  if (!(pers & PER_MASK)
-      && uname(&uname_info) == 0
-      && internal_strstr(uname_info.machine, "64"))
+  if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
+      internal_strstr(uname_info.machine, "64"))
     return 0;
 #endif  // SANITIZER_ANDROID
 
@@ -1095,7 +1101,7 @@ static uptr GetKernelAreaSize() {
 #endif  // SANITIZER_WORDSIZE == 32
 
 uptr GetMaxVirtualAddress() {
-#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__)
+#if SANITIZER_NETBSD && defined(__x86_64__)
   return 0x7f7ffffff000ULL;  // (0x00007f8000000000 - PAGE_SIZE)
 #elif SANITIZER_WORDSIZE == 64
 # if defined(__powerpc64__) || defined(__aarch64__)
@@ -1107,6 +1113,8 @@ uptr GetMaxVirtualAddress() {
   // This should (does) work for both PowerPC64 Endian modes.
   // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
   return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
+#elif SANITIZER_RISCV64
+  return (1ULL << 38) - 1;
 # elif defined(__mips64)
   return (1ULL << 40) - 1;  // 0x000000ffffffffffUL;
 # elif defined(__s390x__)
@@ -1137,7 +1145,8 @@ uptr GetMaxUserVirtualAddress() {
 
 #if !SANITIZER_ANDROID
 uptr GetPageSize() {
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
+    defined(EXEC_PAGESIZE)
   return EXEC_PAGESIZE;
 #elif SANITIZER_FREEBSD || SANITIZER_NETBSD
 // Use sysctl as sysconf can trigger interceptors internally.
@@ -1157,7 +1166,6 @@ uptr GetPageSize() {
 extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len);
 #endif
 
-#if !SANITIZER_OPENBSD
 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
 #if SANITIZER_SOLARIS
   const char *default_module_name = getexecname();
@@ -1196,7 +1204,6 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
   return module_name_len;
 #endif
 }
-#endif // !SANITIZER_OPENBSD
 
 uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
 #if SANITIZER_LINUX
@@ -1229,10 +1236,10 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
 // Call cb for each region mapped by map.
 void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   CHECK_NE(map, nullptr);
-#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
+#if !SANITIZER_FREEBSD
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
-#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
+#endif // !SANITIZER_FREEBSD
   char *base = (char *)map->l_addr;
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
@@ -1404,6 +1411,55 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                        : "memory", "$29" );
   return res;
 }
+#elif SANITIZER_RISCV64
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+                    int *parent_tidptr, void *newtls, int *child_tidptr) {
+  long long res;
+  if (!fn || !child_stack)
+    return -EINVAL;
+  CHECK_EQ(0, (uptr)child_stack % 16);
+  child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+  ((unsigned long long *)child_stack)[0] = (uptr)fn;
+  ((unsigned long long *)child_stack)[1] = (uptr)arg;
+
+  register int (*__fn)(void *) __asm__("a0") = fn;
+  register void *__stack __asm__("a1") = child_stack;
+  register int __flags __asm__("a2") = flags;
+  register void *__arg __asm__("a3") = arg;
+  register int *__ptid __asm__("a4") = parent_tidptr;
+  register void *__tls __asm__("a5") = newtls;
+  register int *__ctid __asm__("a6") = child_tidptr;
+
+  __asm__ __volatile__(
+      "mv a0,a2\n"          /* flags  */
+      "mv a2,a4\n"          /* ptid  */
+      "mv a3,a5\n"          /* tls  */
+      "mv a4,a6\n"          /* ctid  */
+      "addi a7, zero, %9\n" /* clone  */
+
+      "ecall\n"
+
+      /* if (%r0 != 0)
+       *   return %r0;
+       */
+      "bnez a0, 1f\n"
+
+      /* In the child, now. Call "fn(arg)". */
+      "ld  a0,  8(sp)\n"
+      "ld  a1, 16(sp)\n"
+      "jalr a1\n"
+
+      /* Call _exit(%r0).  */
+      "addi  a7, zero, %10\n"
+      "ecall\n"
+      "1:\n"
+
+      : "=r"(res)
+      : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
+        "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
+      : "ra", "memory");
+  return res;
+}
 #elif defined(__aarch64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr) {
@@ -1697,6 +1753,12 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
 }
 #endif  // defined(__x86_64__) && SANITIZER_LINUX
 
+#if SANITIZER_LINUX
+int internal_uname(struct utsname *buf) {
+  return internal_syscall(SYSCALL(uname), buf);
+}
+#endif
+
 #if SANITIZER_ANDROID
 #if __ANDROID_API__ < 21
 extern "C" __attribute__((weak)) int dl_iterate_phdr(
@@ -1779,7 +1841,7 @@ HandleSignalMode GetHandleSignalMode(int signum) {
 }
 
 #if !SANITIZER_GO
-void *internal_start_thread(void(*func)(void *arg), void *arg) {
+void *internal_start_thread(void *(*func)(void *arg), void *arg) {
   // Start the thread with signals blocked, otherwise it can steal user signals.
   __sanitizer_sigset_t set, old;
   internal_sigfillset(&set);
@@ -1790,7 +1852,7 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) {
 #endif
   internal_sigprocmask(SIG_SETMASK, &set, &old);
   void *th;
-  real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg);
+  real_pthread_create(&th, nullptr, func, arg);
   internal_sigprocmask(SIG_SETMASK, &old, nullptr);
   return th;
 }
@@ -1799,7 +1861,7 @@ void internal_join_thread(void *th) {
   real_pthread_join(th, nullptr);
 }
 #else
-void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
+void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
 
 void internal_join_thread(void *th) {}
 #endif
@@ -1827,11 +1889,7 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
 }
 #endif
 
-#if SANITIZER_OPENBSD
-using Context = sigcontext;
-#else
 using Context = ucontext_t;
-#endif
 
 SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
   Context *ucontext = (Context *)context;
@@ -1841,8 +1899,6 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
   uptr err = ucontext->uc_mcontext.mc_err;
 #elif SANITIZER_NETBSD
   uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
-#elif SANITIZER_OPENBSD
-  uptr err = ucontext->sc_err;
 #elif SANITIZER_SOLARIS && defined(__i386__)
   const int Err = 13;
   uptr err = ucontext->uc_mcontext.gregs[Err];
@@ -1924,6 +1980,105 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
 #endif
   u32 instr = *(u32 *)pc;
   return (instr >> 21) & 1 ? WRITE: READ;
+#elif defined(__riscv)
+  unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
+  unsigned faulty_instruction = *(uint16_t *)pc;
+
+#if defined(__riscv_compressed)
+  if ((faulty_instruction & 0x3) != 0x3) {  // it's a compressed instruction
+    // set op_bits to the instruction bits [1, 0, 15, 14, 13]
+    unsigned op_bits =
+        ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13);
+    unsigned rd = faulty_instruction & 0xF80;  // bits 7-11, inclusive
+    switch (op_bits) {
+      case 0b10'010:  // c.lwsp (rd != x0)
+#if __riscv_xlen == 64
+      case 0b10'011:  // c.ldsp (rd != x0)
+#endif
+        return rd ? SignalContext::READ : SignalContext::UNKNOWN;
+      case 0b00'010:  // c.lw
+#if __riscv_flen >= 32 && __riscv_xlen == 32
+      case 0b10'011:  // c.flwsp
+#endif
+#if __riscv_flen >= 32 || __riscv_xlen == 64
+      case 0b00'011:  // c.flw / c.ld
+#endif
+#if __riscv_flen == 64
+      case 0b00'001:  // c.fld
+      case 0b10'001:  // c.fldsp
+#endif
+        return SignalContext::READ;
+      case 0b00'110:  // c.sw
+      case 0b10'110:  // c.swsp
+#if __riscv_flen >= 32 || __riscv_xlen == 64
+      case 0b00'111:  // c.fsw / c.sd
+      case 0b10'111:  // c.fswsp / c.sdsp
+#endif
+#if __riscv_flen == 64
+      case 0b00'101:  // c.fsd
+      case 0b10'101:  // c.fsdsp
+#endif
+        return SignalContext::WRITE;
+      default:
+        return SignalContext::UNKNOWN;
+    }
+  }
+#endif
+
+  unsigned opcode = faulty_instruction & 0x7f;         // lower 7 bits
+  unsigned funct3 = (faulty_instruction >> 12) & 0x7;  // bits 12-14, inclusive
+  switch (opcode) {
+    case 0b0000011:  // loads
+      switch (funct3) {
+        case 0b000:  // lb
+        case 0b001:  // lh
+        case 0b010:  // lw
+#if __riscv_xlen == 64
+        case 0b011:  // ld
+#endif
+        case 0b100:  // lbu
+        case 0b101:  // lhu
+          return SignalContext::READ;
+        default:
+          return SignalContext::UNKNOWN;
+      }
+    case 0b0100011:  // stores
+      switch (funct3) {
+        case 0b000:  // sb
+        case 0b001:  // sh
+        case 0b010:  // sw
+#if __riscv_xlen == 64
+        case 0b011:  // sd
+#endif
+          return SignalContext::WRITE;
+        default:
+          return SignalContext::UNKNOWN;
+      }
+#if __riscv_flen >= 32
+    case 0b0000111:  // floating-point loads
+      switch (funct3) {
+        case 0b010:  // flw
+#if __riscv_flen == 64
+        case 0b011:  // fld
+#endif
+          return SignalContext::READ;
+        default:
+          return SignalContext::UNKNOWN;
+      }
+    case 0b0100111:  // floating-point stores
+      switch (funct3) {
+        case 0b010:  // fsw
+#if __riscv_flen == 64
+        case 0b011:  // fsd
+#endif
+          return SignalContext::WRITE;
+        default:
+          return SignalContext::UNKNOWN;
+      }
+#endif
+    default:
+      return SignalContext::UNKNOWN;
+  }
 #else
   (void)ucontext;
   return UNKNOWN;  // FIXME: Implement.
@@ -1969,11 +2124,6 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
   *pc = ucontext->uc_mcontext.mc_rip;
   *bp = ucontext->uc_mcontext.mc_rbp;
   *sp = ucontext->uc_mcontext.mc_rsp;
-#elif SANITIZER_OPENBSD
-  sigcontext *ucontext = (sigcontext *)context;
-  *pc = ucontext->sc_rip;
-  *bp = ucontext->sc_rbp;
-  *sp = ucontext->sc_rsp;
 # else
   ucontext_t *ucontext = (ucontext_t*)context;
   *pc = ucontext->uc_mcontext.gregs[REG_RIP];
@@ -1986,11 +2136,6 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
   *pc = ucontext->uc_mcontext.mc_eip;
   *bp = ucontext->uc_mcontext.mc_ebp;
   *sp = ucontext->uc_mcontext.mc_esp;
-#elif SANITIZER_OPENBSD
-  sigcontext *ucontext = (sigcontext *)context;
-  *pc = ucontext->sc_eip;
-  *bp = ucontext->sc_ebp;
-  *sp = ucontext->sc_esp;
 # else
   ucontext_t *ucontext = (ucontext_t*)context;
 # if SANITIZER_SOLARIS
@@ -2002,13 +2147,13 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
 # ifndef REG_EBP
 #  define REG_EBP  6 // REG_FP
 # endif
-# ifndef REG_ESP
-#  define REG_ESP 17 // REG_SP
+# ifndef REG_UESP
+#  define REG_UESP 17 // REG_SP
 # endif
 # endif
   *pc = ucontext->uc_mcontext.gregs[REG_EIP];
   *bp = ucontext->uc_mcontext.gregs[REG_EBP];
-  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
+  *sp = ucontext->uc_mcontext.gregs[REG_UESP];
 # endif
 #elif defined(__powerpc__) || defined(__powerpc64__)
   ucontext_t *ucontext = (ucontext_t*)context;
@@ -2087,7 +2232,9 @@ void CheckASLR() {
   }
 
   if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
-    Printf("This sanitizer is not compatible with enabled ASLR\n");
+    Printf("This sanitizer is not compatible with enabled ASLR.\n"
+           "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
+           GetArgv()[0]);
     Die();
   }
 #elif SANITIZER_PPC64V2
@@ -2159,14 +2306,12 @@ void CheckMPROTECT() {
 #endif
 }
 
-void PrintModuleMap() { }
-
 void CheckNoDeepBind(const char *filename, int flag) {
 #ifdef RTLD_DEEPBIND
   if (flag & RTLD_DEEPBIND) {
     Report(
         "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag"
-        " which is incompatibe with sanitizer runtime "
+        " which is incompatible with sanitizer runtime "
         "(see https://github.com/google/sanitizers/issues/611 for details"
         "). If you want to run %s library under sanitizers please remove "
         "RTLD_DEEPBIND from dlopen flags.\n",
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
index d73b539c3cdb8..bb432f75aa86a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h
@@ -14,17 +14,17 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+    SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_freebsd.h"
 #include "sanitizer_platform_limits_netbsd.h"
-#include "sanitizer_platform_limits_openbsd.h"
 #include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_platform_limits_solaris.h"
 #include "sanitizer_posix.h"
 
 struct link_map;  // Opaque type returned by dlopen().
+struct utsname;
 
 namespace __sanitizer {
 // Dirent structure for getdents(). Note that this structure is different from
@@ -59,12 +59,13 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
 // internal_sigaction instead.
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
-  || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \
-  || defined(__arm__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
+    defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
+    defined(__arm__) || SANITIZER_RISCV64
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr);
 #endif
+int internal_uname(struct utsname *buf);
 #elif SANITIZER_FREEBSD
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
 #elif SANITIZER_NETBSD
@@ -107,7 +108,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
 // Releases memory pages entirely within the [beg, end] address range.
 // The pages no longer count toward RSS; reads are guaranteed to return 0.
 // Requires (but does not verify!) that pages are MAP_PRIVATE.
-INLINE void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) {
+inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) {
   // man madvise on Linux promises zero-fill for anonymous private pages.
   // Testing shows the same behaviour for private (but not anonymous) mappings
   // of shm_open() files, as long as the underlying file is untouched.
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
index edbe8402808a8..f20b9001c2c20 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -13,8 +13,8 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
+    SANITIZER_SOLARIS
 
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_atomic.h"
@@ -28,6 +28,10 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
+#if SANITIZER_NETBSD
+#define _RTLD_SOURCE  // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
+#endif
+
 #include <dlfcn.h>  // for dlsym()
 #include <link.h>
 #include <pthread.h>
@@ -35,6 +39,10 @@
 #include <sys/resource.h>
 #include <syslog.h>
 
+#if !defined(ElfW)
+#define ElfW(type) Elf_##type
+#endif
+
 #if SANITIZER_FREEBSD
 #include <pthread_np.h>
 #include <osreldate.h>
@@ -42,11 +50,6 @@
 #define pthread_getattr_np pthread_attr_get_np
 #endif
 
-#if SANITIZER_OPENBSD
-#include <pthread_np.h>
-#include <sys/sysctl.h>
-#endif
-
 #if SANITIZER_NETBSD
 #include <sys/sysctl.h>
 #include <sys/tls.h>
@@ -134,18 +137,13 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
   CHECK_EQ(thr_stksegment(&ss), 0);
   stacksize = ss.ss_size;
   stackaddr = (char *)ss.ss_sp - stacksize;
-#elif SANITIZER_OPENBSD
-  stack_t sattr;
-  CHECK_EQ(pthread_stackseg_np(pthread_self(), &sattr), 0);
-  stackaddr = sattr.ss_sp;
-  stacksize = sattr.ss_size;
 #else  // !SANITIZER_SOLARIS
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
   my_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
   pthread_attr_destroy(&attr);
-#endif // SANITIZER_SOLARIS
+#endif  // SANITIZER_SOLARIS
 
   *stack_top = (uptr)stackaddr + stacksize;
   *stack_bottom = (uptr)stackaddr;
@@ -185,20 +183,19 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
 #endif
 }
 
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&               \
-    !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS
+#if SANITIZER_GLIBC && !SANITIZER_GO
 static uptr g_tls_size;
 
 #ifdef __i386__
-# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
+#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
 #else
-# define CHECK_GET_TLS_STATIC_INFO_VERSION 0
+#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
 #endif
 
 #if CHECK_GET_TLS_STATIC_INFO_VERSION
-# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
+#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
 #else
-# define DL_INTERNAL_FUNCTION
+#define DL_INTERNAL_FUNCTION
 #endif
 
 namespace {
@@ -258,12 +255,11 @@ void InitTlsSize() {
 }
 #else
 void InitTlsSize() { }
-#endif  // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&
-        // !SANITIZER_NETBSD && !SANITIZER_SOLARIS
+#endif  // SANITIZER_GLIBC && !SANITIZER_GO
 
-#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) ||          \
-     defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) ||    \
-     defined(__arm__)) &&                                                      \
+#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) ||       \
+     defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
+     defined(__arm__) || SANITIZER_RISCV64) &&                              \
     SANITIZER_LINUX && !SANITIZER_ANDROID
 // sizeof(struct pthread) from glibc.
 static atomic_uintptr_t thread_descriptor_size;
@@ -297,12 +293,29 @@ uptr ThreadDescriptorSize() {
       val = FIRST_32_SECOND_64(1168, 2288);
     else if (minor <= 14)
       val = FIRST_32_SECOND_64(1168, 2304);
-    else
+    else if (minor < 32)  // Unknown version
       val = FIRST_32_SECOND_64(1216, 2304);
+    else  // minor == 32
+      val = FIRST_32_SECOND_64(1344, 2496);
   }
 #elif defined(__mips__)
   // TODO(sagarthakur): add more values as per different glibc versions.
   val = FIRST_32_SECOND_64(1152, 1776);
+#elif SANITIZER_RISCV64
+  int major;
+  int minor;
+  int patch;
+  if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
+    // TODO: consider adding an optional runtime check for an unknown (untested)
+    // glibc version
+    if (minor <= 28)  // WARNING: the highest tested version is 2.29
+      val = 1772;     // no guarantees for this one
+    else if (minor <= 31)
+      val = 1772;  // tested against glibc 2.29, 2.31
+    else
+      val = 1936;  // tested against glibc 2.32
+  }
+
 #elif defined(__aarch64__)
   // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
   val = 1776;
@@ -323,15 +336,17 @@ uptr ThreadSelfOffset() {
   return kThreadSelfOffset;
 }
 
-#if defined(__mips__) || defined(__powerpc64__)
+#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
 // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
 // head structure. It lies before the static tls blocks.
 static uptr TlsPreTcbSize() {
-# if defined(__mips__)
+#if defined(__mips__)
   const uptr kTcbHead = 16; // sizeof (tcbhead_t)
-# elif defined(__powerpc64__)
+#elif defined(__powerpc64__)
   const uptr kTcbHead = 88; // sizeof (tcbhead_t)
-# endif
+#elif SANITIZER_RISCV64
+  const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
+#endif
   const uptr kTlsAlign = 16;
   const uptr kTlsPreTcbSize =
       RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
@@ -341,11 +356,11 @@ static uptr TlsPreTcbSize() {
 
 uptr ThreadSelf() {
   uptr descr_addr;
-# if defined(__i386__)
+#if defined(__i386__)
   asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-# elif defined(__x86_64__)
+#elif defined(__x86_64__)
   asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-# elif defined(__mips__)
+#elif defined(__mips__)
   // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
   // points to the end of the TCB + 0x7000. The pthread_descr structure is
   // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
@@ -357,12 +372,16 @@ uptr ThreadSelf() {
                 rdhwr %0,$29;\
                 .set pop" : "=r" (thread_pointer));
   descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
-# elif defined(__aarch64__) || defined(__arm__)
+#elif defined(__aarch64__) || defined(__arm__)
   descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
                                       ThreadDescriptorSize();
-# elif defined(__s390__)
+#elif SANITIZER_RISCV64
+  // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
+  uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
+  descr_addr = thread_pointer - TlsPreTcbSize();
+#elif defined(__s390__)
   descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
-# elif defined(__powerpc64__)
+#elif defined(__powerpc64__)
   // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
   // points to the end of the TCB + 0x7000. The pthread_descr structure is
   // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
@@ -371,9 +390,9 @@ uptr ThreadSelf() {
   uptr thread_pointer;
   asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
   descr_addr = thread_pointer - TlsPreTcbSize();
-# else
-#  error "unsupported CPU arch"
-# endif
+#else
+#error "unsupported CPU arch"
+#endif
   return descr_addr;
 }
 #endif  // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
@@ -381,15 +400,15 @@ uptr ThreadSelf() {
 #if SANITIZER_FREEBSD
 static void **ThreadSelfSegbase() {
   void **segbase = 0;
-# if defined(__i386__)
+#if defined(__i386__)
   // sysarch(I386_GET_GSBASE, segbase);
   __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
-# elif defined(__x86_64__)
+#elif defined(__x86_64__)
   // sysarch(AMD64_GET_FSBASE, segbase);
   __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
-# else
-#  error "unsupported CPU arch"
-# endif
+#else
+#error "unsupported CPU arch"
+#endif
   return segbase;
 }
 
@@ -400,7 +419,13 @@ uptr ThreadSelf() {
 
 #if SANITIZER_NETBSD
 static struct tls_tcb * ThreadSelfTlsTcb() {
-  return (struct tls_tcb *)_lwp_getprivate();
+  struct tls_tcb *tcb = nullptr;
+#ifdef __HAVE___LWP_GETTCB_FAST
+  tcb = (struct tls_tcb *)__lwp_gettcb_fast();
+#elif defined(__HAVE___LWP_GETPRIVATE_FAST)
+  tcb = (struct tls_tcb *)__lwp_getprivate_fast();
+#endif
+  return tcb;
 }
 
 uptr ThreadSelf() {
@@ -421,22 +446,40 @@ int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
 }
 #endif  // SANITIZER_NETBSD
 
+#if SANITIZER_ANDROID
+// Bionic provides this API since S.
+extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **,
+                                                                      void **);
+#endif
+
 #if !SANITIZER_GO
 static void GetTls(uptr *addr, uptr *size) {
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-# if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
+#if SANITIZER_ANDROID
+  if (&__libc_get_static_tls_bounds) {
+    void *start_addr;
+    void *end_addr;
+    __libc_get_static_tls_bounds(&start_addr, &end_addr);
+    *addr = reinterpret_cast<uptr>(start_addr);
+    *size =
+        reinterpret_cast<uptr>(end_addr) - reinterpret_cast<uptr>(start_addr);
+  } else {
+    *addr = 0;
+    *size = 0;
+  }
+#elif SANITIZER_LINUX
+#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
   *addr = ThreadSelf();
   *size = GetTlsSize();
   *addr -= *size;
   *addr += ThreadDescriptorSize();
-# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \
-    || defined(__arm__)
+#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
+    defined(__arm__) || SANITIZER_RISCV64
   *addr = ThreadSelf();
   *size = GetTlsSize();
-# else
+#else
   *addr = 0;
   *size = 0;
-# endif
+#endif
 #elif SANITIZER_FREEBSD
   void** segbase = ThreadSelfSegbase();
   *addr = 0;
@@ -464,34 +507,32 @@ static void GetTls(uptr *addr, uptr *size) {
       *addr = (uptr)tcb->tcb_dtv[1];
     }
   }
-#elif SANITIZER_OPENBSD
-  *addr = 0;
-  *size = 0;
-#elif SANITIZER_ANDROID
-  *addr = 0;
-  *size = 0;
 #elif SANITIZER_SOLARIS
   // FIXME
   *addr = 0;
   *size = 0;
 #else
-# error "Unknown OS"
+#error "Unknown OS"
 #endif
 }
 #endif
 
 #if !SANITIZER_GO
 uptr GetTlsSize() {
-#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD ||              \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
+    SANITIZER_SOLARIS
   uptr addr, size;
   GetTls(&addr, &size);
   return size;
-#elif defined(__mips__) || defined(__powerpc64__)
+#elif SANITIZER_GLIBC
+#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
   return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
 #else
   return g_tls_size;
 #endif
+#else
+  return 0;
+#endif
 }
 #endif
 
@@ -520,13 +561,13 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
 #endif
 }
 
-#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
+#if !SANITIZER_FREEBSD
 typedef ElfW(Phdr) Elf_Phdr;
-#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2
+#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001  // v9.2
 #define Elf_Phdr XElf32_Phdr
 #define dl_phdr_info xdl_phdr_info
 #define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
-#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD
+#endif  // !SANITIZER_FREEBSD
 
 struct DlIteratePhdrData {
   InternalMmapVectorNoCtor<LoadedModule> *modules;
@@ -646,7 +687,7 @@ uptr GetRSS() {
 // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as
 // they allocate memory.
 u32 GetNumberOfCPUs() {
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
   u32 ncpu;
   int req[2];
   uptr len = sizeof(ncpu);
@@ -701,7 +742,7 @@ u32 GetNumberOfCPUs() {
 
 #if SANITIZER_LINUX
 
-# if SANITIZER_ANDROID
+#if SANITIZER_ANDROID
 static atomic_uint8_t android_log_initialized;
 
 void AndroidLogInit() {
@@ -745,7 +786,7 @@ void SetAbortMessage(const char *str) {
   if (&android_set_abort_message)
     android_set_abort_message(str);
 }
-# else
+#else
 void AndroidLogInit() {}
 
 static bool ShouldLogAfterPrintf() { return true; }
@@ -753,7 +794,7 @@ static bool ShouldLogAfterPrintf() { return true; }
 void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); }
 
 void SetAbortMessage(const char *str) {}
-# endif  // SANITIZER_ANDROID
+#endif  // SANITIZER_ANDROID
 
 void LogMessageOnPrintf(const char *str) {
   if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
@@ -768,7 +809,7 @@ void LogMessageOnPrintf(const char *str) {
 // initialized after the vDSO function pointers, so if it exists, is not null
 // and is not empty, we can use clock_gettime.
 extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
-INLINE bool CanUseVDSO() {
+inline bool CanUseVDSO() {
   // Bionic is safe, it checks for the vDSO function pointers to be initialized.
   if (SANITIZER_ANDROID)
     return true;
@@ -803,7 +844,6 @@ u64 MonotonicNanoTime() {
 }
 #endif  // SANITIZER_LINUX && !SANITIZER_GO
 
-#if !SANITIZER_OPENBSD
 void ReExec() {
   const char *pathname = "/proc/self/exe";
 
@@ -835,7 +875,48 @@ void ReExec() {
   Printf("execve failed, errno %d\n", rverrno);
   Die();
 }
-#endif  // !SANITIZER_OPENBSD
+
+void UnmapFromTo(uptr from, uptr to) {
+  if (to == from)
+    return;
+  CHECK(to >= from);
+  uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
+  if (UNLIKELY(internal_iserror(res))) {
+    Report("ERROR: %s failed to unmap 0x%zx (%zd) bytes at address %p\n",
+           SanitizerToolName, to - from, to - from, (void *)from);
+    CHECK("unable to unmap" && 0);
+  }
+}
+
+uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
+                      uptr min_shadow_base_alignment,
+                      UNUSED uptr &high_mem_end) {
+  const uptr granularity = GetMmapGranularity();
+  const uptr alignment =
+      Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
+  const uptr left_padding =
+      Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
+
+  const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
+  const uptr map_size = shadow_size + left_padding + alignment;
+
+  const uptr map_start = (uptr)MmapNoAccess(map_size);
+  CHECK_NE(map_start, ~(uptr)0);
+
+  const uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
+
+  UnmapFromTo(map_start, shadow_start - left_padding);
+  UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
+
+  return shadow_start;
+}
+
+void InitializePlatformCommonFlags(CommonFlags *cf) {
+#if SANITIZER_ANDROID
+  if (&__libc_get_static_tls_bounds == nullptr)
+    cf->detect_leaks = false;
+#endif
+}
 
 } // namespace __sanitizer
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp
index 9e3b4f13a4365..bb2f5b5f9f7df 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp
@@ -15,14 +15,15 @@
 
 #if SANITIZER_LINUX && SANITIZER_S390
 
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
-
+#include <dlfcn.h>
 #include <errno.h>
 #include <sys/syscall.h>
 #include <sys/utsname.h>
 #include <unistd.h>
 
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+
 namespace __sanitizer {
 
 // --------------- sanitizer_libc.h
@@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() {
   struct utsname buf;
   unsigned int major, minor, patch = 0;
   // This should never fail, but just in case...
-  if (uname(&buf))
+  if (internal_uname(&buf))
     return false;
   const char *ptr = buf.release;
   major = internal_simple_strtoll(ptr, &ptr, 10);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
index ea4bd02aa92e4..2b53d7d730d7e 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
@@ -27,9 +27,9 @@
 #include "sanitizer_flags.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
 #include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_ptrauth.h"
 
 #if !SANITIZER_IOS
 #include <crt_externs.h>  // for _NSGetEnviron
@@ -137,6 +137,10 @@ int internal_mprotect(void *addr, uptr length, int prot) {
   return mprotect(addr, length, prot);
 }
 
+int internal_madvise(uptr addr, uptr length, int advice) {
+  return madvise((void *)addr, length, advice);
+}
+
 uptr internal_close(fd_t fd) {
   return close(fd);
 }
@@ -208,6 +212,10 @@ uptr internal_getpid() {
   return getpid();
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  UNIMPLEMENTED();
+}
+
 int internal_sigaction(int signum, const void *act, void *oldact) {
   return sigaction(signum,
                    (const struct sigaction *)act, (struct sigaction *)oldact);
@@ -242,7 +250,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
                       (size_t)newlen);
 }
 
-static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
+static fd_t internal_spawn_impl(const char *argv[], const char *envp[],
+                                pid_t *pid) {
   fd_t master_fd = kInvalidFd;
   fd_t slave_fd = kInvalidFd;
 
@@ -298,8 +307,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
 
   // posix_spawn
   char **argv_casted = const_cast<char **>(argv);
-  char **env = GetEnviron();
-  res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env);
+  char **envp_casted = const_cast<char **>(envp);
+  res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
   if (res != 0) return kInvalidFd;
 
   // Disable echo in the new terminal, disable CR.
@@ -316,7 +325,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) {
   return fd;
 }
 
-fd_t internal_spawn(const char *argv[], pid_t *pid) {
+fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {
   // The client program may close its stdin and/or stdout and/or stderr thus
   // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this
   // case the communication is broken if either the parent or the child tries to
@@ -331,7 +340,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) {
       break;
   }
 
-  fd_t fd = internal_spawn_impl(argv, pid);
+  fd_t fd = internal_spawn_impl(argv, envp, pid);
 
   for (; count > 0; count--) {
     internal_close(low_fds[count]);
@@ -382,7 +391,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
   // pthread_get_stacksize_np() returns an incorrect stack size for the main
   // thread on Mavericks. See
   // https://github.com/google/sanitizers/issues/261
-  if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
+  if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization &&
       stacksize == (1 << 19))  {
     struct rlimit rl;
     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
@@ -601,68 +610,132 @@ HandleSignalMode GetHandleSignalMode(int signum) {
   return result;
 }
 
-MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
+// Offset example:
+// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4
+constexpr u16 GetOSMajorKernelOffset() {
+  if (TARGET_OS_OSX) return 4;
+  if (TARGET_OS_IOS || TARGET_OS_TV) return 6;
+  if (TARGET_OS_WATCH) return 13;
+}
+
+using VersStr = char[64];
+
+static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
+  u16 kernel_major = GetDarwinKernelVersion().major;
+  u16 offset = GetOSMajorKernelOffset();
+  CHECK_GE(kernel_major, offset);
+  u16 os_major = kernel_major - offset;
+
+  const char *format = "%d.0";
+  if (TARGET_OS_OSX) {
+    if (os_major >= 16) {  // macOS 11+
+      os_major -= 5;
+    } else {  // macOS 10.15 and below
+      format = "10.%d";
+    }
+  }
+  return internal_snprintf(vers, sizeof(VersStr), format, os_major);
+}
 
-MacosVersion GetMacosVersionInternal() {
-  int mib[2] = { CTL_KERN, KERN_OSRELEASE };
-  char version[100];
-  uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
-  for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
-  // Get the version length.
-  CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1);
-  CHECK_LT(len, maxlen);
-  CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1);
+static void GetOSVersion(VersStr vers) {
+  uptr len = sizeof(VersStr);
+  if (SANITIZER_IOSSIM) {
+    const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION");
+    if (!vers_env) {
+      Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env "
+          "var is not set.\n");
+      Die();
+    }
+    len = internal_strlcpy(vers, vers_env, len);
+  } else {
+    int res =
+        internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
+
+    // XNU 17 (macOS 10.13) and below do not provide the sysctl
+    // `kern.osproductversion` entry (res != 0).
+    bool no_os_version = res != 0;
+
+    // For launchd, sanitizer initialization runs before sysctl is setup
+    // (res == 0 && len != strlen(vers), vers is not a valid version).  However,
+    // the kernel version `kern.osrelease` is available.
+    bool launchd = (res == 0 && internal_strlen(vers) < 3);
+    if (launchd) CHECK_EQ(internal_getpid(), 1);
+
+    if (no_os_version || launchd) {
+      len = ApproximateOSVersionViaKernelVersion(vers);
+    }
+  }
+  CHECK_LT(len, sizeof(VersStr));
+}
 
-  // Expect <major>.<minor>(.<patch>)
-  CHECK_GE(len, 3);
-  const char *p = version;
-  int major = internal_simple_strtoll(p, &p, /*base=*/10);
-  if (*p != '.') return MACOS_VERSION_UNKNOWN;
+void ParseVersion(const char *vers, u16 *major, u16 *minor) {
+  // Format: <major>.<minor>[.<patch>]\0
+  CHECK_GE(internal_strlen(vers), 3);
+  const char *p = vers;
+  *major = internal_simple_strtoll(p, &p, /*base=*/10);
+  CHECK_EQ(*p, '.');
   p += 1;
-  int minor = internal_simple_strtoll(p, &p, /*base=*/10);
-  if (*p != '.') return MACOS_VERSION_UNKNOWN;
-
-  switch (major) {
-    case 9: return MACOS_VERSION_LEOPARD;
-    case 10: return MACOS_VERSION_SNOW_LEOPARD;
-    case 11: return MACOS_VERSION_LION;
-    case 12: return MACOS_VERSION_MOUNTAIN_LION;
-    case 13: return MACOS_VERSION_MAVERICKS;
-    case 14: return MACOS_VERSION_YOSEMITE;
-    case 15: return MACOS_VERSION_EL_CAPITAN;
-    case 16: return MACOS_VERSION_SIERRA;
-    case 17:
-      // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4.
-      if (minor >= 5)
-        return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
-      return MACOS_VERSION_HIGH_SIERRA;
-    case 18: return MACOS_VERSION_MOJAVE;
-    case 19: return MACOS_VERSION_CATALINA;
-    default:
-      if (major < 9) return MACOS_VERSION_UNKNOWN;
-      return MACOS_VERSION_UNKNOWN_NEWER;
+  *minor = internal_simple_strtoll(p, &p, /*base=*/10);
+}
+
+// Aligned versions example:
+// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6
+static void MapToMacos(u16 *major, u16 *minor) {
+  if (TARGET_OS_OSX)
+    return;
+
+  if (TARGET_OS_IOS || TARGET_OS_TV)
+    *major += 2;
+  else if (TARGET_OS_WATCH)
+    *major += 9;
+  else
+    UNREACHABLE("unsupported platform");
+
+  if (*major >= 16) {  // macOS 11+
+    *major -= 5;
+  } else {  // macOS 10.15 and below
+    *minor = *major;
+    *major = 10;
   }
 }
 
-MacosVersion GetMacosVersion() {
-  atomic_uint32_t *cache =
-      reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
-  MacosVersion result =
-      static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
-  if (result == MACOS_VERSION_UNINITIALIZED) {
-    result = GetMacosVersionInternal();
-    atomic_store(cache, result, memory_order_release);
+static MacosVersion GetMacosAlignedVersionInternal() {
+  VersStr vers = {};
+  GetOSVersion(vers);
+
+  u16 major, minor;
+  ParseVersion(vers, &major, &minor);
+  MapToMacos(&major, &minor);
+
+  return MacosVersion(major, minor);
+}
+
+static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type),
+              "MacosVersion cache size");
+static atomic_uint32_t cached_macos_version;
+
+MacosVersion GetMacosAlignedVersion() {
+  atomic_uint32_t::Type result =
+      atomic_load(&cached_macos_version, memory_order_acquire);
+  if (!result) {
+    MacosVersion version = GetMacosAlignedVersionInternal();
+    result = *reinterpret_cast<atomic_uint32_t::Type *>(&version);
+    atomic_store(&cached_macos_version, result, memory_order_release);
   }
-  return result;
+  return *reinterpret_cast<MacosVersion *>(&result);
 }
 
-bool PlatformHasDifferentMemcpyAndMemmove() {
-  // On OS X 10.7 memcpy() and memmove() are both resolved
-  // into memmove$VARIANT$sse42.
-  // See also https://github.com/google/sanitizers/issues/34.
-  // TODO(glider): need to check dynamically that memcpy() and memmove() are
-  // actually the same function.
-  return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
+DarwinKernelVersion GetDarwinKernelVersion() {
+  VersStr vers = {};
+  uptr len = sizeof(VersStr);
+  int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
+  CHECK_EQ(res, 0);
+  CHECK_LT(len, sizeof(VersStr));
+
+  u16 major, minor;
+  ParseVersion(vers, &major, &minor);
+
+  return DarwinKernelVersion(major, minor);
 }
 
 uptr GetRSS() {
@@ -677,13 +750,13 @@ uptr GetRSS() {
   return info.resident_size;
 }
 
-void *internal_start_thread(void(*func)(void *arg), void *arg) {
+void *internal_start_thread(void *(*func)(void *arg), void *arg) {
   // Start the thread with signals blocked, otherwise it can steal user signals.
   __sanitizer_sigset_t set, old;
   internal_sigfillset(&set);
   internal_sigprocmask(SIG_SETMASK, &set, &old);
   pthread_t th;
-  pthread_create(&th, 0, (void*(*)(void *arg))func, arg);
+  pthread_create(&th, 0, func, arg);
   internal_sigprocmask(SIG_SETMASK, &old, 0);
   return th;
 }
@@ -711,7 +784,7 @@ void LogFullErrorReport(const char *buffer) {
 #if !SANITIZER_GO
   // Log with os_trace. This will make it into the crash log.
 #if SANITIZER_OS_TRACE
-  if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) {
+  if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) {
     // os_trace requires the message (format parameter) to be a string literal.
     if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
                          sizeof("AddressSanitizer") - 1) == 0)
@@ -760,16 +833,24 @@ bool SignalContext::IsTrueFaultingAddress() const {
   return si->si_signo == SIGSEGV && si->si_code != 0;
 }
 
+#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
+  #define AARCH64_GET_REG(r) \
+    (uptr)ptrauth_strip(     \
+        (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
+#else
+  #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r
+#endif
+
 static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
   ucontext_t *ucontext = (ucontext_t*)context;
 # if defined(__aarch64__)
-  *pc = ucontext->uc_mcontext->__ss.__pc;
+  *pc = AARCH64_GET_REG(pc);
 #   if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
-  *bp = ucontext->uc_mcontext->__ss.__fp;
+  *bp = AARCH64_GET_REG(fp);
 #   else
-  *bp = ucontext->uc_mcontext->__ss.__lr;
+  *bp = AARCH64_GET_REG(lr);
 #   endif
-  *sp = ucontext->uc_mcontext->__ss.__sp;
+  *sp = AARCH64_GET_REG(sp);
 # elif defined(__x86_64__)
   *pc = ucontext->uc_mcontext->__ss.__rip;
   *bp = ucontext->uc_mcontext->__ss.__rbp;
@@ -787,16 +868,34 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
 # endif
 }
 
-void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
+void SignalContext::InitPcSpBp() {
+  addr = (uptr)ptrauth_strip((void *)addr, 0);
+  GetPcSpBp(context, &pc, &sp, &bp);
+}
+
+// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers
+// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).
+static void DisableMmapExcGuardExceptions() {
+  using task_exc_guard_behavior_t = uint32_t;
+  using task_set_exc_guard_behavior_t =
+      kern_return_t(task_t task, task_exc_guard_behavior_t behavior);
+  auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym(
+      RTLD_DEFAULT, "task_set_exc_guard_behavior");
+  if (set_behavior == nullptr) return;
+  const task_exc_guard_behavior_t task_exc_guard_none = 0;
+  set_behavior(mach_task_self(), task_exc_guard_none);
+}
 
 void InitializePlatformEarly() {
-  // Only use xnu_fast_mmap when on x86_64 and the OS supports it.
+  // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
   use_xnu_fast_mmap =
 #if defined(__x86_64__)
-      GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4;
+      GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
 #else
       false;
 #endif
+  if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0))
+    DisableMmapExcGuardExceptions();
 }
 
 #if !SANITIZER_GO
@@ -837,20 +936,10 @@ bool ReexecDisabled() {
   return false;
 }
 
-extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber;
-static const double kMinDyldVersionWithAutoInterposition = 360.0;
-
-bool DyldNeedsEnvVariable() {
-  // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users
-  // still may want use them on older systems. On older Darwin platforms, dyld
-  // doesn't export dyldVersionNumber symbol and we simply return true.
-  if (!&dyldVersionNumber) return true;
+static bool DyldNeedsEnvVariable() {
   // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
-  // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via
-  // GetMacosVersion() doesn't work for the simulator. Let's instead check
-  // `dyldVersionNumber`, which is exported by dyld, against a known version
-  // number from the first OS release where this appeared.
-  return dyldVersionNumber < kMinDyldVersionWithAutoInterposition;
+  // DYLD_INSERT_LIBRARIES is not set.
+  return GetMacosAlignedVersion() < MacosVersion(10, 11);
 }
 
 void MaybeReexec() {
@@ -996,7 +1085,7 @@ char **GetArgv() {
   return *_NSGetArgv();
 }
 
-#if SANITIZER_IOS
+#if SANITIZER_IOS && !SANITIZER_IOSSIM
 // The task_vm_info struct is normally provided by the macOS SDK, but we need
 // fields only available in 10.12+. Declare the struct manually to be able to
 // build against older SDKs.
@@ -1063,6 +1152,53 @@ uptr GetMaxVirtualAddress() {
   return GetMaxUserVirtualAddress();
 }
 
+uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
+                      uptr min_shadow_base_alignment, uptr &high_mem_end) {
+  const uptr granularity = GetMmapGranularity();
+  const uptr alignment =
+      Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
+  const uptr left_padding =
+      Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
+
+  uptr space_size = shadow_size_bytes + left_padding;
+
+  uptr largest_gap_found = 0;
+  uptr max_occupied_addr = 0;
+  VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size);
+  uptr shadow_start =
+      FindAvailableMemoryRange(space_size, alignment, granularity,
+                               &largest_gap_found, &max_occupied_addr);
+  // If the shadow doesn't fit, restrict the address space to make it fit.
+  if (shadow_start == 0) {
+    VReport(
+        2,
+        "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",
+        largest_gap_found, max_occupied_addr);
+    uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment);
+    if (new_max_vm < max_occupied_addr) {
+      Report("Unable to find a memory range for dynamic shadow.\n");
+      Report(
+          "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, "
+          "new_max_vm = %p\n",
+          space_size, largest_gap_found, max_occupied_addr, new_max_vm);
+      CHECK(0 && "cannot place shadow");
+    }
+    RestrictMemoryToMaxAddress(new_max_vm);
+    high_mem_end = new_max_vm - 1;
+    space_size = (high_mem_end >> shadow_scale) + left_padding;
+    VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size);
+    shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity,
+                                            nullptr, nullptr);
+    if (shadow_start == 0) {
+      Report("Unable to find a memory range after restricting VM.\n");
+      CHECK(0 && "cannot place shadow after restricting vm");
+    }
+  }
+  CHECK_NE((uptr)0, shadow_start);
+  CHECK(IsAligned(shadow_start, alignment));
+  return shadow_start;
+}
+
 uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
                               uptr *largest_gap_found,
                               uptr *max_occupied_addr) {
@@ -1123,6 +1259,8 @@ void SignalContext::DumpAllRegisters(void *context) {
   ucontext_t *ucontext = (ucontext_t*)context;
 # define DUMPREG64(r) \
     Printf("%s = 0x%016llx  ", #r, ucontext->uc_mcontext->__ss.__ ## r);
+# define DUMPREGA64(r) \
+    Printf("   %s = 0x%016llx  ", #r, AARCH64_GET_REG(r));
 # define DUMPREG32(r) \
     Printf("%s = 0x%08x  ", #r, ucontext->uc_mcontext->__ss.__ ## r);
 # define DUMPREG_(r)   Printf(" "); DUMPREG(r);
@@ -1148,7 +1286,7 @@ void SignalContext::DumpAllRegisters(void *context) {
   DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
   DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
   DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
-  DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n");
+  DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");
 # elif defined(__arm__)
 #  define DUMPREG(r) DUMPREG32(r)
   DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
@@ -1181,7 +1319,7 @@ void FormatUUID(char *out, uptr size, const u8 *uuid) {
                     uuid[12], uuid[13], uuid[14], uuid[15]);
 }
 
-void PrintModuleMap() {
+void DumpProcessMap() {
   Printf("Process module map:\n");
   MemoryMappingLayout memory_mapping(false);
   InternalMmapVector<LoadedModule> modules;
@@ -1214,6 +1352,8 @@ u32 GetNumberOfCPUs() {
   return (u32)sysconf(_SC_NPROCESSORS_ONLN);
 }
 
+void InitializePlatformCommonFlags(CommonFlags *cf) {}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_MAC
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
index 2257883084ea9..023071e4f11de 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_mac.h
@@ -30,25 +30,33 @@ struct MemoryMappingLayoutData {
   bool current_instrumented;
 };
 
-enum MacosVersion {
-  MACOS_VERSION_UNINITIALIZED = 0,
-  MACOS_VERSION_UNKNOWN,
-  MACOS_VERSION_LEOPARD,
-  MACOS_VERSION_SNOW_LEOPARD,
-  MACOS_VERSION_LION,
-  MACOS_VERSION_MOUNTAIN_LION,
-  MACOS_VERSION_MAVERICKS,
-  MACOS_VERSION_YOSEMITE,
-  MACOS_VERSION_EL_CAPITAN,
-  MACOS_VERSION_SIERRA,
-  MACOS_VERSION_HIGH_SIERRA,
-  MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4,
-  MACOS_VERSION_MOJAVE,
-  MACOS_VERSION_CATALINA,
-  MACOS_VERSION_UNKNOWN_NEWER
+template <typename VersionType>
+struct VersionBase {
+  u16 major;
+  u16 minor;
+
+  VersionBase(u16 major, u16 minor) : major(major), minor(minor) {}
+
+  bool operator==(const VersionType &other) const {
+    return major == other.major && minor == other.minor;
+  }
+  bool operator>=(const VersionType &other) const {
+    return major > other.major ||
+           (major == other.major && minor >= other.minor);
+  }
+  bool operator<(const VersionType &other) const { return !(*this >= other); }
+};
+
+struct MacosVersion : VersionBase<MacosVersion> {
+  MacosVersion(u16 major, u16 minor) : VersionBase(major, minor) {}
+};
+
+struct DarwinKernelVersion : VersionBase<DarwinKernelVersion> {
+  DarwinKernelVersion(u16 major, u16 minor) : VersionBase(major, minor) {}
 };
 
-MacosVersion GetMacosVersion();
+MacosVersion GetMacosAlignedVersion();
+DarwinKernelVersion GetDarwinKernelVersion();
 
 char **GetEnviron();
 
@@ -67,7 +75,7 @@ asm(".desc ___crashreporter_info__, 0x10");
 namespace __sanitizer {
 static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
 
-INLINE void CRAppendCrashLogMessage(const char *msg) {
+inline void CRAppendCrashLogMessage(const char *msg) {
   BlockingMutexLock l(&crashreporter_info_mutex);
   internal_strlcat(__crashreporter_info_buff__, msg,
                    sizeof(__crashreporter_info_buff__)); }
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
index 11adbe5c25b4b..647bcdfe105e6 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
@@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
   malloc_zone_t *new_zone = (malloc_zone_t *)p;
   internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone));
   new_zone->zone_name = NULL;  // The name will be changed anyway.
-  if (GetMacosVersion() >= MACOS_VERSION_LION) {
-    // Prevent the client app from overwriting the zone contents.
-    // Library functions that need to modify the zone will set PROT_WRITE on it.
-    // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
-    mprotect(new_zone, allocated_size, PROT_READ);
-  }
+  // Prevent the client app from overwriting the zone contents.
+  // Library functions that need to modify the zone will set PROT_WRITE on it.
+  // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
+  mprotect(new_zone, allocated_size, PROT_READ);
   // We're explicitly *NOT* registering the zone.
   return new_zone;
 }
@@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {
   COMMON_MALLOC_ENTER();
   // We don't need to do anything here.  We're not registering new zones, so we
   // don't to unregister.  Just un-mprotect and free() the zone.
-  if (GetMacosVersion() >= MACOS_VERSION_LION) {
-    uptr page_size = GetPageSizeCached();
-    uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
-    mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
-  }
+  uptr page_size = GetPageSizeCached();
+  uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
+  mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
   if (zone->zone_name) {
     COMMON_MALLOC_FREE((void *)zone->zone_name);
   }
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp
index 49a951e04b374..98ac7365da051 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_netbsd.cpp
@@ -110,6 +110,11 @@ int internal_mprotect(void *addr, uptr length, int prot) {
   return _REAL(mprotect, addr, length, prot);
 }
 
+int internal_madvise(uptr addr, uptr length, int advice) {
+  DEFINE__REAL(int, madvise, void *a, uptr b, int c);
+  return _REAL(madvise, (void *)addr, length, advice);
+}
+
 uptr internal_close(fd_t fd) {
   CHECK(&_sys_close);
   return _sys_close(fd);
@@ -265,6 +270,11 @@ uptr internal_getppid() {
   return _REAL(getppid);
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  DEFINE__REAL(int, dlinfo, void *a, int b, void *c);
+  return _REAL(dlinfo, handle, request, p);
+}
+
 uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) {
   DEFINE__REAL(int, __getdents30, int a, void *b, size_t c);
   return _REAL(__getdents30, fd, dirp, count);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp
index ed2d8edeb7a2c..e69de29bb2d1d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_openbsd.cpp
@@ -1,115 +0,0 @@
-//===-- sanitizer_openbsd.cpp ---------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is shared between various sanitizers' runtime libraries and
-// implements Solaris-specific functions.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_OPENBSD
-
-#include <stdio.h>
-
-#include "sanitizer_common.h"
-#include "sanitizer_flags.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_platform_limits_posix.h"
-#include "sanitizer_procmaps.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pthread.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/shm.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-extern char **environ;
-
-namespace __sanitizer {
-
-uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd,
-                   u64 offset) {
-  return (uptr)mmap(addr, length, prot, flags, fd, offset);
-}
-
-uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); }
-
-int internal_mprotect(void *addr, uptr length, int prot) {
-  return mprotect(addr, length, prot);
-}
-
-int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
-                          const void *newp, uptr newlen) {
-  Printf("internal_sysctlbyname not implemented for OpenBSD");
-  Die();
-  return 0;
-}
-
-uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
-  // On OpenBSD we cannot get the full path
-  struct kinfo_proc kp;
-  uptr kl;
-  const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
-  if (internal_sysctl(Mib, ARRAY_SIZE(Mib), &kp, &kl, NULL, 0) != -1)
-    return internal_snprintf(buf,
-                             (KI_MAXCOMLEN < buf_len ? KI_MAXCOMLEN : buf_len),
-                             "%s", kp.p_comm);
-  return (uptr)0;
-}
-
-static void GetArgsAndEnv(char ***argv, char ***envp) {
-  uptr nargv;
-  uptr nenv;
-  int argvmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV};
-  int envmib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ENV};
-  if (internal_sysctl(argvmib, 4, NULL, &nargv, NULL, 0) == -1) {
-    Printf("sysctl KERN_PROC_NARGV failed\n");
-    Die();
-  }
-  if (internal_sysctl(envmib, 4, NULL, &nenv, NULL, 0) == -1) {
-    Printf("sysctl KERN_PROC_NENV failed\n");
-    Die();
-  }
-  if (internal_sysctl(argvmib, 4, &argv, &nargv, NULL, 0) == -1) {
-    Printf("sysctl KERN_PROC_ARGV failed\n");
-    Die();
-  }
-  if (internal_sysctl(envmib, 4, &envp, &nenv, NULL, 0) == -1) {
-    Printf("sysctl KERN_PROC_ENV failed\n");
-    Die();
-  }
-}
-
-char **GetArgv() {
-  char **argv, **envp;
-  GetArgsAndEnv(&argv, &envp);
-  return argv;
-}
-
-char **GetEnviron() {
-  char **argv, **envp;
-  GetArgsAndEnv(&argv, &envp);
-  return envp;
-}
-
-void ReExec() {
-  UNIMPLEMENTED();
-}
-
-}  // namespace __sanitizer
-
-#endif  // SANITIZER_OPENBSD
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
index 6d098e3a78269..79cb5a2a5deec 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform.h
@@ -13,18 +13,31 @@
 #define SANITIZER_PLATFORM_H
 
 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
-  !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \
+  !defined(__APPLE__) && !defined(_WIN32) && \
   !defined(__Fuchsia__) && !defined(__rtems__) && \
   !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__)
 # error "This operating system is not supported"
 #endif
 
+// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
+// function declarations into a .S file which doesn't compile.
+// https://crbug.com/1162741
+#if __has_include(<features.h>) && !defined(__ANDROID__)
+#include <features.h>
+#endif
+
 #if defined(__linux__)
 # define SANITIZER_LINUX   1
 #else
 # define SANITIZER_LINUX   0
 #endif
 
+#if defined(__GLIBC__)
+# define SANITIZER_GLIBC   1
+#else
+# define SANITIZER_GLIBC   0
+#endif
+
 #if defined(__FreeBSD__)
 # define SANITIZER_FREEBSD 1
 #else
@@ -37,12 +50,6 @@
 # define SANITIZER_NETBSD 0
 #endif
 
-#if defined(__OpenBSD__)
-# define SANITIZER_OPENBSD 1
-#else
-# define SANITIZER_OPENBSD 0
-#endif
-
 #if defined(__sun__) && defined(__svr4__)
 # define SANITIZER_SOLARIS 1
 #else
@@ -118,8 +125,7 @@
 
 #define SANITIZER_POSIX \
   (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \
-    SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS || \
-    SANITIZER_EMSCRIPTEN)
+    SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN)
 
 #if __LP64__ || defined(_WIN64)
 #  define SANITIZER_WORDSIZE 64
@@ -139,6 +145,12 @@
 # define SANITIZER_X32 0
 #endif
 
+#if defined(__i386__) || defined(_M_IX86)
+# define SANITIZER_I386 1
+#else
+# define SANITIZER_I386 0
+#endif
+
 #if defined(__mips__)
 # define SANITIZER_MIPS 1
 # if defined(__mips64)
@@ -220,6 +232,12 @@
 # define SANITIZER_MYRIAD2 0
 #endif
 
+#if defined(__riscv) && (__riscv_xlen == 64)
+#define SANITIZER_RISCV64 1
+#else
+#define SANITIZER_RISCV64 0
+#endif
+
 // By default we allow to use SizeClassAllocator64 on 64-bit platform.
 // But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
 // does not work well and we need to fallback to SizeClassAllocator32.
@@ -239,7 +257,13 @@
 // FIXME: this value should be different on different platforms.  Larger values
 // will still work but will consume more memory for TwoLevelByteMap.
 #if defined(__mips__)
+#if SANITIZER_GO && defined(__mips64)
+#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+#else
 # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
+#endif
+#elif SANITIZER_RISCV64
+#define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
 #elif defined(__aarch64__)
 # if SANITIZER_MAC
 // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
@@ -332,7 +356,7 @@
 #endif
 
 #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD || \
-  SANITIZER_OPENBSD || SANITIZER_SOLARIS
+  SANITIZER_SOLARIS
 # define SANITIZER_MADVISE_DONTNEED MADV_FREE
 #else
 # define SANITIZER_MADVISE_DONTNEED MADV_DONTNEED
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 658259830f3d1..ee08024e06987 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -15,127 +15,127 @@
 
 #include "sanitizer_glibc_version.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
 
 #if SANITIZER_POSIX
-# define SI_POSIX 1
+#define SI_POSIX 1
 #else
-# define SI_POSIX 0
+#define SI_POSIX 0
 #endif
 
 #if !SANITIZER_WINDOWS
-# define SI_WINDOWS 0
+#define SI_WINDOWS 0
 #else
-# define SI_WINDOWS 1
+#define SI_WINDOWS 1
 #endif
 
 #if SI_WINDOWS && SI_POSIX
-# error "Windows is not POSIX!"
+#error "Windows is not POSIX!"
 #endif
 
 #if SI_POSIX
-# include "sanitizer_platform_limits_freebsd.h"
-# include "sanitizer_platform_limits_netbsd.h"
-# include "sanitizer_platform_limits_openbsd.h"
-# include "sanitizer_platform_limits_posix.h"
-# include "sanitizer_platform_limits_solaris.h"
+#include "sanitizer_platform_limits_freebsd.h"
+#include "sanitizer_platform_limits_netbsd.h"
+#include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_platform_limits_solaris.h"
 #endif
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-# define SI_LINUX_NOT_ANDROID 1
+#define SI_LINUX_NOT_ANDROID 1
 #else
-# define SI_LINUX_NOT_ANDROID 0
+#define SI_LINUX_NOT_ANDROID 0
 #endif
 
-#if SANITIZER_ANDROID
-# define SI_ANDROID 1
+#if SANITIZER_GLIBC
+#define SI_GLIBC 1
 #else
-# define SI_ANDROID 0
+#define SI_GLIBC 0
 #endif
 
-#if SANITIZER_FREEBSD
-# define SI_FREEBSD 1
+#if SANITIZER_ANDROID
+#define SI_ANDROID 1
 #else
-# define SI_FREEBSD 0
+#define SI_ANDROID 0
 #endif
 
-#if SANITIZER_NETBSD
-# define SI_NETBSD 1
+#if SANITIZER_FREEBSD
+#define SI_FREEBSD 1
 #else
-# define SI_NETBSD 0
+#define SI_FREEBSD 0
 #endif
 
-#if SANITIZER_OPENBSD
-#define SI_OPENBSD 1
+#if SANITIZER_NETBSD
+#define SI_NETBSD 1
 #else
-#define SI_OPENBSD 0
+#define SI_NETBSD 0
 #endif
 
 #if SANITIZER_LINUX
-# define SI_LINUX 1
+#define SI_LINUX 1
 #else
-# define SI_LINUX 0
+#define SI_LINUX 0
 #endif
 
 #if SANITIZER_MAC
-# define SI_MAC 1
-# define SI_NOT_MAC 0
+#define SI_MAC 1
+#define SI_NOT_MAC 0
 #else
-# define SI_MAC 0
-# define SI_NOT_MAC 1
+#define SI_MAC 0
+#define SI_NOT_MAC 1
 #endif
 
 #if SANITIZER_IOS
-# define SI_IOS 1
+#define SI_IOS 1
 #else
-# define SI_IOS 0
+#define SI_IOS 0
 #endif
 
 #if SANITIZER_IOSSIM
-# define SI_IOSSIM 1
+#define SI_IOSSIM 1
 #else
-# define SI_IOSSIM 0
+#define SI_IOSSIM 0
 #endif
 
 #if SANITIZER_WATCHOS
-# define SI_WATCHOS 1
+#define SI_WATCHOS 1
 #else
-# define SI_WATCHOS 0
+#define SI_WATCHOS 0
 #endif
 
 #if SANITIZER_TVOS
-# define SI_TVOS 1
+#define SI_TVOS 1
 #else
-# define SI_TVOS 0
+#define SI_TVOS 0
 #endif
 
 #if SANITIZER_FUCHSIA
-# define SI_NOT_FUCHSIA 0
+#define SI_NOT_FUCHSIA 0
 #else
-# define SI_NOT_FUCHSIA 1
+#define SI_NOT_FUCHSIA 1
 #endif
 
 #if SANITIZER_RTEMS
-# define SI_NOT_RTEMS 0
+#define SI_NOT_RTEMS 0
 #else
-# define SI_NOT_RTEMS 1
+#define SI_NOT_RTEMS 1
 #endif
 
 #if SANITIZER_SOLARIS
-# define SI_SOLARIS 1
+#define SI_SOLARIS 1
 #else
-# define SI_SOLARIS 0
+#define SI_SOLARIS 0
 #endif
 
 #if SANITIZER_SOLARIS32
-# define SI_SOLARIS32 1
+#define SI_SOLARIS32 1
 #else
-# define SI_SOLARIS32 0
+#define SI_SOLARIS32 0
 #endif
 
 #if SANITIZER_POSIX && !SANITIZER_MAC
-# define SI_POSIX_NOT_MAC 1
+#define SI_POSIX_NOT_MAC 1
 #else
-# define SI_POSIX_NOT_MAC 0
+#define SI_POSIX_NOT_MAC 0
 #endif
 
 #if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN
@@ -145,9 +145,9 @@
 #endif
 
 #if SANITIZER_LINUX && !SANITIZER_FREEBSD
-# define SI_LINUX_NOT_FREEBSD 1
-# else
-# define SI_LINUX_NOT_FREEBSD 0
+#define SI_LINUX_NOT_FREEBSD 1
+#else
+#define SI_LINUX_NOT_FREEBSD 0
 #endif
 
 #if SANITIZER_EMSCRIPTEN
@@ -175,21 +175,20 @@
 #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_BCMP \
   SANITIZER_INTERCEPT_MEMCMP &&  \
-      ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
+      ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
-#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
+#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
 #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
-# define SI_MAC_DEPLOYMENT_BELOW_10_7 1
+#define SI_MAC_DEPLOYMENT_BELOW_10_7 1
 #else
-# define SI_MAC_DEPLOYMENT_BELOW_10_7 0
+#define SI_MAC_DEPLOYMENT_BELOW_10_7 0
 #endif
 // memmem on Darwin doesn't exist on 10.6
 // FIXME: enable memmem on Windows.
 #define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7)
 #define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA
-#define SANITIZER_INTERCEPT_MEMRCHR \
-  (SI_FREEBSD || SI_LINUX || SI_NETBSD || SI_OPENBSD)
+#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD)
 
 #define SANITIZER_INTERCEPT_READ SI_POSIX
 #define SANITIZER_INTERCEPT_PREAD SI_POSIX
@@ -202,63 +201,60 @@
 #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
 #define SANITIZER_INTERCEPT_PUTS SI_POSIX
 
-#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
-#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
 
 #define SANITIZER_INTERCEPT_READV SI_POSIX
 #define SANITIZER_INTERCEPT_WRITEV SI_POSIX
 
 #define SANITIZER_INTERCEPT_PREADV \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
+#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
 
-#define SANITIZER_INTERCEPT_PRCTL   SI_LINUX
+#define SANITIZER_INTERCEPT_PRCTL SI_LINUX
 
 #define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX
 #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
 
 #define SANITIZER_INTERCEPT_SCANF SI_POSIX
-#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
 
 #ifndef SANITIZER_INTERCEPT_PRINTF
-# define SANITIZER_INTERCEPT_PRINTF SI_POSIX
-# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
-# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PRINTF SI_POSIX
+#define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
+#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
 #endif
 
 #define SANITIZER_INTERCEPT___PRINTF_CHK \
-  (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
+  (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
 
 #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
 
 #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX
-#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS                            \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
-#define SANITIZER_INTERCEPT_GETPWENT                                          \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
-#define SANITIZER_INTERCEPT_FGETGRENT_R                                       \
-  (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GETPWENT \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_GETPWENT_R \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_FGETPWENT_R \
-  (SI_FREEBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_SETPWENT \
   (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_CLOCK_GETTIME \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
 #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
 #define SANITIZER_INTERCEPT_TIME SI_POSIX
-#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
 #define SANITIZER_INTERCEPT_WAIT SI_POSIX
 #define SANITIZER_INTERCEPT_INET SI_POSIX
-#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM (SI_POSIX && !SI_OPENBSD)
+#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
 #define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX
 #define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX
 #define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX
@@ -270,28 +266,27 @@
   (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
   (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_GETHOSTENT_R \
-  (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
 #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
-#define SANITIZER_INTERCEPT_ACCEPT4 \
-  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD)
+#define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
 #define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD
 #define SANITIZER_INTERCEPT_MODF SI_POSIX
 #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX
 #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX
 #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX
 #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX
+#define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX
 #define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN
 #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX
 #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
 #define SANITIZER_INTERCEPT_READDIR SI_POSIX
 #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
-#if SI_LINUX_NOT_ANDROID && \
-  (defined(__i386) || defined(__x86_64) || defined(__mips64) || \
-    defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-    defined(__s390__))
+#if SI_LINUX_NOT_ANDROID &&                                                \
+    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
+     defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+     defined(__s390__) || SANITIZER_RISCV64)
 #define SANITIZER_INTERCEPT_PTRACE 1
 #else
 #define SANITIZER_INTERCEPT_PTRACE 0
@@ -308,72 +303,68 @@
 #define SANITIZER_INTERCEPT___STRXFRM_L SI_LINUX
 #define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX
 #define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX
-#define SANITIZER_INTERCEPT_WCSNRTOMBS                                        \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
-#define SANITIZER_INTERCEPT_WCRTOMB                                           \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
-#define SANITIZER_INTERCEPT_WCTOMB                                           \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
+#define SANITIZER_INTERCEPT_WCSNRTOMBS \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_WCRTOMB \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_WCTOMB \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_REALPATH SI_POSIX
-#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
-  (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_CONFSTR                                           \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
+#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_CONFSTR \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN
 #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX
 #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SCANDIR \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
 #define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX
 #define SANITIZER_INTERCEPT_POLL SI_POSIX
 #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_WORDEXP \
+#define SANITIZER_INTERCEPT_WORDEXP                                          \
   (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID || \
-    SI_SOLARIS)
+   SI_SOLARIS)  // NOLINT
 #define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX
 #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_SIGSETOPS \
   (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_SIGSET_LOGICOPS SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX
 #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
 #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
 #define SANITIZER_INTERCEPT_BACKTRACE \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
 #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_STATFS \
   (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_STATFS64 \
-  ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID)
+  (((SI_MAC && !TARGET_CPU_ARM64) && !SI_IOS) || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_STATVFS \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX
-#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON (SI_POSIX && !SI_OPENBSD)
+#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX
 #define SANITIZER_INTERCEPT_ETHER_HOST \
   (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_SHMCTL                                       \
   (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
-   SI_NETBSD || SI_OPENBSD || SI_SOLARIS)  // NOLINT
-#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+   SI_NETBSD || SI_SOLARIS)  // NOLINT
+#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
 #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
 #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
   (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED (SI_POSIX && !SI_OPENBSD)
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
 #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
-  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD)
-#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE (SI_POSIX && !SI_OPENBSD)
+  (SI_POSIX && !SI_NETBSD)
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX
 #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \
   (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
@@ -382,17 +373,18 @@
   (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
-  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD)
-#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED \
-  (SI_POSIX && !SI_NETBSD && !SI_OPENBSD)
+  (SI_POSIX && !SI_NETBSD)
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
 #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
   (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED \
-  (SI_LINUX_NOT_ANDROID && !SI_NETBSD && !SI_OPENBSD)
+  (SI_LINUX_NOT_ANDROID && !SI_NETBSD)
 #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
 #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
-#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
+#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
+#define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
 #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
 #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX
 #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX
@@ -403,71 +395,67 @@
 #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
 #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
-#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_RAND_R                                            \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_LINUX_NOT_ANDROID || \
-  SI_SOLARIS)
+#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
+#define SANITIZER_INTERCEPT_RAND_R \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_ICONV \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_TIMES SI_POSIX
 
 // FIXME: getline seems to be available on OSX 10.7
 #define SANITIZER_INTERCEPT_GETLINE \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPT__EXIT \
-  (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_MAC || SI_SOLARIS)
+  (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
-#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
 #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
 #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
-  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
 #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX
 #define SANITIZER_INTERCEPT_GETRESID SI_LINUX
-#define SANITIZER_INTERCEPT_GETIFADDRS                                        \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \
-  SI_SOLARIS)
-#define SANITIZER_INTERCEPT_IF_INDEXTONAME                                    \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \
-  SI_SOLARIS)
+#define SANITIZER_INTERCEPT_GETIFADDRS \
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_IF_INDEXTONAME \
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
 #if SI_LINUX && defined(__arm__)
 #define SANITIZER_INTERCEPT_AEABI_MEM 1
 #else
 #define SANITIZER_INTERCEPT_AEABI_MEM 0
 #endif
-#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
 #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_FTIME \
-  (!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX)
-#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
+#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
+#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
 #define SANITIZER_INTERCEPT_TSEARCH \
-  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
+  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
 #define SANITIZER_INTERCEPT_FOPEN SI_POSIX
-#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
 #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
-  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
+  (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
 #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
 #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
 
 #ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
-#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE                                    \
-  (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_MAC || \
-  SI_SOLARIS)
+#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC || SI_SOLARIS)
 #endif
 
 #define SANITIZER_INTERCEPT_GETPASS \
-  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD)
+  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD)
 #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
 
 #define SANITIZER_INTERCEPT_MLOCKX SI_POSIX
@@ -475,21 +463,20 @@
 #define SANITIZER_INTERCEPT_SEM \
   (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX
-#define SANITIZER_INTERCEPT_MINCORE \
-  (SI_LINUX || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX
 #define SANITIZER_INTERCEPT_CTERMID \
-  (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
+  (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPTOR_HOOKS \
-  (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
+  (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
 #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
 #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
 
 #define SANITIZER_INTERCEPT_STAT \
-  (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
+  (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX)
 #define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID
@@ -502,41 +489,35 @@
   (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD)
 
 #define SANITIZER_INTERCEPT_GETLOADAVG \
-  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD || SI_OPENBSD)
+  (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD)
 
 #define SANITIZER_INTERCEPT_MMAP SI_POSIX
 #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
-  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \
-  SI_NOT_RTEMS)
+#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
 #define SANITIZER_INTERCEPT_MEMALIGN \
-  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS)
-#define SANITIZER_INTERCEPT_PVALLOC \
-  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \
-  SI_NOT_RTEMS)
-#define SANITIZER_INTERCEPT_CFREE \
-  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_FUCHSIA && \
-  SI_NOT_RTEMS)
+  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
+#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
+#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
+#define SANITIZER_INTERCEPT_CFREE SI_GLIBC
 #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
 #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
-#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \
-  (!SI_MAC && !SI_OPENBSD && !SI_NETBSD)
+#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
 #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX
 #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX
 #define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA)
 #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID
 
-#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
+#define SANITIZER_INTERCEPT_ACCT (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_USER_FROM_UID SI_NETBSD
 #define SANITIZER_INTERCEPT_UID_FROM_USER SI_NETBSD
 #define SANITIZER_INTERCEPT_GROUP_FROM_GID SI_NETBSD
 #define SANITIZER_INTERCEPT_GID_FROM_GROUP SI_NETBSD
-#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
-#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
-#define SANITIZER_INTERCEPT_GETGROUPLIST (SI_NETBSD || SI_OPENBSD)
-#define SANITIZER_INTERCEPT_STRLCPY                                            \
-  (SI_NETBSD || SI_FREEBSD || SI_OPENBSD || SI_MAC || SI_ANDROID)
+#define SANITIZER_INTERCEPT_ACCESS (SI_NETBSD || SI_FREEBSD)
+#define SANITIZER_INTERCEPT_FACCESSAT (SI_NETBSD || SI_FREEBSD)
+#define SANITIZER_INTERCEPT_GETGROUPLIST SI_NETBSD
+#define SANITIZER_INTERCEPT_STRLCPY \
+  (SI_NETBSD || SI_FREEBSD || SI_MAC || SI_ANDROID)
 
 #define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX_NOT_ANDROID
@@ -544,22 +525,23 @@
 #define SANITIZER_INTERCEPT_READLINK SI_POSIX
 #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000
-# define SI_MAC_DEPLOYMENT_BELOW_10_10 1
+#define SI_MAC_DEPLOYMENT_BELOW_10_10 1
 #else
-# define SI_MAC_DEPLOYMENT_BELOW_10_10 0
+#define SI_MAC_DEPLOYMENT_BELOW_10_10 0
 #endif
 #define SANITIZER_INTERCEPT_READLINKAT \
   (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_10)
 
-#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_OPENBSD || SI_FREEBSD)
+#define SANITIZER_INTERCEPT_DEVNAME (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_DEVNAME_R (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_FGETLN (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
-#define SANITIZER_INTERCEPT_PROTOENT SI_NETBSD
+#define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
+#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
 #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
-#define SANITIZER_INTERCEPT_SETVBUF (SI_NETBSD || SI_FREEBSD || \
-  SI_LINUX || SI_MAC)
+#define SANITIZER_INTERCEPT_SETVBUF \
+  (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
 #define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC)
 #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD
 #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD
@@ -606,7 +588,13 @@
 #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD
 #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD
 #define SANITIZER_INTERCEPT_QSORT \
-  (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS)
-#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID)
+  (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID)
+#define SANITIZER_INTERCEPT_QSORT_R SI_GLIBC
+// sigaltstack on i386 macOS cannot be intercepted due to setjmp()
+// calling it and assuming that it does not clobber registers.
+#define SANITIZER_INTERCEPT_SIGALTSTACK \
+  (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386))
+#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
+#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
 
 #endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
index 2d1bb1a12da6e..b1c15be58deaa 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
@@ -15,342 +15,346 @@
 
 #if SANITIZER_FREEBSD
 
+#include <sys/capsicum.h>
+#include <sys/consio.h>
+#include <sys/filio.h>
+#include <sys/ipc.h>
+#include <sys/kbio.h>
+#include <sys/link_elf.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/mqueue.h>
+#include <sys/msg.h>
+#include <sys/mtio.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/soundcard.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/timespec.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+//
 #include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip_mroute.h>
+//
 #include <dirent.h>
-#include <fts.h>
+#include <dlfcn.h>
 #include <fstab.h>
+#include <fts.h>
+#include <glob.h>
 #include <grp.h>
+#include <ifaddrs.h>
 #include <limits.h>
-#include <net/if.h>
-#include <netdb.h>
 #include <poll.h>
 #include <pthread.h>
 #include <pwd.h>
 #include <regex.h>
+#include <semaphore.h>
 #include <signal.h>
 #include <stddef.h>
-#include <sys/mman.h>
-#include <sys/capsicum.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <termios.h>
-#include <time.h>
-
-#include <net/route.h>
-#include <sys/mount.h>
-#include <sys/sockio.h>
-#include <sys/socket.h>
-#include <sys/filio.h>
-#include <sys/signal.h>
-#include <sys/timespec.h>
-#include <sys/timeb.h>
-#include <sys/mqueue.h>
-#include <sys/msg.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/statvfs.h>
-#include <sys/soundcard.h>
-#include <sys/mtio.h>
-#include <sys/consio.h>
-#include <sys/kbio.h>
-#include <sys/link_elf.h>
-#include <netinet/ip_mroute.h>
-#include <netinet/in.h>
-#include <net/ethernet.h>
-#include <net/ppp_defs.h>
-#include <glob.h>
 #include <stdio.h>
 #include <stringlist.h>
 #include <term.h>
+#include <termios.h>
+#include <time.h>
+#include <utime.h>
 #include <utmpx.h>
-#include <wchar.h>
 #include <vis.h>
+#include <wchar.h>
+#include <wordexp.h>
 
 #define _KERNEL  // to declare 'shminfo' structure
-# include <sys/shm.h>
+#include <sys/shm.h>
 #undef _KERNEL
 
-#undef INLINE  // to avoid clashes with sanitizers' definitions
-
 #undef IOC_DIRMASK
 
-# include <utime.h>
-# include <sys/ptrace.h>
-# include <semaphore.h>
-
-#include <ifaddrs.h>
-#include <sys/ucontext.h>
-#include <wordexp.h>
-
 // Include these after system headers to avoid name clashes and ambiguities.
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
 #include "sanitizer_platform_limits_freebsd.h"
 
 namespace __sanitizer {
-  unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
-  unsigned struct_utsname_sz = sizeof(struct utsname);
-  unsigned struct_stat_sz = sizeof(struct stat);
-  unsigned struct_rusage_sz = sizeof(struct rusage);
-  unsigned struct_tm_sz = sizeof(struct tm);
-  unsigned struct_passwd_sz = sizeof(struct passwd);
-  unsigned struct_group_sz = sizeof(struct group);
-  unsigned siginfo_t_sz = sizeof(siginfo_t);
-  unsigned struct_sigaction_sz = sizeof(struct sigaction);
-  unsigned struct_itimerval_sz = sizeof(struct itimerval);
-  unsigned pthread_t_sz = sizeof(pthread_t);
-  unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
-  unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
-  unsigned pid_t_sz = sizeof(pid_t);
-  unsigned timeval_sz = sizeof(timeval);
-  unsigned uid_t_sz = sizeof(uid_t);
-  unsigned gid_t_sz = sizeof(gid_t);
-  unsigned fpos_t_sz = sizeof(fpos_t);
-  unsigned mbstate_t_sz = sizeof(mbstate_t);
-  unsigned sigset_t_sz = sizeof(sigset_t);
-  unsigned struct_timezone_sz = sizeof(struct timezone);
-  unsigned struct_tms_sz = sizeof(struct tms);
-  unsigned struct_sigevent_sz = sizeof(struct sigevent);
-  unsigned struct_sched_param_sz = sizeof(struct sched_param);
-  unsigned struct_statfs_sz = sizeof(struct statfs);
-  unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
-  unsigned ucontext_t_sz = sizeof(ucontext_t);
-  unsigned struct_rlimit_sz = sizeof(struct rlimit);
-  unsigned struct_timespec_sz = sizeof(struct timespec);
-  unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
-  unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
-  unsigned struct_timeb_sz = sizeof(struct timeb);
-  unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
-  unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
-  unsigned struct_statvfs_sz = sizeof(struct statvfs);
-  unsigned struct_shminfo_sz = sizeof(struct shminfo);
-  unsigned struct_shm_info_sz = sizeof(struct shm_info);
-  unsigned struct_regmatch_sz = sizeof(regmatch_t);
-  unsigned struct_regex_sz = sizeof(regex_t);
-  unsigned struct_fstab_sz = sizeof(struct fstab);
-  unsigned struct_FTS_sz = sizeof(FTS);
-  unsigned struct_FTSENT_sz = sizeof(FTSENT);
-  unsigned struct_StringList_sz = sizeof(StringList);
-
-  const uptr sig_ign = (uptr)SIG_IGN;
-  const uptr sig_dfl = (uptr)SIG_DFL;
-  const uptr sig_err = (uptr)SIG_ERR;
-  const uptr sa_siginfo = (uptr)SA_SIGINFO;
-
-  int shmctl_ipc_stat = (int)IPC_STAT;
-  int shmctl_ipc_info = (int)IPC_INFO;
-  int shmctl_shm_info = (int)SHM_INFO;
-  int shmctl_shm_stat = (int)SHM_STAT;
-  unsigned struct_utmpx_sz = sizeof(struct utmpx);
-
-  int map_fixed = MAP_FIXED;
-
-  int af_inet = (int)AF_INET;
-  int af_inet6 = (int)AF_INET6;
-
-  uptr __sanitizer_in_addr_sz(int af) {
-    if (af == AF_INET)
-      return sizeof(struct in_addr);
-    else if (af == AF_INET6)
-      return sizeof(struct in6_addr);
-    else
-      return 0;
-  }
-
-  unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
-  int glob_nomatch = GLOB_NOMATCH;
-  int glob_altdirfunc = GLOB_ALTDIRFUNC;
-
-  unsigned path_max = PATH_MAX;
-
-  // ioctl arguments
-  unsigned struct_ifreq_sz = sizeof(struct ifreq);
-  unsigned struct_termios_sz = sizeof(struct termios);
-  unsigned struct_winsize_sz = sizeof(struct winsize);
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
+  void *p = nullptr;
+  return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
+}
+
+unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
+unsigned struct_utsname_sz = sizeof(struct utsname);
+unsigned struct_stat_sz = sizeof(struct stat);
+unsigned struct_rusage_sz = sizeof(struct rusage);
+unsigned struct_tm_sz = sizeof(struct tm);
+unsigned struct_passwd_sz = sizeof(struct passwd);
+unsigned struct_group_sz = sizeof(struct group);
+unsigned siginfo_t_sz = sizeof(siginfo_t);
+unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_stack_t_sz = sizeof(stack_t);
+unsigned struct_itimerval_sz = sizeof(struct itimerval);
+unsigned pthread_t_sz = sizeof(pthread_t);
+unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
+unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
+unsigned pid_t_sz = sizeof(pid_t);
+unsigned timeval_sz = sizeof(timeval);
+unsigned uid_t_sz = sizeof(uid_t);
+unsigned gid_t_sz = sizeof(gid_t);
+unsigned fpos_t_sz = sizeof(fpos_t);
+unsigned mbstate_t_sz = sizeof(mbstate_t);
+unsigned sigset_t_sz = sizeof(sigset_t);
+unsigned struct_timezone_sz = sizeof(struct timezone);
+unsigned struct_tms_sz = sizeof(struct tms);
+unsigned struct_sigevent_sz = sizeof(struct sigevent);
+unsigned struct_sched_param_sz = sizeof(struct sched_param);
+unsigned struct_statfs_sz = sizeof(struct statfs);
+unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+unsigned ucontext_t_sz = sizeof(ucontext_t);
+unsigned struct_rlimit_sz = sizeof(struct rlimit);
+unsigned struct_timespec_sz = sizeof(struct timespec);
+unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
+unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+unsigned struct_timeb_sz = sizeof(struct timeb);
+unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+unsigned struct_statvfs_sz = sizeof(struct statvfs);
+unsigned struct_shminfo_sz = sizeof(struct shminfo);
+unsigned struct_shm_info_sz = sizeof(struct shm_info);
+unsigned struct_regmatch_sz = sizeof(regmatch_t);
+unsigned struct_regex_sz = sizeof(regex_t);
+unsigned struct_fstab_sz = sizeof(struct fstab);
+unsigned struct_FTS_sz = sizeof(FTS);
+unsigned struct_FTSENT_sz = sizeof(FTSENT);
+unsigned struct_StringList_sz = sizeof(StringList);
+
+const uptr sig_ign = (uptr)SIG_IGN;
+const uptr sig_dfl = (uptr)SIG_DFL;
+const uptr sig_err = (uptr)SIG_ERR;
+const uptr sa_siginfo = (uptr)SA_SIGINFO;
+
+int shmctl_ipc_stat = (int)IPC_STAT;
+int shmctl_ipc_info = (int)IPC_INFO;
+int shmctl_shm_info = (int)SHM_INFO;
+int shmctl_shm_stat = (int)SHM_STAT;
+unsigned struct_utmpx_sz = sizeof(struct utmpx);
+
+int map_fixed = MAP_FIXED;
+
+int af_inet = (int)AF_INET;
+int af_inet6 = (int)AF_INET6;
+
+uptr __sanitizer_in_addr_sz(int af) {
+  if (af == AF_INET)
+    return sizeof(struct in_addr);
+  else if (af == AF_INET6)
+    return sizeof(struct in6_addr);
+  else
+    return 0;
+}
+
+unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
+int glob_nomatch = GLOB_NOMATCH;
+int glob_altdirfunc = GLOB_ALTDIRFUNC;
+
+unsigned path_max = PATH_MAX;
+
+// ioctl arguments
+unsigned struct_ifreq_sz = sizeof(struct ifreq);
+unsigned struct_termios_sz = sizeof(struct termios);
+unsigned struct_winsize_sz = sizeof(struct winsize);
 #if SOUND_VERSION >= 0x040000
-  unsigned struct_copr_buffer_sz = 0;
-  unsigned struct_copr_debug_buf_sz = 0;
-  unsigned struct_copr_msg_sz = 0;
+unsigned struct_copr_buffer_sz = 0;
+unsigned struct_copr_debug_buf_sz = 0;
+unsigned struct_copr_msg_sz = 0;
 #else
-  unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
-  unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
-  unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
 #endif
-  unsigned struct_midi_info_sz = sizeof(struct midi_info);
-  unsigned struct_mtget_sz = sizeof(struct mtget);
-  unsigned struct_mtop_sz = sizeof(struct mtop);
-  unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
-  unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
-  unsigned struct_synth_info_sz = sizeof(struct synth_info);
-  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
-  unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
-  unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
-  unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
-  const unsigned long __sanitizer_bufsiz = BUFSIZ;
-
-  const unsigned IOCTL_NOT_PRESENT = 0;
-
-  unsigned IOCTL_FIOASYNC = FIOASYNC;
-  unsigned IOCTL_FIOCLEX = FIOCLEX;
-  unsigned IOCTL_FIOGETOWN = FIOGETOWN;
-  unsigned IOCTL_FIONBIO = FIONBIO;
-  unsigned IOCTL_FIONCLEX = FIONCLEX;
-  unsigned IOCTL_FIOSETOWN = FIOSETOWN;
-  unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
-  unsigned IOCTL_SIOCATMARK = SIOCATMARK;
-  unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
-  unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
-  unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
-  unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
-  unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
-  unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
-  unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
-  unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
-  unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
-  unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
-  unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
-  unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
-  unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
-  unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
-  unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
-  unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
-  unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
-  unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
-  unsigned IOCTL_TIOCCONS = TIOCCONS;
-  unsigned IOCTL_TIOCEXCL = TIOCEXCL;
-  unsigned IOCTL_TIOCGETD = TIOCGETD;
-  unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
-  unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
-  unsigned IOCTL_TIOCMBIC = TIOCMBIC;
-  unsigned IOCTL_TIOCMBIS = TIOCMBIS;
-  unsigned IOCTL_TIOCMGET = TIOCMGET;
-  unsigned IOCTL_TIOCMSET = TIOCMSET;
-  unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
-  unsigned IOCTL_TIOCNXCL = TIOCNXCL;
-  unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
-  unsigned IOCTL_TIOCPKT = TIOCPKT;
-  unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
-  unsigned IOCTL_TIOCSETD = TIOCSETD;
-  unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
-  unsigned IOCTL_TIOCSTI = TIOCSTI;
-  unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
-  unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
-  unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
-  unsigned IOCTL_MTIOCGET = MTIOCGET;
-  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
-  unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
-  unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
-  unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
-  unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
-  unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
-  unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
-  unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
-  unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
-  unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
-  unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
-  unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
-  unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
-  unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
-  unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
-  unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
-  unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
-  unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
-  unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
-  unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
-  unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
-  unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
-  unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
-  unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
-  unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
-  unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
-  unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
-  unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
-  unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
-  unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
-  unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
-  unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
-  unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
-  unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
-  unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
-  unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
-  unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
-  unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
-  unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
-  unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
-  unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
-  unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
-  unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
-  unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
-  unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
-  unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
-  unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
-  unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
-  unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
-  unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
-  unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
-  unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
-  unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
-  unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
-  unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
-  unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
-  unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
-  unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
-  unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
-  unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
-  unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
-  unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
-  unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
-  unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
-  unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
-  unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
-  unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
-  unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
-  unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
-  unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
-  unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
-  unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
-  unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
-  unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
-  unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
-  unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
-  unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
-  unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
-  unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
-  unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
-  unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
-  unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
-  unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
-  unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
-  unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
-  unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
-  unsigned IOCTL_VT_GETMODE = VT_GETMODE;
-  unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
-  unsigned IOCTL_VT_RELDISP = VT_RELDISP;
-  unsigned IOCTL_VT_SETMODE = VT_SETMODE;
-  unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
-  unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
-  unsigned IOCTL_KDDISABIO = KDDISABIO;
-  unsigned IOCTL_KDENABIO = KDENABIO;
-  unsigned IOCTL_KDGETLED = KDGETLED;
-  unsigned IOCTL_KDGETMODE = KDGETMODE;
-  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
-  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
-  unsigned IOCTL_KDMKTONE = KDMKTONE;
-  unsigned IOCTL_KDSETLED = KDSETLED;
-  unsigned IOCTL_KDSETMODE = KDSETMODE;
-  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
-  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
-  unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
-  unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
-
-  const int si_SEGV_MAPERR = SEGV_MAPERR;
-  const int si_SEGV_ACCERR = SEGV_ACCERR;
-  const int unvis_valid = UNVIS_VALID;
-  const int unvis_validpush = UNVIS_VALIDPUSH;
-} // namespace __sanitizer
+unsigned struct_midi_info_sz = sizeof(struct midi_info);
+unsigned struct_mtget_sz = sizeof(struct mtget);
+unsigned struct_mtop_sz = sizeof(struct mtop);
+unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
+unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
+unsigned struct_synth_info_sz = sizeof(struct synth_info);
+unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+const unsigned long __sanitizer_bufsiz = BUFSIZ;
+
+const unsigned IOCTL_NOT_PRESENT = 0;
+
+unsigned IOCTL_FIOASYNC = FIOASYNC;
+unsigned IOCTL_FIOCLEX = FIOCLEX;
+unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+unsigned IOCTL_FIONBIO = FIONBIO;
+unsigned IOCTL_FIONCLEX = FIONCLEX;
+unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+unsigned IOCTL_TIOCCONS = TIOCCONS;
+unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+unsigned IOCTL_TIOCGETD = TIOCGETD;
+unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+unsigned IOCTL_TIOCMGET = TIOCMGET;
+unsigned IOCTL_TIOCMSET = TIOCMSET;
+unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+unsigned IOCTL_TIOCPKT = TIOCPKT;
+unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+unsigned IOCTL_TIOCSETD = TIOCSETD;
+unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+unsigned IOCTL_TIOCSTI = TIOCSTI;
+unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+unsigned IOCTL_MTIOCGET = MTIOCGET;
+unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
+unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
+unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
+unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
+unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+unsigned IOCTL_KDDISABIO = KDDISABIO;
+unsigned IOCTL_KDENABIO = KDENABIO;
+unsigned IOCTL_KDGETLED = KDGETLED;
+unsigned IOCTL_KDGETMODE = KDGETMODE;
+unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+unsigned IOCTL_KDMKTONE = KDMKTONE;
+unsigned IOCTL_KDSETLED = KDSETLED;
+unsigned IOCTL_KDSETMODE = KDSETMODE;
+unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+
+const int si_SEGV_MAPERR = SEGV_MAPERR;
+const int si_SEGV_ACCERR = SEGV_ACCERR;
+const int unvis_valid = UNVIS_VALID;
+const int unvis_validpush = UNVIS_VALIDPUSH;
+}  // namespace __sanitizer
 
 using namespace __sanitizer;
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
index 71cf5b9c35715..5e0ca9c7d7823 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
@@ -18,18 +18,17 @@
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform.h"
-
 #include "sanitizer_platform_limits_posix.h"
 
-// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
-// incorporates the map structure.
-# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-    ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))
 // Get sys/_types.h, because that tells us whether 64-bit inodes are
 // used in struct dirent below.
 #include <sys/_types.h>
 
 namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
+#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+  (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
+
 extern unsigned struct_utsname_sz;
 extern unsigned struct_stat_sz;
 #if defined(__powerpc64__)
@@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz;
 extern unsigned struct_tms_sz;
 extern unsigned struct_itimerspec_sz;
 extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
 extern unsigned struct_sched_param_sz;
 extern unsigned struct_statfs64_sz;
 extern unsigned struct_statfs_sz;
@@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs {
   unsigned int ifa_flags;
   void *ifa_addr;     // (struct sockaddr *)
   void *ifa_netmask;  // (struct sockaddr *)
-# undef ifa_dstaddr
+#undef ifa_dstaddr
   void *ifa_dstaddr;  // (struct sockaddr *)
   void *ifa_data;
 };
@@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz;
 
 extern unsigned struct_fstab_sz;
 extern unsigned struct_StringList_sz;
-} // namespace __sanitizer
+}  // namespace __sanitizer
 
 #define CHECK_TYPE_SIZE(TYPE) \
   COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
 
-#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                       \
-  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
-                 sizeof(((CLASS *) NULL)->MEMBER));                \
-  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==          \
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                      \
+  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \
+                 sizeof(((CLASS *)NULL)->MEMBER));                \
+  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==         \
                  offsetof(CLASS, MEMBER))
 
 // For sigaction, which is a function and struct at the same time,
 // and thus requires explicit "struct" in sizeof() expression.
-#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER)                       \
-  COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
-                 sizeof(((struct CLASS *) NULL)->MEMBER));                \
-  COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) ==          \
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER)                      \
+  COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \
+                 sizeof(((struct CLASS *)NULL)->MEMBER));                \
+  COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) ==         \
                  offsetof(struct CLASS, MEMBER))
 
 #define SIGACTION_SYMNAME sigaction
 
 #endif
 
-#endif // SANITIZER_FREEBSD
+#endif  // SANITIZER_FREEBSD
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
index 48a78c8998a21..c8f2aa5dba4af 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
@@ -34,6 +34,7 @@
 #include <sys/chio.h>
 #include <sys/clockctl.h>
 #include <sys/cpuio.h>
+#include <sys/dkbad.h>
 #include <sys/dkio.h>
 #include <sys/drvctlio.h>
 #include <sys/dvdio.h>
@@ -83,6 +84,7 @@
 
 #include <sys/resource.h>
 #include <sys/sem.h>
+#include <sys/scsiio.h>
 #include <sys/sha1.h>
 #include <sys/sha2.h>
 #include <sys/shm.h>
@@ -139,7 +141,158 @@
 #include <dev/ir/irdaio.h>
 #include <dev/isa/isvio.h>
 #include <dev/isa/wtreg.h>
+#if __has_include(<dev/iscsi/iscsi_ioctl.h>)
 #include <dev/iscsi/iscsi_ioctl.h>
+#else
+/* Fallback for MKISCSI=no */
+
+typedef struct {
+  uint32_t status;
+  uint32_t session_id;
+  uint32_t connection_id;
+} iscsi_conn_status_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint16_t interface_version;
+  uint16_t major;
+  uint16_t minor;
+  uint8_t version_string[224];
+} iscsi_get_version_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t session_id;
+  uint32_t connection_id;
+  struct {
+    unsigned int immediate : 1;
+  } options;
+  uint64_t lun;
+  scsireq_t req; /* from <sys/scsiio.h> */
+} iscsi_iocommand_parameters_t;
+
+typedef enum {
+  ISCSI_AUTH_None = 0,
+  ISCSI_AUTH_CHAP = 1,
+  ISCSI_AUTH_KRB5 = 2,
+  ISCSI_AUTH_SRP = 3
+} iscsi_auth_types_t;
+
+typedef enum {
+  ISCSI_LOGINTYPE_DISCOVERY = 0,
+  ISCSI_LOGINTYPE_NOMAP = 1,
+  ISCSI_LOGINTYPE_MAP = 2
+} iscsi_login_session_type_t;
+
+typedef enum { ISCSI_DIGEST_None = 0, ISCSI_DIGEST_CRC32C = 1 } iscsi_digest_t;
+
+typedef enum {
+  ISCSI_SESSION_TERMINATED = 1,
+  ISCSI_CONNECTION_TERMINATED,
+  ISCSI_RECOVER_CONNECTION,
+  ISCSI_DRIVER_TERMINATING
+} iscsi_event_t;
+
+typedef struct {
+  unsigned int mutual_auth : 1;
+  unsigned int is_secure : 1;
+  unsigned int auth_number : 4;
+  iscsi_auth_types_t auth_type[4];
+} iscsi_auth_info_t;
+
+typedef struct {
+  uint32_t status;
+  int socket;
+  struct {
+    unsigned int HeaderDigest : 1;
+    unsigned int DataDigest : 1;
+    unsigned int MaxConnections : 1;
+    unsigned int DefaultTime2Wait : 1;
+    unsigned int DefaultTime2Retain : 1;
+    unsigned int MaxRecvDataSegmentLength : 1;
+    unsigned int auth_info : 1;
+    unsigned int user_name : 1;
+    unsigned int password : 1;
+    unsigned int target_password : 1;
+    unsigned int TargetName : 1;
+    unsigned int TargetAlias : 1;
+    unsigned int ErrorRecoveryLevel : 1;
+  } is_present;
+  iscsi_auth_info_t auth_info;
+  iscsi_login_session_type_t login_type;
+  iscsi_digest_t HeaderDigest;
+  iscsi_digest_t DataDigest;
+  uint32_t session_id;
+  uint32_t connection_id;
+  uint32_t MaxRecvDataSegmentLength;
+  uint16_t MaxConnections;
+  uint16_t DefaultTime2Wait;
+  uint16_t DefaultTime2Retain;
+  uint16_t ErrorRecoveryLevel;
+  void *user_name;
+  void *password;
+  void *target_password;
+  void *TargetName;
+  void *TargetAlias;
+} iscsi_login_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t session_id;
+} iscsi_logout_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t event_id;
+} iscsi_register_event_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t session_id;
+  uint32_t connection_id;
+} iscsi_remove_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t session_id;
+  void *response_buffer;
+  uint32_t response_size;
+  uint32_t response_used;
+  uint32_t response_total;
+  uint8_t key[224];
+} iscsi_send_targets_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint8_t InitiatorName[224];
+  uint8_t InitiatorAlias[224];
+  uint8_t ISID[6];
+} iscsi_set_node_name_parameters_t;
+
+typedef struct {
+  uint32_t status;
+  uint32_t event_id;
+  iscsi_event_t event_kind;
+  uint32_t session_id;
+  uint32_t connection_id;
+  uint32_t reason;
+} iscsi_wait_event_parameters_t;
+
+#define ISCSI_GET_VERSION _IOWR(0, 1, iscsi_get_version_parameters_t)
+#define ISCSI_LOGIN _IOWR(0, 2, iscsi_login_parameters_t)
+#define ISCSI_LOGOUT _IOWR(0, 3, iscsi_logout_parameters_t)
+#define ISCSI_ADD_CONNECTION _IOWR(0, 4, iscsi_login_parameters_t)
+#define ISCSI_RESTORE_CONNECTION _IOWR(0, 5, iscsi_login_parameters_t)
+#define ISCSI_REMOVE_CONNECTION _IOWR(0, 6, iscsi_remove_parameters_t)
+#define ISCSI_CONNECTION_STATUS _IOWR(0, 7, iscsi_conn_status_parameters_t)
+#define ISCSI_SEND_TARGETS _IOWR(0, 8, iscsi_send_targets_parameters_t)
+#define ISCSI_SET_NODE_NAME _IOWR(0, 9, iscsi_set_node_name_parameters_t)
+#define ISCSI_IO_COMMAND _IOWR(0, 10, iscsi_iocommand_parameters_t)
+#define ISCSI_REGISTER_EVENT _IOWR(0, 11, iscsi_register_event_parameters_t)
+#define ISCSI_DEREGISTER_EVENT _IOWR(0, 12, iscsi_register_event_parameters_t)
+#define ISCSI_WAIT_EVENT _IOWR(0, 13, iscsi_wait_event_parameters_t)
+#define ISCSI_POLL_EVENT _IOWR(0, 14, iscsi_wait_event_parameters_t)
+#endif
 #include <dev/ofw/openfirmio.h>
 #include <dev/pci/amrio.h>
 #include <dev/pci/mlyreg.h>
@@ -161,12 +314,121 @@
 #include <net/slip.h>
 #include <netbt/hci.h>
 #include <netinet/ip_compat.h>
+#if __has_include(<netinet/ip_fil.h>)
 #include <netinet/ip_fil.h>
 #include <netinet/ip_nat.h>
 #include <netinet/ip_proxy.h>
+#else
+/* Fallback for MKIPFILTER=no */
+
+typedef struct ap_control {
+  char apc_label[16];
+  char apc_config[16];
+  unsigned char apc_p;
+  unsigned long apc_cmd;
+  unsigned long apc_arg;
+  void *apc_data;
+  size_t apc_dsize;
+} ap_ctl_t;
+
+typedef struct ipftq {
+  ipfmutex_t ifq_lock;
+  unsigned int ifq_ttl;
+  void *ifq_head;
+  void **ifq_tail;
+  void *ifq_next;
+  void **ifq_pnext;
+  int ifq_ref;
+  unsigned int ifq_flags;
+} ipftq_t;
+
+typedef struct ipfobj {
+  uint32_t ipfo_rev;
+  uint32_t ipfo_size;
+  void *ipfo_ptr;
+  int ipfo_type;
+  int ipfo_offset;
+  int ipfo_retval;
+  unsigned char ipfo_xxxpad[28];
+} ipfobj_t;
+
+#define SIOCADNAT _IOW('r', 60, struct ipfobj)
+#define SIOCRMNAT _IOW('r', 61, struct ipfobj)
+#define SIOCGNATS _IOWR('r', 62, struct ipfobj)
+#define SIOCGNATL _IOWR('r', 63, struct ipfobj)
+#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj)
+#endif
 #include <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
+#if !__NetBSD_Prereq__(9, 99, 51)
 #include <netsmb/smb_dev.h>
+#else
+struct smbioc_flags {
+  int ioc_level;
+  int ioc_mask;
+  int ioc_flags;
+};
+struct smbioc_oshare {
+  int ioc_opt;
+  int ioc_stype;
+  char ioc_share[129];
+  char ioc_password[129];
+  uid_t ioc_owner;
+  gid_t ioc_group;
+  mode_t ioc_mode;
+  mode_t ioc_rights;
+};
+struct smbioc_ossn {
+  int ioc_opt;
+  uint32_t ioc_svlen;
+  struct sockaddr *ioc_server;
+  uint32_t ioc_lolen;
+  struct sockaddr *ioc_local;
+  char ioc_srvname[16];
+  int ioc_timeout;
+  int ioc_retrycount;
+  char ioc_localcs[16];
+  char ioc_servercs[16];
+  char ioc_user[129];
+  char ioc_workgroup[129];
+  char ioc_password[129];
+  uid_t ioc_owner;
+  gid_t ioc_group;
+  mode_t ioc_mode;
+  mode_t ioc_rights;
+};
+struct smbioc_lookup {
+  int ioc_level;
+  int ioc_flags;
+  struct smbioc_ossn ioc_ssn;
+  struct smbioc_oshare ioc_sh;
+};
+struct smbioc_rq {
+  u_char ioc_cmd;
+  u_char ioc_twc;
+  void *ioc_twords;
+  u_short ioc_tbc;
+  void *ioc_tbytes;
+  int ioc_rpbufsz;
+  char *ioc_rpbuf;
+  u_char ioc_rwc;
+  u_short ioc_rbc;
+};
+struct smbioc_rw {
+  u_int16_t ioc_fh;
+  char *ioc_base;
+  off_t ioc_offset;
+  int ioc_cnt;
+};
+#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn)
+#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare)
+#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq)
+#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq)
+#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags)
+#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup)
+#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw)
+#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw)
+#endif
 #include <dev/biovar.h>
 #include <dev/bluetooth/btdev.h>
 #include <dev/bluetooth/btsco.h>
@@ -190,7 +452,21 @@
 #include <dev/sun/vuid_event.h>
 #include <dev/tc/sticio.h>
 #include <dev/usb/ukyopon.h>
+#if !__NetBSD_Prereq__(9, 99, 44)
 #include <dev/usb/urio.h>
+#else
+struct urio_command {
+  unsigned short length;
+  int request;
+  int requesttype;
+  int value;
+  int index;
+  void *buffer;
+  int timeout;
+};
+#define URIO_SEND_COMMAND      _IOWR('U', 200, struct urio_command)
+#define URIO_RECV_COMMAND      _IOWR('U', 201, struct urio_command)
+#endif
 #include <dev/usb/usb.h>
 #include <dev/usb/utoppy.h>
 #include <dev/vme/xio.h>
@@ -199,6 +475,7 @@
 #include <dev/wscons/wsdisplay_usl_io.h>
 #include <fs/autofs/autofs_ioctl.h>
 #include <dirent.h>
+#include <dlfcn.h>
 #include <glob.h>
 #include <grp.h>
 #include <ifaddrs.h>
@@ -244,9 +521,15 @@
 
 // Include these after system headers to avoid name clashes and ambiguities.
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
 #include "sanitizer_platform_limits_netbsd.h"
 
 namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) {
+  void *p = nullptr;
+  return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr;
+}
+
 unsigned struct_utsname_sz = sizeof(struct utsname);
 unsigned struct_stat_sz = sizeof(struct stat);
 unsigned struct_rusage_sz = sizeof(struct rusage);
@@ -255,6 +538,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd);
 unsigned struct_group_sz = sizeof(struct group);
 unsigned siginfo_t_sz = sizeof(siginfo_t);
 unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_stack_t_sz = sizeof(stack_t);
 unsigned struct_itimerval_sz = sizeof(struct itimerval);
 unsigned pthread_t_sz = sizeof(pthread_t);
 unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
index 794efdb6eff6d..9e28dcfef0415 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
@@ -19,18 +19,11 @@
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform.h"
 
-#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
-  ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift))))
-
-#if defined(__x86_64__)
-#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264)
-#elif defined(__i386__)
+namespace __sanitizer {
+void *__sanitizer_get_link_map_by_dlopen_handle(void *handle);
 #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136)
-#endif
+  (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle)
 
-namespace __sanitizer {
 extern unsigned struct_utsname_sz;
 extern unsigned struct_stat_sz;
 extern unsigned struct_rusage_sz;
@@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz;
 extern unsigned struct_tms_sz;
 extern unsigned struct_itimerspec_sz;
 extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
 extern unsigned struct_sched_param_sz;
 extern unsigned struct_statfs_sz;
 extern unsigned struct_sockaddr_sz;
@@ -1030,12 +1024,10 @@ extern unsigned struct_RF_ProgressInfo_sz;
 extern unsigned struct_nvlist_ref_sz;
 extern unsigned struct_StringList_sz;
 
-
 // A special value to mark ioctls that are not present on the target platform,
 // when it can not be determined without including any system headers.
 extern const unsigned IOCTL_NOT_PRESENT;
 
-
 extern unsigned IOCTL_AFM_ADDFMAP;
 extern unsigned IOCTL_AFM_DELFMAP;
 extern unsigned IOCTL_AFM_CLEANFMAP;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
index 12515626ce534..e69de29bb2d1d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
@@ -1,278 +0,0 @@
-//===-- sanitizer_platform_limits_openbsd.cpp -----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of Sanitizer common code.
-//
-// Sizes and layouts of platform-specific NetBSD data structures.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-
-#if SANITIZER_OPENBSD
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <glob.h>
-#include <grp.h>
-#include <ifaddrs.h>
-#include <limits.h>
-#include <link_elf.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/ppp_defs.h>
-#include <net/route.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/ip_mroute.h>
-#include <poll.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <soundcard.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/filio.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/msg.h>
-#include <sys/mtio.h>
-#include <sys/ptrace.h>
-#include <sys/resource.h>
-#include <sys/shm.h>
-#include <sys/signal.h>
-#include <sys/sockio.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <term.h>
-#include <time.h>
-#include <utime.h>
-#include <utmp.h>
-#include <wchar.h>
-
-// Include these after system headers to avoid name clashes and ambiguities.
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_platform_limits_openbsd.h"
-
-namespace __sanitizer {
-unsigned struct_utsname_sz = sizeof(struct utsname);
-unsigned struct_stat_sz = sizeof(struct stat);
-unsigned struct_rusage_sz = sizeof(struct rusage);
-unsigned struct_tm_sz = sizeof(struct tm);
-unsigned struct_passwd_sz = sizeof(struct passwd);
-unsigned struct_group_sz = sizeof(struct group);
-unsigned siginfo_t_sz = sizeof(siginfo_t);
-unsigned struct_sigaction_sz = sizeof(struct sigaction);
-unsigned struct_itimerval_sz = sizeof(struct itimerval);
-unsigned pthread_t_sz = sizeof(pthread_t);
-unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
-unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
-unsigned pid_t_sz = sizeof(pid_t);
-unsigned timeval_sz = sizeof(timeval);
-unsigned uid_t_sz = sizeof(uid_t);
-unsigned gid_t_sz = sizeof(gid_t);
-unsigned mbstate_t_sz = sizeof(mbstate_t);
-unsigned sigset_t_sz = sizeof(sigset_t);
-unsigned struct_timezone_sz = sizeof(struct timezone);
-unsigned struct_tms_sz = sizeof(struct tms);
-unsigned struct_sched_param_sz = sizeof(struct sched_param);
-unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
-unsigned struct_rlimit_sz = sizeof(struct rlimit);
-unsigned struct_timespec_sz = sizeof(struct timespec);
-unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
-unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
-unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
-unsigned struct_statvfs_sz = sizeof(struct statvfs);
-
-const uptr sig_ign = (uptr)SIG_IGN;
-const uptr sig_dfl = (uptr)SIG_DFL;
-const uptr sig_err = (uptr)SIG_ERR;
-const uptr sa_siginfo = (uptr)SA_SIGINFO;
-
-int shmctl_ipc_stat = (int)IPC_STAT;
-
-unsigned struct_utmp_sz = sizeof(struct utmp);
-
-int map_fixed = MAP_FIXED;
-
-int af_inet = (int)AF_INET;
-int af_inet6 = (int)AF_INET6;
-
-uptr __sanitizer_in_addr_sz(int af) {
-  if (af == AF_INET)
-    return sizeof(struct in_addr);
-  else if (af == AF_INET6)
-    return sizeof(struct in6_addr);
-  else
-    return 0;
-}
-
-unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
-
-int glob_nomatch = GLOB_NOMATCH;
-int glob_altdirfunc = GLOB_ALTDIRFUNC;
-
-unsigned path_max = PATH_MAX;
-
-const int si_SEGV_MAPERR = SEGV_MAPERR;
-const int si_SEGV_ACCERR = SEGV_ACCERR;
-}  // namespace __sanitizer
-
-using namespace __sanitizer;
-
-COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
-
-COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
-CHECK_TYPE_SIZE(pthread_key_t);
-
-CHECK_TYPE_SIZE(dl_phdr_info);
-CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
-CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
-CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
-CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
-
-CHECK_TYPE_SIZE(glob_t);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
-CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
-
-CHECK_TYPE_SIZE(addrinfo);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
-CHECK_SIZE_AND_OFFSET(addrinfo, ai_next);
-
-CHECK_TYPE_SIZE(hostent);
-CHECK_SIZE_AND_OFFSET(hostent, h_name);
-CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
-CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
-CHECK_SIZE_AND_OFFSET(hostent, h_length);
-CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
-
-CHECK_TYPE_SIZE(iovec);
-CHECK_SIZE_AND_OFFSET(iovec, iov_base);
-CHECK_SIZE_AND_OFFSET(iovec, iov_len);
-
-CHECK_TYPE_SIZE(msghdr);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
-CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
-
-CHECK_TYPE_SIZE(cmsghdr);
-CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
-CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
-CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
-
-COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
-CHECK_SIZE_AND_OFFSET(dirent, d_fileno);
-CHECK_SIZE_AND_OFFSET(dirent, d_off);
-CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
-
-CHECK_TYPE_SIZE(ifconf);
-CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
-CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
-
-CHECK_TYPE_SIZE(pollfd);
-CHECK_SIZE_AND_OFFSET(pollfd, fd);
-CHECK_SIZE_AND_OFFSET(pollfd, events);
-CHECK_SIZE_AND_OFFSET(pollfd, revents);
-
-CHECK_TYPE_SIZE(nfds_t);
-
-CHECK_TYPE_SIZE(sigset_t);
-
-COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
-// Can't write checks for sa_handler and sa_sigaction due to them being
-// preprocessor macros.
-CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
-
-CHECK_TYPE_SIZE(tm);
-CHECK_SIZE_AND_OFFSET(tm, tm_sec);
-CHECK_SIZE_AND_OFFSET(tm, tm_min);
-CHECK_SIZE_AND_OFFSET(tm, tm_hour);
-CHECK_SIZE_AND_OFFSET(tm, tm_mday);
-CHECK_SIZE_AND_OFFSET(tm, tm_mon);
-CHECK_SIZE_AND_OFFSET(tm, tm_year);
-CHECK_SIZE_AND_OFFSET(tm, tm_wday);
-CHECK_SIZE_AND_OFFSET(tm, tm_yday);
-CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
-CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
-CHECK_SIZE_AND_OFFSET(tm, tm_zone);
-
-CHECK_TYPE_SIZE(ipc_perm);
-CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
-CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
-CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
-CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
-CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
-CHECK_SIZE_AND_OFFSET(ipc_perm, seq);
-CHECK_SIZE_AND_OFFSET(ipc_perm, key);
-
-CHECK_TYPE_SIZE(shmid_ds);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
-CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_atimensec);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
-CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_dtimensec);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
-CHECK_SIZE_AND_OFFSET(shmid_ds, __shm_ctimensec);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
-CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
-
-CHECK_TYPE_SIZE(clock_t);
-
-CHECK_TYPE_SIZE(ifaddrs);
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
-// Compare against the union, because we can't reach into the union in a
-// compliant way.
-#ifdef ifa_dstaddr
-#undef ifa_dstaddr
-#endif
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
-CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
-
-CHECK_TYPE_SIZE(passwd);
-CHECK_SIZE_AND_OFFSET(passwd, pw_name);
-CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
-CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
-CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
-CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
-CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
-
-CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
-
-CHECK_TYPE_SIZE(group);
-CHECK_SIZE_AND_OFFSET(group, gr_name);
-CHECK_SIZE_AND_OFFSET(group, gr_passwd);
-CHECK_SIZE_AND_OFFSET(group, gr_gid);
-CHECK_SIZE_AND_OFFSET(group, gr_mem);
-
-#endif  // SANITIZER_OPENBSD
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h
index 6d8b062716b78..e69de29bb2d1d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_openbsd.h
@@ -1,381 +0,0 @@
-//===-- sanitizer_platform_limits_openbsd.h -------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of Sanitizer common code.
-//
-// Sizes and layouts of platform-specific OpenBSD data structures.
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_PLATFORM_LIMITS_OPENBSD_H
-#define SANITIZER_PLATFORM_LIMITS_OPENBSD_H
-
-#if SANITIZER_OPENBSD
-
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_platform.h"
-
-#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
-  ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift))))
-
-#if defined(__x86_64__)
-#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312)
-#elif defined(__i386__)
-#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164)
-#endif
-
-#define RLIMIT_AS RLIMIT_DATA
-
-namespace __sanitizer {
-extern unsigned struct_utsname_sz;
-extern unsigned struct_stat_sz;
-extern unsigned struct_rusage_sz;
-extern unsigned siginfo_t_sz;
-extern unsigned struct_itimerval_sz;
-extern unsigned pthread_t_sz;
-extern unsigned pthread_mutex_t_sz;
-extern unsigned pthread_cond_t_sz;
-extern unsigned pid_t_sz;
-extern unsigned timeval_sz;
-extern unsigned uid_t_sz;
-extern unsigned gid_t_sz;
-extern unsigned mbstate_t_sz;
-extern unsigned struct_timezone_sz;
-extern unsigned struct_tms_sz;
-extern unsigned struct_itimerspec_sz;
-extern unsigned struct_sigevent_sz;
-extern unsigned struct_statfs_sz;
-extern unsigned struct_sockaddr_sz;
-
-extern unsigned struct_rlimit_sz;
-extern unsigned struct_utimbuf_sz;
-extern unsigned struct_timespec_sz;
-
-struct __sanitizer_iocb {
-  u64 aio_offset;
-  uptr aio_buf;
-  long aio_nbytes;
-  u32 aio_fildes;
-  u32 aio_lio_opcode;
-  long aio_reqprio;
-#if SANITIZER_WORDSIZE == 64
-  u8 aio_sigevent[32];
-#else
-  u8 aio_sigevent[20];
-#endif
-  u32 _state;
-  u32 _errno;
-  long _retval;
-};
-
-struct __sanitizer___sysctl_args {
-  int *name;
-  int nlen;
-  void *oldval;
-  uptr *oldlenp;
-  void *newval;
-  uptr newlen;
-};
-
-struct __sanitizer_sem_t {
-  uptr data[5];
-};
-
-struct __sanitizer_ipc_perm {
-  u32 cuid;
-  u32 cgid;
-  u32 uid;
-  u32 gid;
-  u32 mode;
-  unsigned short seq;
-  long key;
-};
-
-struct __sanitizer_shmid_ds {
-  __sanitizer_ipc_perm shm_perm;
-  int shm_segsz;
-  u32 shm_lpid;
-  u32 shm_cpid;
-  short shm_nattch;
-  u64 shm_atime;
-  long __shm_atimensec;
-  u64 shm_dtime;
-  long __shm_dtimensec;
-  u64 shm_ctime;
-  long __shm_ctimensec;
-  void *_shm_internal;
-};
-
-extern unsigned struct_msqid_ds_sz;
-extern unsigned struct_mq_attr_sz;
-extern unsigned struct_timex_sz;
-extern unsigned struct_statvfs_sz;
-
-struct __sanitizer_iovec {
-  void *iov_base;
-  uptr iov_len;
-};
-
-struct __sanitizer_ifaddrs {
-  struct __sanitizer_ifaddrs *ifa_next;
-  char *ifa_name;
-  unsigned int ifa_flags;
-  struct __sanitizer_sockaddr *ifa_addr;     // (struct sockaddr *)
-  struct __sanitizer_sockaddr *ifa_netmask;  // (struct sockaddr *)
-  struct __sanitizer_sockaddr *ifa_dstaddr;  // (struct sockaddr *)
-  void *ifa_data;
-};
-
-typedef unsigned __sanitizer_pthread_key_t;
-
-typedef long long __sanitizer_time_t;
-typedef int __sanitizer_suseconds_t;
-
-struct __sanitizer_timeval {
-  __sanitizer_time_t tv_sec;
-  __sanitizer_suseconds_t tv_usec;
-};
-
-struct __sanitizer_itimerval {
-  struct __sanitizer_timeval it_interval;
-  struct __sanitizer_timeval it_value;
-};
-
-struct __sanitizer_passwd {
-  char *pw_name;
-  char *pw_passwd;
-  int pw_uid;
-  int pw_gid;
-  __sanitizer_time_t pw_change;
-  char *pw_class;
-  char *pw_gecos;
-  char *pw_dir;
-  char *pw_shell;
-  __sanitizer_time_t pw_expire;
-};
-
-struct __sanitizer_group {
-  char *gr_name;
-  char *gr_passwd;
-  int gr_gid;
-  char **gr_mem;
-};
-
-struct __sanitizer_ether_addr {
-  u8 octet[6];
-};
-
-struct __sanitizer_tm {
-  int tm_sec;
-  int tm_min;
-  int tm_hour;
-  int tm_mday;
-  int tm_mon;
-  int tm_year;
-  int tm_wday;
-  int tm_yday;
-  int tm_isdst;
-  long int tm_gmtoff;
-  const char *tm_zone;
-};
-
-struct __sanitizer_msghdr {
-  void *msg_name;
-  unsigned msg_namelen;
-  struct __sanitizer_iovec *msg_iov;
-  unsigned msg_iovlen;
-  void *msg_control;
-  unsigned msg_controllen;
-  int msg_flags;
-};
-struct __sanitizer_cmsghdr {
-  unsigned cmsg_len;
-  int cmsg_level;
-  int cmsg_type;
-};
-
-struct __sanitizer_dirent {
-  u64 d_fileno;
-  u64 d_off;
-  u16 d_reclen;
-};
-
-typedef u64 __sanitizer_clock_t;
-typedef u32 __sanitizer_clockid_t;
-
-typedef u32 __sanitizer___kernel_uid_t;
-typedef u32 __sanitizer___kernel_gid_t;
-typedef u64 __sanitizer___kernel_off_t;
-typedef struct {
-  u32 fds_bits[8];
-} __sanitizer___kernel_fd_set;
-
-typedef struct {
-  unsigned int pta_magic;
-  int pta_flags;
-  void *pta_private;
-} __sanitizer_pthread_attr_t;
-
-typedef unsigned int __sanitizer_sigset_t;
-
-struct __sanitizer_siginfo {
-  // The size is determined by looking at sizeof of real siginfo_t on linux.
-  u64 opaque[128 / sizeof(u64)];
-};
-
-using __sanitizer_sighandler_ptr = void (*)(int sig);
-using __sanitizer_sigactionhandler_ptr = void (*)(int sig,
-                                                  __sanitizer_siginfo *siginfo,
-                                                  void *uctx);
-
-struct __sanitizer_sigaction {
-  union {
-    __sanitizer_sighandler_ptr handler;
-    __sanitizer_sigactionhandler_ptr sigaction;
-  };
-  __sanitizer_sigset_t sa_mask;
-  int sa_flags;
-};
-
-typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
-
-struct __sanitizer_kernel_sigaction_t {
-  union {
-    void (*handler)(int signo);
-    void (*sigaction)(int signo, void *info, void *ctx);
-  };
-  unsigned long sa_flags;
-  void (*sa_restorer)(void);
-  __sanitizer_kernel_sigset_t sa_mask;
-};
-
-extern const uptr sig_ign;
-extern const uptr sig_dfl;
-extern const uptr sig_err;
-extern const uptr sa_siginfo;
-
-extern int af_inet;
-extern int af_inet6;
-uptr __sanitizer_in_addr_sz(int af);
-
-struct __sanitizer_dl_phdr_info {
-#if SANITIZER_WORDSIZE == 64
-  u64 dlpi_addr;
-#else
-  u32 dlpi_addr;
-#endif
-  const char *dlpi_name;
-  const void *dlpi_phdr;
-#if SANITIZER_WORDSIZE == 64
-  u32 dlpi_phnum;
-#else
-  u16 dlpi_phnum;
-#endif
-};
-
-extern unsigned struct_ElfW_Phdr_sz;
-
-struct __sanitizer_addrinfo {
-  int ai_flags;
-  int ai_family;
-  int ai_socktype;
-  int ai_protocol;
-  unsigned ai_addrlen;
-  struct __sanitizer_sockaddr *ai_addr;
-  char *ai_canonname;
-  struct __sanitizer_addrinfo *ai_next;
-};
-
-struct __sanitizer_hostent {
-  char *h_name;
-  char **h_aliases;
-  int h_addrtype;
-  int h_length;
-  char **h_addr_list;
-};
-
-struct __sanitizer_pollfd {
-  int fd;
-  short events;
-  short revents;
-};
-
-typedef unsigned __sanitizer_nfds_t;
-
-struct __sanitizer_glob_t {
-  int gl_pathc;
-  int gl_matchc;
-  int gl_offs;
-  int gl_flags;
-  char **gl_pathv;
-  void **gl_statv;
-  int (*gl_errfunc)(const char *, int);
-  void (*gl_closedir)(void *dirp);
-  struct dirent *(*gl_readdir)(void *dirp);
-  void *(*gl_opendir)(const char *);
-  int (*gl_lstat)(const char *, void * /* struct stat* */);
-  int (*gl_stat)(const char *, void * /* struct stat* */);
-};
-
-extern int glob_nomatch;
-extern int glob_altdirfunc;
-
-extern unsigned path_max;
-
-typedef char __sanitizer_FILE;
-#define SANITIZER_HAS_STRUCT_FILE 0
-
-extern int shmctl_ipc_stat;
-
-// This simplifies generic code
-#define struct_shminfo_sz -1
-#define struct_shm_info_sz -1
-#define shmctl_shm_stat -1
-#define shmctl_ipc_info -1
-#define shmctl_shm_info -1
-
-extern unsigned struct_utmp_sz;
-extern unsigned struct_utmpx_sz;
-
-extern int map_fixed;
-
-// ioctl arguments
-struct __sanitizer_ifconf {
-  int ifc_len;
-  union {
-    void *ifcu_req;
-  } ifc_ifcu;
-};
-
-extern const int si_SEGV_MAPERR;
-extern const int si_SEGV_ACCERR;
-}  // namespace __sanitizer
-
-#define CHECK_TYPE_SIZE(TYPE) \
-  COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
-
-#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                      \
-  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \
-                 sizeof(((CLASS *)NULL)->MEMBER));                \
-  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==         \
-                 offsetof(CLASS, MEMBER))
-
-// For sigaction, which is a function and struct at the same time,
-// and thus requires explicit "struct" in sizeof() expression.
-#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER)                      \
-  COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \
-                 sizeof(((struct CLASS *)NULL)->MEMBER));                \
-  COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) ==         \
-                 offsetof(struct CLASS, MEMBER))
-
-#define SIGACTION_SYMNAME __sigaction14
-
-#endif  // SANITIZER_OPENBSD
-
-#endif
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
index c44449aee09a6..fe8b04a9c4880 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -11,18 +11,19 @@
 // Sizes and layouts of platform-specific POSIX data structures.
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_platform.h"
-
-#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN
+#if defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
 // Tests in this file assume that off_t-dependent data structures match the
 // libc ABI. For example, struct dirent here is what readdir() function (as
 // exported from libc) returns, and not the user-facing "dirent", which
 // depends on _FILE_OFFSET_BITS setting.
 // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
-#ifdef _FILE_OFFSET_BITS
 #undef _FILE_OFFSET_BITS
 #endif
 
+// Must go after undef _FILE_OFFSET_BITS.
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN
 // Must go after undef _FILE_OFFSET_BITS.
 #include "sanitizer_glibc_version.h"
 
@@ -37,6 +38,7 @@
 #include <pwd.h>
 #include <signal.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
@@ -58,7 +60,6 @@
 #endif
 
 #if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
-#include <fstab.h>
 #include <sys/mount.h>
 #include <sys/timeb.h>
 #include <utmpx.h>
@@ -90,7 +91,8 @@
 #if SANITIZER_LINUX
 # include <utime.h>
 # include <sys/ptrace.h>
-# if defined(__mips64) || defined(__aarch64__) || defined(__arm__)
+#if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
+    SANITIZER_RISCV64
 #  include <asm/ptrace.h>
 #  ifdef __arm__
 typedef struct user_fpregs elf_fpregset_t;
@@ -109,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
 #include <wordexp.h>
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-#include <glob.h>
-#include <obstack.h>
-#include <mqueue.h>
+#if SANITIZER_LINUX
+#if SANITIZER_GLIBC
+#include <fstab.h>
 #include <net/if_ppp.h>
 #include <netax25/ax25.h>
 #include <netipx/ipx.h>
 #include <netrom/netrom.h>
+#include <obstack.h>
 #if HAVE_RPC_XDR_H
 # include <rpc/xdr.h>
 #endif
 #include <scsi/scsi.h>
-#include <sys/mtio.h>
+#else
+#include <linux/if_ppp.h>
+#include <linux/kd.h>
+#include <linux/ppp_defs.h>
+#endif  // SANITIZER_GLIBC
+
+#if SANITIZER_ANDROID
+#include <linux/mtio.h>
+#else
+#include <glob.h>
+#include <mqueue.h>
 #include <sys/kd.h>
+#include <sys/mtio.h>
 #include <sys/shm.h>
 #include <sys/statvfs.h>
 #include <sys/timex.h>
@@ -141,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
 #include <sys/msg.h>
 #include <sys/ipc.h>
 #include <crypt.h>
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif  // SANITIZER_ANDROID
 
-#if SANITIZER_ANDROID
-#include <linux/kd.h>
-#include <linux/mtio.h>
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
-#endif
-
-#if SANITIZER_LINUX
 #include <link.h>
 #include <sys/vfs.h>
 #include <sys/epoll.h>
 #include <linux/capability.h>
+#elif !SANITIZER_EMSCRIPTEN
+#include <fstab.h>
 #endif // SANITIZER_LINUX
 
 #if SANITIZER_MAC
@@ -170,15 +177,16 @@ typedef struct user_fpregs elf_fpregset_t;
 namespace __sanitizer {
   unsigned struct_utsname_sz = sizeof(struct utsname);
   unsigned struct_stat_sz = sizeof(struct stat);
-#if !SANITIZER_IOS
+#if !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64)
   unsigned struct_stat64_sz = sizeof(struct stat64);
-#endif // !SANITIZER_IOS
+#endif // !SANITIZER_IOS && !(SANITIZER_MAC && TARGET_CPU_ARM64)
   unsigned struct_rusage_sz = sizeof(struct rusage);
   unsigned struct_tm_sz = sizeof(struct tm);
   unsigned struct_passwd_sz = sizeof(struct passwd);
   unsigned struct_group_sz = sizeof(struct group);
   unsigned siginfo_t_sz = sizeof(siginfo_t);
   unsigned struct_sigaction_sz = sizeof(struct sigaction);
+  unsigned struct_stack_t_sz = sizeof(stack_t);
   unsigned struct_itimerval_sz = sizeof(struct itimerval);
   unsigned pthread_t_sz = sizeof(pthread_t);
   unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
@@ -196,12 +204,14 @@ namespace __sanitizer {
   unsigned struct_regex_sz = sizeof(regex_t);
   unsigned struct_regmatch_sz = sizeof(regmatch_t);
 
-#if SANITIZER_MAC && !SANITIZER_IOS
+#if (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
   unsigned struct_statfs64_sz = sizeof(struct statfs64);
-#endif // SANITIZER_MAC && !SANITIZER_IOS
+#endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
 
-#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
   unsigned struct_fstab_sz = sizeof(struct fstab);
+#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
+#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN
   unsigned struct_statfs_sz = sizeof(struct statfs);
   unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
   unsigned ucontext_t_sz = sizeof(ucontext_t);
@@ -228,9 +238,9 @@ namespace __sanitizer {
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which
   // has been removed from glibc 2.28.
-#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \
-  || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \
-  || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64)
+#if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) ||     \
+    defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) || \
+    defined(__x86_64__) || SANITIZER_RISCV64
 #define SIZEOF_STRUCT_USTAT 32
 #elif defined(__arm__) || defined(__i386__) || defined(__mips__) \
   || defined(__powerpc__) || defined(__s390__) || defined(__sparc__)
@@ -297,18 +307,21 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
 unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
   int glob_nomatch = GLOB_NOMATCH;
   int glob_altdirfunc = GLOB_ALTDIRFUNC;
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
-    (defined(__i386) || defined(__x86_64) || defined(__mips64) || \
-      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-      defined(__s390__))
+#if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
+    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
+     defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+     defined(__s390__) || SANITIZER_RISCV64)
 #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
   unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
   unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
+#elif SANITIZER_RISCV64
+  unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
+  unsigned struct_user_fpregs_struct_sz = sizeof(struct __riscv_q_ext_state);
 #elif defined(__aarch64__)
   unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state);
@@ -320,7 +333,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
 #endif // __mips64 || __powerpc64__ || __aarch64__
 #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
-    defined(__aarch64__) || defined(__arm__) || defined(__s390__)
+    defined(__aarch64__) || defined(__arm__) || defined(__s390__) ||    \
+    SANITIZER_RISCV64
   unsigned struct_user_fpxregs_struct_sz = 0;
 #else
   unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
@@ -419,7 +433,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned struct_input_id_sz = sizeof(struct input_id);
   unsigned struct_mtpos_sz = sizeof(struct mtpos);
   unsigned struct_rtentry_sz = sizeof(struct rtentry);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
   unsigned struct_termio_sz = sizeof(struct termio);
+#endif
   unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
   unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
   unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
@@ -444,7 +460,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
 #endif // SANITIZER_LINUX
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
   unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
   unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
 #if EV_VERSION > (0x010000)
@@ -467,12 +483,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
   unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
   unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
   unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif  // SANITIZER_GLIBC
 
 #if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN
   unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
@@ -882,6 +896,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
   unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
   unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
+#if SANITIZER_GLIBC
   unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
   unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
   unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
@@ -900,6 +915,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
   unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
   unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
+#endif
   unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
   unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
   unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
@@ -970,7 +986,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
 #endif // SANITIZER_LINUX || SANITIZER_FREEBSD
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD
 CHECK_TYPE_SIZE(glob_t);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
@@ -981,7 +997,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
-#endif
+#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD
 
 CHECK_TYPE_SIZE(addrinfo);
 CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
@@ -1004,17 +1020,27 @@ CHECK_TYPE_SIZE(iovec);
 CHECK_SIZE_AND_OFFSET(iovec, iov_base);
 CHECK_SIZE_AND_OFFSET(iovec, iov_len);
 
+// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
+// many implementations don't conform to the standard. Since we pick the
+// non-conforming glibc definition, exclude the checks for musl (incompatible
+// sizes but compatible offsets).
 CHECK_TYPE_SIZE(msghdr);
 CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
 CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
 CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
 CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+#endif
 CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
 CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+#endif
 CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
 
 CHECK_TYPE_SIZE(cmsghdr);
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
 CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+#endif
 CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
 CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
 
@@ -1128,7 +1154,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
 CHECK_TYPE_SIZE(ether_addr);
 #endif
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC || SANITIZER_FREEBSD
 CHECK_TYPE_SIZE(ipc_perm);
 # if SANITIZER_FREEBSD
 CHECK_SIZE_AND_OFFSET(ipc_perm, key);
@@ -1190,7 +1216,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
 CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
 #endif
 
-#if SANITIZER_LINUX
+#if SANITIZER_GLIBC || SANITIZER_ANDROID
 COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
 #endif
 
@@ -1240,7 +1266,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
 COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
 COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
 CHECK_SIZE_AND_OFFSET(FILE, _flags);
 CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
@@ -1257,9 +1283,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
 CHECK_SIZE_AND_OFFSET(FILE, _markers);
 CHECK_SIZE_AND_OFFSET(FILE, _chain);
 CHECK_SIZE_AND_OFFSET(FILE, _fileno);
-#endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
 COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
 CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
 CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
@@ -1274,7 +1298,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
 CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
 CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
 CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
-#endif
+#endif  // SANITIZER_GLIBC
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD
 CHECK_TYPE_SIZE(sem_t);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index b0896f86720b3..769fe36a90f78 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz;
 extern unsigned struct_tms_sz;
 extern unsigned struct_itimerspec_sz;
 extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
 extern unsigned struct_sched_param_sz;
 extern unsigned struct_statfs64_sz;
 extern unsigned struct_regex_sz;
@@ -98,9 +99,9 @@ const unsigned struct_kernel_stat64_sz = 144;
 const unsigned struct___old_kernel_stat_sz = 0;
 const unsigned struct_kernel_stat_sz = 64;
 const unsigned struct_kernel_stat64_sz = 104;
-#elif defined(__riscv) && __riscv_xlen == 64
+#elif SANITIZER_RISCV64
 const unsigned struct_kernel_stat_sz = 128;
-const unsigned struct_kernel_stat64_sz = 104;
+const unsigned struct_kernel_stat64_sz = 0;  // RISCV64 does not use stat64
 #endif
 struct __sanitizer_perf_event_attr {
   unsigned type;
@@ -442,6 +443,8 @@ struct __sanitizer_cmsghdr {
   int cmsg_type;
 };
 #else
+// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
+// many implementations don't conform to the standard.
 struct __sanitizer_msghdr {
   void *msg_name;
   unsigned msg_namelen;
@@ -705,6 +708,12 @@ struct __sanitizer_dl_phdr_info {
 extern unsigned struct_ElfW_Phdr_sz;
 #endif
 
+struct __sanitizer_protoent {
+  char *p_name;
+  char **p_aliases;
+  int p_proto;
+};
+
 struct __sanitizer_addrinfo {
   int ai_flags;
   int ai_family;
@@ -799,7 +808,7 @@ typedef void __sanitizer_FILE;
 #if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
     (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__))
+     defined(__s390__) || SANITIZER_RISCV64)
 extern unsigned struct_user_regs_struct_sz;
 extern unsigned struct_user_fpregs_struct_sz;
 extern unsigned struct_user_fpxregs_struct_sz;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp
index 9717d98ebf1aa..565b31f68aaee 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.cpp
@@ -72,6 +72,7 @@ namespace __sanitizer {
   unsigned struct_group_sz = sizeof(struct group);
   unsigned siginfo_t_sz = sizeof(siginfo_t);
   unsigned struct_sigaction_sz = sizeof(struct sigaction);
+  unsigned struct_stack_t_sz = sizeof(stack_t);
   unsigned struct_itimerval_sz = sizeof(struct itimerval);
   unsigned pthread_t_sz = sizeof(pthread_t);
   unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
@@ -201,7 +202,8 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
 
-CHECK_TYPE_SIZE(glob_t);
+// There are additional fields we are not interested in.
+COMPILER_CHECK(sizeof(__sanitizer_glob_t) <= sizeof(glob_t));
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h
index 77ae6e6a44dbd..85995e79792d2 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h
@@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz;
 extern unsigned struct_tms_sz;
 extern unsigned struct_itimerspec_sz;
 extern unsigned struct_sigevent_sz;
+extern unsigned struct_stack_t_sz;
 extern unsigned struct_sched_param_sz;
 extern unsigned struct_statfs64_sz;
 extern unsigned struct_statfs_sz;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
index fea3483506f26..fd9025882db1e 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp
@@ -249,6 +249,7 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
   return true;
 }
 
+#if !SANITIZER_MAC
 void DumpProcessMap() {
   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   const sptr kBufSize = 4095;
@@ -263,6 +264,7 @@ void DumpProcessMap() {
   UnmapOrDie(filename, kBufSize);
 }
 #endif
+#endif
 
 const char *GetPwd() {
   return GetEnv("PWD");
@@ -309,7 +311,7 @@ uptr SignalContext::GetAddress() const {
 
 bool SignalContext::IsMemoryAccess() const {
   auto si = static_cast<const siginfo_t *>(siginfo);
-  return si->si_signo == SIGSEGV;
+  return si->si_signo == SIGSEGV || si->si_signo == SIGBUS;
 }
 
 int SignalContext::GetType() const {
@@ -363,10 +365,18 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) {
   CHECK(internal_strlen(name) < sizeof(shmname) - 10);
   internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
                     internal_getpid(), name);
+  int o_cloexec = 0;
+#if defined(O_CLOEXEC)
+  o_cloexec = O_CLOEXEC;
+#endif
   int fd = ReserveStandardFds(
-      internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU));
+      internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU));
   CHECK_GE(fd, 0);
   int res = internal_ftruncate(fd, size);
+#if !defined(O_CLOEXEC)
+  res = fcntl(fd, F_SETFD, FD_CLOEXEC);
+  CHECK_EQ(0, res);
+#endif
   CHECK_EQ(0, res);
   res = internal_unlink(shmname);
   CHECK_EQ(0, res);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
index 70c71f04d2d34..e1a2b48e5cd81 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix.h
@@ -17,7 +17,6 @@
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_freebsd.h"
 #include "sanitizer_platform_limits_netbsd.h"
-#include "sanitizer_platform_limits_openbsd.h"
 #include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_platform_limits_solaris.h"
 
@@ -42,6 +41,7 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                    int fd, u64 offset);
 uptr internal_munmap(void *addr, uptr length);
 int internal_mprotect(void *addr, uptr length, int prot);
+int internal_madvise(uptr addr, uptr length, int advice);
 
 // OS
 uptr internal_filesize(fd_t fd);  // -1 on error.
@@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
 uptr internal_waitpid(int pid, int *status, int options);
 
 int internal_fork();
-fd_t internal_spawn(const char *argv[], pid_t *pid);
+fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid);
 
 int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
                     uptr *oldlenp, const void *newp, uptr newlen);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
index 3c0c91e7cac31..623c9e361701a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -18,7 +18,6 @@
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_limits_netbsd.h"
-#include "sanitizer_platform_limits_openbsd.h"
 #include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_platform_limits_solaris.h"
 #include "sanitizer_posix.h"
@@ -61,27 +60,24 @@ void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
   uptr beg_aligned = RoundUpTo(beg, page_size);
   uptr end_aligned = RoundDownTo(end, page_size);
   if (beg_aligned < end_aligned)
-    // In the default Solaris compilation environment, madvise() is declared
-    // to take a caddr_t arg; casting it to void * results in an invalid
-    // conversion error, so use char * instead.
-    madvise((char *)beg_aligned, end_aligned - beg_aligned,
-            SANITIZER_MADVISE_DONTNEED);
+    internal_madvise(beg_aligned, end_aligned - beg_aligned,
+                     SANITIZER_MADVISE_DONTNEED);
 }
 
 void SetShadowRegionHugePageMode(uptr addr, uptr size) {
 #ifdef MADV_NOHUGEPAGE  // May not be defined on old systems.
   if (common_flags()->no_huge_pages_for_shadow)
-    madvise((char *)addr, size, MADV_NOHUGEPAGE);
+    internal_madvise(addr, size, MADV_NOHUGEPAGE);
   else
-    madvise((char *)addr, size, MADV_HUGEPAGE);
+    internal_madvise(addr, size, MADV_HUGEPAGE);
 #endif  // MADV_NOHUGEPAGE
 }
 
 bool DontDumpShadowMemory(uptr addr, uptr length) {
 #if defined(MADV_DONTDUMP)
-  return madvise((char *)addr, length, MADV_DONTDUMP) == 0;
+  return internal_madvise(addr, length, MADV_DONTDUMP) == 0;
 #elif defined(MADV_NOCORE)
-  return madvise((char *)addr, length, MADV_NOCORE) == 0;
+  return internal_madvise(addr, length, MADV_NOCORE) == 0;
 #else
   return true;
 #endif  // MADV_DONTDUMP
@@ -436,7 +432,8 @@ void AdjustStackSize(void *attr_) {
 #endif // !SANITIZER_GO
 
 pid_t StartSubprocess(const char *program, const char *const argv[],
-                      fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+                      const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
+                      fd_t stderr_fd) {
   auto file_closer = at_scope_exit([&] {
     if (stdin_fd != kInvalidFd) {
       internal_close(stdin_fd);
@@ -479,7 +476,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[],
 
     for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
 
-    execv(program, const_cast<char **>(&argv[0]));
+    internal_execve(program, const_cast<char **>(&argv[0]),
+                    const_cast<char *const *>(envp));
     internal__exit(1);
   }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
index d0e5245f84dab..a56640db43e8a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -15,18 +15,19 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||                \
-    SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
+    SANITIZER_MAC || SANITIZER_SOLARIS ||  \
+    SANITIZER_FUCHSIA
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_fuchsia.h"
 #include "sanitizer_linux.h"
 #include "sanitizer_mac.h"
 #include "sanitizer_mutex.h"
 
 namespace __sanitizer {
 
-
 // Memory protection masks.
 static const uptr kProtectionRead = 1;
 static const uptr kProtectionWrite = 2;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp
index 02ff7c0e91a86..1f489b71ad998 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp
@@ -7,11 +7,11 @@
 //===----------------------------------------------------------------------===//
 //
 // Information about the process mappings
-// (FreeBSD, OpenBSD and NetBSD-specific parts).
+// (FreeBSD and NetBSD-specific parts).
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
 #include "sanitizer_common.h"
 #if SANITIZER_FREEBSD
 #include "sanitizer_freebsd.h"
@@ -28,11 +28,6 @@
 #endif
 
 #include <limits.h>
-#if SANITIZER_OPENBSD
-#define KVME_PROT_READ KVE_PROT_READ
-#define KVME_PROT_WRITE KVE_PROT_WRITE
-#define KVME_PROT_EXEC KVE_PROT_EXEC
-#endif
 
 // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
@@ -51,10 +46,6 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
     KERN_PROC,
     KERN_PROC_VMMAP,
     getpid()
-#elif SANITIZER_OPENBSD
-    CTL_KERN,
-    KERN_PROC_VMMAP,
-    getpid()
 #elif SANITIZER_NETBSD
     CTL_VM,
     VM_PROC,
@@ -71,28 +62,12 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
   CHECK_EQ(Err, 0);
   CHECK_GT(Size, 0);
 
-#if !SANITIZER_OPENBSD
   size_t MmapedSize = Size * 4 / 3;
   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
   Size = MmapedSize;
   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
   CHECK_EQ(Err, 0);
   proc_maps->data = (char *)VmMap;
-#else
-  size_t PageSize = GetPageSize();
-  size_t MmapedSize = Size;
-  MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize;
-  char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()");
-  Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry);
-  if (Size > 0x10000)
-    Size = 0x10000;
-  Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry);
-  Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0);
-  CHECK_EQ(Err, 0);
-  MmapedSize = Size;
-  proc_maps->data = Mem;
-#endif
-
   proc_maps->mmaped_size = MmapedSize;
   proc_maps->len = Size;
 }
@@ -117,13 +92,11 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
   if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
     segment->protection |= kProtectionExecute;
 
-#if !SANITIZER_OPENBSD
   if (segment->filename != NULL && segment->filename_size > 0) {
     internal_snprintf(segment->filename,
                       Min(segment->filename_size, (uptr)PATH_MAX), "%s",
                       VmEntry->kve_path);
   }
-#endif
 
 #if SANITIZER_FREEBSD
   data_.current += VmEntry->kve_structsize;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp
index e0cb47f8ca9a1..f2cfcffaf4764 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cpp
@@ -12,7 +12,7 @@
 #include "sanitizer_platform.h"
 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \
-    SANITIZER_OPENBSD || SANITIZER_SOLARIS
+    SANITIZER_SOLARIS
 
 #include "sanitizer_common.h"
 #include "sanitizer_placement_new.h"
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
new file mode 100644
index 0000000000000..cc3e9be06458e
--- /dev/null
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_fuchsia.cpp
@@ -0,0 +1,80 @@
+//===-- sanitizer_procmaps_fuchsia.cpp
+//----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (Fuchsia-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+
+#include "sanitizer_common.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+// The cache flag is ignored on Fuchsia because a process can always get this
+// information via its process-self handle.
+MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); }
+
+void MemoryMappingLayout::Reset() {
+  data_.data.clear();
+  data_.current = 0;
+
+  size_t count;
+  zx_status_t status = _zx_object_get_info(
+      _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count);
+  if (status != ZX_OK) {
+    return;
+  }
+
+  size_t filled;
+  do {
+    data_.data.resize(count);
+    status = _zx_object_get_info(
+        _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(),
+        count * sizeof(zx_info_maps_t), &filled, &count);
+    if (status != ZX_OK) {
+      data_.data.clear();
+      return;
+    }
+  } while (filled < count);
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {}
+
+bool MemoryMappingLayout::Error() const { return data_.data.empty(); }
+
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+  while (data_.current < data_.data.size()) {
+    const auto &entry = data_.data[data_.current++];
+    if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) {
+      segment->start = entry.base;
+      segment->end = entry.base + entry.size;
+      segment->offset = entry.u.mapping.vmo_offset;
+      const auto flags = entry.u.mapping.mmu_flags;
+      segment->protection =
+          ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) |
+          ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) |
+          ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0);
+      if (segment->filename && segment->filename_size > 0) {
+        uptr len = Min(sizeof(entry.name), segment->filename_size) - 1;
+        internal_strncpy(segment->filename, entry.name, len);
+        segment->filename[len] = 0;
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp
index 8793423a60178..bf813f235bb7a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp
@@ -9,13 +9,13 @@
 // Information about the process mappings (Solaris-specific parts).
 //===----------------------------------------------------------------------===//
 
+// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
+#undef _FILE_OFFSET_BITS
 #include "sanitizer_platform.h"
 #if SANITIZER_SOLARIS
 #include "sanitizer_common.h"
 #include "sanitizer_procmaps.h"
 
-// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
-#undef _FILE_OFFSET_BITS
 #include <procfs.h>
 #include <limits.h>
 
@@ -35,7 +35,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
   if (data_.current >= last) return false;
 
-  prxmap_t *xmapentry = (prxmap_t*)data_.current;
+  prxmap_t *xmapentry =
+      const_cast<prxmap_t *>(reinterpret_cast<const prxmap_t *>(data_.current));
 
   segment->start = (uptr)xmapentry->pr_vaddr;
   segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
new file mode 100644
index 0000000000000..a288068bf9438
--- /dev/null
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
@@ -0,0 +1,23 @@
+//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTRAUTH_H
+#define SANITIZER_PTRAUTH_H
+
+#if __has_feature(ptrauth_calls)
+#include <ptrauth.h>
+#else
+// Copied from <ptrauth.h>
+#define ptrauth_strip(__value, __key) __value
+#define ptrauth_auth_data(__value, __old_key, __old_data) __value
+#define ptrauth_string_discriminator(__string) ((int)0)
+#endif
+
+#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
+
+#endif // SANITIZER_PTRAUTH_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp
index 0d2576c00ab3c..d58bd08fb1a89 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_rtems.cpp
@@ -49,6 +49,10 @@ uptr internal_getpid() {
   return getpid();
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  UNIMPLEMENTED();
+}
+
 bool FileExists(const char *filename) {
   struct stat st;
   if (stat(filename, &st))
@@ -104,8 +108,6 @@ void SetAlternateSignalStack() {}
 void UnsetAlternateSignalStack() {}
 void InitTlsSize() {}
 
-void PrintModuleMap() {}
-
 void SignalContext::DumpAllRegisters(void *context) {}
 const char *DescribeSignalOrException(int signo) { UNIMPLEMENTED(); }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
index 68d9eb65968dd..cefb870f7e258 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
@@ -53,7 +53,10 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) {
 
 INTERCEPTOR(int, sigaction_symname, int signum,
             const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) {
-  if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0;
+  if (GetHandleSignalMode(signum) == kHandleSignalExclusive) {
+    if (!oldact) return 0;
+    act = nullptr;
+  }
   SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact);
 }
 #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname)
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp
index 035f2d0ca292a..8789dcd10a954 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_solaris.cpp
@@ -74,6 +74,20 @@ DECLARE__REAL_AND_INTERNAL(int, mprotect, void *addr, uptr length, int prot) {
   return _REAL(mprotect)(addr, length, prot);
 }
 
+// Illumos' declaration of madvise cannot be made visible if _XOPEN_SOURCE
+// is defined as g++ does on Solaris.
+//
+// This declaration is consistent with Solaris 11.4. Both Illumos and Solaris
+// versions older than 11.4 declared madvise with a caddr_t as the first
+// argument, but we don't currently support Solaris versions older than 11.4,
+// and as mentioned above the declaration is not visible on Illumos so we can
+// use any declaration we like on Illumos.
+extern "C" int madvise(void *, size_t, int);
+
+int internal_madvise(uptr addr, uptr length, int advice) {
+  return madvise((void *)addr, length, advice);
+}
+
 DECLARE__REAL_AND_INTERNAL(uptr, close, fd_t fd) {
   return _REAL(close)(fd);
 }
@@ -146,10 +160,6 @@ DECLARE__REAL_AND_INTERNAL(uptr, sched_yield, void) {
   return sched_yield();
 }
 
-DECLARE__REAL_AND_INTERNAL(void, _exit, int exitcode) {
-  _exit(exitcode);
-}
-
 DECLARE__REAL_AND_INTERNAL(uptr, execve, const char *filename,
                            char *const argv[], char *const envp[]) {
   return _REAL(execve)(filename, argv, envp);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
index 30073a96ceebd..44a95214e38bf 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp
@@ -115,6 +115,12 @@ void StackDepotUnlockAll() {
   theDepot.UnlockAll();
 }
 
+void StackDepotPrintAll() {
+#if !SANITIZER_GO
+  theDepot.PrintAll();
+#endif
+}
+
 bool StackDepotReverseMap::IdDescPair::IdComparator(
     const StackDepotReverseMap::IdDescPair &a,
     const StackDepotReverseMap::IdDescPair &b) {
@@ -139,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
   if (!map_.size())
     return StackTrace();
   IdDescPair pair = {id, nullptr};
-  uptr idx =
-      InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
+  uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
   if (idx > map_.size() || map_[idx].id != id)
     return StackTrace();
   return map_[idx].desc->load();
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
index bf29cb9a006e9..0e26c1fc37c49 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -41,6 +41,7 @@ StackTrace StackDepotGet(u32 id);
 
 void StackDepotLockAll();
 void StackDepotUnlockAll();
+void StackDepotPrintAll();
 
 // Instantiating this class creates a snapshot of StackDepot which can be
 // efficiently queried with StackDepotGet(). You can use it concurrently with
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
index ef1b4f7f70555..1af2c1892eff7 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -13,9 +13,11 @@
 #ifndef SANITIZER_STACKDEPOTBASE_H
 #define SANITIZER_STACKDEPOTBASE_H
 
+#include <stdio.h>
+
+#include "sanitizer_atomic.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_mutex.h"
-#include "sanitizer_atomic.h"
 #include "sanitizer_persistent_allocator.h"
 
 namespace __sanitizer {
@@ -34,6 +36,7 @@ class StackDepotBase {
 
   void LockAll();
   void UnlockAll();
+  void PrintAll();
 
  private:
   static Node *find(Node *s, args_type args, u32 hash);
@@ -172,6 +175,21 @@ void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
   }
 }
 
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::PrintAll() {
+  for (int i = 0; i < kTabSize; ++i) {
+    atomic_uintptr_t *p = &tab[i];
+    lock(p);
+    uptr v = atomic_load(p, memory_order_relaxed);
+    Node *s = (Node *)(v & ~1UL);
+    for (; s; s = s->link) {
+      Printf("Stack for id %u:\n", s->id);
+      s->load().Print();
+    }
+    unlock(p, s);
+  }
+}
+
 } // namespace __sanitizer
 
 #endif // SANITIZER_STACKDEPOTBASE_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
index 7029da649eb86..d84d9c9fba93c 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp
@@ -10,9 +10,11 @@
 // run-time libraries.
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_stacktrace.h"
+
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
-#include "sanitizer_stacktrace.h"
+#include "sanitizer_platform.h"
 
 namespace __sanitizer {
 
@@ -21,6 +23,28 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) {
   return pc + 8;
 #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__)
   return pc + 4;
+#elif SANITIZER_RISCV64
+  // Current check order is 4 -> 2 -> 6 -> 8
+  u8 InsnByte = *(u8 *)(pc);
+  if (((InsnByte & 0x3) == 0x3) && ((InsnByte & 0x1c) != 0x1c)) {
+    // xxxxxxxxxxxbbb11 | 32 bit | bbb != 111
+    return pc + 4;
+  }
+  if ((InsnByte & 0x3) != 0x3) {
+    // xxxxxxxxxxxxxxaa | 16 bit | aa != 11
+    return pc + 2;
+  }
+  // RISC-V encoding allows instructions to be up to 8 bytes long
+  if ((InsnByte & 0x3f) == 0x1f) {
+    // xxxxxxxxxx011111 | 48 bit |
+    return pc + 6;
+  }
+  if ((InsnByte & 0x7f) == 0x3f) {
+    // xxxxxxxxx0111111 | 64 bit |
+    return pc + 8;
+  }
+  // bail-out if could not figure out the instruction size
+  return 0;
 #else
   return pc + 1;
 #endif
@@ -96,6 +120,9 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
     uhwptr pc1 = caller_frame[2];
 #elif defined(__s390__)
     uhwptr pc1 = frame[14];
+#elif defined(__riscv)
+    // frame[-1] contains the return address
+    uhwptr pc1 = frame[-1];
 #else
     uhwptr pc1 = frame[1];
 #endif
@@ -108,7 +135,13 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
       trace_buffer[size++] = (uptr) pc1;
     }
     bottom = (uptr)frame;
-    frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom);
+#if defined(__riscv)
+    // frame[-2] contain fp of the previous frame
+    uptr new_bp = (uptr)frame[-2];
+#else
+    uptr new_bp = (uptr)frame[0];
+#endif
+    frame = GetCanonicFrame(new_bp, stack_top, bottom);
   }
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
index ab71cb6a86a0b..03d4d2dd1568e 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -13,6 +13,7 @@
 #define SANITIZER_STACKTRACE_H
 
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
 
 namespace __sanitizer {
 
@@ -24,8 +25,6 @@ static const u32 kStackTraceMax = 256;
 # define SANITIZER_CAN_FAST_UNWIND 0
 #elif SANITIZER_WINDOWS
 # define SANITIZER_CAN_FAST_UNWIND 0
-#elif SANITIZER_OPENBSD
-# define SANITIZER_CAN_FAST_UNWIND 0
 #else
 # define SANITIZER_CAN_FAST_UNWIND 1
 #endif
@@ -33,7 +32,7 @@ static const u32 kStackTraceMax = 256;
 // Fast unwind is the only option on Mac for now; we will need to
 // revisit this macro when slow unwind works on Mac, see
 // https://github.com/google/sanitizers/issues/137
-#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
+#if SANITIZER_MAC || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN
 # define SANITIZER_CAN_SLOW_UNWIND 0
 #else
 # define SANITIZER_CAN_SLOW_UNWIND 1
@@ -71,8 +70,6 @@ struct StackTrace {
   static uptr GetCurrentPc();
   static inline uptr GetPreviousInstructionPc(uptr pc);
   static uptr GetNextInstructionPc(uptr pc);
-  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
-                                    int out_size);
 };
 
 // Performance-critical, must be in the header.
@@ -88,6 +85,14 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
   return pc - 4;
 #elif defined(__sparc__) || defined(__mips__)
   return pc - 8;
+#elif SANITIZER_RISCV64
+  // RV-64 has variable instruciton length...
+  // C extentions gives us 2-byte instructoins
+  // RV-64 has 4-byte instructions
+  // + RISCV architecture allows instructions up to 8 bytes
+  // It seems difficult to figure out the exact instruction length -
+  // pc - 2 seems like a safe option for the purposes of stack tracing
+  return pc - 2;
 #else
   return pc - 1;
 #endif
@@ -146,9 +151,17 @@ struct BufferedStackTrace : public StackTrace {
   friend class FastUnwindTest;
 };
 
+#if defined(__s390x__)
+static const uptr kFrameSize = 160;
+#elif defined(__s390__)
+static const uptr kFrameSize = 96;
+#else
+static const uptr kFrameSize = 2 * sizeof(uhwptr);
+#endif
+
 // Check if given pointer points into allocated stack area.
 static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
-  return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
+  return frame > stack_bottom && frame < stack_top - kFrameSize;
 }
 
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
index 2559349319b34..d0ef5f31547fa 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
@@ -26,6 +26,7 @@ void StackTrace::Print() const {
   InternalScopedString frame_desc(GetPageSizeCached() * 2);
   InternalScopedString dedup_token(GetPageSizeCached());
   int dedup_frames = common_flags()->dedup_token_length;
+  bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
   uptr frame_num = 0;
   for (uptr i = 0; i < size && trace[i]; i++) {
 #if !SANITIZER_EMSCRIPTEN
@@ -37,12 +38,17 @@ void StackTrace::Print() const {
     // addresses are not return addresses.
     uptr pc = trace[i];
 #endif
-    SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
+    SymbolizedStack *frames;
+    if (symbolize)
+      frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
+    else
+      frames = SymbolizedStack::New(pc);
     CHECK(frames);
     for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
       frame_desc.clear();
       RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
-                  cur->info, common_flags()->symbolize_vs_style,
+                  cur->info.address, symbolize ? &cur->info : nullptr,
+                  common_flags()->symbolize_vs_style,
                   common_flags()->strip_path_prefix);
       Printf("%s\n", frame_desc.data());
       if (dedup_frames-- > 0) {
@@ -114,7 +120,12 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
                               uptr out_buf_size) {
   if (!out_buf_size) return;
   pc = StackTrace::GetPreviousInstructionPc(pc);
-  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+  SymbolizedStack *frame;
+  bool symbolize = RenderNeedsSymbolization(fmt);
+  if (symbolize)
+    frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+  else
+    frame = SymbolizedStack::New(pc);
   if (!frame) {
     internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
     out_buf[out_buf_size - 1] = 0;
@@ -127,7 +138,8 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
   for (SymbolizedStack *cur = frame; cur && out_buf < out_end;
        cur = cur->next) {
     frame_desc.clear();
-    RenderFrame(&frame_desc, fmt, frame_num++, cur->info,
+    RenderFrame(&frame_desc, fmt, frame_num++, cur->info.address,
+                symbolize ? &cur->info : nullptr,
                 common_flags()->symbolize_vs_style,
                 common_flags()->strip_path_prefix);
     if (!frame_desc.length())
@@ -140,6 +152,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
   }
   CHECK(out_buf <= out_end);
   *out_buf = 0;
+  frame->ClearAll();
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp
index 150ff475316bd..c998322d39441 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.cpp
@@ -107,8 +107,14 @@ static const char *DemangleFunctionName(const char *function) {
 static const char kDefaultFormat[] = "    #%n %p %F %L";
 
 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
-                 const AddressInfo &info, bool vs_style,
+                 uptr address, const AddressInfo *info, bool vs_style,
                  const char *strip_path_prefix, const char *strip_func_prefix) {
+  // info will be null in the case where symbolization is not needed for the
+  // given format. This ensures that the code below will get a hard failure
+  // rather than print incorrect information in case RenderNeedsSymbolization
+  // ever ends up out of sync with this function. If non-null, the addresses
+  // should match.
+  CHECK(!info || address == info->address);
   if (0 == internal_strcmp(format, "DEFAULT"))
     format = kDefaultFormat;
   for (const char *p = format; *p != '\0'; p++) {
@@ -126,71 +132,70 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
       buffer->append("%zu", frame_no);
       break;
     case 'p':
-      buffer->append("0x%zx", info.address);
+      buffer->append("0x%zx", address);
       break;
     case 'm':
-      buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
+      buffer->append("%s", StripPathPrefix(info->module, strip_path_prefix));
       break;
     case 'o':
-      buffer->append("0x%zx", info.module_offset);
+      buffer->append("0x%zx", info->module_offset);
       break;
     case 'f':
-      buffer->append("%s",
-        DemangleFunctionName(
-          StripFunctionName(info.function, strip_func_prefix)));
+      buffer->append("%s", DemangleFunctionName(StripFunctionName(
+                               info->function, strip_func_prefix)));
       break;
     case 'q':
-      buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
-                                  ? info.function_offset
+      buffer->append("0x%zx", info->function_offset != AddressInfo::kUnknown
+                                  ? info->function_offset
                                   : 0x0);
       break;
     case 's':
-      buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
+      buffer->append("%s", StripPathPrefix(info->file, strip_path_prefix));
       break;
     case 'l':
-      buffer->append("%d", info.line);
+      buffer->append("%d", info->line);
       break;
     case 'c':
-      buffer->append("%d", info.column);
+      buffer->append("%d", info->column);
       break;
     // Smarter special cases.
     case 'F':
       // Function name and offset, if file is unknown.
-      if (info.function) {
-        buffer->append("in %s",
-                       DemangleFunctionName(
-                         StripFunctionName(info.function, strip_func_prefix)));
-        if (!info.file && info.function_offset != AddressInfo::kUnknown)
-          buffer->append("+0x%zx", info.function_offset);
+      if (info->function) {
+        buffer->append("in %s", DemangleFunctionName(StripFunctionName(
+                                    info->function, strip_func_prefix)));
+        if (!info->file && info->function_offset != AddressInfo::kUnknown)
+          buffer->append("+0x%zx", info->function_offset);
       }
       break;
     case 'S':
       // File/line information.
-      RenderSourceLocation(buffer, info.file, info.line, info.column, vs_style,
-                           strip_path_prefix);
+      RenderSourceLocation(buffer, info->file, info->line, info->column,
+                           vs_style, strip_path_prefix);
       break;
     case 'L':
       // Source location, or module location.
-      if (info.file) {
-        RenderSourceLocation(buffer, info.file, info.line, info.column,
+      if (info->file) {
+        RenderSourceLocation(buffer, info->file, info->line, info->column,
                              vs_style, strip_path_prefix);
-      } else if (info.module) {
-        RenderModuleLocation(buffer, info.module, info.module_offset,
-                             info.module_arch, strip_path_prefix);
+      } else if (info->module) {
+        RenderModuleLocation(buffer, info->module, info->module_offset,
+                             info->module_arch, strip_path_prefix);
       } else {
         buffer->append("(<unknown module>)");
       }
       break;
     case 'M':
       // Module basename and offset, or PC.
-      if (info.address & kExternalPCBit)
-        {} // There PCs are not meaningful.
-      else if (info.module)
+      if (address & kExternalPCBit) {
+        // There PCs are not meaningful.
+      } else if (info->module) {
         // Always strip the module name for %M.
-        RenderModuleLocation(buffer, StripModuleName(info.module),
-                             info.module_offset, info.module_arch, "");
-      else
-        buffer->append("(%p)", (void *)info.address);
+        RenderModuleLocation(buffer, StripModuleName(info->module),
+                             info->module_offset, info->module_arch, "");
+      } else {
+        buffer->append("(%p)", (void *)address);
+      }
       break;
     default:
       Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
@@ -200,6 +205,29 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
   }
 }
 
+bool RenderNeedsSymbolization(const char *format) {
+  if (0 == internal_strcmp(format, "DEFAULT"))
+    format = kDefaultFormat;
+  for (const char *p = format; *p != '\0'; p++) {
+    if (*p != '%')
+      continue;
+    p++;
+    switch (*p) {
+      case '%':
+        break;
+      case 'n':
+        // frame_no
+        break;
+      case 'p':
+        // address
+        break;
+      default:
+        return true;
+    }
+  }
+  return false;
+}
+
 void RenderData(InternalScopedString *buffer, const char *format,
                 const DataInfo *DI, const char *strip_path_prefix) {
   for (const char *p = format; *p != '\0'; p++) {
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
index f7f7629f773f9..96119b2ee9e9f 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -47,10 +47,12 @@ namespace __sanitizer {
 //        module+offset if it is known, or (<unknown module>) string.
 //   %M - prints module basename and offset, if it is known, or PC.
 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
-                 const AddressInfo &info, bool vs_style,
+                 uptr address, const AddressInfo *info, bool vs_style,
                  const char *strip_path_prefix = "",
                  const char *strip_func_prefix = "");
 
+bool RenderNeedsSymbolization(const char *format);
+
 void RenderSourceLocation(InternalScopedString *buffer, const char *file,
                           int line, int column, bool vs_style,
                           const char *strip_path_prefix);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h
index 4e42400571423..7891c1081fe71 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld.h
@@ -32,20 +32,21 @@ class SuspendedThreadsList {
 
   // Can't declare pure virtual functions in sanitizer runtimes:
   // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead.
-  virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
-                                                  uptr *sp) const {
+  virtual PtraceRegistersStatus GetRegistersAndSP(
+      uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
     UNIMPLEMENTED();
   }
 
-  // The buffer in GetRegistersAndSP should be at least this big.
-  virtual uptr RegisterCount() const { UNIMPLEMENTED(); }
   virtual uptr ThreadCount() const { UNIMPLEMENTED(); }
   virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); }
 
+ protected:
+  ~SuspendedThreadsList() {}
+
  private:
   // Prohibit copy and assign.
-  SuspendedThreadsList(const SuspendedThreadsList&);
-  void operator=(const SuspendedThreadsList&);
+  SuspendedThreadsList(const SuspendedThreadsList &) = delete;
+  void operator=(const SuspendedThreadsList &) = delete;
 };
 
 typedef void (*StopTheWorldCallback)(
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
new file mode 100644
index 0000000000000..91bf19e40dad8
--- /dev/null
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp
@@ -0,0 +1,43 @@
+//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// See sanitizer_stoptheworld.h for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FUCHSIA
+
+#include <zircon/sanitizer.h>
+
+#include "sanitizer_stoptheworld.h"
+#include "sanitizer_stoptheworld_fuchsia.h"
+
+namespace __sanitizer {
+
+// The Fuchsia implementation stops the world but doesn't offer a real
+// SuspendedThreadsList argument.  This is enough for ASan's use case,
+// and LSan does not use this API on Fuchsia.
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+  struct Params {
+    StopTheWorldCallback callback;
+    void *argument;
+  } params = {callback, argument};
+  __sanitizer_memory_snapshot(
+      nullptr, nullptr, nullptr, nullptr,
+      [](zx_status_t, void *data) {
+        auto params = reinterpret_cast<Params *>(data);
+        params->callback(SuspendedThreadsListFuchsia(), params->argument);
+      },
+      &params);
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FUCHSIA
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h
new file mode 100644
index 0000000000000..6d9ead6050865
--- /dev/null
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_fuchsia.h
@@ -0,0 +1,20 @@
+//===-- sanitizer_stoptheworld_fuchsia.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_STOPTHEWORLD_FUCHSIA_H
+#define SANITIZER_STOPTHEWORLD_FUCHSIA_H
+
+#include "sanitizer_stoptheworld.h"
+
+namespace __sanitizer {
+
+class SuspendedThreadsListFuchsia final : public SuspendedThreadsList {};
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_STOPTHEWORLD_FUCHSIA_H
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 651d5056dd9d5..53cfddcfbe0be 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -13,10 +13,10 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
-                        defined(__aarch64__) || defined(__powerpc64__) || \
-                        defined(__s390__) || defined(__i386__) || \
-                        defined(__arm__))
+#if SANITIZER_LINUX &&                                                   \
+    (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
+     defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
+     defined(__arm__) || SANITIZER_RISCV64)
 
 #include "sanitizer_stoptheworld.h"
 
@@ -31,7 +31,7 @@
 #include <sys/types.h> // for pid_t
 #include <sys/uio.h> // for iovec
 #include <elf.h> // for NT_PRSTATUS
-#if defined(__aarch64__) && !SANITIZER_ANDROID
+#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID
 // GLIBC 2.20+ sys/user does not include asm/ptrace.h
 # include <asm/ptrace.h>
 #endif
@@ -85,18 +85,18 @@
 
 namespace __sanitizer {
 
-class SuspendedThreadsListLinux : public SuspendedThreadsList {
+class SuspendedThreadsListLinux final : public SuspendedThreadsList {
  public:
   SuspendedThreadsListLinux() { thread_ids_.reserve(1024); }
 
-  tid_t GetThreadID(uptr index) const;
-  uptr ThreadCount() const;
+  tid_t GetThreadID(uptr index) const override;
+  uptr ThreadCount() const override;
   bool ContainsTid(tid_t thread_id) const;
   void Append(tid_t tid);
 
-  PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
-                                          uptr *sp) const;
-  uptr RegisterCount() const;
+  PtraceRegistersStatus GetRegistersAndSP(uptr index,
+                                          InternalMmapVector<uptr> *buffer,
+                                          uptr *sp) const override;
 
  private:
   InternalMmapVector<tid_t> thread_ids_;
@@ -485,6 +485,16 @@ typedef user_regs_struct regs_struct;
 #else
 #define REG_SP rsp
 #endif
+#define ARCH_IOVEC_FOR_GETREGSET
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+#define NT_X86_XSTATE 0x202
+#endif
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET 0x4204
+#endif
+// Compiler may use FP registers to store pointers.
+static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
 
 #elif defined(__powerpc__) || defined(__powerpc64__)
 typedef pt_regs regs_struct;
@@ -501,11 +511,21 @@ typedef struct user regs_struct;
 #elif defined(__aarch64__)
 typedef struct user_pt_regs regs_struct;
 #define REG_SP sp
+static constexpr uptr kExtraRegs[] = {0};
+#define ARCH_IOVEC_FOR_GETREGSET
+
+#elif SANITIZER_RISCV64
+typedef struct user_regs_struct regs_struct;
+// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
+#undef REG_SP
+#define REG_SP sp
+static constexpr uptr kExtraRegs[] = {0};
 #define ARCH_IOVEC_FOR_GETREGSET
 
 #elif defined(__s390__)
 typedef _user_regs_struct regs_struct;
 #define REG_SP gprs[15]
+static constexpr uptr kExtraRegs[] = {0};
 #define ARCH_IOVEC_FOR_GETREGSET
 
 #else
@@ -533,24 +553,58 @@ void SuspendedThreadsListLinux::Append(tid_t tid) {
 }
 
 PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
-    uptr index, uptr *buffer, uptr *sp) const {
+    uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
   pid_t tid = GetThreadID(index);
-  regs_struct regs;
+  constexpr uptr uptr_sz = sizeof(uptr);
   int pterrno;
 #ifdef ARCH_IOVEC_FOR_GETREGSET
-  struct iovec regset_io;
-  regset_io.iov_base = &regs;
-  regset_io.iov_len = sizeof(regs_struct);
-  bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid,
-                                (void*)NT_PRSTATUS, (void*)&regset_io),
-                                &pterrno);
+  auto append = [&](uptr regset) {
+    uptr size = buffer->size();
+    // NT_X86_XSTATE requires 64bit alignment.
+    uptr size_up = RoundUpTo(size, 8 / uptr_sz);
+    buffer->reserve(Max<uptr>(1024, size_up));
+    struct iovec regset_io;
+    for (;; buffer->resize(buffer->capacity() * 2)) {
+      buffer->resize(buffer->capacity());
+      uptr available_bytes = (buffer->size() - size_up) * uptr_sz;
+      regset_io.iov_base = buffer->data() + size_up;
+      regset_io.iov_len = available_bytes;
+      bool fail =
+          internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid,
+                                           (void *)regset, (void *)&regset_io),
+                           &pterrno);
+      if (fail) {
+        VReport(1, "Could not get regset %p from thread %d (errno %d).\n",
+                (void *)regset, tid, pterrno);
+        buffer->resize(size);
+        return false;
+      }
+
+      // Far enough from the buffer size, no need to resize and repeat.
+      if (regset_io.iov_len + 64 < available_bytes)
+        break;
+    }
+    buffer->resize(size_up + RoundUpTo(regset_io.iov_len, uptr_sz) / uptr_sz);
+    return true;
+  };
+
+  buffer->clear();
+  bool fail = !append(NT_PRSTATUS);
+  if (!fail) {
+    // Accept the first available and do not report errors.
+    for (uptr regs : kExtraRegs)
+      if (regs && append(regs))
+        break;
+  }
 #else
-  bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr,
-                                &regs), &pterrno);
-#endif
-  if (isErr) {
+  buffer->resize(RoundUpTo(sizeof(regs_struct), uptr_sz) / uptr_sz);
+  bool fail = internal_iserror(
+      internal_ptrace(PTRACE_GETREGS, tid, nullptr, buffer->data()), &pterrno);
+  if (fail)
     VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
             pterrno);
+#endif
+  if (fail) {
     // ESRCH means that the given thread is not suspended or already dead.
     // Therefore it's unsafe to inspect its data (e.g. walk through stack) and
     // we should notify caller about this.
@@ -558,14 +612,10 @@ PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
                             : REGISTERS_UNAVAILABLE;
   }
 
-  *sp = regs.REG_SP;
-  internal_memcpy(buffer, &regs, sizeof(regs));
+  *sp = reinterpret_cast<regs_struct *>(buffer->data())[0].REG_SP;
   return REGISTERS_AVAILABLE;
 }
 
-uptr SuspendedThreadsListLinux::RegisterCount() const {
-  return sizeof(regs_struct) / sizeof(uptr);
-}
 } // namespace __sanitizer
 
 #endif  // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp
index 9dffd21ecb7cc..5ec30803b7ade 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_mac.cpp
@@ -27,19 +27,19 @@ typedef struct {
   thread_t thread;
 } SuspendedThreadInfo;
 
-class SuspendedThreadsListMac : public SuspendedThreadsList {
+class SuspendedThreadsListMac final : public SuspendedThreadsList {
  public:
   SuspendedThreadsListMac() : threads_(1024) {}
 
-  tid_t GetThreadID(uptr index) const;
+  tid_t GetThreadID(uptr index) const override;
   thread_t GetThread(uptr index) const;
-  uptr ThreadCount() const;
+  uptr ThreadCount() const override;
   bool ContainsThread(thread_t thread) const;
   void Append(thread_t thread);
 
-  PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
-                                          uptr *sp) const;
-  uptr RegisterCount() const;
+  PtraceRegistersStatus GetRegistersAndSP(uptr index,
+                                          InternalMmapVector<uptr> *buffer,
+                                          uptr *sp) const override;
 
  private:
   InternalMmapVector<SuspendedThreadInfo> threads_;
@@ -50,7 +50,7 @@ struct RunThreadArgs {
   void *argument;
 };
 
-void RunThread(void *arg) {
+void *RunThread(void *arg) {
   struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;
   SuspendedThreadsListMac suspended_threads_list;
 
@@ -59,7 +59,7 @@ void RunThread(void *arg) {
   kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads);
   if (err != KERN_SUCCESS) {
     VReport(1, "Failed to get threads for task (errno %d).\n", err);
-    return;
+    return nullptr;
   }
 
   thread_t thread_self = mach_thread_self();
@@ -76,6 +76,7 @@ void RunThread(void *arg) {
   for (unsigned int i = 0; i < num_suspended; ++i) {
     thread_resume(suspended_threads_list.GetThread(i));
   }
+  return nullptr;
 }
 
 void StopTheWorld(StopTheWorldCallback callback, void *argument) {
@@ -141,7 +142,7 @@ void SuspendedThreadsListMac::Append(thread_t thread) {
 }
 
 PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
-    uptr index, uptr *buffer, uptr *sp) const {
+    uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
   thread_t thread = GetThread(index);
   regs_struct regs;
   int err;
@@ -158,8 +159,13 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
                                         : REGISTERS_UNAVAILABLE;
   }
 
-  internal_memcpy(buffer, &regs, sizeof(regs));
+  buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr));
+  internal_memcpy(buffer->data(), &regs, sizeof(regs));
+#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
+  *sp = arm_thread_state64_get_sp(regs);
+#else
   *sp = regs.SP_REG;
+#endif
 
   // On x86_64 and aarch64, we must account for the stack redzone, which is 128
   // bytes.
@@ -168,9 +174,6 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
   return REGISTERS_AVAILABLE;
 }
 
-uptr SuspendedThreadsListMac::RegisterCount() const {
-  return MACHINE_THREAD_STATE_COUNT;
-}
 } // namespace __sanitizer
 
 #endif  // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) ||
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
index 1ed21343254d5..9c7cd64255e55 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
@@ -48,7 +48,7 @@
 
 namespace __sanitizer {
 
-class SuspendedThreadsListNetBSD : public SuspendedThreadsList {
+class SuspendedThreadsListNetBSD final : public SuspendedThreadsList {
  public:
   SuspendedThreadsListNetBSD() { thread_ids_.reserve(1024); }
 
@@ -57,9 +57,9 @@ class SuspendedThreadsListNetBSD : public SuspendedThreadsList {
   bool ContainsTid(tid_t thread_id) const;
   void Append(tid_t tid);
 
-  PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
+  PtraceRegistersStatus GetRegistersAndSP(uptr index,
+                                          InternalMmapVector<uptr> *buffer,
                                           uptr *sp) const;
-  uptr RegisterCount() const;
 
  private:
   InternalMmapVector<tid_t> thread_ids_;
@@ -131,7 +131,7 @@ bool ThreadSuspender::SuspendAllThreads() {
   pl.pl_lwpid = 0;
 
   int val;
-  while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 &&
+  while ((val = internal_ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 &&
          pl.pl_lwpid != 0) {
     suspended_threads_list_.Append(pl.pl_lwpid);
     VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_);
@@ -335,7 +335,7 @@ void SuspendedThreadsListNetBSD::Append(tid_t tid) {
 }
 
 PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP(
-    uptr index, uptr *buffer, uptr *sp) const {
+    uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
   lwpid_t tid = GetThreadID(index);
   pid_t ppid = internal_getppid();
   struct reg regs;
@@ -351,14 +351,12 @@ PtraceRegistersStatus SuspendedThreadsListNetBSD::GetRegistersAndSP(
   }
 
   *sp = PTRACE_REG_SP(&regs);
-  internal_memcpy(buffer, &regs, sizeof(regs));
+  buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr));
+  internal_memcpy(buffer->data(), &regs, sizeof(regs));
 
   return REGISTERS_AVAILABLE;
 }
 
-uptr SuspendedThreadsListNetBSD::RegisterCount() const {
-  return sizeof(struct reg) / sizeof(uptr);
-}
 }  // namespace __sanitizer
 
 #endif
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp
index ce2ece5f4d512..0c4b84c767aa1 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp
@@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
     sym_->end_hook_();
 }
 
+void Symbolizer::LateInitializeTools() {
+  for (auto &tool : tools_) {
+    tool.LateInitialize();
+  }
+}
+
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
index 51648e2d0e8d7..2476b0ea7bf7d 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -209,6 +209,9 @@ class Symbolizer final {
    private:
     const Symbolizer *sym_;
   };
+
+  // Calls `LateInitialize()` on all items in `tools_`.
+  void LateInitializeTools();
 };
 
 #ifdef SANITIZER_WINDOWS
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
index c04797dd61b8b..71de1758b3e9c 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -69,6 +69,14 @@ class SymbolizerTool {
   virtual const char *Demangle(const char *name) {
     return nullptr;
   }
+
+  // Called during the LateInitialize phase of Sanitizer initialization.
+  // Usually this is a safe place to call code that might need to use user
+  // memory allocators.
+  virtual void LateInitialize() {}
+
+ protected:
+  ~SymbolizerTool() {}
 };
 
 // SymbolizerProcess encapsulates communication between the tool and
@@ -80,12 +88,16 @@ class SymbolizerProcess {
   const char *SendCommand(const char *command);
 
  protected:
+  ~SymbolizerProcess() {}
+
   /// The maximum number of arguments required to invoke a tool process.
   static const unsigned kArgVMax = 6;
 
   // Customizable by subclasses.
   virtual bool StartSymbolizerSubprocess();
   virtual bool ReadFromSymbolizer(char *buffer, uptr max_length);
+  // Return the environment to run the symbolizer in.
+  virtual char **GetEnvP() { return GetEnviron(); }
 
  private:
   virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
@@ -121,7 +133,7 @@ class LLVMSymbolizerProcess;
 
 // This tool invokes llvm-symbolizer in a subprocess. It should be as portable
 // as the llvm-symbolizer tool is.
-class LLVMSymbolizer : public SymbolizerTool {
+class LLVMSymbolizer final : public SymbolizerTool {
  public:
   explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator);
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
index e2a0f71420f0e..7b039b894b3be 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -28,7 +28,7 @@
 
 namespace __sanitizer {
 
-class LibbacktraceSymbolizer : public SymbolizerTool {
+class LibbacktraceSymbolizer final : public SymbolizerTool {
  public:
   static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 3b19a6836ec53..710da4c1cecd1 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -12,6 +12,7 @@
 
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
 #include "sanitizer_symbolizer_internal.h"
 
 namespace __sanitizer {
@@ -39,9 +40,9 @@ const char *ExtractToken(const char *str, const char *delims, char **result) {
 }
 
 const char *ExtractInt(const char *str, const char *delims, int *result) {
-  char *buff;
+  char *buff = nullptr;
   const char *ret = ExtractToken(str, delims, &buff);
-  if (buff != 0) {
+  if (buff) {
     *result = (int)internal_atoll(buff);
   }
   InternalFree(buff);
@@ -49,9 +50,9 @@ const char *ExtractInt(const char *str, const char *delims, int *result) {
 }
 
 const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
-  char *buff;
+  char *buff = nullptr;
   const char *ret = ExtractToken(str, delims, &buff);
-  if (buff != 0) {
+  if (buff) {
     *result = (uptr)internal_atoll(buff);
   }
   InternalFree(buff);
@@ -59,9 +60,9 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
 }
 
 const char *ExtractSptr(const char *str, const char *delims, sptr *result) {
-  char *buff;
+  char *buff = nullptr;
   const char *ret = ExtractToken(str, delims, &buff);
-  if (buff != 0) {
+  if (buff) {
     *result = (sptr)internal_atoll(buff);
   }
   InternalFree(buff);
@@ -83,7 +84,7 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
 
 SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
   BlockingMutexLock l(&mu_);
-  const char *module_name;
+  const char *module_name = nullptr;
   uptr module_offset;
   ModuleArch arch;
   SymbolizedStack *res = SymbolizedStack::New(addr);
@@ -103,7 +104,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
 
 bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
   BlockingMutexLock l(&mu_);
-  const char *module_name;
+  const char *module_name = nullptr;
   uptr module_offset;
   ModuleArch arch;
   if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
@@ -124,7 +125,7 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
 
 bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
   BlockingMutexLock l(&mu_);
-  const char *module_name;
+  const char *module_name = nullptr;
   if (!FindModuleNameAndOffsetForAddress(
           addr, &module_name, &info->module_offset, &info->module_arch))
     return false;
@@ -175,7 +176,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
                                                    uptr *module_offset,
                                                    ModuleArch *module_arch) {
   const LoadedModule *module = FindModuleForAddress(address);
-  if (module == nullptr)
+  if (!module)
     return false;
   *module_name = module->full_name();
   *module_offset = address - module->base_address();
@@ -236,7 +237,7 @@ const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
 //   <file_name>:<line_number>:<column_number>
 //   ...
 //   <empty line>
-class LLVMSymbolizerProcess : public SymbolizerProcess {
+class LLVMSymbolizerProcess final : public SymbolizerProcess {
  public:
   explicit LLVMSymbolizerProcess(const char *path)
       : SymbolizerProcess(path, /*use_posix_spawn=*/SANITIZER_MAC) {}
@@ -258,6 +259,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess {
     const char* const kSymbolizerArch = "--default-arch=x86_64";
 #elif defined(__i386__)
     const char* const kSymbolizerArch = "--default-arch=i386";
+#elif SANITIZER_RISCV64
+    const char *const kSymbolizerArch = "--default-arch=riscv64";
 #elif defined(__aarch64__)
     const char* const kSymbolizerArch = "--default-arch=arm64";
 #elif defined(__arm__)
@@ -275,8 +278,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess {
 #endif
 
     const char *const inline_flag = common_flags()->symbolize_inline_frames
-                                        ? "--inlining=true"
-                                        : "--inlining=false";
+                                        ? "--inlines"
+                                        : "--no-inlines";
     int i = 0;
     argv[i++] = path_to_binary;
     argv[i++] = inline_flag;
@@ -292,7 +295,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
 // Windows, so extract tokens from the right hand side first. The column info is
 // also optional.
 static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
-  char *file_line_info = 0;
+  char *file_line_info = nullptr;
   str = ExtractToken(str, "\n", &file_line_info);
   CHECK(file_line_info);
 
@@ -323,7 +326,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
   bool top_frame = true;
   SymbolizedStack *last = res;
   while (true) {
-    char *function_name = 0;
+    char *function_name = nullptr;
     str = ExtractToken(str, "\n", &function_name);
     CHECK(function_name);
     if (function_name[0] == '\0') {
@@ -402,32 +405,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   AddressInfo *info = &stack->info;
   const char *buf = FormatAndSendCommand(
       "CODE", info->module, info->module_offset, info->module_arch);
-  if (buf) {
-    ParseSymbolizePCOutput(buf, stack);
-    return true;
-  }
-  return false;
+  if (!buf)
+    return false;
+  ParseSymbolizePCOutput(buf, stack);
+  return true;
 }
 
 bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
   const char *buf = FormatAndSendCommand(
       "DATA", info->module, info->module_offset, info->module_arch);
-  if (buf) {
-    ParseSymbolizeDataOutput(buf, info);
-    info->start += (addr - info->module_offset); // Add the base address.
-    return true;
-  }
-  return false;
+  if (!buf)
+    return false;
+  ParseSymbolizeDataOutput(buf, info);
+  info->start += (addr - info->module_offset); // Add the base address.
+  return true;
 }
 
 bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) {
   const char *buf = FormatAndSendCommand(
       "FRAME", info->module, info->module_offset, info->module_arch);
-  if (buf) {
-    ParseSymbolizeFrameOutput(buf, &info->locals);
-    return true;
-  }
-  return false;
+  if (!buf)
+    return false;
+  ParseSymbolizeFrameOutput(buf, &info->locals);
+  return true;
 }
 
 const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
@@ -435,21 +435,21 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix,
                                                  uptr module_offset,
                                                  ModuleArch arch) {
   CHECK(module_name);
-  if (arch == kModuleArchUnknown) {
-    if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
-                          command_prefix, module_name,
-                          module_offset) >= static_cast<int>(kBufferSize)) {
-      Report("WARNING: Command buffer too small");
-      return nullptr;
-    }
-  } else {
-    if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n",
-                          command_prefix, module_name, ModuleArchToString(arch),
-                          module_offset) >= static_cast<int>(kBufferSize)) {
-      Report("WARNING: Command buffer too small");
-      return nullptr;
-    }
+  int size_needed = 0;
+  if (arch == kModuleArchUnknown)
+    size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n",
+                                    command_prefix, module_name, module_offset);
+  else
+    size_needed = internal_snprintf(buffer_, kBufferSize,
+                                    "%s \"%s:%s\" 0x%zx\n", command_prefix,
+                                    module_name, ModuleArchToString(arch),
+                                    module_offset);
+
+  if (size_needed >= static_cast<int>(kBufferSize)) {
+    Report("WARNING: Command buffer too small");
+    return nullptr;
   }
+
   return symbolizer_process_->SendCommand(buffer_);
 }
 
@@ -492,16 +492,16 @@ const char *SymbolizerProcess::SendCommand(const char *command) {
     Report("WARNING: Failed to use and restart external symbolizer!\n");
     failed_to_start_ = true;
   }
-  return 0;
+  return nullptr;
 }
 
 const char *SymbolizerProcess::SendCommandImpl(const char *command) {
   if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
-      return 0;
+      return nullptr;
   if (!WriteToSymbolizer(command, internal_strlen(command)))
-      return 0;
+      return nullptr;
   if (!ReadFromSymbolizer(buffer_, kBufferSize))
-      return 0;
+      return nullptr;
   return buffer_;
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
index f26efe5c50b55..5c25b28b5dc96 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
@@ -20,6 +20,7 @@
 
 #include <dlfcn.h>
 #include <errno.h>
+#include <mach/mach.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -32,8 +33,15 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   int result = dladdr((const void *)addr, &info);
   if (!result) return false;
 
-  CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
-  stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr);
+  // Compute offset if possible. `dladdr()` doesn't always ensure that `addr >=
+  // sym_addr` so only compute the offset when this holds. Failure to find the
+  // function offset is not treated as a failure because it might still be
+  // possible to get the symbol name.
+  uptr sym_addr = reinterpret_cast<uptr>(info.dli_saddr);
+  if (addr >= sym_addr) {
+    stack->info.function_offset = addr - sym_addr;
+  }
+
   const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
   if (!demangled) return false;
   stack->info.function = internal_strdup(demangled);
@@ -50,18 +58,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
   return true;
 }
 
-class AtosSymbolizerProcess : public SymbolizerProcess {
+#define K_ATOS_ENV_VAR "__check_mach_ports_lookup"
+
+// This cannot live in `AtosSymbolizerProcess` because instances of that object
+// are allocated by the internal allocator which under ASan is poisoned with
+// kAsanInternalHeapMagic.
+static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000";
+
+class AtosSymbolizerProcess final : public SymbolizerProcess {
  public:
-  explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
+  explicit AtosSymbolizerProcess(const char *path)
       : SymbolizerProcess(path, /*use_posix_spawn*/ true) {
-    // Put the string command line argument in the object so that it outlives
-    // the call to GetArgV.
-    internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid);
+    pid_str_[0] = '\0';
+  }
+
+  void LateInitialize() {
+    if (SANITIZER_IOSSIM) {
+      // `putenv()` may call malloc/realloc so it is only safe to do this
+      // during LateInitialize() or later (i.e. we can't do this in the
+      // constructor).  We also can't do this in `StartSymbolizerSubprocess()`
+      // because in TSan we switch allocators when we're symbolizing.
+      // We use `putenv()` rather than `setenv()` so that we can later directly
+      // write into the storage without LibC getting involved to change what the
+      // variable is set to
+      int result = putenv(kAtosMachPortEnvEntry);
+      CHECK_EQ(result, 0);
+    }
   }
 
  private:
   bool StartSymbolizerSubprocess() override {
     // Configure sandbox before starting atos process.
+
+    // Put the string command line argument in the object so that it outlives
+    // the call to GetArgV.
+    internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid());
+
+    if (SANITIZER_IOSSIM) {
+      // `atos` in the simulator is restricted in its ability to retrieve the
+      // task port for the target process (us) so we need to do extra work
+      // to pass our task port to it.
+      mach_port_t ports[]{mach_task_self()};
+      kern_return_t ret =
+          mach_ports_register(mach_task_self(), ports, /*count=*/1);
+      CHECK_EQ(ret, KERN_SUCCESS);
+
+      // Set environment variable that signals to `atos` that it should look
+      // for our task port. We can't call `setenv()` here because it might call
+      // malloc/realloc. To avoid that we instead update the
+      // `mach_port_env_var_entry_` variable with our current PID.
+      uptr count = internal_snprintf(kAtosMachPortEnvEntry,
+                                     sizeof(kAtosMachPortEnvEntry),
+                                     K_ATOS_ENV_VAR "=%s", pid_str_);
+      CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_));
+      // Document our assumption but without calling `getenv()` in normal
+      // builds.
+      DCHECK(getenv(K_ATOS_ENV_VAR));
+      DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0);
+    }
+
     return SymbolizerProcess::StartSymbolizerSubprocess();
   }
 
@@ -75,7 +130,7 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
     argv[i++] = path_to_binary;
     argv[i++] = "-p";
     argv[i++] = &pid_str_[0];
-    if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
+    if (GetMacosAlignedVersion() == MacosVersion(10, 9)) {
       // On Mavericks atos prints a deprecation warning which we suppress by
       // passing -d. The warning isn't present on other OSX versions, even the
       // newer ones.
@@ -85,8 +140,14 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
   }
 
   char pid_str_[16];
+  // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`.
+  static_assert(sizeof(kAtosMachPortEnvEntry) ==
+                    (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)),
+                "sizes should match");
 };
 
+#undef K_ATOS_ENV_VAR
+
 static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
                                char **out_module, char **out_file, uptr *line,
                                uptr *start_address) {
@@ -138,7 +199,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
 }
 
 AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
-    : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
+    : process_(new (*allocator) AtosSymbolizerProcess(path)) {}
 
 bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   if (!process_) return false;
@@ -165,10 +226,10 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
       start_address = reinterpret_cast<uptr>(info.dli_saddr);
   }
 
-  // Only assig to `function_offset` if we were able to get the function's
-  // start address.
-  if (start_address != AddressInfo::kUnknown) {
-    CHECK(addr >= start_address);
+  // Only assign to `function_offset` if we were able to get the function's
+  // start address and we got a sensible `start_address` (dladdr doesn't always
+  // ensure that `addr >= sym_addr`).
+  if (start_address != AddressInfo::kUnknown && addr >= start_address) {
     stack->info.function_offset = addr - start_address;
   }
   return true;
@@ -188,6 +249,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
   return true;
 }
 
+void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); }
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_MAC
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h
index 68521375e64c4..401d30fa50330 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h
@@ -21,7 +21,7 @@
 
 namespace __sanitizer {
 
-class DlAddrSymbolizer : public SymbolizerTool {
+class DlAddrSymbolizer final : public SymbolizerTool {
  public:
   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
   bool SymbolizeData(uptr addr, DataInfo *info) override;
@@ -29,12 +29,13 @@ class DlAddrSymbolizer : public SymbolizerTool {
 
 class AtosSymbolizerProcess;
 
-class AtosSymbolizer : public SymbolizerTool {
+class AtosSymbolizer final : public SymbolizerTool {
  public:
   explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator);
 
   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
   bool SymbolizeData(uptr addr, DataInfo *info) override;
+  void LateInitialize() override;
 
  private:
   AtosSymbolizerProcess *process_;
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
index 57b4d0c9d9613..30cba08ed5390 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp
@@ -83,18 +83,23 @@ void RenderData(InternalScopedString *buffer, const char *format,
   buffer->append(kFormatData, DI->start);
 }
 
+bool RenderNeedsSymbolization(const char *format) { return false; }
+
 // We don't support the stack_trace_format flag at all.
 void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
-                 const AddressInfo &info, bool vs_style,
+                 uptr address, const AddressInfo *info, bool vs_style,
                  const char *strip_path_prefix, const char *strip_func_prefix) {
-  buffer->append(kFormatFrame, frame_no, info.address);
+  CHECK(!RenderNeedsSymbolization(format));
+  buffer->append(kFormatFrame, frame_no, address);
 }
 
 Symbolizer *Symbolizer::PlatformInit() {
   return new (symbolizer_allocator_) Symbolizer({});
 }
 
-void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
+void Symbolizer::LateInitialize() {
+  Symbolizer::GetOrInit()->LateInitializeTools();
+}
 
 void StartReportDeadlySignal() {}
 void ReportDeadlySignal(const SignalContext &sig, u32 tid,
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index 3918348b47bec..ef7635cf792b4 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -78,13 +78,6 @@ static void InitializeSwiftDemangler() {
 // Attempts to demangle a Swift name. The demangler will return nullptr if a
 // non-Swift name is passed in.
 const char *DemangleSwift(const char *name) {
-  if (!name) return nullptr;
-
-  // Check if we are dealing with a Swift mangled name first.
-  if (name[0] != '_' || name[1] != 'T') {
-    return nullptr;
-  }
-
   if (swift_demangle_f)
     return swift_demangle_f(name, internal_strlen(name), 0, 0, 0);
 
@@ -151,9 +144,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
   GetArgV(path_, argv);
   pid_t pid;
 
+  // Report how symbolizer is being launched for debugging purposes.
+  if (Verbosity() >= 3) {
+    // Only use `Report` for first line so subsequent prints don't get prefixed
+    // with current PID.
+    Report("Launching Symbolizer process: ");
+    for (unsigned index = 0; index < kArgVMax && argv[index]; ++index)
+      Printf("%s ", argv[index]);
+    Printf("\n");
+  }
+
   if (use_posix_spawn_) {
 #if SANITIZER_MAC
-    fd_t fd = internal_spawn(argv, &pid);
+    fd_t fd = internal_spawn(argv, const_cast<const char **>(GetEnvP()), &pid);
     if (fd == kInvalidFd) {
       Report("WARNING: failed to spawn external symbolizer (errno: %d)\n",
              errno);
@@ -173,7 +176,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
       return false;
     }
 
-    pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
+    pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0],
                           /* stdout */ infd[1]);
     if (pid < 0) {
       internal_close(infd[0]);
@@ -198,7 +201,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
   return true;
 }
 
-class Addr2LineProcess : public SymbolizerProcess {
+class Addr2LineProcess final : public SymbolizerProcess {
  public:
   Addr2LineProcess(const char *path, const char *module_name)
       : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
@@ -258,7 +261,7 @@ bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer,
                           output_terminator_, kTerminatorLen);
 }
 
-class Addr2LinePool : public SymbolizerTool {
+class Addr2LinePool final : public SymbolizerTool {
  public:
   explicit Addr2LinePool(const char *addr2line_path,
                          LowLevelAllocator *allocator)
@@ -311,9 +314,10 @@ class Addr2LinePool : public SymbolizerTool {
 
 #if SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
-                                char *Buffer, int MaxLength);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE bool
+__sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+                           char *Buffer, int MaxLength,
+                           bool SymbolizeInlineFrames);
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
                                 char *Buffer, int MaxLength);
@@ -324,7 +328,7 @@ int __sanitizer_symbolize_demangle(const char *Name, char *Buffer,
                                    int MaxLength);
 }  // extern "C"
 
-class InternalSymbolizer : public SymbolizerTool {
+class InternalSymbolizer final : public SymbolizerTool {
  public:
   static InternalSymbolizer *get(LowLevelAllocator *alloc) {
     if (__sanitizer_symbolize_code != 0 &&
@@ -336,7 +340,8 @@ class InternalSymbolizer : public SymbolizerTool {
 
   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
     bool result = __sanitizer_symbolize_code(
-        stack->info.module, stack->info.module_offset, buffer_, kBufferSize);
+        stack->info.module, stack->info.module_offset, buffer_, kBufferSize,
+        common_flags()->symbolize_inline_frames);
     if (result) ParseSymbolizePCOutput(buffer_, stack);
     return result;
   }
@@ -382,7 +387,7 @@ class InternalSymbolizer : public SymbolizerTool {
 };
 #else  // SANITIZER_SUPPORTS_WEAK_HOOKS
 
-class InternalSymbolizer : public SymbolizerTool {
+class InternalSymbolizer final : public SymbolizerTool {
  public:
   static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
 };
@@ -478,7 +483,7 @@ Symbolizer *Symbolizer::PlatformInit() {
 }
 
 void Symbolizer::LateInitialize() {
-  Symbolizer::GetOrInit();
+  Symbolizer::GetOrInit()->LateInitializeTools();
   InitializeSwiftDemangler();
 }
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
index 4783459fba52a..1e3d16141b80a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -33,7 +33,8 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
   if (!common_flags()->print_summary) return;
   InternalScopedString buff(kMaxSummaryLength);
   buff.append("%s ", error_type);
-  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
+  RenderFrame(&buff, "%L %F", 0, info.address, &info,
+              common_flags()->symbolize_vs_style,
               common_flags()->strip_path_prefix);
   ReportErrorSummary(buff.data(), alt_tool_name);
 }
@@ -42,7 +43,7 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info,
 #if SANITIZER_EMSCRIPTEN
 #include <emscripten/em_asm.h>
 
-static INLINE bool ReportSupportsColors() {
+static inline bool ReportSupportsColors() {
   return !!EM_ASM_INT({
     var setting = Module['printWithColors'];
     if (setting != null) {
@@ -61,14 +62,14 @@ bool ReportFile::SupportsColors() {
   return SupportsColoredOutput(fd);
 }
 
-static INLINE bool ReportSupportsColors() {
+static inline bool ReportSupportsColors() {
   return report_file.SupportsColors();
 }
 
 #else  // SANITIZER_FUCHSIA
 
 // Fuchsia's logs always go through post-processing that handles colorization.
-static INLINE bool ReportSupportsColors() { return true; }
+static inline bool ReportSupportsColors() { return true; }
 
 #endif  // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA
 
@@ -224,7 +225,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
     Report("The signal is caused by a %s memory access.\n", access_type);
     if (!sig.is_true_faulting_addr)
       Report("Hint: this fault was caused by a dereference of a high value "
-             "address (see register values below).  Dissassemble the provided "
+             "address (see register values below).  Disassemble the provided "
              "pc to learn which register was used.\n");
     else if (sig.addr < GetPageSizeCached())
       Report("Hint: address points to the zero page.\n");
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp
index 2808779156edd..7db7d3b0eb9d8 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp
@@ -33,7 +33,7 @@ decltype(::UnDecorateSymbolName) *UnDecorateSymbolName;
 
 namespace {
 
-class WinSymbolizerTool : public SymbolizerTool {
+class WinSymbolizerTool final : public SymbolizerTool {
  public:
   // The constructor is provided to avoid synthesized memsets.
   WinSymbolizerTool() {}
@@ -133,10 +133,14 @@ void InitializeDbgHelpIfNeeded() {
   }
 }
 
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wframe-larger-than="
+#endif
 bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
   InitializeDbgHelpIfNeeded();
 
-  // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+  // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
   char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
   PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
   symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
@@ -162,6 +166,9 @@ bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
   // Otherwise, try llvm-symbolizer.
   return got_fileline;
 }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
 
 const char *WinSymbolizerTool::Demangle(const char *name) {
   CHECK(is_dbghelp_initialized);
@@ -310,7 +317,7 @@ Symbolizer *Symbolizer::PlatformInit() {
 }
 
 void Symbolizer::LateInitialize() {
-  Symbolizer::GetOrInit();
+  Symbolizer::GetOrInit()->LateInitializeTools();
 }
 
 }  // namespace __sanitizer
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
index f64b403d62aa8..ba7ed46f861cc 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -13,7 +13,7 @@
 // NetBSD uses libc calls directly
 #if !SANITIZER_NETBSD
 
-#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN
 # define SYSCALL(name) SYS_ ## name
 #else
 # define SYSCALL(name) __NR_ ## name
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc
new file mode 100644
index 0000000000000..89c12602057c7
--- /dev/null
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_linux_riscv64.inc
@@ -0,0 +1,174 @@
+//===-- sanitizer_syscall_linux_riscv64.inc ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of internal_syscall and internal_iserror for Linux/riscv64.
+//
+//===----------------------------------------------------------------------===//
+
+// About local register variables:
+// https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables
+//
+// Kernel ABI...
+// To my surprise I haven't found much information regarding it.
+// Kernel source and internet browsing shows that:
+//  syscall number is passed in a7
+//  (http://man7.org/linux/man-pages/man2/syscall.2.html) results are return in
+//  a0 and a1 (http://man7.org/linux/man-pages/man2/syscall.2.html) arguments
+//  are passed in: a0-a7 (see below)
+//
+//  Regarding the arguments. The only "documentation" I could find is
+//  this comment (!!!) by Bruce Hold on google forums (!!!):
+//    https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/exbrzM3GZDQ
+//    Confirmed by inspecting glibc sources.
+//  Great way to document things.
+#define SYSCALL(name) __NR_##name
+
+#define INTERNAL_SYSCALL_CLOBBERS "memory"
+
+static uptr __internal_syscall(u64 nr) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0");
+  __asm__ volatile("ecall\n\t"
+                   : "=r"(a0)
+                   : "r"(a7)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall0(n) (__internal_syscall)(n)
+
+static uptr __internal_syscall(u64 nr, u64 arg1) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall1(n, a1) (__internal_syscall)(n, (u64)(a1))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall2(n, a1, a2) \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  register u64 a2 asm("a2") = arg3;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1), "r"(a2)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall3(n, a1, a2, a3) \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3,
+                               u64 arg4) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  register u64 a2 asm("a2") = arg3;
+  register u64 a3 asm("a3") = arg4;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1), "r"(a2), "r"(a3)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall4(n, a1, a2, a3, a4) \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
+                               long arg5) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  register u64 a2 asm("a2") = arg3;
+  register u64 a3 asm("a3") = arg4;
+  register u64 a4 asm("a4") = arg5;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall5(n, a1, a2, a3, a4, a5)                       \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
+                       (u64)(a5))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
+                               long arg5, long arg6) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  register u64 a2 asm("a2") = arg3;
+  register u64 a3 asm("a3") = arg4;
+  register u64 a4 asm("a4") = arg5;
+  register u64 a5 asm("a5") = arg6;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6)                   \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
+                       (u64)(a5), (long)(a6))
+
+static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, u64 arg4,
+                               long arg5, long arg6, long arg7) {
+  register u64 a7 asm("a7") = nr;
+  register u64 a0 asm("a0") = arg1;
+  register u64 a1 asm("a1") = arg2;
+  register u64 a2 asm("a2") = arg3;
+  register u64 a3 asm("a3") = arg4;
+  register u64 a4 asm("a4") = arg5;
+  register u64 a5 asm("a5") = arg6;
+  register u64 a6 asm("a6") = arg7;
+  __asm__ volatile("ecall\n\t"
+                   : "+r"(a0)
+                   : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
+                     "r"(a6)
+                   : INTERNAL_SYSCALL_CLOBBERS);
+  return a0;
+}
+#define __internal_syscall7(n, a1, a2, a3, a4, a5, a6, a7)               \
+  (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \
+                       (u64)(a5), (long)(a6), (long)(a7))
+
+#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n
+#define __SYSCALL_NARGS(...) \
+  __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, )
+#define __SYSCALL_CONCAT_X(a, b) a##b
+#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b)
+#define __SYSCALL_DISP(b, ...) \
+  __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__)
+
+// Helper function used to avoid clobbering of errno.
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval >= (uptr)-4095) {
+    if (rverrno)
+      *rverrno = -retval;
+    return true;
+  }
+  return false;
+}
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc
index 02b7e11b1677f..c4a9d99fe2f01 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_syscalls_netbsd.inc
@@ -42,8 +42,8 @@
 // DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
 //
 // Generated with: generate_netbsd_syscalls.awk
-// Generated date: 2019-12-24
-// Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp
+// Generated date: 2020-09-10
+// Generated from: syscalls.master,v 1.306 2020/08/14 00:53:16 riastradh Exp
 //
 //===----------------------------------------------------------------------===//
 
@@ -872,7 +872,13 @@ PRE_SYSCALL(dup2)(long long from_, long long to_) { /* Nothing to do */ }
 POST_SYSCALL(dup2)(long long res, long long from_, long long to_) {
   /* Nothing to do */
 }
-/* syscall 91 has been skipped */
+PRE_SYSCALL(getrandom)(void *buf_, long long buflen_, long long flags_) {
+  /* TODO */
+}
+POST_SYSCALL(getrandom)
+(long long res, void *buf_, long long buflen_, long long flags_) {
+  /* TODO */
+}
 PRE_SYSCALL(fcntl)(long long fd_, long long cmd_, void *arg_) {
   /* Nothing to do */
 }
@@ -1332,9 +1338,29 @@ PRE_SYSCALL(compat_09_ouname)(void *name_) { /* TODO */ }
 POST_SYSCALL(compat_09_ouname)(long long res, void *name_) { /* TODO */ }
 PRE_SYSCALL(sysarch)(long long op_, void *parms_) { /* TODO */ }
 POST_SYSCALL(sysarch)(long long res, long long op_, void *parms_) { /* TODO */ }
-/* syscall 166 has been skipped */
-/* syscall 167 has been skipped */
-/* syscall 168 has been skipped */
+PRE_SYSCALL(__futex)
+(void *uaddr_, long long op_, long long val_, void *timeout_, void *uaddr2_,
+  long long val2_, long long val3_) {
+  /* TODO */
+}
+POST_SYSCALL(__futex)
+(long long res, void *uaddr_, long long op_, long long val_, void *timeout_,
+  void *uaddr2_, long long val2_, long long val3_) {
+  /* TODO */
+}
+PRE_SYSCALL(__futex_set_robust_list)(void *head_, long long len_) { /* TODO */ }
+POST_SYSCALL(__futex_set_robust_list)
+(long long res, void *head_, long long len_) {
+  /* TODO */
+}
+PRE_SYSCALL(__futex_get_robust_list)
+(long long lwpid_, void **headp_, void *lenp_) {
+  /* TODO */
+}
+POST_SYSCALL(__futex_get_robust_list)
+(long long res, long long lwpid_, void **headp_, void *lenp_) {
+  /* TODO */
+}
 #if !defined(_LP64)
 PRE_SYSCALL(compat_10_osemsys)
 (long long which_, long long a2_, long long a3_, long long a4_, long long a5_) {
@@ -3824,6 +3850,87 @@ PRE_SYSCALL(__fhstatvfs190)
 }
 POST_SYSCALL(__fhstatvfs190)
 (long long res, void *fhp_, long long fh_size_, void *buf_, long long flags_) {}
+PRE_SYSCALL(__acl_get_link)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_get_link)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_set_link)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_set_link)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_delete_link)(void *path_, long long type_) { /* TODO */ }
+POST_SYSCALL(__acl_delete_link)(long long res, void *path_, long long type_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_aclcheck_link)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_aclcheck_link)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_get_file)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_get_file)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_set_file)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_set_file)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_get_fd)(long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_get_fd)
+(long long res, long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_set_fd)(long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_set_fd)
+(long long res, long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_delete_file)(void *path_, long long type_) { /* TODO */ }
+POST_SYSCALL(__acl_delete_file)(long long res, void *path_, long long type_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_delete_fd)(long long filedes_, long long type_) { /* TODO */ }
+POST_SYSCALL(__acl_delete_fd)
+(long long res, long long filedes_, long long type_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_aclcheck_file)(void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_aclcheck_file)
+(long long res, void *path_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(__acl_aclcheck_fd)
+(long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+POST_SYSCALL(__acl_aclcheck_fd)
+(long long res, long long filedes_, long long type_, void *aclp_) {
+  /* TODO */
+}
+PRE_SYSCALL(lpathconf)(void *path_, long long name_) { /* TODO */ }
+POST_SYSCALL(lpathconf)(long long res, void *path_, long long name_) {
+  /* TODO */
+}
 #undef SYS_MAXSYSARGS
 } // extern "C"
 
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
index 493aa988f7e6d..85c522a31cac4 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -39,8 +39,6 @@ enum class ThreadType {
 class ThreadContextBase {
  public:
   explicit ThreadContextBase(u32 tid);
-  ~ThreadContextBase();  // Should never be called.
-
   const u32 tid;  // Thread ID. Main thread should have tid = 0.
   u64 unique_id;  // Unique thread ID.
   u32 reuse_count;  // Number of times this tid was reused.
@@ -80,6 +78,9 @@ class ThreadContextBase {
   virtual void OnCreated(void *arg) {}
   virtual void OnReset() {}
   virtual void OnDetached(void *arg) {}
+
+ protected:
+  ~ThreadContextBase();
 };
 
 typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp
index 9ca898a306a88..1f664b6cf5b8f 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cpp
@@ -12,6 +12,7 @@
 
 #include "sanitizer_tls_get_addr.h"
 
+#include "sanitizer_atomic.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_interceptors.h"
 
@@ -42,46 +43,66 @@ static atomic_uintptr_t number_of_live_dtls;
 
 static const uptr kDestroyedThread = -1;
 
-static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
-  if (!size) return;
-  VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
-  UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
+static void DTLS_Deallocate(DTLS::DTVBlock *block) {
+  VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
+  UnmapOrDie(block, sizeof(DTLS::DTVBlock));
   atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
 }
 
-static inline void DTLS_Resize(uptr new_size) {
-  if (dtls.dtv_size >= new_size) return;
-  new_size = RoundUpToPowerOfTwo(new_size);
-  new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
-  DTLS::DTV *new_dtv =
-      (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
+static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
+  uptr v = atomic_load(cur, memory_order_acquire);
+  if (v == kDestroyedThread)
+    return nullptr;
+  DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
+  if (next)
+    return next;
+  DTLS::DTVBlock *new_dtv =
+      (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
+  uptr prev = 0;
+  if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
+                                      memory_order_seq_cst)) {
+    UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
+    return (DTLS::DTVBlock *)prev;
+  }
   uptr num_live_dtls =
       atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
-  VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
-  CHECK_LT(num_live_dtls, 1 << 20);
-  uptr old_dtv_size = dtls.dtv_size;
-  DTLS::DTV *old_dtv = dtls.dtv;
-  if (old_dtv_size)
-    internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
-  dtls.dtv = new_dtv;
-  dtls.dtv_size = new_size;
-  if (old_dtv_size)
-    DTLS_Deallocate(old_dtv, old_dtv_size);
+  VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
+  return new_dtv;
+}
+
+static DTLS::DTV *DTLS_Find(uptr id) {
+  VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
+  static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
+  DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
+  if (!cur)
+    return nullptr;
+  for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
+  return cur->dtvs + id;
 }
 
 void DTLS_Destroy() {
   if (!common_flags()->intercept_tls_get_addr) return;
-  VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
-  uptr s = dtls.dtv_size;
-  dtls.dtv_size = kDestroyedThread;  // Do this before unmap for AS-safety.
-  DTLS_Deallocate(dtls.dtv, s);
+  VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
+  DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
+      &dtls.dtv_block, kDestroyedThread, memory_order_release);
+  while (block) {
+    DTLS::DTVBlock *next =
+        (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
+    DTLS_Deallocate(block);
+    block = next;
+  }
 }
 
 #if defined(__powerpc64__) || defined(__mips__)
 // This is glibc's TLS_DTV_OFFSET:
 // "Dynamic thread vector pointers point 0x8000 past the start of each
-//  TLS block."
+//  TLS block." (sysdeps/<arch>/dl-tls.h)
 static const uptr kDtvOffset = 0x8000;
+#elif defined(__riscv)
+// This is glibc's TLS_DTV_OFFSET:
+// "Dynamic thread vector pointers point 0x800 past the start of each
+// TLS block." (sysdeps/riscv/dl-tls.h)
+static const uptr kDtvOffset = 0x800;
 #else
 static const uptr kDtvOffset = 0;
 #endif
@@ -91,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
   if (!common_flags()->intercept_tls_get_addr) return 0;
   TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
   uptr dso_id = arg->dso_id;
-  if (dtls.dtv_size == kDestroyedThread) return 0;
-  DTLS_Resize(dso_id + 1);
-  if (dtls.dtv[dso_id].beg) return 0;
+  DTLS::DTV *dtv = DTLS_Find(dso_id);
+  if (!dtv || dtv->beg)
+    return 0;
   uptr tls_size = 0;
   uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
   VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
@@ -121,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
     // This may happen inside the DTOR of main thread, so just ignore it.
     tls_size = 0;
   }
-  dtls.dtv[dso_id].beg = tls_beg;
-  dtls.dtv[dso_id].size = tls_size;
-  return dtls.dtv + dso_id;
+  dtv->beg = tls_beg;
+  dtv->size = tls_size;
+  return dtv;
 }
 
 void DTLS_on_libc_memalign(void *ptr, uptr size) {
@@ -136,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
 DTLS *DTLS_Get() { return &dtls; }
 
 bool DTLSInDestruction(DTLS *dtls) {
-  return dtls->dtv_size == kDestroyedThread;
+  return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
+         kDestroyedThread;
 }
 
 #else
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h
index c7cd5a8bffcf9..a599c0bbc75cc 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h
@@ -28,6 +28,7 @@
 #ifndef SANITIZER_TLS_GET_ADDR_H
 #define SANITIZER_TLS_GET_ADDR_H
 
+#include "sanitizer_atomic.h"
 #include "sanitizer_common.h"
 
 namespace __sanitizer {
@@ -38,15 +39,31 @@ struct DTLS {
   struct DTV {
     uptr beg, size;
   };
+  struct DTVBlock {
+    atomic_uintptr_t next;
+    DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
+  };
+
+  static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
 
-  uptr dtv_size;
-  DTV *dtv;  // dtv_size elements, allocated by MmapOrDie.
+  atomic_uintptr_t dtv_block;
 
   // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
   uptr last_memalign_size;
   uptr last_memalign_ptr;
 };
 
+template <typename Fn>
+void ForEachDVT(DTLS *dtls, const Fn &fn) {
+  DTLS::DTVBlock *block =
+      (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
+  while (block) {
+    int id = 0;
+    for (auto &d : block->dtvs) fn(d, id++);
+    block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
+  }
+}
+
 // Returns pointer and size of a linker-allocated TLS block.
 // Each block is returned exactly once.
 DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp
index 8e06940685dcb..7e01c81d0422a 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp
@@ -37,8 +37,16 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
   // Skip the RTL frames by searching for the PC in the stacktrace.
   uptr pc_location = LocatePcInTrace(pc);
   PopStackFrames(pc_location);
+
+  // Replace the first frame with the PC because the frame in the
+  // stacktrace might be incorrect.
+  trace_buffer[0] = pc;
 }
 
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wframe-larger-than="
+#endif
 void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
   CHECK(context);
   CHECK_GE(max_depth, 2);
@@ -70,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
     trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
   }
 }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
 #endif  // #if !SANITIZER_GO
 
 #endif  // SANITIZER_WINDOWS
diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
index 36dde49d87083..63c90785f2702 100644
--- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
+++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
@@ -94,6 +94,10 @@ uptr internal_getpid() {
   return GetProcessId(GetCurrentProcess());
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  UNIMPLEMENTED();
+}
+
 // In contrast to POSIX, on Windows GetCurrentThreadId()
 // returns a system-unique identifier.
 tid_t GetTid() {
@@ -344,6 +348,22 @@ bool DontDumpShadowMemory(uptr addr, uptr length) {
   return true;
 }
 
+uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
+                      uptr min_shadow_base_alignment,
+                      UNUSED uptr &high_mem_end) {
+  const uptr granularity = GetMmapGranularity();
+  const uptr alignment =
+      Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
+  const uptr left_padding =
+      Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
+  uptr space_size = shadow_size_bytes + left_padding;
+  uptr shadow_start = FindAvailableMemoryRange(space_size, alignment,
+                                               granularity, nullptr, nullptr);
+  CHECK_NE((uptr)0, shadow_start);
+  CHECK(IsAligned(shadow_start, alignment));
+  return shadow_start;
+}
+
 uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
                               uptr *largest_gap_found,
                               uptr *max_occupied_addr) {
@@ -471,8 +491,6 @@ void DumpProcessMap() {
 }
 #endif
 
-void PrintModuleMap() { }
-
 void DisableCoreDumperIfNecessary() {
   // Do nothing.
 }
@@ -593,6 +611,10 @@ static uptr GetPreferredBase(const char *modname) {
   return (uptr)pe_header->ImageBase;
 }
 
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wframe-larger-than="
+#endif
 void ListOfModules::init() {
   clearOrInit();
   HANDLE cur_process = GetCurrentProcess();
@@ -654,6 +676,9 @@ void ListOfModules::init() {
   }
   UnmapOrDie(hmodules, modules_buffer_size);
 }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
 
 void ListOfModules::fallbackInit() { clear(); }
 
@@ -787,7 +812,7 @@ uptr GetRSS() {
   return counters.WorkingSetSize;
 }
 
-void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
+void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
 void internal_join_thread(void *th) { }
 
 // ---------------------- BlockingMutex ---------------- {{{1
@@ -938,22 +963,27 @@ void SignalContext::InitPcSpBp() {
 
 uptr SignalContext::GetAddress() const {
   EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
-  return exception_record->ExceptionInformation[1];
+  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+    return exception_record->ExceptionInformation[1];
+  return (uptr)exception_record->ExceptionAddress;
 }
 
 bool SignalContext::IsMemoryAccess() const {
-  return GetWriteFlag() != SignalContext::UNKNOWN;
+  return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
+         EXCEPTION_ACCESS_VIOLATION;
 }
 
-bool SignalContext::IsTrueFaultingAddress() const {
-  // FIXME: Provide real implementation for this. See Linux and Mac variants.
-  return IsMemoryAccess();
-}
+bool SignalContext::IsTrueFaultingAddress() const { return true; }
 
 SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
   EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
+
+  // The write flag is only available for access violation exceptions.
+  if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
+    return SignalContext::UNKNOWN;
+
   // The contents of this array are documented at
-  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
+  // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
   // The first element indicates read as 0, write as 1, or execute as 8.  The
   // second element is the faulting address.
   switch (exception_record->ExceptionInformation[0]) {
@@ -1060,7 +1090,8 @@ char **GetEnviron() {
 }
 
 pid_t StartSubprocess(const char *program, const char *const argv[],
-                      fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+                      const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
+                      fd_t stderr_fd) {
   // FIXME: implement on this platform
   // Should be implemented based on
   // SymbolizerProcess::StarAtSymbolizerSubprocess
@@ -1119,6 +1150,8 @@ void LogFullErrorReport(const char *buffer) {
 }
 #endif // SANITIZER_WIN_TRACE
 
+void InitializePlatformCommonFlags(CommonFlags *cf) {}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc b/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc
index 7e7216c5b4ab7..4e0c2bcf0e65f 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_checks.inc
@@ -18,6 +18,8 @@
 
 UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
 UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
+UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use",
+            "nullability-assign")
 UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
 UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
 UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment")
@@ -30,6 +32,7 @@ UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
             "integer-divide-by-zero")
 UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
 UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use")
+UBSAN_CHECK(InvalidObjCCast, "invalid-objc-cast", "invalid-objc-cast")
 UBSAN_CHECK(ImplicitUnsignedIntegerTruncation,
             "implicit-unsigned-integer-truncation",
             "implicit-unsigned-integer-truncation")
@@ -54,6 +57,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
 UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
 UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
             "returns-nonnull-attribute")
+UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return",
+            "nullability-return")
 UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
+UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument",
+            "nullability-arg")
 UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
 UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp
index 529cc6985763b..c8f7960db42ac 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_diag.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_diag.cc -----------------------------------------------------===//
+//===-- ubsan_diag.cpp ----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
index c22fd17499725..300179adae28c 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_diag_standalone.cc ------------------------------------------===//
+//===-- ubsan_diag_standalone.cpp -----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp
index 210b831507d2e..48bb217d45695 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_flags.cc ----------------------------------------------------===//
+//===-- ubsan_flags.cpp ---------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -26,10 +26,6 @@ extern "C" void emscripten_builtin_free(void *);
 
 namespace __ubsan {
 
-const char *MaybeCallUbsanDefaultOptions() {
-  return (&__ubsan_default_options) ? __ubsan_default_options() : "";
-}
-
 static const char *GetFlag(const char *flag) {
   // We cannot call getenv() from inside a preinit array initializer
   if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
@@ -76,8 +72,7 @@ void InitializeFlags() {
   RegisterUbsanFlags(&parser, f);
 
   // Override from user-specified string.
-  parser.ParseString(MaybeCallUbsanDefaultOptions());
-
+  parser.ParseString(__ubsan_default_options());
   // Override from environment variable.
 #if SANITIZER_EMSCRIPTEN
   char *options = (char*) EM_ASM_INT({
@@ -88,7 +83,7 @@ void InitializeFlags() {
   parser.ParseString(options);
   emscripten_builtin_free(options);
 #else
-  parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+  parser.ParseStringFromEnv("UBSAN_OPTIONS");
 #endif // SANITIZER_EMSCRIPTEN
 
   InitializeCommonFlags();
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h
index daa0d7c701e04..c47009bafe539 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.h
@@ -34,8 +34,6 @@ inline Flags *flags() { return &ubsan_flags; }
 void InitializeFlags();
 void RegisterUbsanFlags(FlagParser *parser, Flags *f);
 
-const char *MaybeCallUbsanDefaultOptions();
-
 }  // namespace __ubsan
 
 extern "C" {
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp
index 938ac89750f36..b070a378c0d47 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_handlers.cc -------------------------------------------------===//
+//===-- ubsan_handlers.cpp ------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -16,6 +16,7 @@
 #include "ubsan_diag.h"
 #include "ubsan_flags.h"
 #include "ubsan_monitor.h"
+#include "ubsan_value.h"
 
 #include "sanitizer_common/sanitizer_common.h"
 
@@ -36,6 +37,45 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
   return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
 }
 
+/// Situations in which we might emit a check for the suitability of a
+/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
+/// clang.
+enum TypeCheckKind {
+  /// Checking the operand of a load. Must be suitably sized and aligned.
+  TCK_Load,
+  /// Checking the destination of a store. Must be suitably sized and aligned.
+  TCK_Store,
+  /// Checking the bound value in a reference binding. Must be suitably sized
+  /// and aligned, but is not required to refer to an object (until the
+  /// reference is used), per core issue 453.
+  TCK_ReferenceBinding,
+  /// Checking the object expression in a non-static data member access. Must
+  /// be an object within its lifetime.
+  TCK_MemberAccess,
+  /// Checking the 'this' pointer for a call to a non-static member function.
+  /// Must be an object within its lifetime.
+  TCK_MemberCall,
+  /// Checking the 'this' pointer for a constructor call.
+  TCK_ConstructorCall,
+  /// Checking the operand of a static_cast to a derived pointer type. Must be
+  /// null or an object within its lifetime.
+  TCK_DowncastPointer,
+  /// Checking the operand of a static_cast to a derived reference type. Must
+  /// be an object within its lifetime.
+  TCK_DowncastReference,
+  /// Checking the operand of a cast to a base object. Must be suitably sized
+  /// and aligned.
+  TCK_Upcast,
+  /// Checking the operand of a cast to a virtual base object. Must be an
+  /// object within its lifetime.
+  TCK_UpcastToVirtualBase,
+  /// Checking the value assigned to a _Nonnull pointer. Must not be null.
+  TCK_NonnullAssign,
+  /// Checking the operand of a dynamic_cast or a typeid expression.  Must be
+  /// null or an object within its lifetime.
+  TCK_DynamicOperation
+};
+
 const char *TypeCheckKinds[] = {
     "load of", "store to", "reference binding to", "member access within",
     "member call on", "constructor call on", "downcast of", "downcast of",
@@ -50,7 +90,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
   uptr Alignment = (uptr)1 << Data->LogAlignment;
   ErrorType ET;
   if (!Pointer)
-    ET = ErrorType::NullPointerUse;
+    ET = (Data->TypeCheckKind == TCK_NonnullAssign)
+             ? ErrorType::NullPointerUseWithNullability
+             : ErrorType::NullPointerUse;
   else if (Pointer & (Alignment - 1))
     ET = ErrorType::MisalignedPointerUse;
   else
@@ -71,6 +113,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
 
   switch (ET) {
   case ErrorType::NullPointerUse:
+  case ErrorType::NullPointerUseWithNullability:
     Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
         << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
     break;
@@ -598,13 +641,44 @@ void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
   Die();
 }
 
+static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer,
+                                  ReportOptions Opts) {
+  SourceLocation Loc = Data->Loc.acquire();
+  ErrorType ET = ErrorType::InvalidObjCCast;
+
+  if (ignoreReport(Loc, Opts, ET))
+    return;
+
+  ScopedReport R(Opts, Loc, ET);
+
+  const char *GivenClass = getObjCClassName(Pointer);
+  const char *GivenClassStr = GivenClass ? GivenClass : "<unknown type>";
+
+  Diag(Loc, DL_Error, ET,
+       "invalid ObjC cast, object is a '%0', but expected a %1")
+      << GivenClassStr << Data->ExpectedType;
+}
+
+void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data,
+                                               ValueHandle Pointer) {
+  GET_REPORT_OPTIONS(false);
+  handleInvalidObjCCast(Data, Pointer, Opts);
+}
+void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data,
+                                                     ValueHandle Pointer) {
+  GET_REPORT_OPTIONS(true);
+  handleInvalidObjCCast(Data, Pointer, Opts);
+  Die();
+}
+
 static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
                                 ReportOptions Opts, bool IsAttr) {
   if (!LocPtr)
     UNREACHABLE("source location pointer is null!");
 
   SourceLocation Loc = LocPtr->acquire();
-  ErrorType ET = ErrorType::InvalidNullReturn;
+  ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
+                        : ErrorType::InvalidNullReturnWithNullability;
 
   if (ignoreReport(Loc, Opts, ET))
     return;
@@ -648,7 +722,8 @@ void __ubsan::__ubsan_handle_nullability_return_v1_abort(
 static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
                              bool IsAttr) {
   SourceLocation Loc = Data->Loc.acquire();
-  ErrorType ET = ErrorType::InvalidNullArgument;
+  ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
+                        : ErrorType::InvalidNullArgumentWithNullability;
 
   if (ignoreReport(Loc, Opts, ET))
     return;
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h
index 22ca96422381c..219fb15de55fe 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -168,6 +168,14 @@ struct InvalidBuiltinData {
 /// Handle a builtin called in an invalid way.
 RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data)
 
+struct InvalidObjCCast {
+  SourceLocation Loc;
+  const TypeDescriptor &ExpectedType;
+};
+
+/// Handle an invalid ObjC cast.
+RECOVERABLE(invalid_objc_cast, InvalidObjCCast *Data, ValueHandle Pointer)
+
 struct NonNullReturnData {
   SourceLocation AttrLoc;
 };
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
index 9c324cc19a11f..2a6d558de0342 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
+//===-- ubsan_handlers_cxx.cpp --------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp
index f0bbe1ef10768..e0be5a72ec42f 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init.cc -----------------------------------------------------===//
+//===-- ubsan_init.cpp ----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -37,10 +37,12 @@ static void CommonStandaloneInit() {
   SanitizerToolName = GetSanititizerToolName();
   CacheBinaryName();
   InitializeFlags();
+  __sanitizer::InitializePlatformEarly();
   __sanitizer_set_report_path(common_flags()->log_path);
   AndroidLogInit();
   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
   CommonInit();
+  Symbolizer::LateInitialize();
 }
 
 void __ubsan::InitAsStandalone() {
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
index 323c2c1f9a474..91c3f57b424b9 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init_standalone.cc ------------------------------------------===//
+//===-- ubsan_init_standalone.cpp -----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
index bf344a2a9fcdb..fabbf919a4022 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_init_standalone_preinit.cc ---------------------------------===//
+//===-- ubsan_init_standalone_preinit.cpp --------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc b/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc
index 1e44bc2171ded..94337d85017b4 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_interface.inc
@@ -27,6 +27,8 @@ INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion)
 INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion_abort)
 INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin)
 INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort)
+INTERFACE_FUNCTION(__ubsan_handle_invalid_objc_cast)
+INTERFACE_FUNCTION(__ubsan_handle_invalid_objc_cast_abort)
 INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value)
 INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value_abort)
 INTERFACE_FUNCTION(__ubsan_handle_missing_return)
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp
index cb97a8ff1b887..d064e95f76f72 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_monitor.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===//
+//===-- ubsan_monitor.cpp ---------------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h b/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h
index 684af5a5c179b..82efd0c3414ee 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_platform.h
@@ -14,7 +14,7 @@
 
 // Other platforms should be easy to add, and probably work as-is.
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||        \
-    defined(__NetBSD__) || defined(__OpenBSD__) || \
+    defined(__NetBSD__) || \
     (defined(__sun__) && defined(__svr4__)) || \
     defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) || \
     defined(__EMSCRIPTEN__)
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
index 5f8a8c0662d4f..8d980e1a26391 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
@@ -1,5 +1,4 @@
-//=-- ubsan_signals_standalone.cc
-//------------------------------------------------===//
+//=-- ubsan_signals_standalone.cpp ----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
index 431495672b55a..8f4b9aee50bbd 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash.cc ------------------------------------------------===//
+//===-- ubsan_type_hash.cpp -----------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -11,7 +11,7 @@
 // permitted to use language features which require a C++ ABI library.
 //
 // Most of the implementation lives in an ABI-specific source file
-// (ubsan_type_hash_{itanium,win}.cc).
+// (ubsan_type_hash_{itanium,win}.cpp).
 //
 //===----------------------------------------------------------------------===//
 
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
index c4b048f20a8c9..d82b542a020e7 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash_itanium.cc ----------------------------------------===//
+//===-- ubsan_type_hash_itanium.cpp ---------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -12,10 +12,11 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 #include "ubsan_platform.h"
-#if CAN_SANITIZE_UB && !SANITIZER_WINDOWS
+#if CAN_SANITIZE_UB && !defined(_MSC_VER)
 #include "ubsan_type_hash.h"
 
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_ptrauth.h"
 
 // The following are intended to be binary compatible with the definitions
 // given in the Itanium ABI. We make no attempt to be ODR-compatible with
@@ -194,6 +195,7 @@ struct VtablePrefix {
   std::type_info *TypeInfo;
 };
 VtablePrefix *getVtablePrefix(void *Vtable) {
+  Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0);
   VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
   VtablePrefix *Prefix = Vptr - 1;
   if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
index c7b2e45af4e66..106fa1b85a558 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_type_hash_win.cc --------------------------------------------===//
+//===-- ubsan_type_hash_win.cpp -------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -12,7 +12,7 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 #include "ubsan_platform.h"
-#if CAN_SANITIZE_UB && SANITIZER_WINDOWS
+#if CAN_SANITIZE_UB && defined(_MSC_VER)
 #include "ubsan_type_hash.h"
 
 #include "sanitizer_common/sanitizer_common.h"
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp
index ba336a6673ca7..79c3ba991d398 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_value.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_value.cc ----------------------------------------------------===//
+//===-- ubsan_value.cpp ---------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -16,9 +16,57 @@
 #include "ubsan_value.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+
+// TODO(dliew): Prefer '__APPLE__' here over 'SANITIZER_MAC', as the latter is
+// unclear. rdar://58124919 tracks using a more obviously portable guard.
+#if defined(__APPLE__)
+#include <dlfcn.h>
+#endif
 
 using namespace __ubsan;
 
+typedef const char *(*ObjCGetClassNameTy)(void *);
+
+const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
+#if defined(__APPLE__)
+  // We need to query the ObjC runtime for some information, but do not want
+  // to introduce a static dependency from the ubsan runtime onto ObjC. Try to
+  // grab a handle to the ObjC runtime used by the process.
+  static bool AttemptedDlopen = false;
+  static void *ObjCHandle = nullptr;
+  static void *ObjCObjectGetClassName = nullptr;
+
+  // Prevent threads from racing to dlopen().
+  static __sanitizer::StaticSpinMutex Lock;
+  {
+    __sanitizer::SpinMutexLock Guard(&Lock);
+
+    if (!AttemptedDlopen) {
+      ObjCHandle = dlopen(
+          "/usr/lib/libobjc.A.dylib",
+          RTLD_LAZY         // Only bind symbols when used.
+              | RTLD_LOCAL  // Only make symbols available via the handle.
+              | RTLD_NOLOAD // Do not load the dylib, just grab a handle if the
+                            // image is already loaded.
+              | RTLD_FIRST  // Only search the image pointed-to by the handle.
+      );
+      AttemptedDlopen = true;
+      if (!ObjCHandle)
+        return nullptr;
+      ObjCObjectGetClassName = dlsym(ObjCHandle, "object_getClassName");
+    }
+  }
+
+  if (!ObjCObjectGetClassName)
+    return nullptr;
+
+  return ObjCGetClassNameTy(ObjCObjectGetClassName)((void *)Pointer);
+#else
+  return nullptr;
+#endif
+}
+
 SIntMax Value::getSIntValue() const {
   CHECK(getType().isSignedIntegerTy());
   if (isInlineInt()) {
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_value.h b/system/lib/compiler-rt/lib/ubsan/ubsan_value.h
index a216e3a147e91..e0957276dd241 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_value.h
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_value.h
@@ -135,6 +135,9 @@ class TypeDescriptor {
 /// \brief An opaque handle to a value.
 typedef uptr ValueHandle;
 
+/// Returns the class name of the given ObjC object, or null if the name
+/// cannot be found.
+const char *getObjCClassName(ValueHandle Pointer);
 
 /// \brief Representation of an operand value provided by the instrumented code.
 ///
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
index fd39e210af0a8..5ac7fc3e08e4c 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_dll_thunk.cc --------------------------------------------===//
+//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
index 87ada6131cde0..00722b4033a53 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_dynamic_runtime_thunk.cc --------------------------------===//
+//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
index 8cf6344ce1d80..01db0c0ce78ab 100644
--- a/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
+++ b/system/lib/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp
@@ -1,4 +1,4 @@
-//===-- ubsan_win_weak_interception.cc ------------------------------------===//
+//===-- ubsan_win_weak_interception.cpp -----------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
index ed62ddd0fa348..6a1903da62ce7 100644
--- a/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
+++ b/system/lib/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
@@ -10,7 +10,7 @@ extern "C" void ubsan_message(const char *msg);
 static void message(const char *msg) { ubsan_message(msg); }
 #else
 static void message(const char *msg) {
-  write(2, msg, strlen(msg));
+  (void)write(2, msg, strlen(msg));
 }
 #endif
 
@@ -109,6 +109,7 @@ HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
 HANDLER(float_cast_overflow, "float-cast-overflow")
 HANDLER(load_invalid_value, "load-invalid-value")
 HANDLER(invalid_builtin, "invalid-builtin")
+HANDLER(invalid_objc_cast, "invalid-objc-cast")
 HANDLER(function_type_mismatch, "function-type-mismatch")
 HANDLER(implicit_conversion, "implicit-conversion")
 HANDLER(nonnull_arg, "nonnull-arg")
diff --git a/system/lib/compiler-rt/readme.txt b/system/lib/compiler-rt/readme.txt
index 7d2e23e59d57f..ea377d0dc9a0f 100644
--- a/system/lib/compiler-rt/readme.txt
+++ b/system/lib/compiler-rt/readme.txt
@@ -1,7 +1,7 @@
 llvm's compiler-rt
 ------------------
 
-These files are from the llvm-project based on release 10.0.0.
+These files are from the llvm-project based on release 12.0.0.
 
 We maintain a local fork of llvm-project that contains any emscripten
 specific patches:
@@ -10,8 +10,8 @@ specific patches:
 
 The current patch is based on:
 
-tag: llvmorg-10.0.0
-git: d32170dbd5b0d54436537b6b75beaf44324e0c28
+tag: llvmorg-12.0.0
+git: d28af7c654d8db0b68c175db5ce212d74fb5e9bc
 
 Update Instructions
 -------------------
@@ -23,4 +23,4 @@ Modifications
 
 For a list of changes from upstream see the compiler-rt files that are part of:
 
-https://github.com/llvm/llvm-project/compare/llvmorg-10.0.0...emscripten-core:emscripten-libs-10.0.0
+https://github.com/llvm/llvm-project/compare/llvmorg-12.0.0...emscripten-core:emscripten-libs-12.0.0
diff --git a/system/lib/pthread/library_pthread_stub.c b/system/lib/pthread/library_pthread_stub.c
index 38ac19d075be2..bca3408a5a846 100644
--- a/system/lib/pthread/library_pthread_stub.c
+++ b/system/lib/pthread/library_pthread_stub.c
@@ -188,10 +188,13 @@ _Noreturn void pthread_exit(void* status) {
    exit((int)status);
 }
 
-int pthread_detach(pthread_t t) {
+int emscripten_builtin_pthread_detach(pthread_t t) {
   return 0;
 }
 
+weak_alias(emscripten_builtin_pthread_detach, pthread_detach);
+weak_alias(emscripten_builtin_pthread_detach, thrd_detach);
+
 pthread_t emscripten_main_browser_thread_id() {
   return __pthread_self();
 }
