Update aosp/master compiler-rt for rebase to r233350

Change-Id: I5f20256ce73ec7b5956f742b4062f850bf11b667
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 6929e68..91a7037 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -7,6 +7,7 @@
 if(COMPILER_RT_HAS_SANITIZER_COMMON)
   add_subdirectory(interception)
   add_subdirectory(sanitizer_common)
+  add_subdirectory(lsan)
 endif()
 
 if(COMPILER_RT_HAS_ASAN)
@@ -19,10 +20,6 @@
   add_subdirectory(dfsan)
 endif()
 
-if(COMPILER_RT_HAS_LSAN OR COMPILER_RT_HAS_LSAN_COMMON)
-  add_subdirectory(lsan)
-endif()
-
 if(COMPILER_RT_HAS_MSAN)
   add_subdirectory(msan)
 endif()
diff --git a/lib/asan/Android.mk b/lib/asan/Android.mk
index 4314c02..ccb4545 100644
--- a/lib/asan/Android.mk
+++ b/lib/asan/Android.mk
@@ -79,6 +79,7 @@
   ../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc \
   ../sanitizer_common/sanitizer_symbolizer_libcdep.cc \
   ../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc \
+  ../sanitizer_common/sanitizer_symbolizer_process_libcdep.cc \
   ../sanitizer_common/sanitizer_symbolizer_win.cc \
   ../sanitizer_common/sanitizer_thread_registry.cc \
   ../sanitizer_common/sanitizer_tls_get_addr.cc \
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index 90cb6f8..8b771fb 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -106,12 +106,8 @@
     set(ASAN_COMMON_RUNTIME_OBJECTS
       $<TARGET_OBJECTS:RTInterception.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
-    if(NOT WIN32)
-      # We can't build Leak Sanitizer on Windows yet.
-      list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
-           $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
-    endif()
+      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+      $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
 
     add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
       SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 853a181..8906d1e 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -212,20 +212,6 @@
   }
 }
 
-#if SANITIZER_WINDOWS  // Should only be called on Windows.
-SANITIZER_INTERFACE_ATTRIBUTE
-void UnregisterGlobalsInRange(void *beg, void *end) {
-  if (!flags()->report_globals)
-    return;
-  BlockingMutexLock lock(&mu_for_globals);
-  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
-    void *address = (void *)l->g->beg;
-    if (beg <= address && address < end)
-      UnregisterGlobal(l->g);
-  }
-}
-#endif
-
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index df57696..585181c 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -65,7 +65,7 @@
       }                                                                 \
       if (!suppressed) {                                                \
         GET_CURRENT_PC_BP_SP;                                           \
-        __asan_report_error(pc, bp, sp, __bad, isWrite, __size);        \
+        __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);     \
       }                                                                 \
     }                                                                   \
   } while (0)
@@ -120,17 +120,6 @@
 DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
 DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
 
-#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name)                                        \
-  do {                                                                   \
-    if ((!INTERCEPT_FUNCTION(name) || !REAL(name)))                      \
-      VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
-  } while (0)
-#else
-// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
-#define ASAN_INTERCEPT_FUNC(name)
-#endif  // SANITIZER_MAC
-
 #define ASAN_INTERCEPTOR_ENTER(ctx, func)                                      \
   AsanInterceptorContext _ctx = {#func};                                       \
   ctx = (void *)&_ctx;                                                         \
@@ -206,12 +195,6 @@
 };
 
 static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
-#if SANITIZER_WINDOWS
-  // FIXME: this is a bandaid fix for PR22025.
-  AsanThread *t = (AsanThread*)arg;
-  SetCurrentThread(t);
-  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
-#else
   ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
   AsanThread *t = nullptr;
   while ((t = reinterpret_cast<AsanThread *>(
@@ -219,7 +202,6 @@
     internal_sched_yield();
   SetCurrentThread(t);
   return t->ThreadStart(GetTid(), &param->is_registered);
-#endif
 }
 
 #if ASAN_INTERCEPT_PTHREAD_CREATE
@@ -363,30 +345,6 @@
 }
 #endif
 
-#if SANITIZER_WINDOWS
-INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
-  CHECK(REAL(RaiseException));
-  __asan_handle_no_return();
-  REAL(RaiseException)(a, b, c, d);
-}
-
-INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
-  CHECK(REAL(_except_handler3));
-  __asan_handle_no_return();
-  return REAL(_except_handler3)(a, b, c, d);
-}
-
-#if ASAN_DYNAMIC
-// This handler is named differently in -MT and -MD CRTs.
-#define _except_handler4 _except_handler4_common
-#endif
-INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
-  CHECK(REAL(_except_handler4));
-  __asan_handle_no_return();
-  return REAL(_except_handler4)(a, b, c, d);
-}
-#endif
-
 static inline int CharCmp(unsigned char c1, unsigned char c2) {
   return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
 }
@@ -813,36 +771,6 @@
 }
 #endif  // ASAN_INTERCEPT_FORK
 
-#if SANITIZER_WINDOWS
-INTERCEPTOR_WINAPI(DWORD, CreateThread,
-                   void* security, uptr stack_size,
-                   DWORD (__stdcall *start_routine)(void*), void* arg,
-                   DWORD thr_flags, void* tid) {
-  // Strict init-order checking is thread-hostile.
-  if (flags()->strict_init_order)
-    StopInitOrderChecking();
-  GET_STACK_TRACE_THREAD;
-  // FIXME: The CreateThread interceptor is not the same as a pthread_create
-  // one.  This is a bandaid fix for PR22025.
-  bool detached = false;  // FIXME: how can we determine it on Windows?
-  u32 current_tid = GetCurrentTidOrInvalid();
-  AsanThread *t =
-        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
-  return REAL(CreateThread)(security, stack_size,
-                            asan_thread_start, t, thr_flags, tid);
-}
-
-namespace __asan {
-void InitializeWindowsInterceptors() {
-  ASAN_INTERCEPT_FUNC(CreateThread);
-  ASAN_INTERCEPT_FUNC(RaiseException);
-  ASAN_INTERCEPT_FUNC(_except_handler3);
-  ASAN_INTERCEPT_FUNC(_except_handler4);
-}
-
-}  // namespace __asan
-#endif
-
 // ---------------------- InitializeAsanInterceptors ---------------- {{{1
 namespace __asan {
 void InitializeAsanInterceptors() {
@@ -925,10 +853,7 @@
   ASAN_INTERCEPT_FUNC(fork);
 #endif
 
-  // Some Windows-specific interceptors.
-#if SANITIZER_WINDOWS
-  InitializeWindowsInterceptors();
-#endif
+  InitializePlatformInterceptors();
 
   VReport(1, "AddressSanitizer: libc interceptors initialized\n");
 }
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index ee3b82a..488ada7 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -92,9 +92,21 @@
 DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
                              struct sigaction *oldact)
 
+#if !SANITIZER_MAC
+#define ASAN_INTERCEPT_FUNC(name)                                        \
+  do {                                                                   \
+    if ((!INTERCEPT_FUNCTION(name) || !REAL(name)))                      \
+      VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
+  } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif  // SANITIZER_MAC
+
 namespace __asan {
 
 void InitializeAsanInterceptors();
+void InitializePlatformInterceptors();
 
 #define ENSURE_ASAN_INITED() do { \
   CHECK(!asan_init_is_running); \
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index ea7540f..8ed4ee3 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -128,7 +128,7 @@
 
   SANITIZER_INTERFACE_ATTRIBUTE
   void __asan_report_error(uptr pc, uptr bp, uptr sp,
-                           uptr addr, int is_write, uptr access_size);
+                           uptr addr, int is_write, uptr access_size, u32 exp);
 
   SANITIZER_INTERFACE_ATTRIBUTE
   int __asan_set_error_exit_code(int exit_code);
@@ -165,6 +165,21 @@
   SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
   SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
 
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load8(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load16(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store1(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store2(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store4(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store8(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store16(uptr p, u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr p, uptr size,
+                                                      u32 exp);
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr p, uptr size,
+                                                       u32 exp);
+
   SANITIZER_INTERFACE_ATTRIBUTE
       void* __asan_memcpy(void *dst, const void *src, uptr size);
   SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index ffd3ff8..394e460 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -62,21 +62,6 @@
 class AsanThread;
 using __sanitizer::StackTrace;
 
-struct SignalContext {
-  void *context;
-  uptr addr;
-  uptr pc;
-  uptr sp;
-  uptr bp;
-
-  SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
-      context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
-  }
-
-  // Creates signal context in a platform-specific manner.
-  static SignalContext Create(void *siginfo, void *context);
-};
-
 void AsanInitFromRtl();
 
 // asan_rtl.cc
@@ -90,7 +75,6 @@
 void AsanCheckDynamicRTPrereqs();
 void AsanCheckIncompatibleRT();
 
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
 void AsanOnSIGSEGV(int, void *siginfo, void *context);
 
 void DisableReexec();
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 8e8bafd..f4f187f 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -68,6 +68,8 @@
 
 namespace __asan {
 
+void InitializePlatformInterceptors() {}
+
 void DisableReexec() {
   // No need to re-exec on Linux.
 }
@@ -152,78 +154,6 @@
 }
 #endif  // SANITIZER_ANDROID
 
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
-#if defined(__arm__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.arm_pc;
-  *bp = ucontext->uc_mcontext.arm_fp;
-  *sp = ucontext->uc_mcontext.arm_sp;
-#elif defined(__aarch64__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.pc;
-  *bp = ucontext->uc_mcontext.regs[29];
-  *sp = ucontext->uc_mcontext.sp;
-#elif defined(__hppa__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.sc_iaoq[0];
-  /* GCC uses %r3 whenever a frame pointer is needed.  */
-  *bp = ucontext->uc_mcontext.sc_gr[3];
-  *sp = ucontext->uc_mcontext.sc_gr[30];
-#elif defined(__x86_64__)
-# if SANITIZER_FREEBSD
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.mc_rip;
-  *bp = ucontext->uc_mcontext.mc_rbp;
-  *sp = ucontext->uc_mcontext.mc_rsp;
-# else
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
-  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
-  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
-# endif
-#elif defined(__i386__)
-# if SANITIZER_FREEBSD
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.mc_eip;
-  *bp = ucontext->uc_mcontext.mc_ebp;
-  *sp = ucontext->uc_mcontext.mc_esp;
-# else
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
-  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
-  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
-# endif
-#elif defined(__powerpc__) || defined(__powerpc64__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.regs->nip;
-  *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
-  // The powerpc{,64}-linux ABIs do not specify r31 as the frame
-  // pointer, but GCC always uses r31 when we need a frame pointer.
-  *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
-#elif defined(__sparc__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  uptr *stk_ptr;
-# if defined (__arch64__)
-  *pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
-  *sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
-  stk_ptr = (uptr *) (*sp + 2047);
-  *bp = stk_ptr[15];
-# else
-  *pc = ucontext->uc_mcontext.gregs[REG_PC];
-  *sp = ucontext->uc_mcontext.gregs[REG_O6];
-  stk_ptr = (uptr *) *sp;
-  *bp = stk_ptr[15];
-# endif
-#elif defined(__mips__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-  *pc = ucontext->uc_mcontext.gregs[31];
-  *bp = ucontext->uc_mcontext.gregs[30];
-  *sp = ucontext->uc_mcontext.gregs[29];
-#else
-# error "Unsupported arch"
-#endif
-}
-
 void AsanPlatformThreadInit() {
   // Nothing here for now.
 }
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index b353686..b2618d7 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -40,19 +40,7 @@
 
 namespace __asan {
 
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
-  ucontext_t *ucontext = (ucontext_t*)context;
-# if SANITIZER_WORDSIZE == 64
-  *pc = ucontext->uc_mcontext->__ss.__rip;
-  *bp = ucontext->uc_mcontext->__ss.__rbp;
-  *sp = ucontext->uc_mcontext->__ss.__rsp;
-# else
-  *pc = ucontext->uc_mcontext->__ss.__eip;
-  *bp = ucontext->uc_mcontext->__ss.__ebp;
-  *sp = ucontext->uc_mcontext->__ss.__esp;
-# endif  // SANITIZER_WORDSIZE
-}
-
+void InitializePlatformInterceptors() {}
 
 bool PlatformHasDifferentMemcpyAndMemmove() {
   // On OS X 10.7 memcpy() and memmove() are both resolved
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index e2b1f4d..569d359 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -112,7 +112,7 @@
   if (!flags()->allow_user_poisoning || size == 0) return;
   uptr beg_addr = (uptr)addr;
   uptr end_addr = beg_addr + size;
-  VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
+  VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
           (void *)end_addr);
   ShadowSegmentEndpoint beg(beg_addr);
   ShadowSegmentEndpoint end(end_addr);
@@ -152,7 +152,7 @@
   if (!flags()->allow_user_poisoning || size == 0) return;
   uptr beg_addr = (uptr)addr;
   uptr end_addr = beg_addr + size;
-  VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
+  VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
           (void *)end_addr);
   ShadowSegmentEndpoint beg(beg_addr);
   ShadowSegmentEndpoint end(end_addr);
@@ -218,7 +218,7 @@
         __asan::AddressIsPoisoned(__p + __size - 1))) {       \
       GET_CURRENT_PC_BP_SP;                                   \
       uptr __bad = __asan_region_is_poisoned(__p, __size);    \
-      __asan_report_error(pc, bp, sp, __bad, isWrite, __size);\
+      __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\
     }                                                         \
   } while (false);                                            \
 
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index ad31458..4652dde 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -32,13 +32,6 @@
 
 namespace __asan {
 
-SignalContext SignalContext::Create(void *siginfo, void *context) {
-  uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
-  uptr pc, sp, bp;
-  GetPcSpBp(context, &pc, &sp, &bp);
-  return SignalContext(context, addr, pc, sp, bp);
-}
-
 void AsanOnSIGSEGV(int, void *siginfo, void *context) {
   ScopedDeadlySignal signal_scope(GetCurrentThread());
   int code = (int)((siginfo_t*)siginfo)->si_code;
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index ad75262..c1c340c 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -939,9 +939,18 @@
 using namespace __asan;  // NOLINT
 
 void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
-                         uptr access_size) {
+                         uptr access_size, u32 exp) {
   ENABLE_FRAME_POINTER;
 
+  // Optimization experiments.
+  // The experiments can be used to evaluate potential optimizations that remove
+  // instrumentation (assess false negatives). Instead of completely removing
+  // some instrumentation, compiler can emit special calls into runtime
+  // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
+  // mask of experiments (exp).
+  // The reaction to a non-zero value of exp is to be defined.
+  (void)exp;
+
   // Determine the error type.
   const char *bug_descr = "unknown-crash";
   if (AddrIsInMem(addr)) {
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 9126e71..f346615 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -112,11 +112,15 @@
 // -------------------------- Run-time entry ------------------- {{{1
 // exported functions
 #define ASAN_REPORT_ERROR(type, is_write, size)                     \
-extern "C" NOINLINE INTERFACE_ATTRIBUTE                        \
-void __asan_report_ ## type ## size(uptr addr);                \
-void __asan_report_ ## type ## size(uptr addr) {               \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE                             \
+void __asan_report_ ## type ## size(uptr addr) {                    \
   GET_CALLER_PC_BP_SP;                                              \
-  __asan_report_error(pc, bp, sp, addr, is_write, size);            \
+  __asan_report_error(pc, bp, sp, addr, is_write, size, 0);         \
+}                                                                   \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE                             \
+void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) {       \
+  GET_CALLER_PC_BP_SP;                                              \
+  __asan_report_error(pc, bp, sp, addr, is_write, size, exp);       \
 }
 
 ASAN_REPORT_ERROR(load, false, 1)
@@ -132,18 +136,20 @@
 
 #define ASAN_REPORT_ERROR_N(type, is_write)                    \
 extern "C" NOINLINE INTERFACE_ATTRIBUTE                        \
-void __asan_report_ ## type ## _n(uptr addr, uptr size);       \
 void __asan_report_ ## type ## _n(uptr addr, uptr size) {      \
   GET_CALLER_PC_BP_SP;                                         \
-  __asan_report_error(pc, bp, sp, addr, is_write, size);       \
+  __asan_report_error(pc, bp, sp, addr, is_write, size, 0);    \
+}                                                              \
+extern "C" NOINLINE INTERFACE_ATTRIBUTE                        \
+void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) {      \
+  GET_CALLER_PC_BP_SP;                                                      \
+  __asan_report_error(pc, bp, sp, addr, is_write, size, exp);               \
 }
 
 ASAN_REPORT_ERROR_N(load, false)
 ASAN_REPORT_ERROR_N(store, true)
 
-#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size)                      \
-  extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \
-  void __asan_##type##size(uptr addr) {                                        \
+#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg)        \
     uptr sp = MEM_TO_SHADOW(addr);                                             \
     uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp)          \
                                         : *reinterpret_cast<u16 *>(sp);        \
@@ -155,10 +161,19 @@
           *__asan_test_only_reported_buggy_pointer = addr;                     \
         } else {                                                               \
           GET_CALLER_PC_BP_SP;                                                 \
-          __asan_report_error(pc, bp, sp, addr, is_write, size);               \
+          __asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg);      \
         }                                                                      \
       }                                                                        \
-    }                                                                          \
+    }
+
+#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size)                      \
+  extern "C" NOINLINE INTERFACE_ATTRIBUTE                                      \
+  void __asan_##type##size(uptr addr) {                                        \
+    ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0)                  \
+  }                                                                            \
+  extern "C" NOINLINE INTERFACE_ATTRIBUTE                                      \
+  void __asan_exp_##type##size(uptr addr, u32 exp) {                           \
+    ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp)                \
   }
 
 ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
@@ -173,18 +188,38 @@
 ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
 
 extern "C"
-NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) {
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_loadN(uptr addr, uptr size) {
   if (__asan_region_is_poisoned(addr, size)) {
     GET_CALLER_PC_BP_SP;
-    __asan_report_error(pc, bp, sp, addr, false, size);
+    __asan_report_error(pc, bp, sp, addr, false, size, 0);
   }
 }
 
 extern "C"
-NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) {
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_exp_loadN(uptr addr, uptr size, u32 exp) {
   if (__asan_region_is_poisoned(addr, size)) {
     GET_CALLER_PC_BP_SP;
-    __asan_report_error(pc, bp, sp, addr, true, size);
+    __asan_report_error(pc, bp, sp, addr, false, size, exp);
+  }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_storeN(uptr addr, uptr size) {
+  if (__asan_region_is_poisoned(addr, size)) {
+    GET_CALLER_PC_BP_SP;
+    __asan_report_error(pc, bp, sp, addr, true, size, 0);
+  }
+}
+
+extern "C"
+NOINLINE INTERFACE_ATTRIBUTE
+void __asan_exp_storeN(uptr addr, uptr size, u32 exp) {
+  if (__asan_region_is_poisoned(addr, size)) {
+    GET_CALLER_PC_BP_SP;
+    __asan_report_error(pc, bp, sp, addr, true, size, exp);
   }
 }
 
@@ -203,26 +238,40 @@
     case 3: __asan_report_load4(0); break;
     case 4: __asan_report_load8(0); break;
     case 5: __asan_report_load16(0); break;
-    case 6: __asan_report_store1(0); break;
-    case 7: __asan_report_store2(0); break;
-    case 8: __asan_report_store4(0); break;
-    case 9: __asan_report_store8(0); break;
-    case 10: __asan_report_store16(0); break;
-    case 12: __asan_register_globals(0, 0); break;
-    case 13: __asan_unregister_globals(0, 0); break;
-    case 14: __asan_set_death_callback(0); break;
-    case 15: __asan_set_error_report_callback(0); break;
-    case 16: __asan_handle_no_return(); break;
-    case 17: __asan_address_is_poisoned(0); break;
-    case 25: __asan_poison_memory_region(0, 0); break;
-    case 26: __asan_unpoison_memory_region(0, 0); break;
-    case 27: __asan_set_error_exit_code(0); break;
-    case 30: __asan_before_dynamic_init(0); break;
-    case 31: __asan_after_dynamic_init(); break;
-    case 32: __asan_poison_stack_memory(0, 0); break;
-    case 33: __asan_unpoison_stack_memory(0, 0); break;
-    case 34: __asan_region_is_poisoned(0, 0); break;
-    case 35: __asan_describe_address(0); break;
+    case 6: __asan_report_load_n(0, 0); break;
+    case 7: __asan_report_store1(0); break;
+    case 8: __asan_report_store2(0); break;
+    case 9: __asan_report_store4(0); break;
+    case 10: __asan_report_store8(0); break;
+    case 11: __asan_report_store16(0); break;
+    case 12: __asan_report_store_n(0, 0); break;
+    case 13: __asan_report_exp_load1(0, 0); break;
+    case 14: __asan_report_exp_load2(0, 0); break;
+    case 15: __asan_report_exp_load4(0, 0); break;
+    case 16: __asan_report_exp_load8(0, 0); break;
+    case 17: __asan_report_exp_load16(0, 0); break;
+    case 18: __asan_report_exp_load_n(0, 0, 0); break;
+    case 19: __asan_report_exp_store1(0, 0); break;
+    case 20: __asan_report_exp_store2(0, 0); break;
+    case 21: __asan_report_exp_store4(0, 0); break;
+    case 22: __asan_report_exp_store8(0, 0); break;
+    case 23: __asan_report_exp_store16(0, 0); break;
+    case 24: __asan_report_exp_store_n(0, 0, 0); break;
+    case 25: __asan_register_globals(0, 0); break;
+    case 26: __asan_unregister_globals(0, 0); break;
+    case 27: __asan_set_death_callback(0); break;
+    case 28: __asan_set_error_report_callback(0); break;
+    case 29: __asan_handle_no_return(); break;
+    case 30: __asan_address_is_poisoned(0); break;
+    case 31: __asan_poison_memory_region(0, 0); break;
+    case 32: __asan_unpoison_memory_region(0, 0); break;
+    case 33: __asan_set_error_exit_code(0); break;
+    case 34: __asan_before_dynamic_init(0); break;
+    case 35: __asan_after_dynamic_init(); break;
+    case 36: __asan_poison_stack_memory(0, 0); break;
+    case 37: __asan_unpoison_stack_memory(0, 0); break;
+    case 38: __asan_region_is_poisoned(0, 0); break;
+    case 39: __asan_describe_address(0); break;
   }
 }
 
diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc
index 3f76e20..41887b5 100644
--- a/lib/asan/asan_suppressions.cc
+++ b/lib/asan/asan_suppressions.cc
@@ -81,14 +81,10 @@
     uptr addr = stack->trace[i];
 
     if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
-      const char *module_name;
-      uptr module_offset;
       // Match "interceptor_via_lib" suppressions.
-      if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
-                                                  &module_offset) &&
-          suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) {
-        return true;
-      }
+      if (const char *module_name = symbolizer->GetModuleNameForPc(addr))
+        if (suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s))
+          return true;
     }
 
     if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 5b1d0da..addb3d4 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -22,10 +22,13 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_report.h"
+#include "asan_stack.h"
 #include "asan_thread.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 
+using namespace __asan;  // NOLINT
+
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 int __asan_should_detect_stack_use_after_return() {
@@ -33,6 +36,7 @@
   return __asan_option_detect_stack_use_after_return;
 }
 
+// -------------------- A workaround for the abscence of weak symbols ----- {{{
 // We don't have a direct equivalent of weak symbols when using MSVC, but we can
 // use the /alternatename directive to tell the linker to default a specific
 // symbol to a specific value, which works nicely for allocator hooks and
@@ -47,11 +51,105 @@
 #pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options")    // NOLINT
 #pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions")    // NOLINT
 #pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error")                  // NOLINT
+// }}}
 }  // extern "C"
 
+// ---------------------- Windows-specific inteceptors ---------------- {{{
+INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
+  CHECK(REAL(RaiseException));
+  __asan_handle_no_return();
+  REAL(RaiseException)(a, b, c, d);
+}
+
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+  CHECK(REAL(_except_handler3));
+  __asan_handle_no_return();
+  return REAL(_except_handler3)(a, b, c, d);
+}
+
+#if ASAN_DYNAMIC
+// This handler is named differently in -MT and -MD CRTs.
+#define _except_handler4 _except_handler4_common
+#endif
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+  CHECK(REAL(_except_handler4));
+  __asan_handle_no_return();
+  return REAL(_except_handler4)(a, b, c, 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);
+}
+
+INTERCEPTOR_WINAPI(DWORD, CreateThread,
+                   void* security, uptr stack_size,
+                   DWORD (__stdcall *start_routine)(void*), void* arg,
+                   DWORD thr_flags, void* tid) {
+  // Strict init-order checking is thread-hostile.
+  if (flags()->strict_init_order)
+    StopInitOrderChecking();
+  GET_STACK_TRACE_THREAD;
+  // FIXME: The CreateThread interceptor is not the same as a pthread_create
+  // one.  This is a bandaid fix for PR22025.
+  bool detached = false;  // FIXME: how can we determine it on Windows?
+  u32 current_tid = GetCurrentTidOrInvalid();
+  AsanThread *t =
+        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
+  return REAL(CreateThread)(security, stack_size,
+                            asan_thread_start, t, thr_flags, tid);
+}
+
+namespace {
+BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
+
+void EnsureWorkerThreadRegistered() {
+  // FIXME: GetCurrentThread relies on TSD, which might not play well with
+  // system thread pools.  We might want to use something like reference
+  // counting to zero out GetCurrentThread() underlying storage when the last
+  // work item finishes?  Or can we disable reclaiming of threads in the pool?
+  BlockingMutexLock l(&mu_for_thread_tracking);
+  if (__asan::GetCurrentThread())
+    return;
+
+  AsanThread *t = AsanThread::Create(
+      /* start_routine */ nullptr, /* arg */ nullptr,
+      /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true);
+  t->Init();
+  asanThreadRegistry().StartThread(t->tid(), 0, 0);
+  SetCurrentThread(t);
+}
+}  // namespace
+
+INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) {
+  // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to
+  // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc.
+  // System worker pool threads are created at arbitraty point in time and
+  // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory
+  // instead and don't register a specific parent_tid/stack.
+  EnsureWorkerThreadRegistered();
+  return REAL(NtWaitForWorkViaWorkerFactory)(a, b);
+}
+
+// }}}
+
 namespace __asan {
 
-// ---------------------- TSD ---------------- {{{1
+void InitializePlatformInterceptors() {
+  ASAN_INTERCEPT_FUNC(CreateThread);
+  ASAN_INTERCEPT_FUNC(RaiseException);
+  ASAN_INTERCEPT_FUNC(_except_handler3);
+  ASAN_INTERCEPT_FUNC(_except_handler4);
+
+  // NtWaitForWorkViaWorkerFactory is always linked dynamically.
+  CHECK(::__interception::OverrideFunction(
+      "NtWaitForWorkViaWorkerFactory",
+      (uptr)WRAP(NtWaitForWorkViaWorkerFactory),
+      (uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
+}
+
+// ---------------------- TSD ---------------- {{{
 static bool tsd_key_inited = false;
 
 static __declspec(thread) void *fake_tsd = 0;
@@ -74,7 +172,9 @@
 void PlatformTSDDtor(void *tsd) {
   AsanThread::TSDDtor(tsd);
 }
-// ---------------------- Various stuff ---------------- {{{1
+// }}}
+
+// ---------------------- Various stuff ---------------- {{{
 void DisableReexec() {
   // No need to re-exec on Windows.
 }
@@ -108,23 +208,6 @@
 
 static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
 
-SignalContext SignalContext::Create(void *siginfo, void *context) {
-  EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
-  CONTEXT *context_record = (CONTEXT*)context;
-
-  uptr pc = (uptr)exception_record->ExceptionAddress;
-#ifdef _WIN64
-  uptr bp = (uptr)context_record->Rbp;
-  uptr sp = (uptr)context_record->Rsp;
-#else
-  uptr bp = (uptr)context_record->Ebp;
-  uptr sp = (uptr)context_record->Esp;
-#endif
-  uptr access_addr = exception_record->ExceptionInformation[1];
-
-  return SignalContext(context, access_addr, pc, sp, bp);
-}
-
 static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
   EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
   CONTEXT *context = info->ContextRecord;
@@ -177,7 +260,7 @@
 static __declspec(allocate(".CRT$XIZ"))
     int (*__intercept_seh)() = __asan_set_seh_filter;
 #endif
-
+// }}}
 }  // namespace __asan
 
 #endif  // _WIN32
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
index 7b94302..0c363fe 100644
--- a/lib/asan/asan_win_dll_thunk.cc
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -319,6 +319,8 @@
 INTERFACE_FUNCTION(__sanitizer_ptr_sub)
 INTERFACE_FUNCTION(__sanitizer_report_error_summary)
 INTERFACE_FUNCTION(__sanitizer_reset_coverage)
+INTERFACE_FUNCTION(__sanitizer_get_number_of_counters)
+INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
 INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
 INTERFACE_FUNCTION(__sanitizer_set_death_callback)
 INTERFACE_FUNCTION(__sanitizer_set_report_path)
diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc
index 1945614..d59f9f5 100644
--- a/lib/asan/asan_win_dynamic_runtime_thunk.cc
+++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -15,7 +15,8 @@
 //
 // This includes:
 //  - forwarding the detect_stack_use_after_return runtime option
-//  - installing a custom SEH handler
+//  - working around deficiencies of the MD runtime
+//  - installing a custom SEH handlerx
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,9 +25,13 @@
 // simplifies the build procedure.
 #ifdef ASAN_DYNAMIC_RUNTIME_THUNK
 #include <windows.h>
-#include <psapi.h>
 
-extern "C" {
+// First, declare CRT sections we'll be using in this file
+#pragma section(".CRT$XID", long, read)  // NOLINT
+#pragma section(".CRT$XIZ", long, read)  // NOLINT
+#pragma section(".CRT$XTW", long, read)  // NOLINT
+#pragma section(".CRT$XTY", long, read)  // NOLINT
+
 ////////////////////////////////////////////////////////////////////////////////
 // Define a copy of __asan_option_detect_stack_use_after_return that should be
 // used when linking an MD runtime with a set of object files on Windows.
@@ -38,82 +43,55 @@
 // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
 // just to work around this issue, let's clone the a variable that is
 // constant after initialization anyways.
+extern "C" {
 __declspec(dllimport) int __asan_should_detect_stack_use_after_return();
 int __asan_option_detect_stack_use_after_return =
     __asan_should_detect_stack_use_after_return();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does.
-// To work around this, for each DLL we schedule a call to
-// UnregisterGlobalsInRange atexit() specifying the address range of the DLL
-// image to unregister globals in that range.   We don't do the same
-// for the main module (.exe) as the asan_globals.cc allocator is destroyed
-// by the time UnregisterGlobalsInRange is executed.
-// See PR22545 for the details.
-namespace __asan {
-__declspec(dllimport)
-void UnregisterGlobalsInRange(void *beg, void *end);
-}
+// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
+// unload or on exit.  ASan relies on LLVM global_dtors to call
+// __asan_unregister_globals on these events, which unfortunately doesn't work
+// with the MD runtime, see PR22545 for the details.
+// To work around this, for each DLL we schedule a call to UnregisterGlobals
+// using atexit() that calls a small subset of C terminators
+// where LLVM global_dtors is placed.  Fingers crossed, no other C terminators
+// are there.
+extern "C" void __cdecl _initterm(void *a, void *b);
 
 namespace {
-void *this_module_base, *this_module_end;
+__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0;
+__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0;
 
 void UnregisterGlobals() {
-  __asan::UnregisterGlobalsInRange(this_module_base, this_module_end);
+  _initterm(&before_global_dtors, &after_global_dtors);
 }
 
 int ScheduleUnregisterGlobals() {
-  HMODULE this_module = 0;
-  // Increments the reference counter of the DLL module, so need to call
-  // FreeLibrary later.
-  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                         (LPCTSTR)&UnregisterGlobals, &this_module))
-    return 1;
-
-  // Skip the main module.
-  if (this_module == GetModuleHandle(0))
-    return 0;
-
-  MODULEINFO mi;
-  bool success =
-      GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi));
-  if (!FreeLibrary(this_module))
-    return 2;
-  if (!success)
-    return 3;
-
-  this_module_base = mi.lpBaseOfDll;
-  this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
-
   return atexit(UnregisterGlobals);
 }
+
+// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after
+// atexit() is initialized (.CRT$XIC).  As this is executed before C++
+// initializers (think ctors for globals), UnregisterGlobals gets executed after
+// dtors for C++ globals.
+__declspec(allocate(".CRT$XID"))
+int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
+
 }  // namespace
 
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 // ASan SEH handling.
-extern "C" __declspec(dllimport) int __asan_set_seh_filter();
-static int SetSEHFilter() { return __asan_set_seh_filter(); }
-
-///////////////////////////////////////////////////////////////////////////////
-// We schedule some work at start-up by placing callbacks to our code to the
-// list of CRT C initializers.
-//
-// First, declare sections we'll be using:
-#pragma section(".CRT$XID", long, read)  // NOLINT
-#pragma section(".CRT$XIZ", long, read)  // NOLINT
-
-// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized
-// (.CRT$XIC) but before the C++ constructors (.CRT$XCA).
-__declspec(allocate(".CRT$XID"))
-static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
-
 // We need to set the ASan-specific SEH handler at the end of CRT initialization
 // of each module (see also asan_win.cc).
-//
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+
 // Unfortunately, putting a pointer to __asan_set_seh_filter into
 // __asan_intercept_seh gets optimized out, so we have to use an extra function.
-extern "C" __declspec(allocate(".CRT$XIZ"))
-int (*__asan_seh_interceptor)() = SetSEHFilter;
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
 
 #endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index 59fceaa..b9d3ad3 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -23,6 +23,7 @@
 binary_name_filter = None
 fix_filename_patterns = None
 logfile = sys.stdin
+allow_system_symbolizer = True
 
 # FIXME: merge the code that calls fix_filename().
 def fix_filename(file_name):
@@ -392,6 +393,8 @@
           [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
     result = symbolizers[binary].symbolize(addr, binary, offset)
     if result is None:
+      if not allow_system_symbolizer:
+        raise Exception('Failed to launch or use llvm-symbolizer.')
       # Initialize system symbolizer only if other symbolizers failed.
       symbolizers[binary].append_symbolizer(
           SystemSymbolizerFactory(self.system, addr, binary))
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
index 1d8b04d..200de2c 100644
--- a/lib/asan/tests/asan_asm_test.cc
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -232,7 +232,7 @@
   long magic = 0x1234;
   long r = 0x0;
 
-#if defined(__x86_64__)
+#if defined(__x86_64__) && !defined(__ILP32__)
   __asm__("xorq %%rax, %%rax  \n\t"
           "movq (%[p]), %%rax \n\t"
           "sete %%al          \n\t"
@@ -248,7 +248,7 @@
           : [r] "=r"(r)
           : [p] "r"(&magic)
           : "eax", "memory");
-#endif // defined(__x86_64__)
+#endif // defined(__x86_64__) && !defined(__ILP32__)
 
   ASSERT_EQ(0x1, r);
 }
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 952b05e..aa08080 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -31,13 +31,13 @@
 
 template<typename T>
 NOINLINE void uaf_test(int size, int off) {
-  char *p = (char *)malloc_aaa(size);
+  void *p = malloc_aaa(size);
   free_aaa(p);
   for (int i = 1; i < 100; i++)
     free_aaa(malloc_aaa(i));
   fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
           (long)sizeof(T), p, off);
-  asan_write((T*)(p + off));
+  asan_write((T *)((char *)p + off));
 }
 
 TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
@@ -436,10 +436,10 @@
 
 void DoubleFree() {
   int *x = (int*)malloc(100 * sizeof(int));
-  fprintf(stderr, "DoubleFree: x=%p\n", x);
+  fprintf(stderr, "DoubleFree: x=%p\n", (void *)x);
   free(x);
   free(x);
-  fprintf(stderr, "should have failed in the second free(%p)\n", x);
+  fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x);
   abort();
 }
 
@@ -569,17 +569,6 @@
 }
 
 #if !defined(_WIN32)  // Only basic longjmp is available on Windows.
-NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
-  // create three red zones for these two stack objects.
-  int a;
-  int b;
-
-  int *A = Ident(&a);
-  int *B = Ident(&b);
-  *A = *B;
-  __builtin_longjmp((void**)buf, 1);
-}
-
 NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
   // create three red zones for these two stack objects.
   int a;
@@ -605,6 +594,17 @@
 #if !defined(__ANDROID__) && !defined(__arm__) && \
     !defined(__powerpc64__) && !defined(__powerpc__) && \
     !defined(__aarch64__)
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  __builtin_longjmp((void**)buf, 1);
+}
+
 // Does not work on Power and ARM:
 // https://code.google.com/p/address-sanitizer/issues/detail?id=185
 TEST(AddressSanitizer, BuiltinLongJmpTest) {
@@ -1243,7 +1243,7 @@
   const size_t kAllocSize = (1 << 28) - 1024;
   size_t total_size = 0;
   while (true) {
-    char *x = (char*)malloc(kAllocSize);
+    void *x = malloc(kAllocSize);
     memset(x, 0, kAllocSize);
     total_size += kAllocSize;
     fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c
index 8dc0fb1..ede7659 100644
--- a/lib/builtins/clear_cache.c
+++ b/lib/builtins/clear_cache.c
@@ -9,11 +9,12 @@
  */
 
 #include "int_lib.h"
+#include <stddef.h>
 
 #if __APPLE__
   #include <libkern/OSCacheControl.h>
 #endif
-#if defined(__FreeBSD__) && defined(__arm__)
+#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__)
   #include <sys/types.h>
   #include <machine/sysarch.h>
 #endif
@@ -25,6 +26,7 @@
 #if defined(__mips__)
   #include <sys/cachectl.h>
   #include <sys/syscall.h>
+  #include <unistd.h>
   #if defined(__ANDROID__) && defined(__LP64__)
     /*
      * clear_mips_cache - Invalidates instruction cache for Mips.
@@ -89,7 +91,7 @@
  * so there is nothing to do
  */
 #elif defined(__arm__) && !defined(__APPLE__)
-    #if defined(__FreeBSD__) || defined(__NetBSD__)
+    #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__)
         struct arm_sync_icache_args arg;
 
         arg.addr = (uintptr_t)start;
@@ -126,6 +128,7 @@
 #elif defined(__aarch64__) && !defined(__APPLE__)
   uint64_t xstart = (uint64_t)(uintptr_t) start;
   uint64_t xend = (uint64_t)(uintptr_t) end;
+  uint64_t addr;
 
   // Get Cache Type Info
   uint64_t ctr_el0;
@@ -136,12 +139,12 @@
    * uintptr_t in case this runs in an IPL32 environment.
    */
   const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
-  for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size)
+  for (addr = xstart; addr < xend; addr += dcache_line_size)
     __asm __volatile("dc cvau, %0" :: "r"(addr));
   __asm __volatile("dsb ish");
 
   const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
-  for (uint64_t addr = xstart; addr < xend; addr += icache_line_size)
+  for (addr = xstart; addr < xend; addr += icache_line_size)
     __asm __volatile("ic ivau, %0" :: "r"(addr));
   __asm __volatile("isb sy");
 #else
diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c
index 86f9f6c..67b124a 100644
--- a/lib/builtins/fixdfdi.c
+++ b/lib/builtins/fixdfdi.c
@@ -6,40 +6,17 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *            su_int is a 32 bit integral type
- *            value in double is representable in di_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
-
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
 ARM_EABI_FNALIAS(d2lz, fixdfdi)
 
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
 COMPILER_RT_ABI di_int
-__fixdfdi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0)
-        return 0;
-    di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
-    dwords r;
-    r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
-    r.s.low = fb.u.s.low;
-    if (e > 52)
-        r.all <<= (e - 52);
-    else
-        r.all >>= (52 - e);
-    return (r.all ^ s) - s;
-} 
+__fixdfdi(fp_t a) {
+    return __fixint(a);
+}
diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c
index 88b2ff5..704e65b 100644
--- a/lib/builtins/fixdfsi.c
+++ b/lib/builtins/fixdfsi.c
@@ -1,50 +1,22 @@
-//===-- lib/fixdfsi.c - Double-precision -> integer 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.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements double-precision to integer conversion for the
-// compiler-rt library.  No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
+/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===
+ *
+ *                     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 DOUBLE_PRECISION
 #include "fp_lib.h"
-
-#include "int_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 ARM_EABI_FNALIAS(d2iz, fixdfsi)
 
-COMPILER_RT_ABI int
+COMPILER_RT_ABI si_int
 __fixdfsi(fp_t a) {
-    
-    // Break a into sign, exponent, significand
-    const rep_t aRep = toRep(a);
-    const rep_t aAbs = aRep & absMask;
-    const int sign = aRep & signBit ? -1 : 1;
-    const int exponent = (aAbs >> significandBits) - exponentBias;
-    const rep_t significand = (aAbs & significandMask) | implicitBit;
-    
-    // If 0 < exponent < significandBits, right shift to get the result.
-    if ((unsigned int)exponent < significandBits) {
-        return sign * (significand >> (significandBits - exponent));
-    }
-    
-    // If exponent is negative, the result is zero.
-    else if (exponent < 0) {
-        return 0;
-    }
-    
-    // If significandBits < exponent, left shift to get the result.  This shift
-    // may end up being larger than the type width, which incurs undefined
-    // behavior, but the conversion itself is undefined in that case, so
-    // whatever the compiler decides to do is fine.
-    else {
-        return sign * (significand << (exponent - significandBits));
-    }
+    return __fixint(a);
 }
diff --git a/lib/builtins/fixdfti.c b/lib/builtins/fixdfti.c
index 2c27f4b..aaf225e 100644
--- a/lib/builtins/fixdfti.c
+++ b/lib/builtins/fixdfti.c
@@ -6,40 +6,21 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
 
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in double is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 COMPILER_RT_ABI ti_int
-__fixdfti(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0)
-        return 0;
-    ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31;
-    ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all);
-    if (e > 52)
-        r <<= (e - 52);
-    else
-        r >>= (52 - e);
-    return (r ^ s) - s;
+__fixdfti(fp_t a) {
+    return __fixint(a);
 }
 
 #endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c
index 4f6cfdd..835ff85 100644
--- a/lib/builtins/fixsfdi.c
+++ b/lib/builtins/fixsfdi.c
@@ -1,43 +1,23 @@
 /* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
  *
- *                    The LLVM Compiler Infrastructure
+ *                     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.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in di_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 
 ARM_EABI_FNALIAS(f2lz, fixsfdi)
 
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
 COMPILER_RT_ABI di_int
-__fixsfdi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0)
-        return 0;
-    di_int s = (si_int)(fb.u & 0x80000000) >> 31;
-    di_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return (r ^ s) - s;
+__fixsfdi(fp_t a) {
+    return __fixint(a);
 }
diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c
index e3cc42d..f045536 100644
--- a/lib/builtins/fixsfsi.c
+++ b/lib/builtins/fixsfsi.c
@@ -1,47 +1,22 @@
-//===-- lib/fixsfsi.c - Single-precision -> integer 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.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements single-precision to integer conversion for the
-// compiler-rt library.  No range checking is performed; the behavior of this
-// conversion is undefined for out of range values in the C standard.
-//
-//===----------------------------------------------------------------------===//
+/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===
+ *
+ *                     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 SINGLE_PRECISION
 #include "fp_lib.h"
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 ARM_EABI_FNALIAS(f2iz, fixsfsi)
 
-COMPILER_RT_ABI int
+COMPILER_RT_ABI si_int
 __fixsfsi(fp_t a) {
-    // Break a into sign, exponent, significand
-    const rep_t aRep = toRep(a);
-    const rep_t aAbs = aRep & absMask;
-    const int sign = aRep & signBit ? -1 : 1;
-    const int exponent = (aAbs >> significandBits) - exponentBias;
-    const rep_t significand = (aAbs & significandMask) | implicitBit;
-    
-    // If 0 < exponent < significandBits, right shift to get the result.
-    if ((unsigned int)exponent < significandBits) {
-        return sign * (significand >> (significandBits - exponent));
-    }
-    
-    // If exponent is negative, the result is zero.
-    else if (exponent < 0) {
-        return 0;
-    }
-    
-    // If significandBits < exponent, left shift to get the result.  This shift
-    // may end up being larger than the type width, which incurs undefined
-    // behavior, but the conversion itself is undefined in that case, so
-    // whatever the compiler decides to do is fine.
-    else {
-        return sign * (significand << (exponent - significandBits));
-    }
+    return __fixint(a);
 }
diff --git a/lib/builtins/fixsfti.c b/lib/builtins/fixsfti.c
index 6a1a1c6..3a159b3 100644
--- a/lib/builtins/fixsfti.c
+++ b/lib/builtins/fixsfti.c
@@ -6,40 +6,21 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixsfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in ti_int (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
 
 COMPILER_RT_ABI ti_int
-__fixsfti(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0)
-        return 0;
-    ti_int s = (si_int)(fb.u & 0x80000000) >> 31;
-    ti_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return (r ^ s) - s;
+__fixsfti(fp_t a) {
+    return __fixint(a);
 }
 
 #endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixtfdi.c b/lib/builtins/fixtfdi.c
new file mode 100644
index 0000000..bc9dea1
--- /dev/null
+++ b/lib/builtins/fixtfdi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===
+ *
+ *                     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)
+typedef di_int fixint_t;
+typedef du_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI di_int
+__fixtfdi(fp_t a) {
+    return __fixint(a);
+}
+#endif
diff --git a/lib/builtins/fixtfsi.c b/lib/builtins/fixtfsi.c
new file mode 100644
index 0000000..feb3de8
--- /dev/null
+++ b/lib/builtins/fixtfsi.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===
+ *
+ *                     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)
+typedef si_int fixint_t;
+typedef su_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI si_int
+__fixtfsi(fp_t a) {
+    return __fixint(a);
+}
+#endif
diff --git a/lib/builtins/fixtfti.c b/lib/builtins/fixtfti.c
new file mode 100644
index 0000000..ee4ada8
--- /dev/null
+++ b/lib/builtins/fixtfti.c
@@ -0,0 +1,23 @@
+/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------===
+ *
+ *                     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)
+typedef ti_int fixint_t;
+typedef tu_int fixuint_t;
+#include "fp_fixint_impl.inc"
+
+COMPILER_RT_ABI ti_int
+__fixtfti(fp_t a) {
+    return __fixint(a);
+}
+#endif
diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c
index 9e63713..f4f689e 100644
--- a/lib/builtins/fixunsdfdi.c
+++ b/lib/builtins/fixunsdfdi.c
@@ -6,42 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             du_int is a 64 bit integral type
- *             value in double is representable in du_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
 
 COMPILER_RT_ABI du_int
-__fixunsdfdi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    udwords r;
-    r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000;
-    r.s.low = fb.u.s.low;
-    if (e > 52)
-        r.all <<= (e - 52);
-    else
-        r.all >>= (52 - e);
-    return r.all;
+__fixunsdfdi(fp_t a) {
+    return __fixuint(a);
 }
diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c
index c6a3c75..232d342 100644
--- a/lib/builtins/fixunsdfsi.c
+++ b/lib/builtins/fixunsdfsi.c
@@ -6,39 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in double is representable in su_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
 
 COMPILER_RT_ABI su_int
-__fixunsdfsi(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    return (
-                0x80000000u                      |
-                ((fb.u.s.high & 0x000FFFFF) << 11) |
-                (fb.u.s.low >> 21)
-           ) >> (31 - e);
+__fixunsdfsi(fp_t a) {
+    return __fixuint(a);
 }
diff --git a/lib/builtins/fixunsdfti.c b/lib/builtins/fixunsdfti.c
index cc6c84f..c3d7df9 100644
--- a/lib/builtins/fixunsdfti.c
+++ b/lib/builtins/fixunsdfti.c
@@ -6,42 +6,18 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsdfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
 #include "int_lib.h"
 
 #ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: double is a IEEE 64 bit floating point type 
- *             tu_int is a 64 bit integral type
- *             value in double is representable in tu_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 COMPILER_RT_ABI tu_int
-__fixunsdfti(double a)
-{
-    double_bits fb;
-    fb.f = a;
-    int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023;
-    if (e < 0 || (fb.u.s.high & 0x80000000))
-        return 0;
-    tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL);
-    if (e > 52)
-        r <<= (e - 52);
-    else
-        r >>= (52 - e);
-    return r;
+__fixunsdftti(fp_t a) {
+    return __fixuint(a);
 }
-
 #endif /* CRT_HAS_128BIT */
diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c
index 69d5952..cd21cfd 100644
--- a/lib/builtins/fixunssfdi.c
+++ b/lib/builtins/fixunssfdi.c
@@ -6,39 +6,16 @@
  * Source Licenses. See LICENSE.TXT for details.
  *
  * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             du_int is a 64 bit integral type
- *             value in float is representable in du_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
 
 COMPILER_RT_ABI du_int
-__fixunssfdi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    du_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfdi(fp_t a) {
+    return __fixuint(a);
 }
diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c
index e034139..cc2b05b 100644
--- a/lib/builtins/fixunssfsi.c
+++ b/lib/builtins/fixunssfsi.c
@@ -12,34 +12,14 @@
  * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
-
-/* Returns: convert a to a unsigned int, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             su_int is a 32 bit integral type
- *             value in float is representable in su_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#define SINGLE_PRECISION
+#include "fp_lib.h"
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
 
 COMPILER_RT_ABI su_int
-__fixunssfsi(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    su_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfsi(fp_t a) {
+    return __fixuint(a);
 }
diff --git a/lib/builtins/fixunssfti.c b/lib/builtins/fixunssfti.c
index 4da9e24..862d7bd 100644
--- a/lib/builtins/fixunssfti.c
+++ b/lib/builtins/fixunssfti.c
@@ -12,36 +12,15 @@
  * ===----------------------------------------------------------------------===
  */
 
-#include "int_lib.h"
+#define SINGLE_PRECISION
+#include "fp_lib.h"
 
-#ifdef CRT_HAS_128BIT
-
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- *          Negative values all become zero.
- */
-
-/* Assumption: float is a IEEE 32 bit floating point type 
- *             tu_int is a 64 bit integral type
- *             value in float is representable in tu_int or is negative 
- *                 (no range checking performed)
- */
-
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+#if defined(CRT_HAS_128BIT)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
 
 COMPILER_RT_ABI tu_int
-__fixunssfti(float a)
-{
-    float_bits fb;
-    fb.f = a;
-    int e = ((fb.u & 0x7F800000) >> 23) - 127;
-    if (e < 0 || (fb.u & 0x80000000))
-        return 0;
-    tu_int r = (fb.u & 0x007FFFFF) | 0x00800000;
-    if (e > 23)
-        r <<= (e - 23);
-    else
-        r >>= (23 - e);
-    return r;
+__fixunssfti(fp_t a) {
+    return __fixuint(a);
 }
-
-#endif /* CRT_HAS_128BIT */
+#endif
diff --git a/lib/builtins/fixunstfdi.c b/lib/builtins/fixunstfdi.c
new file mode 100644
index 0000000..b2995f6
--- /dev/null
+++ b/lib/builtins/fixunstfdi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===
+ *
+ *                     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)
+typedef du_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI du_int
+__fixunstfdi(fp_t a) {
+    return __fixuint(a);
+}
+#endif
diff --git a/lib/builtins/fixunstfsi.c b/lib/builtins/fixunstfsi.c
new file mode 100644
index 0000000..b5d3f6a
--- /dev/null
+++ b/lib/builtins/fixunstfsi.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ *                     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)
+typedef su_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI su_int
+__fixunstfsi(fp_t a) {
+    return __fixuint(a);
+}
+#endif
diff --git a/lib/builtins/fixunstfti.c b/lib/builtins/fixunstfti.c
new file mode 100644
index 0000000..22ff9df
--- /dev/null
+++ b/lib/builtins/fixunstfti.c
@@ -0,0 +1,22 @@
+/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
+ *
+ *                     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)
+typedef tu_int fixuint_t;
+#include "fp_fixuint_impl.inc"
+
+COMPILER_RT_ABI tu_int
+__fixunstfti(fp_t a) {
+    return __fixuint(a);
+}
+#endif
diff --git a/lib/builtins/fixunsxfdi.c b/lib/builtins/fixunsxfdi.c
index 7224d46..075304e 100644
--- a/lib/builtins/fixunsxfdi.c
+++ b/lib/builtins/fixunsxfdi.c
@@ -38,6 +38,8 @@
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
+        return ~(du_int)0;
     return fb.u.low.all >> (63 - e);
 }
 
diff --git a/lib/builtins/fixunsxfsi.c b/lib/builtins/fixunsxfsi.c
index df0a18e..c3c70f7 100644
--- a/lib/builtins/fixunsxfsi.c
+++ b/lib/builtins/fixunsxfsi.c
@@ -23,7 +23,6 @@
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
  *             su_int is a 32 bit integral type
  *             value in long double is representable in su_int or is negative 
- *                 (no range checking performed)
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -38,6 +37,8 @@
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
+        return ~(su_int)0;
     return fb.u.low.s.high >> (31 - e);
 }
 
diff --git a/lib/builtins/fixunsxfti.c b/lib/builtins/fixunsxfti.c
index 42e5073..fb39d00 100644
--- a/lib/builtins/fixunsxfti.c
+++ b/lib/builtins/fixunsxfti.c
@@ -21,9 +21,8 @@
  */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             tu_int is a 64 bit integral type
+ *             tu_int is a 128 bit integral type
  *             value in long double is representable in tu_int or is negative 
- *                 (no range checking performed)
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -38,6 +37,8 @@
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0 || (fb.u.high.s.low & 0x00008000))
         return 0;
+    if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
+        return ~(tu_int)0;
     tu_int r = fb.u.low.all;
     if (e > 63)
         r <<= (e - 63);
diff --git a/lib/builtins/fixxfdi.c b/lib/builtins/fixxfdi.c
index afc79d8..011787f 100644
--- a/lib/builtins/fixxfdi.c
+++ b/lib/builtins/fixxfdi.c
@@ -19,7 +19,7 @@
 /* Returns: convert a to a signed long long, rounding toward zero. */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             su_int is a 32 bit integral type
+ *             di_int is a 64 bit integral type
  *             value in long double is representable in di_int (no range checking performed)
  */
 
@@ -30,11 +30,15 @@
 COMPILER_RT_ABI di_int
 __fixxfdi(long double a)
 {
+    const di_int di_max = (di_int)((~(du_int)0) / 2);
+    const di_int di_min = -di_max - 1;
     long_double_bits fb;
     fb.f = a;
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
     if (e < 0)
         return 0;
+    if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
+        return a > 0 ? di_max : di_min;
     di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
     di_int r = fb.u.low.all;
     r = (du_int)r >> (63 - e);
diff --git a/lib/builtins/fixxfti.c b/lib/builtins/fixxfti.c
index 3d0a279..968a4f0 100644
--- a/lib/builtins/fixxfti.c
+++ b/lib/builtins/fixxfti.c
@@ -19,8 +19,8 @@
 /* Returns: convert a to a signed long long, rounding toward zero. */
 
 /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- *             su_int is a 32 bit integral type
- *             value in long double is representable in ti_int (no range checking performed)
+ *             ti_int is a 128 bit integral type
+ *             value in long double is representable in ti_int
  */
 
 /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
@@ -30,6 +30,8 @@
 COMPILER_RT_ABI ti_int
 __fixxfti(long double a)
 {
+    const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
+    const ti_int ti_min = -ti_max - 1;
     long_double_bits fb;
     fb.f = a;
     int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
@@ -37,6 +39,8 @@
         return 0;
     ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
     ti_int r = fb.u.low.all;
+    if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
+        return a > 0 ? ti_max : ti_min;
     if (e > 63)
         r <<= (e - 63);
     else
diff --git a/lib/builtins/fp_fixint_impl.inc b/lib/builtins/fp_fixint_impl.inc
new file mode 100644
index 0000000..035e87c
--- /dev/null
+++ b/lib/builtins/fp_fixint_impl.inc
@@ -0,0 +1,41 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixint_t __fixint(fp_t a) {
+    const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
+    const fixint_t fixint_min = -fixint_max - 1;
+    // Break a into sign, exponent, significand
+    const rep_t aRep = toRep(a);
+    const rep_t aAbs = aRep & absMask;
+    const fixint_t sign = aRep & signBit ? -1 : 1;
+    const int exponent = (aAbs >> significandBits) - exponentBias;
+    const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+    // If exponent is negative, the result is zero.
+    if (exponent < 0)
+        return 0;
+
+    // If the value is too large for the integer type, saturate.
+    if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
+        return sign == 1 ? fixint_max : fixint_min;
+
+    // If 0 <= exponent < significandBits, right shift to get the result.
+    // Otherwise, shift left.
+    if (exponent < significandBits)
+        return sign * (significand >> (significandBits - exponent));
+    else
+        return sign * ((fixint_t)significand << (exponent - significandBits));
+}
diff --git a/lib/builtins/fp_fixuint_impl.inc b/lib/builtins/fp_fixuint_impl.inc
new file mode 100644
index 0000000..5fefab0
--- /dev/null
+++ b/lib/builtins/fp_fixuint_impl.inc
@@ -0,0 +1,39 @@
+//===-- lib/fixdfsi.c - Double-precision -> integer 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements float to unsigned integer conversion for the
+// compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+static inline fixuint_t __fixuint(fp_t a) {
+    // Break a into sign, exponent, significand
+    const rep_t aRep = toRep(a);
+    const rep_t aAbs = aRep & absMask;
+    const int sign = aRep & signBit ? -1 : 1;
+    const int exponent = (aAbs >> significandBits) - exponentBias;
+    const rep_t significand = (aAbs & significandMask) | implicitBit;
+
+    // If either the value or the exponent is negative, the result is zero.
+    if (sign == -1 || exponent < 0)
+        return 0;
+
+    // If the value is too large for the integer type, saturate.
+    if ((unsigned)exponent > sizeof(fixuint_t) * CHAR_BIT)
+        return ~(fixuint_t)0;
+
+    // If 0 <= exponent < significandBits, right shift to get the result.
+    // Otherwise, shift left.
+    if (exponent < significandBits)
+        return significand >> (significandBits - exponent);
+    else
+        return (fixuint_t)significand << (exponent - significandBits);
+}
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index de5b2ce..5a8da38 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -333,7 +333,7 @@
 
 static void dfsan_fini() {
   if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
-    fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */);
+    fd_t fd = OpenFile(flags().dump_labels_at_exit, WrOnly);
     if (fd == kInvalidFd) {
       Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
              flags().dump_labels_at_exit);
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index 5257325..9e9aca2 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -219,7 +219,6 @@
     namespace __interception { \
       FUNC_TYPE(func) PTR_TO_REAL(func); \
     } \
-    DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \
     extern "C" \
     INTERCEPTOR_ATTRIBUTE \
     ret_type __stdcall WRAP(func)(__VA_ARGS__)
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index cd241c3..19cf184 100644
--- a/lib/interception/interception_win.cc
+++ b/lib/interception/interception_win.cc
@@ -84,6 +84,7 @@
         cursor += 2;
         continue;
       case '\xE9':  // E9 XX YY ZZ WW = jmp WWZZYYXX
+      case '\xB8':  // B8 XX YY ZZ WW = mov eax, WWZZYYXX
         cursor += 5;
         continue;
     }
@@ -182,10 +183,14 @@
 }
 
 static const void **InterestingDLLsAvailable() {
-  const char *InterestingDLLs[] = {"kernel32.dll",
-                                   "msvcr110.dll", // VS2012
-                                   "msvcr120.dll", // VS2013
-                                   NULL};
+  const char *InterestingDLLs[] = {
+    "kernel32.dll",
+    "msvcr110.dll", // VS2012
+    "msvcr120.dll", // VS2013
+    // NTDLL should go last as it exports some functions that we should override
+    // in the CRT [presumably only used internally].
+    "ntdll.dll", NULL
+  };
   static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
   if (!result[0]) {
     for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index a6119af..8ac2ae0 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -435,13 +435,11 @@
   Suppression *s = nullptr;
 
   // Suppress by module name.
-  const char *module_name;
-  uptr module_offset;
   SuppressionContext *suppressions = GetSuppressionContext();
-  if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name,
-                                                           &module_offset) &&
-      suppressions->Match(module_name, kSuppressionLeak, &s))
-    return s;
+  if (const char *module_name =
+          Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
+    if (suppressions->Match(module_name, kSuppressionLeak, &s))
+      return s;
 
   // Suppress by file or function name.
   SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index e008bd3..4bc8254 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -33,6 +33,7 @@
   -Wno-deprecated-declarations
   -Wno-unused-variable
   -Wno-zero-length-array
+  -Wno-uninitialized
   -Werror=sign-compare
 )
 set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index daa3094..d9acbbe 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -8,10 +8,10 @@
 \*===----------------------------------------------------------------------===*/
 
 #include "InstrProfiling.h"
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/errno.h>
 
 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
 
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 6eb6ca8..5b32b6a 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -27,6 +27,7 @@
   sanitizer_suppressions.cc
   sanitizer_symbolizer.cc
   sanitizer_symbolizer_libbacktrace.cc
+  sanitizer_symbolizer_mac.cc
   sanitizer_symbolizer_win.cc
   sanitizer_tls_get_addr.cc
   sanitizer_thread_registry.cc
@@ -42,6 +43,7 @@
   sanitizer_stoptheworld_linux_libcdep.cc
   sanitizer_symbolizer_libcdep.cc
   sanitizer_symbolizer_posix_libcdep.cc
+  sanitizer_symbolizer_process_libcdep.cc
   sanitizer_unwind_posix_libcdep.cc)
 
 # Explicitly list all sanitizer_common headers. Not all of these are
@@ -91,7 +93,10 @@
   sanitizer_stoptheworld.h
   sanitizer_suppressions.h
   sanitizer_symbolizer.h
+  sanitizer_symbolizer_internal.h
   sanitizer_symbolizer_libbacktrace.h
+  sanitizer_symbolizer_mac.h
+  sanitizer_symbolizer_win.h
   sanitizer_syscall_generic.inc
   sanitizer_syscall_linux_x86_64.inc
   sanitizer_thread_registry.h)
@@ -137,12 +142,6 @@
       DEFS ${SANITIZER_COMMON_DEFINITIONS})
     list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch}
                                             RTSanitizerCommonLibc.${arch})
-    add_compiler_rt_runtime(clang_rt.san-${arch} ${arch} STATIC
-      SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
-      CFLAGS ${SANITIZER_CFLAGS}
-      DEFS ${SANITIZER_COMMON_DEFINITIONS})
-    add_dependencies(sanitizer_common clang_rt.san-${arch})
   endforeach()
 endif()
 
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 4be3c7a..956fc99 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -16,6 +16,8 @@
 #include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_placement_new.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -56,7 +58,7 @@
   }
 
   internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
-  uptr openrv = OpenFile(full_path, true);
+  uptr openrv = OpenFile(full_path, WrOnly);
   if (internal_iserror(openrv)) {
     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
     internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
@@ -142,7 +144,7 @@
   *buff_size = 0;
   // The files we usually open are not seekable, so try different buffer sizes.
   for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
-    uptr openrv = OpenFile(file_name, /*write*/ false);
+    uptr openrv = OpenFile(file_name, RdOnly);
     if (internal_iserror(openrv, errno_p)) return 0;
     fd_t fd = openrv;
     UnmapOrDie(*buff, *buff_size);
@@ -206,12 +208,12 @@
                             const char *strip_path_prefix) {
   if (filepath == 0) return 0;
   if (strip_path_prefix == 0) return filepath;
-  const char *pos = internal_strstr(filepath, strip_path_prefix);
-  if (pos == 0) return filepath;
-  pos += internal_strlen(strip_path_prefix);
-  if (pos[0] == '.' && pos[1] == '/')
-    pos += 2;
-  return pos;
+  const char *res = filepath;
+  if (const char *pos = internal_strstr(filepath, strip_path_prefix))
+    res = pos + internal_strlen(strip_path_prefix);
+  if (res[0] == '.' && res[1] == '/')
+    res += 2;
+  return res;
 }
 
 const char *StripModuleName(const char *module) {
@@ -230,17 +232,16 @@
   __sanitizer_report_error_summary(buff.data());
 }
 
-void ReportErrorSummary(const char *error_type, const char *file,
-                        int line, const char *function) {
+#ifndef SANITIZER_GO
+void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
   if (!common_flags()->print_summary)
     return;
   InternalScopedString buff(kMaxSummaryLength);
-  buff.append("%s %s:%d %s", error_type,
-              file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
-                   : "??",
-              line, function ? function : "??");
+  buff.append("%s ", error_type);
+  RenderFrame(&buff, "%L %F", 0, info, common_flags()->strip_path_prefix);
   ReportErrorSummary(buff.data());
 }
+#endif
 
 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
   full_name_ = internal_strdup(module_name);
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index ff13ef1..0dfa815 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -25,6 +25,7 @@
 
 namespace __sanitizer {
 struct StackTrace;
+struct AddressInfo;
 
 // Constants.
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -186,7 +187,13 @@
 extern uptr stoptheworld_tracer_pid;
 extern uptr stoptheworld_tracer_ppid;
 
-uptr OpenFile(const char *filename, bool write);
+enum FileAccessMode {
+  RdOnly,
+  WrOnly,
+  RdWr
+};
+
+uptr OpenFile(const char *filename, FileAccessMode mode);
 // Opens the file 'file_name" and reads up to 'max_len' bytes.
 // The resulting buffer is mmaped and stored in '*buff'.
 // The size of the mmaped region is stored in '*buff_size',
@@ -215,6 +222,11 @@
 bool SetEnv(const char *name, const char *value);
 const char *GetPwd();
 char *FindPathToBinary(const char *name);
+bool IsPathSeparator(const char c);
+bool IsAbsolutePath(const char *path);
+
+// Returns the path to the main executable.
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
 u32 GetUid();
 void ReExec();
 bool StackSizeIsUnlimited();
@@ -288,9 +300,9 @@
 // and pass it to __sanitizer_report_error_summary.
 void ReportErrorSummary(const char *error_message);
 // Same as above, but construct error_message as:
-//   error_type file:line function
-void ReportErrorSummary(const char *error_type, const char *file,
-                        int line, const char *function);
+//   error_type file:line[:column][ function]
+void ReportErrorSummary(const char *error_type, const AddressInfo &info);
+// Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
 void ReportErrorSummary(const char *error_type, StackTrace *trace);
 
 // Math
@@ -439,11 +451,15 @@
   const T *data() const {
     return data_;
   }
+  T *data() {
+    return data_;
+  }
   uptr capacity() const {
     return capacity_;
   }
 
   void clear() { size_ = 0; }
+  bool empty() const { return size() == 0; }
 
  private:
   void Resize(uptr new_capacity) {
@@ -532,6 +548,7 @@
 // executable or a shared object).
 class LoadedModule {
  public:
+  LoadedModule() : full_name_(nullptr), base_address_(0) {}
   LoadedModule(const char *module_name, uptr base_address);
   void clear();
   void addAddressRange(uptr beg, uptr end, bool executable);
@@ -607,6 +624,23 @@
 #endif
 }
 
+struct SignalContext {
+  void *context;
+  uptr addr;
+  uptr pc;
+  uptr sp;
+  uptr bp;
+
+  SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
+      context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
+  }
+
+  // Creates signal context in a platform-specific manner.
+  static SignalContext Create(void *siginfo, void *context);
+};
+
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+
 }  // namespace __sanitizer
 
 inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 17ef689..9622e60 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -44,20 +44,16 @@
 void ReportErrorSummary(const char *error_type, StackTrace *stack) {
   if (!common_flags()->print_summary)
     return;
-#if !SANITIZER_GO
-  if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) {
-    // Currently, we include the first stack frame into the report summary.
-    // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
-    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
-    SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
-    const AddressInfo &ai = frame->info;
-    ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
-    frame->ClearAll();
+  if (stack->size == 0) {
+    ReportErrorSummary(error_type);
+    return;
   }
-#else
-  AddressInfo ai;
-  ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
-#endif
+  // Currently, we include the first stack frame into the report summary.
+  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+  ReportErrorSummary(error_type, frame->info);
+  frame->ClearAll();
 }
 
 static void (*SoftRssLimitExceededCallback)(bool exceeded);
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index 49887b1..94863c6 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -24,8 +24,12 @@
 //    and atomically set Guard to -Guard.
 //  - __sanitizer_cov_dump: dump the coverage data to disk.
 //  For every module of the current process that has coverage data
-//  this will create a file module_name.PID.sancov. The file format is simple:
-//  it's just a sorted sequence of 4-byte offsets in the module.
+//  this will create a file module_name.PID.sancov.
+//
+// The file format is simple: the first 8 bytes is the magic,
+// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the
+// magic defines the size of the following offsets.
+// The rest of the data is the offsets in the module.
 //
 // Eventually, this coverage implementation should be obsoleted by a more
 // powerful general purpose Clang/LLVM coverage instrumentation.
@@ -43,6 +47,9 @@
 #include "sanitizer_symbolizer.h"
 #include "sanitizer_flags.h"
 
+static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL;
+static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
+
 static atomic_uint32_t dump_once_guard;  // Ensure that CovDump runs only once.
 
 static atomic_uintptr_t coverage_counter;
@@ -77,21 +84,32 @@
                  uptr cache_size);
   void DumpCallerCalleePairs();
   void DumpTrace();
+  void DumpAsBitSet();
+  void DumpCounters();
+  void DumpOffsets();
+  void DumpAll();
 
   ALWAYS_INLINE
   void TraceBasicBlock(s32 *id);
 
   void InitializeGuardArray(s32 *guards);
-  void InitializeGuards(s32 *guards, uptr n, const char *module_name);
+  void InitializeGuards(s32 *guards, uptr n, const char *module_name,
+                        uptr caller_pc);
+  void InitializeCounters(u8 *counters, uptr n);
   void ReinitializeGuards();
+  uptr GetNumberOf8bitCounters();
+  uptr Update8bitCounterBitsetAndClearCounters(u8 *bitset);
 
   uptr *data();
   uptr size();
 
  private:
+  void DirectOpen();
+  void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end);
+
   // Maximal size pc array may ever grow.
   // We MmapNoReserve this space to ensure that the array is contiguous.
-  static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 24, 1 << 27);
+  static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27);
   // The amount file mapping for the pc array is grown by.
   static const uptr kPcArrayMmapSize = 64 * 1024;
 
@@ -110,8 +128,22 @@
   // Vector of coverage guard arrays, protected by mu.
   InternalMmapVectorNoCtor<s32*> guard_array_vec;
 
-  // Vector of module (compilation unit) names.
-  InternalMmapVectorNoCtor<const char*> comp_unit_name_vec;
+  struct NamedPcRange {
+    const char *copied_module_name;
+    uptr beg, end; // elements [beg,end) in pc_array.
+  };
+
+  // Vector of module and compilation unit pc ranges.
+  InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec;
+  InternalMmapVectorNoCtor<NamedPcRange> module_name_vec;
+
+  struct CounterAndSize {
+    u8 *counters;
+    uptr n;
+  };
+
+  InternalMmapVectorNoCtor<CounterAndSize> counters_vec;
+  uptr num_8bit_counters;
 
   // Caller-Callee (cc) array, size and current index.
   static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
@@ -133,8 +165,6 @@
   static const uptr kTrPcArrayMaxSize    = FIRST_32_SECOND_64(1 << 22, 1 << 27);
 
   StaticSpinMutex mu;
-
-  void DirectOpen();
 };
 
 static CoverageData coverage_data;
@@ -145,9 +175,9 @@
   InternalScopedString path(kMaxPathLength);
   internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
                     coverage_dir, internal_getpid());
-  pc_fd = OpenFile(path.data(), true);
+  pc_fd = OpenFile(path.data(), RdWr);
   if (internal_iserror(pc_fd)) {
-    Report(" Coverage: failed to open %s for writing\n", path.data());
+    Report(" Coverage: failed to open %s for reading/writing\n", path.data());
     Die();
   }
 
@@ -184,6 +214,8 @@
            GetMmapGranularity());
   tr_event_array_size = kTrEventArrayMaxSize;
   tr_event_pointer = tr_event_array;
+
+  num_8bit_counters = 0;
 }
 
 void CoverageData::InitializeGuardArray(s32 *guards) {
@@ -289,16 +321,70 @@
   atomic_store(&pc_array_size, size, memory_order_release);
 }
 
+void CoverageData::InitializeCounters(u8 *counters, uptr n) {
+  if (!counters) return;
+  CHECK_EQ(reinterpret_cast<uptr>(counters) % 16, 0);
+  n = RoundUpTo(n, 16); // The compiler must ensure that counters is 16-aligned.
+  SpinMutexLock l(&mu);
+  counters_vec.push_back({counters, n});
+  num_8bit_counters += n;
+}
+
+void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg,
+                                       uptr range_end) {
+  auto sym = Symbolizer::GetOrInit();
+  if (!sym)
+    return;
+  const char *module_name = sym->GetModuleNameForPc(caller_pc);
+  if (!module_name) return;
+  if (module_name_vec.empty() ||
+      internal_strcmp(module_name_vec.back().copied_module_name, module_name))
+    module_name_vec.push_back(
+        {internal_strdup(module_name), range_beg, range_end});
+  else
+    module_name_vec.back().end = range_end;
+}
+
 void CoverageData::InitializeGuards(s32 *guards, uptr n,
-                                    const char *module_name) {
+                                    const char *comp_unit_name,
+                                    uptr caller_pc) {
   // The array 'guards' has n+1 elements, we use the element zero
   // to store 'n'.
   CHECK_LT(n, 1 << 30);
   guards[0] = static_cast<s32>(n);
   InitializeGuardArray(guards);
   SpinMutexLock l(&mu);
-  comp_unit_name_vec.push_back(module_name);
+  uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed);
+  uptr range_beg = range_end - n;
+  comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end});
   guard_array_vec.push_back(guards);
+  UpdateModuleNameVec(caller_pc, range_beg, range_end);
+}
+
+static const uptr kBundleCounterBits = 16;
+
+// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64
+// we insert the global counter into the first 16 bits of the PC.
+uptr BundlePcAndCounter(uptr pc, uptr counter) {
+  if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
+    return pc;
+  static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1;
+  if (counter > kMaxCounter)
+    counter = kMaxCounter;
+  CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits));
+  return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits));
+}
+
+uptr UnbundlePc(uptr bundle) {
+  if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
+    return bundle;
+  return (bundle << kBundleCounterBits) >> kBundleCounterBits;
+}
+
+uptr UnbundleCounter(uptr bundle) {
+  if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
+    return 0;
+  return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits);
 }
 
 // If guard is negative, atomically set it to -guard and store the PC in
@@ -316,8 +402,8 @@
     return;  // May happen after fork when pc_array_index becomes 0.
   CHECK_LT(idx * sizeof(uptr),
            atomic_load(&pc_array_size, memory_order_acquire));
-  pc_array[idx] = pc;
-  atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+  uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+  pc_array[idx] = BundlePcAndCounter(pc, counter);
 }
 
 // Registers a pair caller=>callee.
@@ -354,6 +440,64 @@
   }
 }
 
+uptr CoverageData::GetNumberOf8bitCounters() {
+  return num_8bit_counters;
+}
+
+// Map every 8bit counter to a 8-bit bitset and clear the counter.
+uptr CoverageData::Update8bitCounterBitsetAndClearCounters(u8 *bitset) {
+  uptr num_new_bits = 0;
+  uptr cur = 0;
+  // For better speed we map 8 counters to 8 bytes of bitset at once.
+  static const uptr kBatchSize = 8;
+  CHECK_EQ(reinterpret_cast<uptr>(bitset) % kBatchSize, 0);
+  for (uptr i = 0, len = counters_vec.size(); i < len; i++) {
+    u8 *c = counters_vec[i].counters;
+    uptr n = counters_vec[i].n;
+    CHECK_EQ(n % 16, 0);
+    CHECK_EQ(cur % kBatchSize, 0);
+    CHECK_EQ(reinterpret_cast<uptr>(c) % kBatchSize, 0);
+    if (!bitset) {
+      internal_bzero_aligned16(c, n);
+      cur += n;
+      continue;
+    }
+    for (uptr j = 0; j < n; j += kBatchSize, cur += kBatchSize) {
+      CHECK_LT(cur, num_8bit_counters);
+      u64 *pc64 = reinterpret_cast<u64*>(c + j);
+      u64 *pb64 = reinterpret_cast<u64*>(bitset + cur);
+      u64 c64 = *pc64;
+      u64 old_bits_64 = *pb64;
+      u64 new_bits_64 = old_bits_64;
+      if (c64) {
+        *pc64 = 0;
+        for (uptr k = 0; k < kBatchSize; k++) {
+          u64 x = (c64 >> (8 * k)) & 0xff;
+          if (x) {
+            u64 bit = 0;
+            /**/ if (x >= 128) bit = 128;
+            else if (x >= 32) bit = 64;
+            else if (x >= 16) bit = 32;
+            else if (x >= 8) bit = 16;
+            else if (x >= 4) bit = 8;
+            else if (x >= 3) bit = 4;
+            else if (x >= 2) bit = 2;
+            else if (x >= 1) bit = 1;
+            u64 mask = bit << (8 * k);
+            if (!(new_bits_64 & mask)) {
+              num_new_bits++;
+              new_bits_64 |= mask;
+            }
+          }
+        }
+        *pb64 = new_bits_64;
+      }
+    }
+  }
+  CHECK_EQ(cur, num_8bit_counters);
+  return num_new_bits;
+}
+
 uptr *CoverageData::data() {
   return pc_array;
 }
@@ -413,23 +557,23 @@
 // If packed = true and name == 0: <pid>.<sancov>.<packed>.
 // If packed = true and name != 0: <name>.<sancov>.<packed> (name is
 // user-supplied).
-static int CovOpenFile(bool packed, const char *name,
-                       const char *extension = "sancov") {
-  InternalScopedString path(kMaxPathLength);
+static int CovOpenFile(InternalScopedString *path, bool packed,
+                       const char *name, const char *extension = "sancov") {
+  path->clear();
   if (!packed) {
     CHECK(name);
-    path.append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(),
+    path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(),
                 extension);
   } else {
     if (!name)
-      path.append("%s/%zd.%s.packed", coverage_dir, internal_getpid(),
+      path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(),
                   extension);
     else
-      path.append("%s/%s.%s.packed", coverage_dir, name, extension);
+      path->append("%s/%s.%s.packed", coverage_dir, name, extension);
   }
-  uptr fd = OpenFile(path.data(), true);
+  uptr fd = OpenFile(path->data(), WrOnly);
   if (internal_iserror(fd)) {
-    Report(" SanitizerCoverage: failed to open %s for writing\n", path.data());
+    Report(" SanitizerCoverage: failed to open %s for writing\n", path->data());
     return -1;
   }
   return fd;
@@ -446,24 +590,25 @@
   for (uptr i = 0, n = size(); i < n; i++) {
     const char *module_name = "<unknown>";
     uptr module_address = 0;
-    sym->GetModuleNameAndOffsetForPC(pc_array[i], &module_name,
+    sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name,
                                      &module_address);
     out.append("%s 0x%zx\n", module_name, module_address);
   }
-  int fd = CovOpenFile(false, "trace-points");
+  InternalScopedString path(kMaxPathLength);
+  int fd = CovOpenFile(&path, false, "trace-points");
   if (fd < 0) return;
   internal_write(fd, out.data(), out.length());
   internal_close(fd);
 
-  fd = CovOpenFile(false, "trace-compunits");
+  fd = CovOpenFile(&path, false, "trace-compunits");
   if (fd < 0) return;
   out.clear();
   for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
-    out.append("%s\n", comp_unit_name_vec[i]);
+    out.append("%s\n", comp_unit_name_vec[i].copied_module_name);
   internal_write(fd, out.data(), out.length());
   internal_close(fd);
 
-  fd = CovOpenFile(false, "trace-events");
+  fd = CovOpenFile(&path, false, "trace-events");
   if (fd < 0) return;
   uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
   u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array);
@@ -514,7 +659,8 @@
                  callee_module_address);
     }
   }
-  int fd = CovOpenFile(false, "caller-callee");
+  InternalScopedString path(kMaxPathLength);
+  int fd = CovOpenFile(&path, false, "caller-callee");
   if (fd < 0) return;
   internal_write(fd, out.data(), out.length());
   internal_close(fd);
@@ -534,86 +680,124 @@
   tr_event_pointer++;
 }
 
-static void CovDumpAsBitSet() {
-  if (!common_flags()->coverage_bitset) return;
-  if (!coverage_data.size()) return;
-  int fd = CovOpenFile(/* packed */false, "combined", "bitset-sancov");
-  if (fd < 0) return;
-  uptr n = coverage_data.size();
-  uptr n_set_bits = 0;
-  InternalScopedBuffer<char> out(n);
-  for (uptr i = 0; i < n; i++) {
-    uptr pc = coverage_data.data()[i];
-    out[i] = pc ? '1' : '0';
-    if (pc)
-      n_set_bits++;
+void CoverageData::DumpCounters() {
+  if (!common_flags()->coverage_counters) return;
+  uptr n = coverage_data.GetNumberOf8bitCounters();
+  if (!n) return;
+  InternalScopedBuffer<u8> bitset(n);
+  coverage_data.Update8bitCounterBitsetAndClearCounters(bitset.data());
+  InternalScopedString path(kMaxPathLength);
+
+  for (uptr m = 0; m < module_name_vec.size(); m++) {
+    auto r = module_name_vec[m];
+    CHECK(r.copied_module_name);
+    CHECK_LE(r.beg, r.end);
+    CHECK_LE(r.end, size());
+    const char *base_name = StripModuleName(r.copied_module_name);
+    int fd =
+        CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov");
+    if (fd < 0) return;
+    internal_write(fd, bitset.data() + r.beg, r.end - r.beg);
+    internal_close(fd);
+    VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg,
+            base_name);
   }
-  internal_write(fd, out.data(), n);
-  internal_close(fd);
-  VReport(1, " CovDump: bitset of %zd bits written, %zd bits are set\n", n,
-          n_set_bits);
 }
 
-// Dump the coverage on disk.
-static void CovDump() {
-  if (!coverage_enabled || common_flags()->coverage_direct) return;
-#if !SANITIZER_WINDOWS
-  if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
-    return;
-  CovDumpAsBitSet();
-  coverage_data.DumpTrace();
-  if (!common_flags()->coverage_pcs) return;
-  uptr size = coverage_data.size();
-  InternalMmapVector<u32> offsets(size);
-  uptr *vb = coverage_data.data();
-  uptr *ve = vb + size;
-  SortArray(vb, size);
-  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
-  uptr mb, me, off, prot;
-  InternalScopedString module(kMaxPathLength);
+void CoverageData::DumpAsBitSet() {
+  if (!common_flags()->coverage_bitset) return;
+  if (!size()) return;
+  InternalScopedBuffer<char> out(size());
   InternalScopedString path(kMaxPathLength);
-  for (int i = 0;
-       proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
-       i++) {
-    if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
-      continue;
-    while (vb < ve && *vb < mb) vb++;
-    if (vb >= ve) break;
-    if (*vb < me) {
-      offsets.clear();
-      const uptr *old_vb = vb;
-      CHECK_LE(off, *vb);
-      for (; vb < ve && *vb < me; vb++) {
-        uptr diff = *vb - (i ? mb : 0) + off;
-        CHECK_LE(diff, 0xffffffffU);
-        offsets.push_back(static_cast<u32>(diff));
+  for (uptr m = 0; m < module_name_vec.size(); m++) {
+    uptr n_set_bits = 0;
+    auto r = module_name_vec[m];
+    CHECK(r.copied_module_name);
+    CHECK_LE(r.beg, r.end);
+    CHECK_LE(r.end, size());
+    for (uptr i = r.beg; i < r.end; i++) {
+      uptr pc = UnbundlePc(pc_array[i]);
+      out[i] = pc ? '1' : '0';
+      if (pc)
+        n_set_bits++;
+    }
+    const char *base_name = StripModuleName(r.copied_module_name);
+    int fd = CovOpenFile(&path, /* packed */ false, base_name, "bitset-sancov");
+    if (fd < 0) return;
+    internal_write(fd, out.data() + r.beg, r.end - r.beg);
+    internal_close(fd);
+    VReport(1,
+            " CovDump: bitset of %zd bits written for '%s', %zd bits are set\n",
+            r.end - r.beg, base_name, n_set_bits);
+  }
+}
+
+void CoverageData::DumpOffsets() {
+  auto sym = Symbolizer::GetOrInit();
+  if (!common_flags()->coverage_pcs) return;
+  CHECK_NE(sym, nullptr);
+  InternalMmapVector<uptr> offsets(0);
+  InternalScopedString path(kMaxPathLength);
+  for (uptr m = 0; m < module_name_vec.size(); m++) {
+    offsets.clear();
+    uptr num_words_for_magic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
+    for (uptr i = 0; i < num_words_for_magic; i++)
+      offsets.push_back(0);
+    auto r = module_name_vec[m];
+    CHECK(r.copied_module_name);
+    CHECK_LE(r.beg, r.end);
+    CHECK_LE(r.end, size());
+    for (uptr i = r.beg; i < r.end; i++) {
+      uptr pc = UnbundlePc(pc_array[i]);
+      uptr counter = UnbundleCounter(pc_array[i]);
+      if (!pc) continue; // Not visited.
+      const char *unused;
+      uptr offset = 0;
+      sym->GetModuleNameAndOffsetForPC(pc, &unused, &offset);
+      offsets.push_back(BundlePcAndCounter(offset, counter));
+    }
+
+    CHECK_GE(offsets.size(), num_words_for_magic);
+    SortArray(offsets.data(), offsets.size());
+    for (uptr i = 0; i < offsets.size(); i++)
+      offsets[i] = UnbundlePc(offsets[i]);
+
+    uptr num_offsets = offsets.size() - num_words_for_magic;
+    u64 *magic_p = reinterpret_cast<u64*>(offsets.data());
+    CHECK_EQ(*magic_p, 0ULL);
+    // FIXME: we may want to write 32-bit offsets even in 64-mode
+    // if all the offsets are small enough.
+    *magic_p = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
+
+    const char *module_name = StripModuleName(r.copied_module_name);
+    if (cov_sandboxed) {
+      if (cov_fd >= 0) {
+        CovWritePacked(internal_getpid(), module_name, offsets.data(),
+                       offsets.size() * sizeof(offsets[0]));
+        VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
       }
-      const char *module_name = StripModuleName(module.data());
-      if (cov_sandboxed) {
-        if (cov_fd >= 0) {
-          CovWritePacked(internal_getpid(), module_name, offsets.data(),
-                         offsets.size() * sizeof(u32));
-          VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb);
-        }
-      } else {
-        // One file per module per process.
-        path.clear();
-        path.append("%s/%s.%zd.sancov", coverage_dir, module_name,
-                    internal_getpid());
-        int fd = CovOpenFile(false /* packed */, module_name);
-        if (fd > 0) {
-          internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
-          internal_close(fd);
-          VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
-                  vb - old_vb);
-        }
-      }
+    } else {
+      // One file per module per process.
+      int fd = CovOpenFile(&path, false /* packed */, module_name);
+      if (fd < 0) continue;
+      internal_write(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
+      internal_close(fd);
+      VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
     }
   }
   if (cov_fd >= 0)
     internal_close(cov_fd);
-  coverage_data.DumpCallerCalleePairs();
-#endif  // !SANITIZER_WINDOWS
+}
+
+void CoverageData::DumpAll() {
+  if (!coverage_enabled || common_flags()->coverage_direct) return;
+  if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
+    return;
+  DumpAsBitSet();
+  DumpCounters();
+  DumpTrace();
+  DumpOffsets();
+  DumpCallerCalleePairs();
 }
 
 void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
@@ -623,15 +807,18 @@
   if (!cov_sandboxed) return;
   cov_fd = args->coverage_fd;
   cov_max_block_size = args->coverage_max_block_size;
-  if (cov_fd < 0)
+  if (cov_fd < 0) {
+    InternalScopedString path(kMaxPathLength);
     // Pre-open the file now. The sandbox won't allow us to do it later.
-    cov_fd = CovOpenFile(true /* packed */, 0);
+    cov_fd = CovOpenFile(&path, true /* packed */, 0);
+  }
 }
 
 int MaybeOpenCovFile(const char *name) {
   CHECK(name);
   if (!coverage_enabled) return -1;
-  return CovOpenFile(true /* packed */, name);
+  InternalScopedString path(kMaxPathLength);
+  return CovOpenFile(&path, true /* packed */, name);
 }
 
 void CovBeforeFork() {
@@ -674,7 +861,8 @@
 }
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) {
   atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
-  if (__sanitizer::atomic_load(atomic_guard, memory_order_relaxed))
+  if (static_cast<s32>(
+          __sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) < 0)
     __sanitizer_cov(guard);
 }
 SANITIZER_INTERFACE_ATTRIBUTE void
@@ -687,10 +875,14 @@
   coverage_dir = common_flags()->coverage_dir;
   coverage_data.Init();
 }
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
+  coverage_data.DumpAll();
+}
 SANITIZER_INTERFACE_ATTRIBUTE void
-__sanitizer_cov_module_init(s32 *guards, uptr npcs, const char *module_name) {
-  coverage_data.InitializeGuards(guards, npcs, module_name);
+__sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters,
+                            const char *comp_unit_name) {
+  coverage_data.InitializeGuards(guards, npcs, comp_unit_name, GET_CALLER_PC());
+  coverage_data.InitializeCounters(counters, npcs);
   if (!common_flags()->coverage_direct) return;
   if (SANITIZER_ANDROID && coverage_enabled) {
     // dlopen/dlclose interceptors do not work on Android, so we rely on
@@ -728,4 +920,14 @@
   *data = coverage_data.data();
   return coverage_data.size();
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_number_of_counters() {
+  return coverage_data.GetNumberOf8bitCounters();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) {
+  return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset);
+}
 }  // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index 6b5e91f..d3bde4b 100644
--- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -102,7 +102,7 @@
                                "%s/%zd.sancov.map.tmp", coverage_dir,
                                internal_getpid());
   CHECK_LE(res, tmp_path.size());
-  uptr map_fd = OpenFile(tmp_path.data(), true);
+  uptr map_fd = OpenFile(tmp_path.data(), WrOnly);
   if (internal_iserror(map_fd, &err)) {
     Report(" Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
            err);
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index 58f7f37..884602f 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -111,13 +111,18 @@
     bool, coverage, false,
     "If set, coverage information will be dumped at program shutdown (if the "
     "coverage instrumentation was enabled at compile time).")
-// On by default, but works only if coverage == true.
 COMMON_FLAG(bool, coverage_pcs, true,
             "If set (and if 'coverage' is set too), the coverage information "
             "will be dumped as a set of PC offsets for every module.")
+COMMON_FLAG(bool, coverage_order_pcs, false,
+             "If true, the PCs will be dumped in the order they've"
+             " appeared during the execution.")
 COMMON_FLAG(bool, coverage_bitset, false,
             "If set (and if 'coverage' is set too), the coverage information "
             "will also be dumped as a bitset to a separate file.")
+COMMON_FLAG(bool, coverage_counters, false,
+            "If set (and if 'coverage' is set too), the bitmap that corresponds"
+            " to coverage counters will be dumped.")
 COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
             "If set, coverage information will be dumped directly to a memory "
             "mapped file. This way data is not lost even if the process is "
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 8029181..8d2ea48 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -57,6 +57,7 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <ucontext.h>
 #include <unistd.h>
 
 #if SANITIZER_FREEBSD
@@ -147,11 +148,6 @@
 #endif
 }
 
-uptr OpenFile(const char *filename, bool write) {
-  return internal_open(filename,
-      write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
-}
-
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   sptr res;
   HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
@@ -168,7 +164,8 @@
 
 uptr internal_ftruncate(fd_t fd, uptr size) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
+  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
+               (OFF_T)size));
   return res;
 }
 
@@ -558,6 +555,7 @@
 }
 
 #if SANITIZER_LINUX
+#define SA_RESTORER 0x04000000
 // Doesn't set sa_restorer, use with caution (see below).
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
   __sanitizer_kernel_sigaction_t k_act, k_oldact;
@@ -570,7 +568,8 @@
     k_act.sigaction = u_act->sigaction;
     internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
                     sizeof(__sanitizer_kernel_sigset_t));
-    k_act.sa_flags = u_act->sa_flags;
+    // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL).
+    k_act.sa_flags = u_act->sa_flags | SA_RESTORER;
     // FIXME: most often sa_restorer is unset, however the kernel requires it
     // to point to a valid signal restorer that calls the rt_sigreturn syscall.
     // If sa_restorer passed to the kernel is NULL, the program may crash upon
@@ -928,6 +927,78 @@
 void internal_join_thread(void *th) {}
 #endif
 
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+#if defined(__arm__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.arm_pc;
+  *bp = ucontext->uc_mcontext.arm_fp;
+  *sp = ucontext->uc_mcontext.arm_sp;
+#elif defined(__aarch64__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.pc;
+  *bp = ucontext->uc_mcontext.regs[29];
+  *sp = ucontext->uc_mcontext.sp;
+#elif defined(__hppa__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.sc_iaoq[0];
+  /* GCC uses %r3 whenever a frame pointer is needed.  */
+  *bp = ucontext->uc_mcontext.sc_gr[3];
+  *sp = ucontext->uc_mcontext.sc_gr[30];
+#elif defined(__x86_64__)
+# if SANITIZER_FREEBSD
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.mc_rip;
+  *bp = ucontext->uc_mcontext.mc_rbp;
+  *sp = ucontext->uc_mcontext.mc_rsp;
+# else
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
+  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
+  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
+# endif
+#elif defined(__i386__)
+# if SANITIZER_FREEBSD
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.mc_eip;
+  *bp = ucontext->uc_mcontext.mc_ebp;
+  *sp = ucontext->uc_mcontext.mc_esp;
+# else
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
+  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
+  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
+# endif
+#elif defined(__powerpc__) || defined(__powerpc64__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.regs->nip;
+  *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
+  // The powerpc{,64}-linux ABIs do not specify r31 as the frame
+  // pointer, but GCC always uses r31 when we need a frame pointer.
+  *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
+#elif defined(__sparc__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  uptr *stk_ptr;
+# if defined (__arch64__)
+  *pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
+  *sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
+  stk_ptr = (uptr *) (*sp + 2047);
+  *bp = stk_ptr[15];
+# else
+  *pc = ucontext->uc_mcontext.gregs[REG_PC];
+  *sp = ucontext->uc_mcontext.gregs[REG_O6];
+  stk_ptr = (uptr *) *sp;
+  *bp = stk_ptr[15];
+# endif
+#elif defined(__mips__)
+  ucontext_t *ucontext = (ucontext_t*)context;
+  *pc = ucontext->uc_mcontext.gregs[31];
+  *bp = ucontext->uc_mcontext.gregs[30];
+  *sp = ucontext->uc_mcontext.gregs[29];
+#else
+# error "Unsupported arch"
+#endif
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index b2e603d..2ce2025 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -80,8 +80,6 @@
 // information).
 bool LibraryNameIs(const char *full_name, const char *base_name);
 
-// Read the name of the current binary from /proc/self/exe.
-uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
 // Cache the value of /proc/self/exe.
 void CacheBinaryName();
 
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index c71b625..1c099d8 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -488,7 +488,7 @@
 uptr GetRSS() {
   if (!common_flags()->can_use_proc_maps_statm)
     return GetRSSFromGetrusage();
-  uptr fd = OpenFile("/proc/self/statm", false);
+  uptr fd = OpenFile("/proc/self/statm", RdOnly);
   if ((sptr)fd < 0)
     return GetRSSFromGetrusage();
   char buf[64];
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 39a5c7e..91a5b7d 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -31,9 +31,11 @@
 
 #include <crt_externs.h>  // for _NSGetEnviron
 #include <fcntl.h>
+#include <mach-o/dyld.h>
 #include <pthread.h>
 #include <sched.h>
 #include <signal.h>
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
@@ -69,11 +71,6 @@
   return open(filename, flags, mode);
 }
 
-uptr OpenFile(const char *filename, bool write) {
-  return internal_open(filename,
-      write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
-}
-
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   return read(fd, buf, count);
 }
@@ -204,6 +201,21 @@
   return 0;
 }
 
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+  CHECK_LE(kMaxPathLength, buf_len);
+
+  // On OS X the executable path is saved to the stack by dyld. Reading it
+  // from there is much faster than calling dladdr, especially for large
+  // binaries with symbols.
+  InternalScopedString exe_path(kMaxPathLength);
+  uint32_t size = exe_path.size();
+  if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
+      realpath(exe_path.data(), buf) != 0) {
+    return internal_strlen(buf);
+  }
+  return 0;
+}
+
 void ReExec() {
   UNIMPLEMENTED();
 }
@@ -328,6 +340,19 @@
 void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
 void internal_join_thread(void *th) { }
 
+void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+  ucontext_t *ucontext = (ucontext_t*)context;
+# if SANITIZER_WORDSIZE == 64
+  *pc = ucontext->uc_mcontext->__ss.__rip;
+  *bp = ucontext->uc_mcontext->__ss.__rbp;
+  *sp = ucontext->uc_mcontext->__ss.__rsp;
+# else
+  *pc = ucontext->uc_mcontext->__ss.__eip;
+  *bp = ucontext->uc_mcontext->__ss.__ebp;
+  *sp = ucontext->uc_mcontext->__ss.__esp;
+# endif  // SANITIZER_WORDSIZE
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 5bc41c2..5e01212 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -20,6 +20,8 @@
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
 
+#include <fcntl.h>
+#include <signal.h>
 #include <sys/mman.h>
 
 #if SANITIZER_LINUX
@@ -47,7 +49,7 @@
 #if SANITIZER_WORDSIZE == 32
 // Take care of unusable kernel area in top gigabyte.
 static uptr GetKernelAreaSize() {
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_X32
   const uptr gbyte = 1UL << 30;
 
   // Firstly check if there are writable segments
@@ -79,7 +81,7 @@
   return gbyte;
 #else
   return 0;
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_LINUX && !SANITIZER_X32
 }
 #endif  // SANITIZER_WORDSIZE == 32
 
@@ -203,8 +205,18 @@
                                MAP_NORESERVE, -1, 0);
 }
 
+uptr OpenFile(const char *filename, FileAccessMode mode) {
+  int flags;
+  switch (mode) {
+    case RdOnly: flags = O_RDONLY; break;
+    case WrOnly: flags = O_WRONLY | O_CREAT; break;
+    case RdWr: flags = O_RDWR | O_CREAT; break;
+  }
+  return internal_open(filename, flags, 0660);
+}
+
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
-  uptr openrv = OpenFile(file_name, false);
+  uptr openrv = OpenFile(file_name, RdOnly);
   CHECK(!internal_iserror(openrv));
   fd_t fd = openrv;
   uptr fsize = internal_filesize(fd);
@@ -219,9 +231,10 @@
   uptr flags = MAP_SHARED;
   if (addr) flags |= MAP_FIXED;
   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
-  if (internal_iserror(p)) {
-    Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset,
-           size, p);
+  int mmap_errno = 0;
+  if (internal_iserror(p, &mmap_errno)) {
+    Printf("could not map writable file (%zd, %zu, %zu): %zd, errno: %d\n",
+           fd, offset, size, p, mmap_errno);
     return 0;
   }
   return (void *)p;
@@ -293,6 +306,14 @@
   return 0;
 }
 
+bool IsPathSeparator(const char c) {
+  return c == '/';
+}
+
+bool IsAbsolutePath(const char *path) {
+  return path != nullptr && IsPathSeparator(path[0]);
+}
+
 void ReportFile::Write(const char *buffer, uptr length) {
   SpinMutexLock l(mu);
   static const char *kWriteError =
@@ -319,6 +340,13 @@
   return false;
 }
 
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+  uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
+  uptr pc, sp, bp;
+  GetPcSpBp(context, &pc, &sp, &bp);
+  return SignalContext(context, addr, pc, sp, bp);
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h
index a326467..aa6f5d8 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld.h
+++ b/lib/sanitizer_common/sanitizer_stoptheworld.h
@@ -59,7 +59,8 @@
 
 // Suspend all threads in the current process and run the callback on the list
 // of suspended threads. This function will resume the threads before returning.
-// The callback should not call any libc functions.
+// The callback should not call any libc functions. The callback must not call
+// exit() nor _exit() and instead return to the caller.
 // This function should NOT be called from multiple threads simultaneously.
 void StopTheWorld(StopTheWorldCallback callback, void *argument);
 
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index ad20e39..64e1c79 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -19,6 +19,7 @@
 #include "sanitizer_stoptheworld.h"
 
 #include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_atomic.h"
 
 #include <errno.h>
 #include <sched.h> // for CLONE_* definitions
@@ -70,11 +71,25 @@
 COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
 
 namespace __sanitizer {
+
+// Structure for passing arguments into the tracer thread.
+struct TracerThreadArgument {
+  StopTheWorldCallback callback;
+  void *callback_argument;
+  // The tracer thread waits on this mutex while the parent finishes its
+  // preparations.
+  BlockingMutex mutex;
+  // Tracer thread signals its completion by setting done.
+  atomic_uintptr_t done;
+  uptr parent_pid;
+};
+
 // This class handles thread suspending/unsuspending in the tracer thread.
 class ThreadSuspender {
  public:
-  explicit ThreadSuspender(pid_t pid)
-    : pid_(pid) {
+  explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg)
+    : arg(arg)
+    , pid_(pid) {
       CHECK_GE(pid, 0);
     }
   bool SuspendAllThreads();
@@ -83,6 +98,7 @@
   SuspendedThreadsList &suspended_threads_list() {
     return suspended_threads_list_;
   }
+  TracerThreadArgument *arg;
  private:
   SuspendedThreadsList suspended_threads_list_;
   pid_t pid_;
@@ -103,7 +119,7 @@
     VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno);
     return false;
   } else {
-    VReport(1, "Attached to thread %d.\n", tid);
+    VReport(2, "Attached to thread %d.\n", tid);
     // The thread is not guaranteed to stop before ptrace returns, so we must
     // wait on it. Note: if the thread receives a signal concurrently,
     // we can get notification about the signal before notification about stop.
@@ -143,7 +159,7 @@
     int pterrno;
     if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
                           &pterrno)) {
-      VReport(1, "Detached from thread %d.\n", tid);
+      VReport(2, "Detached from thread %d.\n", tid);
     } else {
       // Either the thread is dead, or we are already detached.
       // The latter case is possible, for instance, if this function was called
@@ -188,25 +204,23 @@
 static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS,
                                     SIGXCPU, SIGXFSZ };
 
-// Structure for passing arguments into the tracer thread.
-struct TracerThreadArgument {
-  StopTheWorldCallback callback;
-  void *callback_argument;
-  // The tracer thread waits on this mutex while the parent finishes its
-  // preparations.
-  BlockingMutex mutex;
-  uptr parent_pid;
-};
-
 static DieCallbackType old_die_callback;
 
 // Signal handler to wake up suspended threads when the tracer thread dies.
-static void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
-  if (thread_suspender_instance != NULL) {
+static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
+  SignalContext ctx = SignalContext::Create(siginfo, uctx);
+  VPrintf(1, "Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n",
+      signum, ctx.addr, ctx.pc, ctx.sp);
+  ThreadSuspender *inst = thread_suspender_instance;
+  if (inst != NULL) {
     if (signum == SIGABRT)
-      thread_suspender_instance->KillAllThreads();
+      inst->KillAllThreads();
     else
-      thread_suspender_instance->ResumeAllThreads();
+      inst->ResumeAllThreads();
+    SetDieCallback(old_die_callback);
+    old_die_callback = NULL;
+    thread_suspender_instance = NULL;
+    atomic_store(&inst->arg->done, 1, memory_order_relaxed);
   }
   internal__exit((signum == SIGABRT) ? 1 : 2);
 }
@@ -218,10 +232,15 @@
   // point. So we correctly handle calls to Die() from within the callback, but
   // not those that happen before or after the callback. Hopefully there aren't
   // a lot of opportunities for that to happen...
-  if (thread_suspender_instance)
-    thread_suspender_instance->KillAllThreads();
+  ThreadSuspender *inst = thread_suspender_instance;
+  if (inst != NULL && stoptheworld_tracer_pid == internal_getpid()) {
+    inst->KillAllThreads();
+    thread_suspender_instance = NULL;
+  }
   if (old_die_callback)
     old_die_callback();
+  SetDieCallback(old_die_callback);
+  old_die_callback = NULL;
 }
 
 // Size of alternative stack for signal handlers in the tracer thread.
@@ -244,7 +263,7 @@
   old_die_callback = GetDieCallback();
   SetDieCallback(TracerThreadDieCallback);
 
-  ThreadSuspender thread_suspender(internal_getppid());
+  ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument);
   // Global pointer for the signal handler.
   thread_suspender_instance = &thread_suspender;
 
@@ -276,11 +295,9 @@
     thread_suspender.ResumeAllThreads();
     exit_code = 0;
   }
-  // Note, this is a bad race. If TracerThreadDieCallback is already started
-  // in another thread and observed that thread_suspender_instance != 0,
-  // it can call KillAllThreads on the destroyed variable.
   SetDieCallback(old_die_callback);
   thread_suspender_instance = NULL;
+  atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed);
   return exit_code;
 }
 
@@ -354,6 +371,7 @@
   tracer_thread_argument.callback = callback;
   tracer_thread_argument.callback_argument = argument;
   tracer_thread_argument.parent_pid = internal_getpid();
+  atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed);
   const uptr kTracerStackSize = 2 * 1024 * 1024;
   ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
   // Block the execution of TracerThread until after we have set ptrace
@@ -402,14 +420,27 @@
 #endif
     // Allow the tracer thread to start.
     tracer_thread_argument.mutex.Unlock();
-    // Since errno is shared between this thread and the tracer thread, we
-    // must avoid using errno while the tracer thread is running.
-    // At this point, any signal will either be blocked or kill us, so waitpid
-    // should never return (and set errno) while the tracer thread is alive.
-    uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
-    if (internal_iserror(waitpid_status, &local_errno))
+    // NOTE: errno is shared between this thread and the tracer thread.
+    // internal_waitpid() may call syscall() which can access/spoil errno,
+    // so we can't call it now. Instead we for the tracer thread to finish using
+    // the spin loop below. Man page for sched_yield() says "In the Linux
+    // implementation, sched_yield() always succeeds", so let's hope it does not
+    // spoil errno. Note that this spin loop runs only for brief periods before
+    // the tracer thread has suspended us and when it starts unblocking threads.
+    while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0)
+      sched_yield();
+    // Now the tracer thread is about to exit and does not touch errno,
+    // wait for it.
+    for (;;) {
+      uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
+      if (!internal_iserror(waitpid_status, &local_errno))
+        break;
+      if (local_errno == EINTR)
+        continue;
       VReport(1, "Waiting on the tracer thread failed (errno %d).\n",
               local_errno);
+      break;
+    }
   }
 }
 
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
index 2b697e9..8009b4d 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -30,18 +30,50 @@
   internal_memset(has_suppression_type_, 0, suppression_types_num_);
 }
 
+static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
+                                                /*out*/char *new_file_path,
+                                                uptr new_file_path_size) {
+  InternalScopedString exec(kMaxPathLength);
+  if (ReadBinaryName(exec.data(), exec.size())) {
+    const char *file_name_pos = StripModuleName(exec.data());
+    uptr path_to_exec_len = file_name_pos - exec.data();
+    internal_strncat(new_file_path, exec.data(),
+                     Min(path_to_exec_len, new_file_path_size - 1));
+    internal_strncat(new_file_path, file_path,
+                     new_file_path_size - internal_strlen(new_file_path) - 1);
+    return true;
+  }
+  return false;
+}
+
 void SuppressionContext::ParseFromFile(const char *filename) {
   if (filename[0] == '\0')
     return;
+
+  // If we cannot find the file, check if its location is relative to
+  // the location of the executable.
+  InternalScopedString new_file_path(kMaxPathLength);
+  if (!FileExists(filename) && !IsAbsolutePath(filename) &&
+      GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(),
+                                          new_file_path.size())) {
+    filename = new_file_path.data();
+  }
+
+  // Read the file.
   char *file_contents;
   uptr buffer_size;
-  uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
-                                        1 << 26 /* max_len */);
+  const uptr max_len = 1 << 26;
+  uptr contents_size =
+    ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len);
+  VPrintf(1, "%s: reading suppressions file at %s\n",
+          SanitizerToolName, filename);
+
   if (contents_size == 0) {
     Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
            filename);
     Die();
   }
+
   Parse(file_contents);
 }
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
index 135720e..df7661a 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -16,7 +16,7 @@
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_placement_new.h"
-#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_internal.h"
 
 namespace __sanitizer {
 
@@ -33,9 +33,7 @@
   function_offset = kUnknown;
 }
 
-void AddressInfo::FillAddressAndModuleInfo(uptr addr, const char *mod_name,
-                                           uptr mod_offset) {
-  address = addr;
+void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset) {
   module = internal_strdup(mod_name);
   module_offset = mod_offset;
 }
@@ -70,13 +68,6 @@
 StaticSpinMutex Symbolizer::init_mu_;
 LowLevelAllocator Symbolizer::symbolizer_allocator_;
 
-Symbolizer *Symbolizer::Disable() {
-  CHECK_EQ(0, symbolizer_);
-  // Initialize a dummy symbolizer.
-  symbolizer_ = new(symbolizer_allocator_) Symbolizer;
-  return symbolizer_;
-}
-
 void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
                           Symbolizer::EndSymbolizationHook end_hook) {
   CHECK(start_hook_ == 0 && end_hook_ == 0);
@@ -84,7 +75,8 @@
   end_hook_ = end_hook;
 }
 
-Symbolizer::Symbolizer() : start_hook_(0), end_hook_(0) {}
+Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
+    : tools_(tools), start_hook_(0), end_hook_(0) {}
 
 Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
     : sym_(sym) {
@@ -97,4 +89,76 @@
     sym_->end_hook_();
 }
 
+SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
+  BlockingMutexLock l(&mu_);
+  const char *module_name;
+  uptr module_offset;
+  SymbolizedStack *res = SymbolizedStack::New(addr);
+  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
+                                                 &module_offset))
+    return res;
+  // Always fill data about module name and offset.
+  res->info.FillModuleInfo(module_name, module_offset);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (tool->SymbolizePC(addr, res)) {
+      return res;
+    }
+  }
+  return res;
+}
+
+bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+  BlockingMutexLock l(&mu_);
+  const char *module_name;
+  uptr module_offset;
+  if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name,
+                                                 &module_offset))
+    return false;
+  info->Clear();
+  info->module = internal_strdup(module_name);
+  info->module_offset = module_offset;
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (tool->SymbolizeData(addr, info)) {
+      return true;
+    }
+  }
+  return true;
+}
+
+bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                 uptr *module_address) {
+  BlockingMutexLock l(&mu_);
+  return PlatformFindModuleNameAndOffsetForAddress(pc, module_name,
+                                                   module_address);
+}
+
+void Symbolizer::Flush() {
+  BlockingMutexLock l(&mu_);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    tool->Flush();
+  }
+}
+
+const char *Symbolizer::Demangle(const char *name) {
+  BlockingMutexLock l(&mu_);
+  for (auto iter = Iterator(&tools_); iter.hasNext();) {
+    auto *tool = iter.next();
+    SymbolizerScope sym_scope(this);
+    if (const char *demangled = tool->Demangle(name))
+      return demangled;
+  }
+  return PlatformDemangle(name);
+}
+
+void Symbolizer::PrepareForSandboxing() {
+  BlockingMutexLock l(&mu_);
+  PlatformPrepareForSandboxing();
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 3a80774..225da70 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -43,8 +43,7 @@
   AddressInfo();
   // Deletes all strings and resets all fields.
   void Clear();
-  void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
-                                uptr mod_offset);
+  void FillModuleInfo(const char *mod_name, uptr mod_offset);
 };
 
 // Linked list of symbolized frames (each frame is described by AddressInfo).
@@ -74,6 +73,8 @@
   void Clear();
 };
 
+class SymbolizerTool;
+
 class Symbolizer {
  public:
   /// Initialize and return platform-specific implementation of symbolizer
@@ -81,26 +82,22 @@
   static Symbolizer *GetOrInit();
   // Returns a list of symbolized frames for a given address (containing
   // all inlined functions, if necessary).
-  virtual SymbolizedStack *SymbolizePC(uptr address) {
-    return SymbolizedStack::New(address);
-  }
-  virtual bool SymbolizeData(uptr address, DataInfo *info) {
-    return false;
-  }
-  virtual bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
-                                           uptr *module_address) {
-    return false;
-  }
-  virtual bool CanReturnFileLineInfo() {
-    return false;
+  SymbolizedStack *SymbolizePC(uptr address);
+  bool SymbolizeData(uptr address, DataInfo *info);
+  bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                   uptr *module_address);
+  const char *GetModuleNameForPc(uptr pc) {
+    const char *module_name = 0;
+    uptr unused;
+    if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused))
+      return module_name;
+    return nullptr;
   }
   // Release internal caches (if any).
-  virtual void Flush() {}
+  void Flush();
   // Attempts to demangle the provided C++ mangled name.
-  virtual const char *Demangle(const char *name) {
-    return name;
-  }
-  virtual void PrepareForSandboxing() {}
+  const char *Demangle(const char *name);
+  void PrepareForSandboxing();
 
   // Allow user to install hooks that would be called before/after Symbolizer
   // does the actual file/line info fetching. Specific sanitizers may need this
@@ -115,14 +112,28 @@
  private:
   /// Platform-specific function for creating a Symbolizer object.
   static Symbolizer *PlatformInit();
-  /// Initialize the symbolizer in a disabled state.  Not thread safe.
-  static Symbolizer *Disable();
+
+  virtual bool PlatformFindModuleNameAndOffsetForAddress(
+      uptr address, const char **module_name, uptr *module_offset) {
+    UNIMPLEMENTED();
+  }
+  // Platform-specific default demangler, must not return nullptr.
+  virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); }
+  virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); }
 
   static Symbolizer *symbolizer_;
   static StaticSpinMutex init_mu_;
 
+  // Mutex locked from public methods of |Symbolizer|, so that the internals
+  // (including individual symbolizer tools and platform-specific methods) are
+  // always synchronized.
+  BlockingMutex mu_;
+
+  typedef IntrusiveList<SymbolizerTool>::Iterator Iterator;
+  IntrusiveList<SymbolizerTool> tools_;
+
  protected:
-  Symbolizer();
+  explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);
 
   static LowLevelAllocator symbolizer_allocator_;
 
@@ -137,61 +148,6 @@
   };
 };
 
-class ExternalSymbolizerInterface {
- public:
-  // Can't declare pure virtual functions in sanitizer runtimes:
-  // __cxa_pure_virtual might be unavailable.
-  virtual char *SendCommand(bool is_data, const char *module_name,
-                            uptr module_offset) {
-    UNIMPLEMENTED();
-  }
-};
-
-// SymbolizerProcess encapsulates communication between the tool and
-// external symbolizer program, running in a different subprocess.
-// SymbolizerProcess may not be used from two threads simultaneously.
-class SymbolizerProcess : public ExternalSymbolizerInterface {
- public:
-  explicit SymbolizerProcess(const char *path);
-  char *SendCommand(bool is_data, const char *module_name,
-                    uptr module_offset) override;
-
- private:
-  bool Restart();
-  char *SendCommandImpl(bool is_data, const char *module_name,
-                        uptr module_offset);
-  bool ReadFromSymbolizer(char *buffer, uptr max_length);
-  bool WriteToSymbolizer(const char *buffer, uptr length);
-  bool StartSymbolizerSubprocess();
-
-  virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
-                                  const char *module_name,
-                                  uptr module_offset) const {
-    UNIMPLEMENTED();
-  }
-
-  virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
-    UNIMPLEMENTED();
-  }
-
-  virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
-    UNIMPLEMENTED();
-  }
-
-  const char *path_;
-  int input_fd_;
-  int output_fd_;
-
-  static const uptr kBufferSize = 16 * 1024;
-  char buffer_[kBufferSize];
-
-  static const uptr kMaxTimesRestarted = 5;
-  static const int kSymbolizerStartupTimeMillis = 10;
-  uptr times_restarted_;
-  bool failed_to_start_;
-  bool reported_invalid_path_;
-};
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_SYMBOLIZER_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h
new file mode 100644
index 0000000..66ae809
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -0,0 +1,109 @@
+//===-- sanitizer_symbolizer_internal.h -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Header for internal classes and functions to be used by implementations of
+// symbolizers.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_INTERNAL_H
+#define SANITIZER_SYMBOLIZER_INTERNAL_H
+
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// Parsing helpers, 'str' is searched for delimiter(s) and a string or uptr
+// is extracted. When extracting a string, a newly allocated (using
+// InternalAlloc) and null-terminataed buffer is returned. They return a pointer
+// to the next characted after the found delimiter.
+const char *ExtractToken(const char *str, const char *delims, char **result);
+const char *ExtractInt(const char *str, const char *delims, int *result);
+const char *ExtractUptr(const char *str, const char *delims, uptr *result);
+const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
+                                      char **result);
+
+const char *DemangleCXXABI(const char *name);
+
+// SymbolizerTool is an interface that is implemented by individual "tools"
+// that can perform symbolication (external llvm-symbolizer, libbacktrace,
+// Windows DbgHelp symbolizer, etc.).
+class SymbolizerTool {
+ public:
+  // The main |Symbolizer| class implements a "fallback chain" of symbolizer
+  // tools. In a request to symbolize an address, if one tool returns false,
+  // the next tool in the chain will be tried.
+  SymbolizerTool *next;
+
+  SymbolizerTool() : next(nullptr) { }
+
+  // Can't declare pure virtual functions in sanitizer runtimes:
+  // __cxa_pure_virtual might be unavailable.
+
+  // The |stack| parameter is inout. It is pre-filled with the address,
+  // module base and module offset values and is to be used to construct
+  // other stack frames.
+  virtual bool SymbolizePC(uptr addr, SymbolizedStack *stack) {
+    UNIMPLEMENTED();
+  }
+
+  // The |info| parameter is inout. It is pre-filled with the module base
+  // and module offset values.
+  virtual bool SymbolizeData(uptr addr, DataInfo *info) {
+    UNIMPLEMENTED();
+  }
+
+  virtual void Flush() {}
+
+  // Return nullptr to fallback to the default platform-specific demangler.
+  virtual const char *Demangle(const char *name) {
+    return nullptr;
+  }
+};
+
+// SymbolizerProcess encapsulates communication between the tool and
+// external symbolizer program, running in a different subprocess.
+// SymbolizerProcess may not be used from two threads simultaneously.
+class SymbolizerProcess {
+ public:
+  explicit SymbolizerProcess(const char *path, bool use_forkpty = false);
+  const char *SendCommand(const char *command);
+
+ private:
+  bool Restart();
+  const char *SendCommandImpl(const char *command);
+  bool ReadFromSymbolizer(char *buffer, uptr max_length);
+  bool WriteToSymbolizer(const char *buffer, uptr length);
+  bool StartSymbolizerSubprocess();
+
+  virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+    UNIMPLEMENTED();
+  }
+
+  virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+    UNIMPLEMENTED();
+  }
+
+  const char *path_;
+  int input_fd_;
+  int output_fd_;
+
+  static const uptr kBufferSize = 16 * 1024;
+  char buffer_[kBufferSize];
+
+  static const uptr kMaxTimesRestarted = 5;
+  static const int kSymbolizerStartupTimeMillis = 10;
+  uptr times_restarted_;
+  bool failed_to_start_;
+  bool reported_invalid_path_;
+  bool use_forkpty_;
+};
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SYMBOLIZER_INTERNAL_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
index 9317a78..5735466 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -33,6 +33,8 @@
 
 namespace __sanitizer {
 
+static char *DemangleAlloc(const char *name, bool always_alloc);
+
 #if SANITIZER_LIBBACKTRACE
 
 namespace {
@@ -86,17 +88,20 @@
 struct SymbolizeCodeCallbackArg {
   SymbolizedStack *first;
   SymbolizedStack *last;
-  const char *module_name;
-  uptr module_offset;
+  uptr frames_symbolized;
 
-  void append(SymbolizedStack *f) {
-    if (last != nullptr) {
-      last->next = f;
-      last = f;
-    } else {
-      first = f;
-      last = f;
+  AddressInfo *get_new_frame(uintptr_t addr) {
+    CHECK(last);
+    if (frames_symbolized > 0) {
+      SymbolizedStack *cur = SymbolizedStack::New(addr);
+      AddressInfo *info = &cur->info;
+      info->FillModuleInfo(first->info.module, first->info.module_offset);
+      last->next = cur;
+      last = cur;
     }
+    CHECK_EQ(addr, first->info.address);
+    CHECK_EQ(addr, last->info.address);
+    return &last->info;
   }
 };
 
@@ -106,15 +111,12 @@
                                        const char *function) {
   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
   if (function) {
-    SymbolizedStack *cur = SymbolizedStack::New(addr);
-    cdata->append(cur);
-    AddressInfo *info = &cur->info;
-    info->FillAddressAndModuleInfo(addr, cdata->module_name,
-                                   cdata->module_offset);
-    info->function = LibbacktraceSymbolizer::Demangle(function, true);
+    AddressInfo *info = cdata->get_new_frame(addr);
+    info->function = DemangleAlloc(function, /*always_alloc*/ true);
     if (filename)
       info->file = internal_strdup(filename);
     info->line = lineno;
+    cdata->frames_symbolized++;
   }
   return 0;
 }
@@ -123,12 +125,9 @@
                                   const char *symname, uintptr_t, uintptr_t) {
   SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata;
   if (symname) {
-    SymbolizedStack *cur = SymbolizedStack::New(addr);
-    cdata->append(cur);
-    AddressInfo *info = &cur->info;
-    info->FillAddressAndModuleInfo(addr, cdata->module_name,
-                                   cdata->module_offset);
-    info->function = LibbacktraceSymbolizer::Demangle(symname, true);
+    AddressInfo *info = cdata->get_new_frame(addr);
+    info->function = DemangleAlloc(symname, /*always_alloc*/ true);
+    cdata->frames_symbolized++;
   }
 }
 
@@ -136,7 +135,7 @@
                                   uintptr_t symval, uintptr_t symsize) {
   DataInfo *info = (DataInfo *)vdata;
   if (symname && symval) {
-    info->name = LibbacktraceSymbolizer::Demangle(symname, true);
+    info->name = DemangleAlloc(symname, /*always_alloc*/ true);
     info->start = symval;
     info->size = symsize;
   }
@@ -156,21 +155,18 @@
   return new(*alloc) LibbacktraceSymbolizer(state);
 }
 
-SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
-                                                       const char *module_name,
-                                                       uptr module_offset) {
+bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   SymbolizeCodeCallbackArg data;
-  data.first = nullptr;
-  data.last = nullptr;
-  data.module_name = module_name;
-  data.module_offset = module_offset;
+  data.first = stack;
+  data.last = stack;
+  data.frames_symbolized = 0;
   backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
                    ErrorCallback, &data);
-  if (data.first)
-    return data.first;
+  if (data.frames_symbolized > 0)
+    return true;
   backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
                     ErrorCallback, &data);
-  return data.first;
+  return (data.frames_symbolized > 0);
 }
 
 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
@@ -185,11 +181,9 @@
   return 0;
 }
 
-SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr,
-                                                       const char *module_name,
-                                                       uptr module_offset) {
+bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   (void)state_;
-  return nullptr;
+  return false;
 }
 
 bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
@@ -198,7 +192,7 @@
 
 #endif  // SANITIZER_LIBBACKTRACE
 
-char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) {
+static char *DemangleAlloc(const char *name, bool always_alloc) {
 #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
   if (char *demangled = CplusV3Demangle(name))
     return demangled;
@@ -208,4 +202,8 @@
   return 0;
 }
 
+const char *LibbacktraceSymbolizer::Demangle(const char *name) {
+  return DemangleAlloc(name, /*always_alloc*/ false);
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
index 1ff0050..00b465a 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -16,7 +16,7 @@
 
 #include "sanitizer_platform.h"
 #include "sanitizer_common.h"
-#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_internal.h"
 
 #ifndef SANITIZER_LIBBACKTRACE
 # define SANITIZER_LIBBACKTRACE 0
@@ -28,17 +28,16 @@
 
 namespace __sanitizer {
 
-class LibbacktraceSymbolizer {
+class LibbacktraceSymbolizer : public SymbolizerTool {
  public:
   static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
 
-  SymbolizedStack *SymbolizeCode(uptr addr, const char *module_name,
-                                 uptr module_offset);
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
 
-  bool SymbolizeData(uptr addr, DataInfo *info);
+  bool SymbolizeData(uptr addr, DataInfo *info) override;
 
   // May return NULL if demangling failed.
-  static char *Demangle(const char *name, bool always_alloc = false);
+  const char *Demangle(const char *name) override;
 
  private:
   explicit LibbacktraceSymbolizer(void *state) : state_(state) {}
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index 63c9356..f1e2289 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -11,18 +11,62 @@
 // run-time libraries.
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_allocator_internal.h"
 #include "sanitizer_internal_defs.h"
-#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_internal.h"
 
 namespace __sanitizer {
 
+const char *ExtractToken(const char *str, const char *delims, char **result) {
+  uptr prefix_len = internal_strcspn(str, delims);
+  *result = (char*)InternalAlloc(prefix_len + 1);
+  internal_memcpy(*result, str, prefix_len);
+  (*result)[prefix_len] = '\0';
+  const char *prefix_end = str + prefix_len;
+  if (*prefix_end != '\0') prefix_end++;
+  return prefix_end;
+}
+
+const char *ExtractInt(const char *str, const char *delims, int *result) {
+  char *buff;
+  const char *ret = ExtractToken(str, delims, &buff);
+  if (buff != 0) {
+    *result = (int)internal_atoll(buff);
+  }
+  InternalFree(buff);
+  return ret;
+}
+
+const char *ExtractUptr(const char *str, const char *delims, uptr *result) {
+  char *buff;
+  const char *ret = ExtractToken(str, delims, &buff);
+  if (buff != 0) {
+    *result = (uptr)internal_atoll(buff);
+  }
+  InternalFree(buff);
+  return ret;
+}
+
+const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
+                                      char **result) {
+  const char *found_delimiter = internal_strstr(str, delimiter);
+  uptr prefix_len =
+      found_delimiter ? found_delimiter - str : internal_strlen(str);
+  *result = (char *)InternalAlloc(prefix_len + 1);
+  internal_memcpy(*result, str, prefix_len);
+  (*result)[prefix_len] = '\0';
+  const char *prefix_end = str + prefix_len;
+  if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter);
+  return prefix_end;
+}
+
 Symbolizer *Symbolizer::GetOrInit() {
   SpinMutexLock l(&init_mu_);
   if (symbolizer_)
     return symbolizer_;
-  if ((symbolizer_ = PlatformInit()))
-    return symbolizer_;
-  return Disable();
+  symbolizer_ = PlatformInit();
+  CHECK(symbolizer_);
+  return symbolizer_;
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
new file mode 100644
index 0000000..c2397ef
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc
@@ -0,0 +1,151 @@
+//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries.
+//
+// Implementation of Mac-specific "atos" symbolizer.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_mac.h"
+#include "sanitizer_symbolizer_mac.h"
+
+namespace __sanitizer {
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <util.h>
+
+bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
+  Dl_info info;
+  int result = dladdr((const void *)addr, &info);
+  if (!result) return false;
+  const char *demangled = DemangleCXXABI(info.dli_sname);
+  stack->info.function = internal_strdup(demangled);
+  return true;
+}
+
+bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+  return false;
+}
+
+class AtosSymbolizerProcess : public SymbolizerProcess {
+ public:
+  explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid)
+      : SymbolizerProcess(path, /*use_forkpty*/ true),
+        parent_pid_(parent_pid) {}
+
+ private:
+  bool ReachedEndOfOutput(const char *buffer, uptr length) const override {
+    return (length >= 1 && buffer[length - 1] == '\n');
+  }
+
+  void ExecuteWithDefaultArgs(const char *path_to_binary) const override {
+    // The `atos` binary has some issues with DYLD_ROOT_PATH on i386.
+    unsetenv("DYLD_ROOT_PATH");
+
+    char pid_str[16];
+    internal_snprintf(pid_str, sizeof(pid_str), "%d", parent_pid_);
+    if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) {
+      // 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.
+      execl(path_to_binary, path_to_binary, "-p", pid_str, "-d", (char *)0);
+    } else {
+      execl(path_to_binary, path_to_binary, "-p", pid_str, (char *)0);
+    }
+  }
+
+  pid_t parent_pid_;
+};
+
+static const char *kAtosErrorMessages[] = {
+  "atos cannot examine process",
+  "unable to get permission to examine process",
+  "An admin user name and password is required",
+  "could not load inserted library",
+  "architecture mismatch between analysis process",
+};
+
+static bool IsAtosErrorMessage(const char *str) {
+  for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
+    if (internal_strstr(str, kAtosErrorMessages[i])) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool ParseCommandOutput(const char *str, SymbolizedStack *res) {
+  // Trim ending newlines.
+  char *trim;
+  ExtractTokenUpToDelimiter(str, "\n", &trim);
+
+  // The line from `atos` is in one of these formats:
+  //   myfunction (in library.dylib) (sourcefile.c:17)
+  //   myfunction (in library.dylib) + 0x1fe
+  //   0xdeadbeef (in library.dylib) + 0x1fe
+  //   0xdeadbeef (in library.dylib)
+  //   0xdeadbeef
+
+  if (IsAtosErrorMessage(trim)) {
+    Report("atos returned an error: %s\n", trim);
+    InternalFree(trim);
+    return false;
+  }
+
+  const char *rest = trim;
+  char *function_name;
+  rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name);
+  if (internal_strncmp(function_name, "0x", 2) != 0)
+    res->info.function = function_name;
+  else
+    InternalFree(function_name);
+  rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module);
+
+  if (rest[0] == '(') {
+    rest++;
+    rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file);
+    char *extracted_line_number;
+    rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number);
+    res->info.line = internal_atoll(extracted_line_number);
+    InternalFree(extracted_line_number);
+  }
+
+  InternalFree(trim);
+  return true;
+}
+
+AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
+    : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {}
+
+bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
+  if (!process_) return false;
+  char command[32];
+  internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
+  const char *buf = process_->SendCommand(command);
+  if (!buf) return false;
+  if (!ParseCommandOutput(buf, stack)) {
+    process_ = nullptr;
+    return false;
+  }
+  return true;
+}
+
+bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; }
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/lib/sanitizer_common/sanitizer_symbolizer_mac.h
new file mode 100644
index 0000000..068644d
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.h
@@ -0,0 +1,48 @@
+//===-- sanitizer_symbolizer_mac.h ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries.
+//
+// Header for Mac-specific "atos" symbolizer.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_SYMBOLIZER_MAC_H
+#define SANITIZER_SYMBOLIZER_MAC_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "sanitizer_symbolizer_internal.h"
+
+namespace __sanitizer {
+
+class DlAddrSymbolizer : public SymbolizerTool {
+ public:
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+  bool SymbolizeData(uptr addr, DataInfo *info) override;
+};
+
+class AtosSymbolizerProcess;
+
+class AtosSymbolizer : public SymbolizerTool {
+ public:
+  explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator);
+
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+  bool SymbolizeData(uptr addr, DataInfo *info) override;
+
+ private:
+  AtosSymbolizerProcess *process_;
+};
+
+} // namespace __sanitizer
+
+#endif  // SANITIZER_MAC
+
+#endif // SANITIZER_SYMBOLIZER_MAC_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index deb3429..189b0ab 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -21,12 +21,10 @@
 #include "sanitizer_linux.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_internal.h"
 #include "sanitizer_symbolizer_libbacktrace.h"
+#include "sanitizer_symbolizer_mac.h"
 
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/wait.h>
 #include <unistd.h>
 
 // C++ demangling function, as required by Itanium C++ ABI. This is weak,
@@ -41,7 +39,7 @@
 namespace __sanitizer {
 
 // Attempts to demangle the name via __cxa_demangle from __cxxabiv1.
-static const char *DemangleCXXABI(const char *name) {
+const char *DemangleCXXABI(const char *name) {
   // FIXME: __cxa_demangle aggressively insists on allocating memory.
   // There's not much we can do about that, short of providing our
   // own demangler (libc++abi's implementation could be adapted so that
@@ -55,217 +53,6 @@
   return name;
 }
 
-// Extracts the prefix of "str" that consists of any characters not
-// present in "delims" string, and copies this prefix to "result", allocating
-// space for it.
-// Returns a pointer to "str" after skipping extracted prefix and first
-// delimiter char.
-static const char *ExtractToken(const char *str, const char *delims,
-                                char **result) {
-  uptr prefix_len = internal_strcspn(str, delims);
-  *result = (char*)InternalAlloc(prefix_len + 1);
-  internal_memcpy(*result, str, prefix_len);
-  (*result)[prefix_len] = '\0';
-  const char *prefix_end = str + prefix_len;
-  if (*prefix_end != '\0') prefix_end++;
-  return prefix_end;
-}
-
-// Same as ExtractToken, but converts extracted token to integer.
-static const char *ExtractInt(const char *str, const char *delims,
-                              int *result) {
-  char *buff;
-  const char *ret = ExtractToken(str, delims, &buff);
-  if (buff != 0) {
-    *result = (int)internal_atoll(buff);
-  }
-  InternalFree(buff);
-  return ret;
-}
-
-static const char *ExtractUptr(const char *str, const char *delims,
-                               uptr *result) {
-  char *buff;
-  const char *ret = ExtractToken(str, delims, &buff);
-  if (buff != 0) {
-    *result = (uptr)internal_atoll(buff);
-  }
-  InternalFree(buff);
-  return ret;
-}
-
-SymbolizerProcess::SymbolizerProcess(const char *path)
-    : path_(path),
-      input_fd_(kInvalidFd),
-      output_fd_(kInvalidFd),
-      times_restarted_(0),
-      failed_to_start_(false),
-      reported_invalid_path_(false) {
-  CHECK(path_);
-  CHECK_NE(path_[0], '\0');
-}
-
-char *SymbolizerProcess::SendCommand(bool is_data, const char *module_name,
-                                     uptr module_offset) {
-  for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
-    // Start or restart symbolizer if we failed to send command to it.
-    if (char *res = SendCommandImpl(is_data, module_name, module_offset))
-      return res;
-    Restart();
-  }
-  if (!failed_to_start_) {
-    Report("WARNING: Failed to use and restart external symbolizer!\n");
-    failed_to_start_ = true;
-  }
-  return 0;
-}
-
-bool SymbolizerProcess::Restart() {
-  if (input_fd_ != kInvalidFd)
-    internal_close(input_fd_);
-  if (output_fd_ != kInvalidFd)
-    internal_close(output_fd_);
-  return StartSymbolizerSubprocess();
-}
-
-char *SymbolizerProcess::SendCommandImpl(bool is_data, const char *module_name,
-                                         uptr module_offset) {
-  if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
-      return 0;
-  CHECK(module_name);
-  if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name,
-                          module_offset))
-      return 0;
-  if (!WriteToSymbolizer(buffer_, internal_strlen(buffer_)))
-      return 0;
-  if (!ReadFromSymbolizer(buffer_, kBufferSize))
-      return 0;
-  return buffer_;
-}
-
-bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
-  if (max_length == 0)
-    return true;
-  uptr read_len = 0;
-  while (true) {
-    uptr just_read = internal_read(input_fd_, buffer + read_len,
-                                   max_length - read_len - 1);
-    // We can't read 0 bytes, as we don't expect external symbolizer to close
-    // its stdout.
-    if (just_read == 0 || just_read == (uptr)-1) {
-      Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
-      return false;
-    }
-    read_len += just_read;
-    if (ReachedEndOfOutput(buffer, read_len))
-      break;
-  }
-  buffer[read_len] = '\0';
-  return true;
-}
-
-bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
-  if (length == 0)
-    return true;
-  uptr write_len = internal_write(output_fd_, buffer, length);
-  if (write_len == 0 || write_len == (uptr)-1) {
-    Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
-    return false;
-  }
-  return true;
-}
-
-bool SymbolizerProcess::StartSymbolizerSubprocess() {
-  if (!FileExists(path_)) {
-    if (!reported_invalid_path_) {
-      Report("WARNING: invalid path to external symbolizer!\n");
-      reported_invalid_path_ = true;
-    }
-    return false;
-  }
-
-  int *infd = NULL;
-  int *outfd = NULL;
-  // The client program may close its stdin and/or stdout and/or stderr
-  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
-  // In this case the communication between the forked processes may be
-  // broken if either the parent or the child tries to close or duplicate
-  // these descriptors. The loop below produces two pairs of file
-  // descriptors, each greater than 2 (stderr).
-  int sock_pair[5][2];
-  for (int i = 0; i < 5; i++) {
-    if (pipe(sock_pair[i]) == -1) {
-      for (int j = 0; j < i; j++) {
-        internal_close(sock_pair[j][0]);
-        internal_close(sock_pair[j][1]);
-      }
-      Report("WARNING: Can't create a socket pair to start "
-             "external symbolizer (errno: %d)\n", errno);
-      return false;
-    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
-      if (infd == NULL) {
-        infd = sock_pair[i];
-      } else {
-        outfd = sock_pair[i];
-        for (int j = 0; j < i; j++) {
-          if (sock_pair[j] == infd) continue;
-          internal_close(sock_pair[j][0]);
-          internal_close(sock_pair[j][1]);
-        }
-        break;
-      }
-    }
-  }
-  CHECK(infd);
-  CHECK(outfd);
-
-  // Real fork() may call user callbacks registered with pthread_atfork().
-  int pid = internal_fork();
-  if (pid == -1) {
-    // Fork() failed.
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    Report("WARNING: failed to fork external symbolizer "
-           " (errno: %d)\n", errno);
-    return false;
-  } else if (pid == 0) {
-    // Child subprocess.
-    internal_close(STDOUT_FILENO);
-    internal_close(STDIN_FILENO);
-    internal_dup2(outfd[0], STDIN_FILENO);
-    internal_dup2(infd[1], STDOUT_FILENO);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
-      internal_close(fd);
-    ExecuteWithDefaultArgs(path_);
-    internal__exit(1);
-  }
-
-  // Continue execution in parent process.
-  internal_close(outfd[0]);
-  internal_close(infd[1]);
-  input_fd_ = infd[0];
-  output_fd_ = outfd[1];
-
-  // Check that symbolizer subprocess started successfully.
-  int pid_status;
-  SleepForMillis(kSymbolizerStartupTimeMillis);
-  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
-  if (exited_pid != 0) {
-    // Either waitpid failed, or child has already exited.
-    Report("WARNING: external symbolizer didn't start up correctly!\n");
-    return false;
-  }
-
-  return true;
-}
-
-
 // Parses one or more two-line strings in the following format:
 //   <function_name>
 //   <file_name>:<line_number>[:<column_number>]
@@ -288,8 +75,7 @@
       top_frame = false;
     } else {
       cur = SymbolizedStack::New(res->info.address);
-      cur->info.FillAddressAndModuleInfo(res->info.address, res->info.module,
-                                         res->info.module_offset);
+      cur->info.FillModuleInfo(res->info.module, res->info.module_offset);
       last->next = cur;
       last = cur;
     }
@@ -343,13 +129,6 @@
   explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
 
  private:
-  bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
-                          const char *module_name, uptr module_offset) const {
-    internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n",
-                      is_data ? "DATA " : "", module_name, module_offset);
-    return true;
-  }
-
   bool ReachedEndOfOutput(const char *buffer, uptr length) const {
     // Empty line marks the end of llvm-symbolizer output.
     return length >= 2 && buffer[length - 1] == '\n' &&
@@ -377,6 +156,44 @@
   }
 };
 
+class LLVMSymbolizer : public SymbolizerTool {
+ public:
+  explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator)
+      : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {}
+
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
+    if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module,
+                                      stack->info.module_offset)) {
+      ParseSymbolizePCOutput(buf, stack);
+      return true;
+    }
+    return false;
+  }
+
+  bool SymbolizeData(uptr addr, DataInfo *info) override {
+    if (const char *buf =
+            SendCommand(/*is_data*/ true, info->module, info->module_offset)) {
+      ParseSymbolizeDataOutput(buf, info);
+      info->start += (addr - info->module_offset);  // Add the base address.
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  const char *SendCommand(bool is_data, const char *module_name,
+                          uptr module_offset) {
+    CHECK(module_name);
+    internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
+                      is_data ? "DATA " : "", module_name, module_offset);
+    return symbolizer_process_->SendCommand(buffer_);
+  }
+
+  LLVMSymbolizerProcess *symbolizer_process_;
+  static const uptr kBufferSize = 16 * 1024;
+  char buffer_[kBufferSize];
+};
+
 class Addr2LineProcess : public SymbolizerProcess {
  public:
   Addr2LineProcess(const char *path, const char *module_name)
@@ -385,15 +202,6 @@
   const char *module_name() const { return module_name_; }
 
  private:
-  bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
-                          const char *module_name, uptr module_offset) const {
-    if (is_data)
-      return false;
-    CHECK_EQ(0, internal_strcmp(module_name, module_name_));
-    internal_snprintf(buffer, max_length, "0x%zx\n", module_offset);
-    return true;
-  }
-
   bool ReachedEndOfOutput(const char *buffer, uptr length) const {
     // Output should consist of two lines.
     int num_lines = 0;
@@ -413,16 +221,28 @@
   const char *module_name_;  // Owned, leaked.
 };
 
-class Addr2LinePool : public ExternalSymbolizerInterface {
+class Addr2LinePool : public SymbolizerTool {
  public:
   explicit Addr2LinePool(const char *addr2line_path,
                          LowLevelAllocator *allocator)
       : addr2line_path_(addr2line_path), allocator_(allocator),
         addr2line_pool_(16) {}
 
-  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
-    if (is_data)
-      return 0;
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
+    if (const char *buf =
+            SendCommand(stack->info.module, stack->info.module_offset)) {
+      ParseSymbolizePCOutput(buf, stack);
+      return true;
+    }
+    return false;
+  }
+
+  bool SymbolizeData(uptr addr, DataInfo *info) override {
+    return false;
+  }
+
+ private:
+  const char *SendCommand(const char *module_name, uptr module_offset) {
     Addr2LineProcess *addr2line = 0;
     for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
       if (0 ==
@@ -436,10 +256,13 @@
           new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
       addr2line_pool_.push_back(addr2line);
     }
-    return addr2line->SendCommand(is_data, module_name, module_offset);
+    CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name()));
+    char buffer_[kBufferSize];
+    internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset);
+    return addr2line->SendCommand(buffer_);
   }
 
- private:
+  static const uptr kBufferSize = 32;
   const char *addr2line_path_;
   LowLevelAllocator *allocator_;
   InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
@@ -460,10 +283,8 @@
                                    int MaxLength);
 }  // extern "C"
 
-class InternalSymbolizer {
+class InternalSymbolizer : public SymbolizerTool {
  public:
-  typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
-
   static InternalSymbolizer *get(LowLevelAllocator *alloc) {
     if (__sanitizer_symbolize_code != 0 &&
         __sanitizer_symbolize_data != 0) {
@@ -472,20 +293,29 @@
     return 0;
   }
 
-  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
-    SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
-                                                : __sanitizer_symbolize_code;
-    if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
-      return buffer_;
-    return 0;
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
+    bool result = __sanitizer_symbolize_code(
+        stack->info.module, stack->info.module_offset, buffer_, kBufferSize);
+    if (result) ParseSymbolizePCOutput(buffer_, stack);
+    return result;
   }
 
-  void Flush() {
+  bool SymbolizeData(uptr addr, DataInfo *info) override {
+    bool result = __sanitizer_symbolize_data(info->module, info->module_offset,
+                                             buffer_, kBufferSize);
+    if (result) {
+      ParseSymbolizeDataOutput(buffer_, info);
+      info->start += (addr - info->module_offset);  // Add the base address.
+    }
+    return result;
+  }
+
+  void Flush() override {
     if (__sanitizer_symbolize_flush)
       __sanitizer_symbolize_flush();
   }
 
-  const char *Demangle(const char *name) {
+  const char *Demangle(const char *name) override {
     if (__sanitizer_symbolize_demangle) {
       for (uptr res_length = 1024;
            res_length <= InternalSizeClassMap::kMaxSize;) {
@@ -512,146 +342,35 @@
 };
 #else  // SANITIZER_SUPPORTS_WEAK_HOOKS
 
-class InternalSymbolizer {
+class InternalSymbolizer : public SymbolizerTool {
  public:
   static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
-  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
-    return 0;
-  }
-  void Flush() { }
-  const char *Demangle(const char *name) { return name; }
 };
 
 #endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
 
 class POSIXSymbolizer : public Symbolizer {
  public:
-  POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer,
-                  InternalSymbolizer *internal_symbolizer,
-                  LibbacktraceSymbolizer *libbacktrace_symbolizer)
-      : Symbolizer(),
-        external_symbolizer_(external_symbolizer),
-        internal_symbolizer_(internal_symbolizer),
-        libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
+  explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> tools)
+      : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {}
 
-  SymbolizedStack *SymbolizePC(uptr addr) override {
-    BlockingMutexLock l(&mu_);
-    const char *module_name;
-    uptr module_offset;
-    if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
-      return SymbolizedStack::New(addr);
-    // First, try to use libbacktrace symbolizer (if it's available).
-    if (libbacktrace_symbolizer_ != 0) {
-      mu_.CheckLocked();
-      if (SymbolizedStack *res = libbacktrace_symbolizer_->SymbolizeCode(
-              addr, module_name, module_offset))
-        return res;
-    }
-    // Always fill data about module name and offset.
-    SymbolizedStack *res = SymbolizedStack::New(addr);
-    res->info.FillAddressAndModuleInfo(addr, module_name, module_offset);
-
-    const char *str = SendCommand(false, module_name, module_offset);
-    if (str == 0) {
-      // Symbolizer was not initialized or failed.
-      return res;
-    }
-
-    ParseSymbolizePCOutput(str, res);
-    return res;
-  }
-
-  bool SymbolizeData(uptr addr, DataInfo *info) override {
-    BlockingMutexLock l(&mu_);
-    LoadedModule *module = FindModuleForAddress(addr);
-    if (module == 0)
-      return false;
-    const char *module_name = module->full_name();
-    uptr module_offset = addr - module->base_address();
-    info->Clear();
-    info->module = internal_strdup(module_name);
-    info->module_offset = module_offset;
-    // First, try to use libbacktrace symbolizer (if it's available).
-    if (libbacktrace_symbolizer_ != 0) {
-      mu_.CheckLocked();
-      if (libbacktrace_symbolizer_->SymbolizeData(addr, info))
-        return true;
-    }
-    const char *str = SendCommand(true, module_name, module_offset);
-    if (str == 0)
-      return true;
-    ParseSymbolizeDataOutput(str, info);
-    info->start += module->base_address();
-    return true;
-  }
-
-  bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
-                                   uptr *module_address) override {
-    BlockingMutexLock l(&mu_);
-    return FindModuleNameAndOffsetForAddress(pc, module_name, module_address);
-  }
-
-  bool CanReturnFileLineInfo() override {
-    return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
-           libbacktrace_symbolizer_ != 0;
-  }
-
-  void Flush() override {
-    BlockingMutexLock l(&mu_);
-    if (internal_symbolizer_ != 0) {
-      SymbolizerScope sym_scope(this);
-      internal_symbolizer_->Flush();
-    }
-  }
-
-  const char *Demangle(const char *name) override {
-    BlockingMutexLock l(&mu_);
-    // Run hooks even if we don't use internal symbolizer, as cxxabi
-    // demangle may call system functions.
-    SymbolizerScope sym_scope(this);
-    // Try to use libbacktrace demangler (if available).
-    if (libbacktrace_symbolizer_ != 0) {
-      if (const char *demangled = libbacktrace_symbolizer_->Demangle(name))
-        return demangled;
-    }
-    if (internal_symbolizer_ != 0)
-      return internal_symbolizer_->Demangle(name);
+ private:
+  const char *PlatformDemangle(const char *name) override {
     return DemangleCXXABI(name);
   }
 
-  void PrepareForSandboxing() override {
+  void PlatformPrepareForSandboxing() override {
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-    BlockingMutexLock l(&mu_);
     // Cache /proc/self/exe on Linux.
     CacheBinaryName();
 #endif
   }
 
- private:
-  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
-    mu_.CheckLocked();
-    // First, try to use internal symbolizer.
-    if (internal_symbolizer_) {
-      SymbolizerScope sym_scope(this);
-      return internal_symbolizer_->SendCommand(is_data, module_name,
-                                               module_offset);
-    }
-    // Otherwise, fall back to external symbolizer.
-    if (external_symbolizer_) {
-      SymbolizerScope sym_scope(this);
-      return external_symbolizer_->SendCommand(is_data, module_name,
-                                               module_offset);
-    }
-    return 0;
-  }
-
   LoadedModule *FindModuleForAddress(uptr address) {
-    mu_.CheckLocked();
     bool modules_were_reloaded = false;
-    if (modules_ == 0 || !modules_fresh_) {
-      modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate(
-          kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
-      CHECK(modules_);
+    if (!modules_fresh_) {
+      for (uptr i = 0; i < n_modules_; i++)
+        modules_[i].clear();
       n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
                                     /* filter */ 0);
       CHECK_GT(n_modules_, 0);
@@ -675,9 +394,9 @@
     return 0;
   }
 
-  bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
-                                         uptr *module_offset) {
-    mu_.CheckLocked();
+  bool PlatformFindModuleNameAndOffsetForAddress(uptr address,
+                                                 const char **module_name,
+                                                 uptr *module_offset) override {
     LoadedModule *module = FindModuleForAddress(address);
     if (module == 0)
       return false;
@@ -688,53 +407,94 @@
 
   // 16K loaded modules should be enough for everyone.
   static const uptr kMaxNumberOfModuleContexts = 1 << 14;
-  LoadedModule *modules_;  // Array of module descriptions is leaked.
+  LoadedModule modules_[kMaxNumberOfModuleContexts];
   uptr n_modules_;
   // If stale, need to reload the modules before looking up addresses.
   bool modules_fresh_;
-  BlockingMutex mu_;
-
-  ExternalSymbolizerInterface *external_symbolizer_;  // Leaked.
-  InternalSymbolizer *const internal_symbolizer_;     // Leaked.
-  LibbacktraceSymbolizer *libbacktrace_symbolizer_;   // Leaked.
 };
 
-Symbolizer *Symbolizer::PlatformInit() {
-  if (!common_flags()->symbolize) {
-    return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
+static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
+  const char *path = common_flags()->external_symbolizer_path;
+  const char *binary_name = path ? StripModuleName(path) : "";
+  if (path && path[0] == '\0') {
+    VReport(2, "External symbolizer is explicitly disabled.\n");
+    return nullptr;
+  } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
+    VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
+    return new(*allocator) LLVMSymbolizer(path, allocator);
+  } else if (!internal_strcmp(binary_name, "atos")) {
+#if SANITIZER_MAC
+    VReport(2, "Using atos at user-specified path: %s\n", path);
+    return new(*allocator) AtosSymbolizer(path, allocator);
+#else  // SANITIZER_MAC
+    Report("ERROR: Using `atos` is only supported on Darwin.\n");
+    Die();
+#endif  // SANITIZER_MAC
+  } else if (!internal_strcmp(binary_name, "addr2line")) {
+    VReport(2, "Using addr2line at user-specified path: %s\n", path);
+    return new(*allocator) Addr2LinePool(path, allocator);
+  } else if (path) {
+    Report("ERROR: External symbolizer path is set to '%s' which isn't "
+           "a known symbolizer. Please set the path to the llvm-symbolizer "
+           "binary or other known tool.\n", path);
+    Die();
   }
-  InternalSymbolizer* internal_symbolizer =
-      InternalSymbolizer::get(&symbolizer_allocator_);
-  ExternalSymbolizerInterface *external_symbolizer = 0;
-  LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
 
-  if (!internal_symbolizer) {
-    libbacktrace_symbolizer =
-        LibbacktraceSymbolizer::get(&symbolizer_allocator_);
-    if (!libbacktrace_symbolizer) {
-      const char *path_to_external = common_flags()->external_symbolizer_path;
-      if (path_to_external && path_to_external[0] == '\0') {
-        // External symbolizer is explicitly disabled. Do nothing.
-      } else {
-        // Find path to llvm-symbolizer if it's not provided.
-        if (!path_to_external)
-          path_to_external = FindPathToBinary("llvm-symbolizer");
-        if (path_to_external) {
-          external_symbolizer = new(symbolizer_allocator_)
-              LLVMSymbolizerProcess(path_to_external);
-        } else if (common_flags()->allow_addr2line) {
-          // If llvm-symbolizer is not found, try to use addr2line.
-          if (const char *addr2line_path = FindPathToBinary("addr2line")) {
-            external_symbolizer = new(symbolizer_allocator_)
-                Addr2LinePool(addr2line_path, &symbolizer_allocator_);
-          }
-        }
-      }
+  // Otherwise symbolizer program is unknown, let's search $PATH
+  CHECK(path == nullptr);
+  if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
+    VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
+    return new(*allocator) LLVMSymbolizer(found_path, allocator);
+  }
+#if SANITIZER_MAC
+  if (const char *found_path = FindPathToBinary("atos")) {
+    VReport(2, "Using atos found at: %s\n", found_path);
+    return new(*allocator) AtosSymbolizer(found_path, allocator);
+  }
+#endif  // SANITIZER_MAC
+  if (common_flags()->allow_addr2line) {
+    if (const char *found_path = FindPathToBinary("addr2line")) {
+      VReport(2, "Using addr2line found at: %s\n", found_path);
+      return new(*allocator) Addr2LinePool(found_path, allocator);
     }
   }
+  return nullptr;
+}
 
-  return new(symbolizer_allocator_) POSIXSymbolizer(
-      external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
+static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
+                                  LowLevelAllocator *allocator) {
+  if (!common_flags()->symbolize) {
+    VReport(2, "Symbolizer is disabled.\n");
+    return;
+  }
+  if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
+    VReport(2, "Using internal symbolizer.\n");
+    list->push_back(tool);
+    return;
+  }
+  if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
+    VReport(2, "Using libbacktrace symbolizer.\n");
+    list->push_back(tool);
+    return;
+  }
+
+  if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
+    list->push_back(tool);
+  } else {
+    VReport(2, "No internal or external symbolizer found.\n");
+  }
+
+#if SANITIZER_MAC
+  VReport(2, "Using dladdr symbolizer.\n");
+  list->push_back(new(*allocator) DlAddrSymbolizer());
+#endif  // SANITIZER_MAC
+}
+
+Symbolizer *Symbolizer::PlatformInit() {
+  IntrusiveList<SymbolizerTool> list;
+  list.clear();
+  ChooseSymbolizerTools(&list, &symbolizer_allocator_);
+  return new(symbolizer_allocator_) POSIXSymbolizer(list);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
new file mode 100644
index 0000000..98d16e0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc
@@ -0,0 +1,228 @@
+//===-- sanitizer_symbolizer_process_libcdep.cc ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of SymbolizerProcess used by external symbolizers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_symbolizer_internal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if SANITIZER_MAC
+#include <util.h>  // for forkpty()
+#endif  // SANITIZER_MAC
+
+namespace __sanitizer {
+
+SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty)
+    : path_(path),
+      input_fd_(kInvalidFd),
+      output_fd_(kInvalidFd),
+      times_restarted_(0),
+      failed_to_start_(false),
+      reported_invalid_path_(false),
+      use_forkpty_(use_forkpty) {
+  CHECK(path_);
+  CHECK_NE(path_[0], '\0');
+}
+
+const char *SymbolizerProcess::SendCommand(const char *command) {
+  for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+    // Start or restart symbolizer if we failed to send command to it.
+    if (const char *res = SendCommandImpl(command))
+      return res;
+    Restart();
+  }
+  if (!failed_to_start_) {
+    Report("WARNING: Failed to use and restart external symbolizer!\n");
+    failed_to_start_ = true;
+  }
+  return 0;
+}
+
+bool SymbolizerProcess::Restart() {
+  if (input_fd_ != kInvalidFd)
+    internal_close(input_fd_);
+  if (output_fd_ != kInvalidFd)
+    internal_close(output_fd_);
+  return StartSymbolizerSubprocess();
+}
+
+const char *SymbolizerProcess::SendCommandImpl(const char *command) {
+  if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+      return 0;
+  if (!WriteToSymbolizer(command, internal_strlen(command)))
+      return 0;
+  if (!ReadFromSymbolizer(buffer_, kBufferSize))
+      return 0;
+  return buffer_;
+}
+
+bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
+  if (max_length == 0)
+    return true;
+  uptr read_len = 0;
+  while (true) {
+    uptr just_read = internal_read(input_fd_, buffer + read_len,
+                                   max_length - read_len - 1);
+    // We can't read 0 bytes, as we don't expect external symbolizer to close
+    // its stdout.
+    if (just_read == 0 || just_read == (uptr)-1) {
+      Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
+      return false;
+    }
+    read_len += just_read;
+    if (ReachedEndOfOutput(buffer, read_len))
+      break;
+  }
+  buffer[read_len] = '\0';
+  return true;
+}
+
+bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
+  if (length == 0)
+    return true;
+  uptr write_len = internal_write(output_fd_, buffer, length);
+  if (write_len == 0 || write_len == (uptr)-1) {
+    Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
+    return false;
+  }
+  return true;
+}
+
+bool SymbolizerProcess::StartSymbolizerSubprocess() {
+  if (!FileExists(path_)) {
+    if (!reported_invalid_path_) {
+      Report("WARNING: invalid path to external symbolizer!\n");
+      reported_invalid_path_ = true;
+    }
+    return false;
+  }
+
+  int pid;
+  if (use_forkpty_) {
+#if SANITIZER_MAC
+    fd_t fd = kInvalidFd;
+    // Use forkpty to disable buffering in the new terminal.
+    pid = forkpty(&fd, 0, 0, 0);
+    if (pid == -1) {
+      // forkpty() failed.
+      Report("WARNING: failed to fork external symbolizer (errno: %d)\n",
+             errno);
+      return false;
+    } else if (pid == 0) {
+      // Child subprocess.
+      ExecuteWithDefaultArgs(path_);
+      internal__exit(1);
+    }
+
+    // Continue execution in parent process.
+    input_fd_ = output_fd_ = fd;
+
+    // Disable echo in the new terminal, disable CR.
+    struct termios termflags;
+    tcgetattr(fd, &termflags);
+    termflags.c_oflag &= ~ONLCR;
+    termflags.c_lflag &= ~ECHO;
+    tcsetattr(fd, TCSANOW, &termflags);
+#else  // SANITIZER_MAC
+    UNIMPLEMENTED();
+#endif  // SANITIZER_MAC
+  } else {
+    int *infd = NULL;
+    int *outfd = NULL;
+    // The client program may close its stdin and/or stdout and/or stderr
+    // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+    // In this case the communication between the forked processes may be
+    // broken if either the parent or the child tries to close or duplicate
+    // these descriptors. The loop below produces two pairs of file
+    // descriptors, each greater than 2 (stderr).
+    int sock_pair[5][2];
+    for (int i = 0; i < 5; i++) {
+      if (pipe(sock_pair[i]) == -1) {
+        for (int j = 0; j < i; j++) {
+          internal_close(sock_pair[j][0]);
+          internal_close(sock_pair[j][1]);
+        }
+        Report("WARNING: Can't create a socket pair to start "
+               "external symbolizer (errno: %d)\n", errno);
+        return false;
+      } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+        if (infd == NULL) {
+          infd = sock_pair[i];
+        } else {
+          outfd = sock_pair[i];
+          for (int j = 0; j < i; j++) {
+            if (sock_pair[j] == infd) continue;
+            internal_close(sock_pair[j][0]);
+            internal_close(sock_pair[j][1]);
+          }
+          break;
+        }
+      }
+    }
+    CHECK(infd);
+    CHECK(outfd);
+
+    // Real fork() may call user callbacks registered with pthread_atfork().
+    pid = internal_fork();
+    if (pid == -1) {
+      // Fork() failed.
+      internal_close(infd[0]);
+      internal_close(infd[1]);
+      internal_close(outfd[0]);
+      internal_close(outfd[1]);
+      Report("WARNING: failed to fork external symbolizer "
+             " (errno: %d)\n", errno);
+      return false;
+    } else if (pid == 0) {
+      // Child subprocess.
+      internal_close(STDOUT_FILENO);
+      internal_close(STDIN_FILENO);
+      internal_dup2(outfd[0], STDIN_FILENO);
+      internal_dup2(infd[1], STDOUT_FILENO);
+      internal_close(outfd[0]);
+      internal_close(outfd[1]);
+      internal_close(infd[0]);
+      internal_close(infd[1]);
+      for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
+        internal_close(fd);
+      ExecuteWithDefaultArgs(path_);
+      internal__exit(1);
+    }
+
+    // Continue execution in parent process.
+    internal_close(outfd[0]);
+    internal_close(infd[1]);
+    input_fd_ = infd[0];
+    output_fd_ = outfd[1];
+  }
+
+  // Check that symbolizer subprocess started successfully.
+  int pid_status;
+  SleepForMillis(kSymbolizerStartupTimeMillis);
+  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+  if (exited_pid != 0) {
+    // Either waitpid failed, or child has already exited.
+    Report("WARNING: external symbolizer didn't start up correctly!\n");
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index ed96a3a..67ed4b3 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -18,139 +18,153 @@
 #include <dbghelp.h>
 #pragma comment(lib, "dbghelp.lib")
 
-#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_win.h"
+#include "sanitizer_symbolizer_internal.h"
 
 namespace __sanitizer {
 
-class WinSymbolizer : public Symbolizer {
- public:
-  WinSymbolizer() : initialized_(false) {}
+namespace {
 
-  SymbolizedStack *SymbolizePC(uptr addr) override {
-    SymbolizedStack *frame = SymbolizedStack::New(addr);
+bool is_dbghelp_initialized = false;
 
-    BlockingMutexLock l(&dbghelp_mu_);
-    InitializeIfNeeded();
+bool TrySymInitialize() {
+  SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
+  return SymInitialize(GetCurrentProcess(), 0, TRUE);
+  // FIXME: We don't call SymCleanup() on exit yet - should we?
+}
 
-    // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
-    char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
-    PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
-    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
-    symbol->MaxNameLen = MAX_SYM_NAME;
-    DWORD64 offset = 0;
-    BOOL got_objname = SymFromAddr(GetCurrentProcess(),
-                                   (DWORD64)addr, &offset, symbol);
-    if (!got_objname)
-      return frame;
-
-    DWORD unused;
-    IMAGEHLP_LINE64 line_info;
-    line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
-    BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
-                                             &unused, &line_info);
-    frame->info.function = internal_strdup(symbol->Name);
-    frame->info.function_offset = (uptr)offset;
-    if (got_fileline) {
-      frame->info.file = internal_strdup(line_info.FileName);
-      frame->info.line = line_info.LineNumber;
-    }
-
-    IMAGEHLP_MODULE64 mod_info;
-    internal_memset(&mod_info, 0, sizeof(mod_info));
-    mod_info.SizeOfStruct = sizeof(mod_info);
-    if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
-      frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName,
-                                           addr - (uptr)mod_info.BaseOfImage);
-    return frame;
+// Initializes DbgHelp library, if it's not yet initialized. Calls to this
+// function should be synchronized with respect to other calls to DbgHelp API
+// (e.g. from WinSymbolizerTool).
+void InitializeDbgHelpIfNeeded() {
+  if (is_dbghelp_initialized)
+    return;
+  if (!TrySymInitialize()) {
+    // OK, maybe the client app has called SymInitialize already.
+    // That's a bit unfortunate for us as all the DbgHelp functions are
+    // single-threaded and we can't coordinate with the app.
+    // FIXME: Can we stop the other threads at this point?
+    // Anyways, we have to reconfigure stuff to make sure that SymInitialize
+    // has all the appropriate options set.
+    // Cross our fingers and reinitialize DbgHelp.
+    Report("*** WARNING: Failed to initialize DbgHelp!              ***\n");
+    Report("*** Most likely this means that the app is already      ***\n");
+    Report("*** using DbgHelp, possibly with incompatible flags.    ***\n");
+    Report("*** Due to technical reasons, symbolization might crash ***\n");
+    Report("*** or produce wrong results.                           ***\n");
+    SymCleanup(GetCurrentProcess());
+    TrySymInitialize();
   }
+  is_dbghelp_initialized = true;
 
-  bool CanReturnFileLineInfo() override {
+  // When an executable is run from a location different from the one where it
+  // was originally built, we may not see the nearby PDB files.
+  // To work around this, let's append the directory of the main module
+  // to the symbol search path.  All the failures below are not fatal.
+  const size_t kSymPathSize = 2048;
+  static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
+  if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
+    Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
+    return;
+  }
+  size_t sz = wcslen(path_buffer);
+  if (sz) {
+    CHECK_EQ(0, wcscat_s(path_buffer, L";"));
+    sz++;
+  }
+  DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
+  if (res == 0 || res == MAX_PATH) {
+    Report("*** WARNING: Failed to getting the EXE directory ***\n");
+    return;
+  }
+  // Write the zero character in place of the last backslash to get the
+  // directory of the main module at the end of path_buffer.
+  wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
+  CHECK_NE(last_bslash, 0);
+  *last_bslash = L'\0';
+  if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
+    Report("*** WARNING: Failed to SymSetSearchPathW\n");
+    return;
+  }
+}
+
+}  // namespace
+
+bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
+  InitializeDbgHelpIfNeeded();
+
+  // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+  char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
+  PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
+  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+  symbol->MaxNameLen = MAX_SYM_NAME;
+  DWORD64 offset = 0;
+  BOOL got_objname = SymFromAddr(GetCurrentProcess(),
+                                 (DWORD64)addr, &offset, symbol);
+  if (!got_objname)
+    return false;
+
+  DWORD unused;
+  IMAGEHLP_LINE64 line_info;
+  line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+  BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
+                                           &unused, &line_info);
+  frame->info.function = internal_strdup(symbol->Name);
+  frame->info.function_offset = (uptr)offset;
+  if (got_fileline) {
+    frame->info.file = internal_strdup(line_info.FileName);
+    frame->info.line = line_info.LineNumber;
+  }
+  return true;
+}
+
+const char *WinSymbolizerTool::Demangle(const char *name) {
+  CHECK(is_dbghelp_initialized);
+  static char demangle_buffer[1000];
+  if (name[0] == '\01' &&
+      UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
+                           UNDNAME_NAME_ONLY))
+    return demangle_buffer;
+  else
+    return name;
+}
+
+bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name,
+                                       uptr *module_offset) {
+  InitializeDbgHelpIfNeeded();
+
+  IMAGEHLP_MODULE64 mod_info;
+  internal_memset(&mod_info, 0, sizeof(mod_info));
+  mod_info.SizeOfStruct = sizeof(mod_info);
+  if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) {
+    *module_name = mod_info.ImageName;
+    *module_offset = addr - (uptr)mod_info.BaseOfImage;
     return true;
   }
+  return false;
+}
 
-  const char *Demangle(const char *name) override {
-    CHECK(initialized_);
-    static char demangle_buffer[1000];
-    if (name[0] == '\01' &&
-        UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
-                             UNDNAME_NAME_ONLY))
-      return demangle_buffer;
-    else
-      return name;
-  }
-
-  // FIXME: Implement GetModuleNameAndOffsetForPC().
+// TODO(kuba.brecka): To be merged with POSIXSymbolizer.
+class WinSymbolizer : public Symbolizer {
+ public:
+  explicit WinSymbolizer(IntrusiveList<SymbolizerTool> tools)
+      : Symbolizer(tools) {}
 
  private:
-  void InitializeIfNeeded() {
-    if (initialized_)
-      return;
-    if (!TrySymInitialize()) {
-      // OK, maybe the client app has called SymInitialize already.
-      // That's a bit unfortunate for us as all the DbgHelp functions are
-      // single-threaded and we can't coordinate with the app.
-      // FIXME: Can we stop the other threads at this point?
-      // Anyways, we have to reconfigure stuff to make sure that SymInitialize
-      // has all the appropriate options set.
-      // Cross our fingers and reinitialize DbgHelp.
-      Report("*** WARNING: Failed to initialize DbgHelp!              ***\n");
-      Report("*** Most likely this means that the app is already      ***\n");
-      Report("*** using DbgHelp, possibly with incompatible flags.    ***\n");
-      Report("*** Due to technical reasons, symbolization might crash ***\n");
-      Report("*** or produce wrong results.                           ***\n");
-      SymCleanup(GetCurrentProcess());
-      TrySymInitialize();
-    }
-    initialized_ = true;
-
-    // When an executable is run from a location different from the one where it
-    // was originally built, we may not see the nearby PDB files.
-    // To work around this, let's append the directory of the main module
-    // to the symbol search path.  All the failures below are not fatal.
-    const size_t kSymPathSize = 2048;
-    static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
-    if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
-      Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
-      return;
-    }
-    size_t sz = wcslen(path_buffer);
-    if (sz) {
-      CHECK_EQ(0, wcscat_s(path_buffer, L";"));
-      sz++;
-    }
-    DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
-    if (res == 0 || res == MAX_PATH) {
-      Report("*** WARNING: Failed to getting the EXE directory ***\n");
-      return;
-    }
-    // Write the zero character in place of the last backslash to get the
-    // directory of the main module at the end of path_buffer.
-    wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
-    CHECK_NE(last_bslash, 0);
-    *last_bslash = L'\0';
-    if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
-      Report("*** WARNING: Failed to SymSetSearchPathW\n");
-      return;
-    }
+  bool PlatformFindModuleNameAndOffsetForAddress(
+      uptr addr, const char **module_name, uptr *module_offset) override {
+    return ::FindModuleNameAndOffsetForAddress(addr, module_name,
+                                               module_offset);
   }
-
-  bool TrySymInitialize() {
-    SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
-    return SymInitialize(GetCurrentProcess(), 0, TRUE);
-    // FIXME: We don't call SymCleanup() on exit yet - should we?
-  }
-
-  // All DbgHelp functions are single threaded, so we should use a mutex to
-  // serialize accesses.
-  BlockingMutex dbghelp_mu_;
-  bool initialized_;
+  const char *PlatformDemangle(const char *name) override { return name; }
+  void PlatformPrepareForSandboxing() override { }
 };
 
 Symbolizer *Symbolizer::PlatformInit() {
-  static bool called_once = false;
-  CHECK(!called_once && "Shouldn't create more than one symbolizer");
-  called_once = true;
-  return new(symbolizer_allocator_) WinSymbolizer();
+  IntrusiveList<SymbolizerTool> list;
+  list.clear();
+  list.push_back(new(symbolizer_allocator_) WinSymbolizerTool());
+  return new(symbolizer_allocator_) WinSymbolizer(list);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.h b/lib/sanitizer_common/sanitizer_symbolizer_win.h
new file mode 100644
index 0000000..72ac5e5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.h
@@ -0,0 +1,31 @@
+//===-- sanitizer_symbolizer_win.h ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Header file for the Windows symbolizer tool.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_WIN_H
+#define SANITIZER_SYMBOLIZER_WIN_H
+
+#include "sanitizer_symbolizer_internal.h"
+
+namespace __sanitizer {
+
+class WinSymbolizerTool : public SymbolizerTool {
+ public:
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+  bool SymbolizeData(uptr addr, DataInfo *info) override {
+    return false;
+  }
+  const char *Demangle(const char *name) override;
+};
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SYMBOLIZER_WIN_H
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 335ceca..3ec9084 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -313,6 +313,19 @@
   return 0;
 }
 
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+  // Nothing here for now.
+  return 0;
+}
+
+bool IsPathSeparator(const char c) {
+  return c == '\\' || c == '/';
+}
+
+bool IsAbsolutePath(const char *path) {
+  UNIMPLEMENTED();
+}
+
 void SleepForSeconds(int seconds) {
   Sleep(seconds * 1000);
 }
@@ -368,7 +381,7 @@
   UNIMPLEMENTED();
 }
 
-uptr OpenFile(const char *filename, bool write) {
+uptr OpenFile(const char *filename, FileAccessMode mode) {
   UNIMPLEMENTED();
 }
 
@@ -618,6 +631,23 @@
   return true;
 }
 
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+  EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
+  CONTEXT *context_record = (CONTEXT*)context;
+
+  uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+  uptr bp = (uptr)context_record->Rbp;
+  uptr sp = (uptr)context_record->Rsp;
+#else
+  uptr bp = (uptr)context_record->Ebp;
+  uptr sp = (uptr)context_record->Esp;
+#endif
+  uptr access_addr = exception_record->ExceptionInformation[1];
+
+  return SignalContext(context, access_addr, pc, sp, bp);
+}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 7ed05d7..9108a81 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -17,7 +17,6 @@
 
 # Filters
 # TODO: remove some of these filters
-LLVM_LINT_FILTER=-,+whitespace
 COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
 -build/namespaces
 ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
@@ -60,9 +59,6 @@
   ${LITLINT} "$@" 2>>$ERROR_LOG
 }
 
-run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
-  lib/Transforms/Instrumentation/*Sanitizer.cpp &
-
 if [ "${COMPILER_RT}" = "" ]; then
   COMPILER_RT=projects/compiler-rt
 fi
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index 566116e..53180d0 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -9,35 +9,77 @@
 import bisect
 import os.path
 
-prog_name = "";
+prog_name = ""
 
 def Usage():
   print >> sys.stderr, "Usage: \n" + \
-      " " + prog_name + " merge file1 [file2 ...]  > output\n" \
-      " " + prog_name + " print file1 [file2 ...]\n" \
-      " " + prog_name + " unpack file1 [file2 ...]\n" \
-      " " + prog_name + " rawunpack file1 [file2 ...]\n"
+      " " + prog_name + " [32|64] merge file1 [file2 ...]  > output\n" \
+      " " + prog_name + " [32|64] print file1 [file2 ...]\n" \
+      " " + prog_name + " [32|64] unpack file1 [file2 ...]\n" \
+      " " + prog_name + " [32|64] rawunpack file1 [file2 ...]\n"
   exit(1)
 
+def CheckBits(bits):
+  if bits != 32 and bits != 64:
+    raise Exception("Wrong bitness: %d" % bits)
+
+def TypeCodeForBits(bits):
+  CheckBits(bits)
+  return 'L' if bits == 64 else 'I'
+
+kMagic32SecondHalf = 0xFFFFFF32;
+kMagic64SecondHalf = 0xFFFFFF64;
+kMagicFirstHalf    = 0xC0BFFFFF;
+
+def MagicForBits(bits):
+  CheckBits(bits)
+  if sys.byteorder == 'little':
+    return [kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf, kMagicFirstHalf]
+  else:
+    return [kMagicFirstHalf, kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf]
+
+def ReadMagicAndReturnBitness(f, path):
+  magic_bytes = f.read(8)
+  magic_words = struct.unpack('II', magic_bytes);
+  bits = 0
+  idx = 1 if sys.byteorder == 'little' else 0
+  if magic_words[idx] == kMagicFirstHalf:
+    if magic_words[1-idx] == kMagic64SecondHalf:
+      bits = 64
+    elif magic_words[1-idx] == kMagic32SecondHalf:
+      bits = 32
+  if bits == 0:
+    raise Exception('Bad magic word in %s' % path)
+  return bits
+
 def ReadOneFile(path):
   with open(path, mode="rb") as f:
     f.seek(0, 2)
     size = f.tell()
     f.seek(0, 0)
-    s = set(array.array('I', f.read(size)))
-  print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path)
+    if size < 8:
+      raise Exception('File %s is short (< 8 bytes)' % path)
+    bits = ReadMagicAndReturnBitness(f, path)
+    size -= 8
+    s = array.array(TypeCodeForBits(bits), f.read(size))
+  print >>sys.stderr, "%s: read %d %d-bit PCs from %s" % (prog_name, size * 8 / bits, bits, path)
   return s
 
 def Merge(files):
   s = set()
   for f in files:
-    s = s.union(ReadOneFile(f))
+    s = s.union(set(ReadOneFile(f)))
   print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
     (prog_name, len(files), len(s))
   return sorted(s)
 
 def PrintFiles(files):
-  s = Merge(files)
+  if len(files) > 1:
+    s = Merge(files)
+  else:  # If there is just on file, print the PCs in order.
+    s = ReadOneFile(files[0])
+    print >> sys.stderr, "%s: 1 file merged; %d PCs total" % \
+      (prog_name, len(s))
   for i in s:
     print "0x%x" % i
 
@@ -45,7 +87,11 @@
   if sys.stdout.isatty():
     Usage()
   s = Merge(files)
-  a = array.array('I', s)
+  bits = 32
+  if max(s) > 0xFFFFFFFF:
+    bits = 64
+  array.array('I', MagicForBits(bits)).tofile(sys.stdout)
+  a = array.array(TypeCodeForBits(bits), s)
   a.tofile(sys.stdout)
 
 
@@ -82,6 +128,8 @@
   with open(map_path, mode="rt") as f_map:
     print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
     bits = int(f_map.readline())
+    if bits != 32 and bits != 64:
+      raise Exception('Wrong bits size in the map')
     for line in f_map:
       parts = line.rstrip().split()
       mem_map.append((int(parts[0], 16),
@@ -97,11 +145,7 @@
     f.seek(0, 2)
     size = f.tell()
     f.seek(0, 0)
-    if bits == 64:
-      typecode = 'L'
-    else:
-      typecode = 'I'
-    pcs = array.array(typecode, f.read(size))
+    pcs = array.array(TypeCodeForBits(bits), f.read(size))
     mem_map_pcs = [[] for i in range(0, len(mem_map))]
 
     for pc in pcs:
@@ -119,9 +163,10 @@
       assert path.endswith('.sancov.raw')
       dst_path = module_path + '.' + os.path.basename(path)[:-4]
       print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path)
-      arr = array.array('I')
+      arr = array.array(TypeCodeForBits(bits))
       arr.fromlist(sorted(pc_list))
       with open(dst_path, 'ab') as f2:
+        array.array('I', MagicForBits(bits)).tofile(f2)
         arr.tofile(f2)
 
 def RawUnpack(files):
@@ -135,6 +180,7 @@
   prog_name = sys.argv[0]
   if len(sys.argv) <= 2:
     Usage();
+
   if sys.argv[1] == "print":
     PrintFiles(sys.argv[2:])
   elif sys.argv[1] == "merge":
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 75008db..b062c5a 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -28,6 +28,7 @@
   sanitizer_stacktrace_test.cc
   sanitizer_stoptheworld_test.cc
   sanitizer_suppressions_test.cc
+  sanitizer_symbolizer_test.cc
   sanitizer_test_main.cc
   sanitizer_thread_registry_test.cc)
 
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index 8712d2c..279f6fe 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -78,14 +78,14 @@
 
   char tmpfile[128];
   temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
-  uptr openrv = OpenFile(tmpfile, true);
+  uptr openrv = OpenFile(tmpfile, WrOnly);
   EXPECT_FALSE(internal_iserror(openrv));
   fd_t fd = openrv;
   EXPECT_EQ(len1, internal_write(fd, str1, len1));
   EXPECT_EQ(len2, internal_write(fd, str2, len2));
   internal_close(fd);
 
-  openrv = OpenFile(tmpfile, false);
+  openrv = OpenFile(tmpfile, RdOnly);
   EXPECT_FALSE(internal_iserror(openrv));
   fd = openrv;
   uptr fsize = internal_filesize(fd);
@@ -134,7 +134,7 @@
   char tmpfile[128];
   temp_file_name(tmpfile, sizeof(tmpfile),
                  "sanitizer_common.internalmmapwithoffset.tmp.");
-  uptr res = OpenFile(tmpfile, true);
+  uptr res = OpenFile(tmpfile, RdWr);
   ASSERT_FALSE(internal_iserror(res));
   fd_t fd = res;
 
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index ac820c2..a8bd726 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -30,11 +30,11 @@
   }
 
   void *mapping;
-  uptr *fake_stack;
+  uhwptr *fake_stack;
   const uptr fake_stack_size = 10;
-  uptr start_pc;
-  uptr fake_top;
-  uptr fake_bottom;
+  uhwptr start_pc;
+  uhwptr fake_top;
+  uhwptr fake_bottom;
   BufferedStackTrace trace;
 };
 
@@ -48,7 +48,7 @@
   Mprotect((uptr)mapping, ps);
 
   // Unwinder may peek 1 word down from the starting FP.
-  fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr));
+  fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr));
 
   // Fill an array of pointers with fake fp+retaddr pairs.  Frame pointers have
   // even indices.
@@ -57,12 +57,12 @@
     fake_stack[i+1] = PC(i + 1); // retaddr
   }
   // Mark the last fp point back up to terminate the stack trace.
-  fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0];
+  fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uhwptr)&fake_stack[0];
 
   // Top is two slots past the end because FastUnwindStack subtracts two.
-  fake_top = (uptr)&fake_stack[fake_stack_size + 2];
+  fake_top = (uhwptr)&fake_stack[fake_stack_size + 2];
   // Bottom is one slot before the start because FastUnwindStack uses >.
-  fake_bottom = (uptr)mapping;
+  fake_bottom = (uhwptr)mapping;
   start_pc = PC(0);
 }
 
@@ -85,7 +85,7 @@
 // From: http://code.google.com/p/address-sanitizer/issues/detail?id=162
 TEST_F(FastUnwindTest, FramePointerLoop) {
   // Make one fp point to itself.
-  fake_stack[4] = (uptr)&fake_stack[4];
+  fake_stack[4] = (uhwptr)&fake_stack[4];
   if (!TryFastUnwind(kStackTraceMax))
     return;
   // Should get all on-stack retaddrs up to the 4th slot and start_pc.
@@ -114,7 +114,7 @@
     return;
   EXPECT_EQ(1U, trace.size);
   EXPECT_EQ(start_pc, trace.trace[0]);
-  EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
+  EXPECT_EQ((uhwptr)&fake_stack[0], trace.top_frame_bp);
 }
 
 TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
@@ -127,7 +127,7 @@
 TEST_F(FastUnwindTest, FPBelowPrevFP) {
   // The next FP points to unreadable memory inside the stack limits, but below
   // current FP.
-  fake_stack[0] = (uptr)&fake_stack[-50];
+  fake_stack[0] = (uhwptr)&fake_stack[-50];
   fake_stack[1] = PC(1);
   if (!TryFastUnwind(3))
     return;
diff --git a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
index b6786ba..802af39 100644
--- a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc
@@ -189,6 +189,16 @@
   pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex);
 }
 
+static void SegvCallback(const SuspendedThreadsList &suspended_threads_list,
+                         void *argument) {
+  *(volatile int*)0x1234 = 0;
+}
+
+TEST(StopTheWorld, SegvInCallback) {
+  // Test that tracer thread catches SIGSEGV.
+  StopTheWorld(&SegvCallback, NULL);
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LINUX && defined(__x86_64__)
diff --git a/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc b/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc
new file mode 100644
index 0000000..429ac59
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc
@@ -0,0 +1,58 @@
+//===-- sanitizer_symbolizer_test.cc --------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for sanitizer_symbolizer.h and sanitizer_symbolizer_internal.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_symbolizer_internal.h"
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(Symbolizer, ExtractToken) {
+  char *token;
+  const char *rest;
+
+  rest = ExtractToken("a;b;c", ";", &token);
+  EXPECT_STREQ("a", token);
+  EXPECT_STREQ("b;c", rest);
+  InternalFree(token);
+
+  rest = ExtractToken("aaa-bbb.ccc", ";.-*", &token);
+  EXPECT_STREQ("aaa", token);
+  EXPECT_STREQ("bbb.ccc", rest);
+  InternalFree(token);
+}
+
+TEST(Symbolizer, ExtractInt) {
+  int token;
+  const char *rest = ExtractInt("123,456;789", ";,", &token);
+  EXPECT_EQ(123, token);
+  EXPECT_STREQ("456;789", rest);
+}
+
+TEST(Symbolizer, ExtractUptr) {
+  uptr token;
+  const char *rest = ExtractUptr("123,456;789", ";,", &token);
+  EXPECT_EQ(123U, token);
+  EXPECT_STREQ("456;789", rest);
+}
+
+TEST(Symbolizer, ExtractTokenUpToDelimiter) {
+  char *token;
+  const char *rest =
+      ExtractTokenUpToDelimiter("aaa-+-bbb-+-ccc", "-+-", &token);
+  EXPECT_STREQ("aaa", token);
+  EXPECT_STREQ("bbb-+-ccc", rest);
+  InternalFree(token);
+}
+
+}  // namespace __sanitizer
diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old
index 9e0693f..fbdb9dd 100644
--- a/lib/tsan/Makefile.old
+++ b/lib/tsan/Makefile.old
@@ -11,7 +11,9 @@
 	CXXFLAGS += -O3
 endif
 ifeq ($(CXX), $(CLANG)++)
-  CXXFLAGS+= -Wno-unused-private-field -Wno-static-in-inline -Wgnu
+  CXXFLAGS += -Wno-unused-private-field -Wno-static-in-inline -Wgnu
+else
+  CXXFLAGS += -Wno-maybe-uninitialized
 endif
 
 LIBTSAN=rtl/libtsan.a
diff --git a/lib/tsan/rtl/Makefile.old b/lib/tsan/rtl/Makefile.old
index 150b376..627e03b 100644
--- a/lib/tsan/rtl/Makefile.old
+++ b/lib/tsan/rtl/Makefile.old
@@ -15,6 +15,7 @@
 ifeq ($(DEBUG), 0)
   CXXFLAGS+=-fomit-frame-pointer
 ifeq ($(CXX), g++)
+  CXXFLAGS+=-Wno-maybe-uninitialized
   CXXFLAGS+=-Wframe-larger-than=512
 endif  # CXX=g++
 endif  # DEBUG=0
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 31ff7d5..c45bcdc 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -145,7 +145,10 @@
 const sighandler_t SIG_DFL = (sighandler_t)0;
 const sighandler_t SIG_IGN = (sighandler_t)1;
 const sighandler_t SIG_ERR = (sighandler_t)-1;
-#ifdef __mips__
+#if SANITIZER_FREEBSD
+const int SA_SIGINFO = 0x40;
+const int SIG_SETMASK = 3;
+#elif defined(__mips__)
 const int SA_SIGINFO = 8;
 const int SIG_SETMASK = 3;
 #else
@@ -167,7 +170,7 @@
   ucontext_t ctx;
 };
 
-struct SignalContext {
+struct ThreadSignalContext {
   int int_signal_send;
   atomic_uintptr_t in_blocking_func;
   atomic_uintptr_t have_pending_signals;
@@ -194,10 +197,10 @@
 
 }  // namespace __tsan
 
-static SignalContext *SigCtx(ThreadState *thr) {
-  SignalContext *ctx = (SignalContext*)thr->signal_ctx;
+static ThreadSignalContext *SigCtx(ThreadState *thr) {
+  ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx;
   if (ctx == 0 && !thr->is_dead) {
-    ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
+    ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext");
     MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
     thr->signal_ctx = ctx;
   }
@@ -298,7 +301,7 @@
   }
 
   ThreadState *thr;
-  SignalContext *ctx;
+  ThreadSignalContext *ctx;
 };
 
 TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
@@ -410,7 +413,7 @@
 }
 
 static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
-  if (thr->shadow_stack_pos == 0)  // called from libc guts during bootstrap
+  if (!thr->is_inited)  // called from libc guts during bootstrap
     return;
   // Cleanup old bufs.
   JmpBufGarbageCollect(thr, sp);
@@ -419,7 +422,7 @@
   buf->sp = sp;
   buf->mangled_sp = mangled_sp;
   buf->shadow_stack_pos = thr->shadow_stack_pos;
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
   buf->in_blocking_func = sctx ?
       atomic_load(&sctx->in_blocking_func, memory_order_relaxed) :
@@ -442,7 +445,7 @@
       // Unwind the stack.
       while (thr->shadow_stack_pos > buf->shadow_stack_pos)
         FuncExit(thr);
-      SignalContext *sctx = SigCtx(thr);
+      ThreadSignalContext *sctx = SigCtx(thr);
       if (sctx) {
         sctx->int_signal_send = buf->int_signal_send;
         atomic_store(&sctx->in_blocking_func, buf->in_blocking_func,
@@ -666,9 +669,12 @@
 }
 
 TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
-  SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size);
-  MemoryAccessRange(thr, pc, (uptr)dst, size, true);
-  MemoryAccessRange(thr, pc, (uptr)src, size, false);
+  // On FreeBSD we get here from libthr internals on thread initialization.
+  if (cur_thread()->is_inited) {
+    SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size);
+    MemoryAccessRange(thr, pc, (uptr)dst, size, true);
+    MemoryAccessRange(thr, pc, (uptr)src, size, false);
+  }
   return internal_memcpy(dst, src, size);
 }
 
@@ -797,6 +803,7 @@
 TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
   SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
   DontNeedShadowFor((uptr)addr, sz);
+  ctx->metamap.ResetRange(thr, pc, (uptr)addr, (uptr)sz);
   int res = REAL(munmap)(addr, sz);
   return res;
 }
@@ -878,7 +885,7 @@
   {
     ThreadState *thr = cur_thread();
     ThreadFinish(thr);
-    SignalContext *sctx = thr->signal_ctx;
+    ThreadSignalContext *sctx = thr->signal_ctx;
     if (sctx) {
       thr->signal_ctx = 0;
       UnmapOrDie(sctx, sizeof(*sctx));
@@ -1940,7 +1947,7 @@
 }
 
 void ProcessPendingSignals(ThreadState *thr) {
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   if (sctx == 0 ||
       atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0)
     return;
@@ -1948,8 +1955,8 @@
   atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
   // These are too big for stack.
   static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
-  REAL(sigfillset)(&emptyset);
-  pthread_sigmask(SIG_SETMASK, &emptyset, &oldset);
+  CHECK_EQ(0, REAL(sigfillset)(&emptyset));
+  CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &emptyset, &oldset));
   for (int sig = 0; sig < kSigCount; sig++) {
     SignalDesc *signal = &sctx->pending_signals[sig];
     if (signal->armed) {
@@ -1958,13 +1965,13 @@
           &signal->siginfo, &signal->ctx);
     }
   }
-  pthread_sigmask(SIG_SETMASK, &oldset, 0);
+  CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0));
   atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
 }
 
 }  // namespace __tsan
 
-static bool is_sync_signal(SignalContext *sctx, int sig) {
+static bool is_sync_signal(ThreadSignalContext *sctx, int sig) {
   return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
       sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
       // If we are sending signal to ourselves, we must process it now.
@@ -1974,7 +1981,7 @@
 void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
     my_siginfo_t *info, void *ctx) {
   ThreadState *thr = cur_thread();
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   if (sig < 0 || sig >= kSigCount) {
     VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig);
     return;
@@ -2083,7 +2090,7 @@
 
 TSAN_INTERCEPTOR(int, raise, int sig) {
   SCOPED_TSAN_INTERCEPTOR(raise, sig);
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   CHECK_NE(sctx, 0);
   int prev = sctx->int_signal_send;
   sctx->int_signal_send = sig;
@@ -2095,7 +2102,7 @@
 
 TSAN_INTERCEPTOR(int, kill, int pid, int sig) {
   SCOPED_TSAN_INTERCEPTOR(kill, pid, sig);
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   CHECK_NE(sctx, 0);
   int prev = sctx->int_signal_send;
   if (pid == (int)internal_getpid()) {
@@ -2111,7 +2118,7 @@
 
 TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) {
   SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig);
-  SignalContext *sctx = SigCtx(thr);
+  ThreadSignalContext *sctx = SigCtx(thr);
   CHECK_NE(sctx, 0);
   int prev = sctx->int_signal_send;
   if (tid == pthread_self()) {
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 7e69cb4..18bad14 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -335,10 +335,8 @@
     Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
 
   if (ReportStack *stack = ChooseSummaryStack(rep)) {
-    if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) {
-      const AddressInfo &info = frame->info;
-      ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
-    }
+    if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames))
+      ReportErrorSummary(rep_typ_str, frame->info);
   }
 
   Printf("==================\n");
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index b76f3e0..1c64caf 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -153,7 +153,7 @@
     } else {
       InternalScopedString filename(kMaxPathLength);
       filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
-      uptr openrv = OpenFile(filename.data(), true);
+      uptr openrv = OpenFile(filename.data(), WrOnly);
       if (internal_iserror(openrv)) {
         Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
             &filename[0]);
@@ -461,7 +461,7 @@
 #endif
 
 u32 CurrentStackId(ThreadState *thr, uptr pc) {
-  if (thr->shadow_stack_pos == 0)  // May happen during bootstrap.
+  if (!thr->is_inited)  // May happen during bootstrap.
     return 0;
   if (pc != 0) {
 #ifndef SANITIZER_GO
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 7a60e5c..d32688e 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -313,7 +313,7 @@
   }
 };
 
-struct SignalContext;
+struct ThreadSignalContext;
 
 struct JmpBuf {
   uptr sp;
@@ -371,6 +371,7 @@
   const int unique_id;
   bool in_symbolizer;
   bool in_ignored_lib;
+  bool is_inited;
   bool is_dead;
   bool is_freeing;
   bool is_vptr_access;
@@ -387,7 +388,7 @@
   DDLogicalThread *dd_lt;
 
   atomic_uintptr_t in_signal_handler;
-  SignalContext *signal_ctx;
+  ThreadSignalContext *signal_ctx;
 
   DenseSlabAllocCache block_cache;
   DenseSlabAllocCache sync_cache;
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 8ed1fbf..66c78cf 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -120,6 +120,7 @@
   AcquireImpl(thr, 0, &sync);
   StatInc(thr, StatSyncAcquire);
   sync.Reset(&thr->clock_cache);
+  thr->is_inited = true;
   DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
           "tls_addr=%zx tls_size=%zx\n",
           tid, (uptr)epoch0, args->stk_addr, args->stk_size,
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 5413f04..7315729 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -21,6 +21,7 @@
 #include "tsan_mman.h"
 #include "tsan_platform.h"
 
+#ifndef SANITIZER_GO
 // Suppressions for true/false positives in standard libraries.
 static const char *const std_suppressions =
 // Libstdc++ 4.4 has data races in std::string.
@@ -33,7 +34,6 @@
 "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
 
 // Can be overriden in frontend.
-#ifndef SANITIZER_GO
 extern "C" const char *WEAK __tsan_default_suppressions() {
   return 0;
 }
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 1041073..49c4d15 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -80,7 +80,8 @@
   return sz;
 }
 
-void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+  bool has_something = false;
   u32 *meta = MemToMeta(p);
   u32 *end = MemToMeta(p + sz);
   if (end == meta)
@@ -91,6 +92,7 @@
     for (;;) {
       if (idx == 0)
         break;
+      has_something = true;
       if (idx & kFlagBlock) {
         block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
         break;
@@ -106,6 +108,64 @@
       }
     }
   }
+  return has_something;
+}
+
+// ResetRange removes all meta objects from the range.
+// It is called for large mmap-ed regions. The function is best-effort wrt
+// freeing of meta objects, because we don't want to page in the whole range
+// which can be huge. The function probes pages one-by-one until it finds a page
+// without meta objects, at this point it stops freeing meta objects. Because
+// thread stacks grow top-down, we do the same starting from end as well.
+void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+  const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
+  const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
+  if (sz <= 4 * kPageSize) {
+    // If the range is small, just do the normal free procedure.
+    FreeRange(thr, pc, p, sz);
+    return;
+  }
+  // First, round both ends of the range to page size.
+  uptr diff = RoundUp(p, kPageSize) - p;
+  if (diff != 0) {
+    FreeRange(thr, pc, p, diff);
+    p += diff;
+    sz -= diff;
+  }
+  diff = p + sz - RoundDown(p + sz, kPageSize);
+  if (diff != 0) {
+    FreeRange(thr, pc, p + sz - diff, diff);
+    sz -= diff;
+  }
+  // Now we must have a non-empty page-aligned range.
+  CHECK_GT(sz, 0);
+  CHECK_EQ(p, RoundUp(p, kPageSize));
+  CHECK_EQ(sz, RoundUp(sz, kPageSize));
+  const uptr p0 = p;
+  const uptr sz0 = sz;
+  // Probe start of the range.
+  while (sz > 0) {
+    bool has_something = FreeRange(thr, pc, p, kPageSize);
+    p += kPageSize;
+    sz -= kPageSize;
+    if (!has_something)
+      break;
+  }
+  // Probe end of the range.
+  while (sz > 0) {
+    bool has_something = FreeRange(thr, pc, p - kPageSize, kPageSize);
+    sz -= kPageSize;
+    if (!has_something)
+      break;
+  }
+  // Finally, page out the whole range (including the parts that we've just
+  // freed). Note: we can't simply madvise, because we need to leave a zeroed
+  // range (otherwise __tsan_java_move can crash if it encounters a left-over
+  // meta objects in java heap).
+  uptr metap = (uptr)MemToMeta(p0);
+  uptr metasz = sz0 / kMetaRatio;
+  UnmapOrDie((void*)metap, metasz);
+  MmapFixedNoReserve(metap, metasz);
 }
 
 MBlock* MetaMap::GetBlock(uptr p) {
diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h
index 574810d..2d12cdf 100644
--- a/lib/tsan/rtl/tsan_sync.h
+++ b/lib/tsan/rtl/tsan_sync.h
@@ -73,7 +73,8 @@
 
   void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
   uptr FreeBlock(ThreadState *thr, uptr pc, uptr p);
-  void FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
+  bool FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
+  void ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
   MBlock* GetBlock(uptr p);
 
   SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index 6683272..a8b3f61 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -22,34 +22,61 @@
 add_custom_target(ubsan)
 
 if(APPLE)
-  # Build universal binary on APPLE.
-  add_compiler_rt_osx_static_runtime(clang_rt.ubsan_osx
-    ARCH ${UBSAN_SUPPORTED_ARCH}
-    SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
-            $<TARGET_OBJECTS:RTSanitizerCommon.osx>
-    CFLAGS ${UBSAN_CXXFLAGS})
-  add_dependencies(ubsan clang_rt.ubsan_osx)
+  foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+    add_compiler_rt_darwin_object_library(RTUbsan ${os}
+      ARCH ${UBSAN_SUPPORTED_ARCH}
+      SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
+      CFLAGS ${UBSAN_CXXFLAGS})
+
+    add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os}
+      ARCH ${UBSAN_SUPPORTED_ARCH}
+      SOURCES $<TARGET_OBJECTS:RTUbsan.${os}>
+              $<TARGET_OBJECTS:RTSanitizerCommon.${os}>
+      LINKFLAGS -lc++abi)
+
+    add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+  endforeach()
 else()
   # Build separate libraries for each target.
   foreach(arch ${UBSAN_SUPPORTED_ARCH})
-    # Main UBSan runtime.
-    add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC
-      SOURCES ${UBSAN_SOURCES}
-      CFLAGS ${UBSAN_CFLAGS})
+    add_compiler_rt_object_library(RTUbsan ${arch}
+      SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS})
     # C++-specific parts of UBSan runtime. Requires a C++ ABI library.
-    add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC
-      SOURCES ${UBSAN_CXX_SOURCES}
+    add_compiler_rt_object_library(RTUbsan_cxx ${arch}
+      SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS})
+
+    # Standalone UBSan runtimes.
+    add_compiler_rt_runtime(clang_rt.ubsan_standalone-${arch} ${arch} STATIC
+      SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTUbsan.${arch}>
+      CFLAGS ${UBSAN_CFLAGS})
+    add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC
+      SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
       CFLAGS ${UBSAN_CXXFLAGS})
+    # UBSan runtimes used when another sanitizer is available.
+    add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC
+      SOURCES $<TARGET_OBJECTS:RTUbsan.${arch}>
+      CFLAGS ${UBSAN_CFLAGS})
+    add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC
+      SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
+      CFLAGS ${UBSAN_CXXFLAGS})
+
     add_dependencies(ubsan
-      clang_rt.san-${arch}
       clang_rt.ubsan-${arch}
-      clang_rt.ubsan_cxx-${arch})
+      clang_rt.ubsan_cxx-${arch}
+      clang_rt.ubsan_standalone-${arch}
+      clang_rt.ubsan_standalone_cxx-${arch})
     if (UNIX AND NOT ${arch} MATCHES "i386|i686")
       add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra)
       add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra)
+      add_sanitizer_rt_symbols(clang_rt.ubsan_standalone-${arch} ubsan.syms.extra)
+      add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx-${arch} ubsan.syms.extra)
       add_dependencies(ubsan
         clang_rt.ubsan-${arch}-symbols
-        clang_rt.ubsan_cxx-${arch}-symbols)
+        clang_rt.ubsan_cxx-${arch}-symbols
+        clang_rt.ubsan_standalone-${arch}-symbols
+        clang_rt.ubsan_standalone_cxx-${arch}-symbols)
     endif()
   endforeach()
 endif()
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 4f2a2a9..2314fb6 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_diag.h"
 #include "ubsan_init.h"
 #include "ubsan_flags.h"
@@ -49,8 +51,13 @@
   if (Loc.isSourceLocation()) {
     SourceLocation SLoc = Loc.getSourceLocation();
     if (!SLoc.isInvalid()) {
-      ReportErrorSummary("undefined-behavior", SLoc.getFilename(),
-                         SLoc.getLine(), "");
+      AddressInfo AI;
+      AI.file = internal_strdup(SLoc.getFilename());
+      AI.line = SLoc.getLine();
+      AI.column = SLoc.getColumn();
+      AI.function = internal_strdup("");  // Avoid printing ?? as function name.
+      ReportErrorSummary("undefined-behavior", AI);
+      AI.Clear();
       return;
     }
   }
@@ -356,3 +363,5 @@
   Suppression *s;
   return suppression_ctx->Match(TypeName, kVptrCheck, &s);
 }
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
index 0dbffc9..49ada8a 100644
--- a/lib/ubsan/ubsan_flags.cc
+++ b/lib/ubsan/ubsan_flags.cc
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
@@ -77,3 +79,5 @@
 const char *__ubsan_default_options() { return ""; }
 }  // extern "C"
 #endif
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 78e7508..a65b2f5 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_handlers.h"
 #include "ubsan_diag.h"
 
@@ -419,3 +421,5 @@
   handleNonNullArg(Data, Opts);
   Die();
 }
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc
index 4718e6e..b3cda32 100644
--- a/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/lib/ubsan/ubsan_handlers_cxx.cc
@@ -13,6 +13,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_handlers_cxx.h"
 #include "ubsan_diag.h"
 #include "ubsan_type_hash.h"
@@ -79,3 +81,5 @@
   GET_REPORT_OPTIONS(true);
   HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
 }
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
index 219273d..9527269 100644
--- a/lib/ubsan/ubsan_init.cc
+++ b/lib/ubsan/ubsan_init.cc
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_diag.h"
 #include "ubsan_init.h"
 #include "ubsan_flags.h"
@@ -61,3 +63,5 @@
 };
 static UbsanInitializer ubsan_initializer;
 #endif  // SANITIZER_CAN_USE_PREINIT_ARRAY
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h
new file mode 100644
index 0000000..efb7974
--- /dev/null
+++ b/lib/ubsan/ubsan_platform.h
@@ -0,0 +1,26 @@
+//===-- ubsan_platform.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the platforms which UBSan is supported at.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_PLATFORM_H
+#define UBSAN_PLATFORM_H
+
+// Other platforms should be easy to add, and probably work as-is.
+#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \
+    (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
+     defined(__aarch64__) || defined(__mips__))
+# define CAN_SANITIZE_UB 1
+#else
+# define CAN_SANITIZE_UB 0
+# error "UBSan not supported for this platform!"
+#endif
+
+#endif
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index a388bcc..c85d68d 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -13,6 +13,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_type_hash.h"
 
 #include "sanitizer_common/sanitizer_common.h"
@@ -248,3 +250,5 @@
   return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
                          ObjectType ? ObjectType->__type_name : "<unknown>");
 }
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc
index ab74720..ea91d63 100644
--- a/lib/ubsan/ubsan_value.cc
+++ b/lib/ubsan/ubsan_value.cc
@@ -12,6 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
 #include "ubsan_value.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -100,3 +102,5 @@
   }
   UNREACHABLE("unexpected floating point bit width");
 }
+
+#endif  // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_value.h b/lib/ubsan/ubsan_value.h
index a681084..72eee15 100644
--- a/lib/ubsan/ubsan_value.h
+++ b/lib/ubsan/ubsan_value.h
@@ -14,12 +14,6 @@
 #ifndef UBSAN_VALUE_H
 #define UBSAN_VALUE_H
 
-// For now, only support Linux, FreeBSD and Darwin. Other platforms should
-// be easy to add, and probably work as-is.
-#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__)
-#error "UBSan not supported for this platform!"
-#endif
-
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
 
@@ -32,7 +26,6 @@
 #define HAVE_INT128_T 0
 #endif
 
-
 namespace __ubsan {
 
 /// \brief Largest integer types we support.