Update aosp/master compiler-rt for rebase to r222486.

Change-Id: I38047809dbac0425193c82e810315998adbb380d
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f35a096..472d49c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@
 
 # Check if compiler-rt is built as a standalone project.
 if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
-  project(CompilerRT)
+  project(CompilerRT C CXX)
   set(COMPILER_RT_STANDALONE_BUILD TRUE)
 else()
   set(COMPILER_RT_STANDALONE_BUILD FALSE)
@@ -160,7 +160,6 @@
 set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 # Setup custom SDK sysroots.
-set(COMPILER_RT_DARWIN_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/darwin)
 set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux)
 
 set(COMPILER_RT_EXTRA_ANDROID_HEADERS ${COMPILER_RT_SOURCE_DIR}/android/include)
@@ -179,9 +178,6 @@
   set(TARGET_32_BIT_CFLAGS "")
 endif()
 
-# List of architectures we can target.
-set(COMPILER_RT_SUPPORTED_ARCH)
-
 function(get_target_flags_for_arch arch out_var)
   list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
   if(ARCH_INDEX EQUAL -1)
@@ -191,52 +187,6 @@
   endif()
 endfunction()
 
-# Try to compile a very simple source file to ensure we can target the given
-# platform. We use the results of these tests to build only the various target
-# runtime libraries supported by our current compilers cross-compiling
-# abilities.
-set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
-file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <limits>\nint main() {}\n")
-
-# test_target_arch(<arch> <target flags...>)
-# Sets the target flags for a given architecture and determines if this
-# architecture is supported by trying to build a simple file.
-macro(test_target_arch arch)
-  set(TARGET_${arch}_CFLAGS ${ARGN})
-  try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
-              COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
-              OUTPUT_VARIABLE TARGET_${arch}_OUTPUT
-              CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${TARGET_${arch}_CFLAGS}")
-  if(${CAN_TARGET_${arch}})
-    list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
-  elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "${arch}" OR
-         "${arch}" STREQUAL "arm_android")
-    # Bail out if we cannot target the architecture we plan to test.
-    message(FATAL_ERROR "Cannot compile for ${arch}:\n${TARGET_${arch}_OUTPUT}")
-  endif()
-endmacro()
-
-if(ANDROID)
-  test_target_arch(arm_android "")
-else()
-  if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
-    if (NOT MSVC)
-      test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
-    endif()
-    test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
-  elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
-    test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
-  elseif("${LLVM_NATIVE_ARCH}" STREQUAL "Mips")
-    test_target_arch(mips "")
-  endif()
-
-  # Build ARM libraries if we are configured to test on ARM
-  if("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "arm|aarch64")
-    test_target_arch(arm "-march=armv7-a")
-    test_target_arch(aarch64 "-march=armv8-a")
-  endif()
-endif()
-
 # We support running instrumented tests when we're not cross compiling
 # and target a UNIX-like system or Windows.
 # We can run tests on Android even when we are cross-compiling.
@@ -247,26 +197,17 @@
   option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
 endif()
 
-# Check if compiler-rt is built with libc++.
-find_flag_in_string("${CMAKE_CXX_FLAGS}" "-stdlib=libc++"
-                    COMPILER_RT_USES_LIBCXX)
-
-function(filter_available_targets out_var)
-  set(archs)
-  foreach(arch ${ARGN})
-    list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
-    if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
-      list(APPEND archs ${arch})
-    endif()
-  endforeach()
-  set(${out_var} ${archs} PARENT_SCOPE)
-endfunction()
-
 option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
 # COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
 pythonize_bool(COMPILER_RT_DEBUG)
 
+# We have to support both static and dynamic/shared runtime on Windows.
+# Android only works with dynamic runtime.
+if(WIN32 OR ANDROID)
+option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" ON)
+else()
 option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" OFF)
+endif()
 
 #================================
 # Setup Compiler Flags
@@ -291,23 +232,31 @@
 endif()
 
 # Provide some common commmandline flags for Sanitizer runtimes.
-append_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
 
 if(MSVC)
-  # Remove /MD flag so that it doesn't conflict with /MT.
+  # Replace the /MD[d] flags with /MT.
+  # FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
   if(COMPILER_RT_HAS_MT_FLAG)
-    string(REGEX REPLACE "(^| ) */MDd? *( |$)" "\\1 \\2" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-    list(APPEND SANITIZER_COMMON_CFLAGS /MT)
+    foreach(flag_var
+      CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+      CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+      if(${flag_var} MATCHES "/MD")
+        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+      elseif(${flag_var} MATCHES "/MDd")
+        string(REGEX REPLACE "/MDd" "/MT" ${flag_var} "${${flag_var}}")
+      endif()
+    endforeach()
   endif()
-  append_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
-  append_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
+  append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
+  append_list_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
 endif()
 
 # Build with optimization, unless we're in debug mode. If we're using MSVC,
@@ -326,12 +275,15 @@
 endif()
 
 # Turn off several warnings.
-append_if(COMPILER_RT_HAS_WNO_GNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_WNO_VARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_WNO_C99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_WNO_NON_VIRTUAL_DTOR_FLAG -Wno-non-virtual-dtor SANITIZER_COMMON_CFLAGS)
-append_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
-
+append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG -Wno-non-virtual-dtor SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
 if(APPLE)
   # Obtain the iOS Simulator SDK path from xcodebuild.
   execute_process(
@@ -346,13 +298,10 @@
     list(APPEND SANITIZER_COMMON_SUPPORTED_DARWIN_OS iossim)
   endif()
 
-  if(COMPILER_RT_USES_LIBCXX)
-    set(SANITIZER_MIN_OSX_VERSION 10.7)
-  else()
-    set(SANITIZER_MIN_OSX_VERSION 10.6)
-  endif()
+  set(SANITIZER_MIN_OSX_VERSION 10.7)
+  set(CMAKE_OSX_DEPLOYMENT_TARGET "") # We're setting the flag manually below.
   set(DARWIN_osx_CFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
-  set(DARWIN_iossim_CFLAGS 
+  set(DARWIN_iossim_CFLAGS
     -mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})
   set(DARWIN_osx_LINKFLAGS)
   set(DARWIN_iossim_LINKFLAGS
@@ -361,18 +310,6 @@
     -isysroot ${IOSSIM_SDK_DIR})
 endif()
 
-# Architectures supported by Sanitizer runtimes. Specific sanitizers may
-# support only subset of these (e.g. TSan works on x86_64 only).
-filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
-  x86_64 i386 powerpc64 arm aarch64 mips)
-filter_available_targets(ASAN_SUPPORTED_ARCH x86_64 i386 powerpc64 arm mips)
-filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64)
-filter_available_targets(LSAN_SUPPORTED_ARCH x86_64)
-filter_available_targets(MSAN_SUPPORTED_ARCH x86_64)
-filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 arm aarch64)
-filter_available_targets(TSAN_SUPPORTED_ARCH x86_64)
-filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 arm aarch64)
-
 add_subdirectory(include)
 
 set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
diff --git a/SDKs/darwin/README.txt b/SDKs/darwin/README.txt
deleted file mode 100644
index ea30af3..0000000
--- a/SDKs/darwin/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-The Darwin platforms are all similar enough we roll them into one SDK, and use
-preprocessor tricks to get the right definitions for the few things which
-diverge between OS X and iOS.
diff --git a/SDKs/darwin/usr/include/errno.h b/SDKs/darwin/usr/include/errno.h
deleted file mode 100644
index f06e537..0000000
--- a/SDKs/darwin/usr/include/errno.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#include <sys/errno.h>
diff --git a/SDKs/darwin/usr/include/fcntl.h b/SDKs/darwin/usr/include/fcntl.h
deleted file mode 100644
index a5f91e3..0000000
--- a/SDKs/darwin/usr/include/fcntl.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#include <sys/fcntl.h>
diff --git a/SDKs/darwin/usr/include/inttypes.h b/SDKs/darwin/usr/include/inttypes.h
deleted file mode 100644
index 406fa6f..0000000
--- a/SDKs/darwin/usr/include/inttypes.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* ===-- inttypes.h - stub SDK header for compiler-rt -----------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __INTTYPES_H__
-#define __INTTYPES_H__
-
-#if __WORDSIZE == 64
-#define __INTTYPE_PRI64__ "l"
-#else
-#define __INTTYPE_PRI64__ "ll"
-#endif
-
-#define PRId8  "hhd"
-#define PRId16 "hd"
-#define PRId32 "d"
-#define PRId64 __INTTYPE_PRI64__ "d"
-
-#define PRIi8  "hhi"
-#define PRIi16 "hi"
-#define PRIi32 "i"
-#define PRIi64 __INTTYPE_PRI64__ "i"
-
-#define PRIo8  "hho"
-#define PRIo16 "ho"
-#define PRIo32 "o"
-#define PRIo64 __INTTYPE_PRI64__ "o"
-
-#define PRIu8  "hhu"
-#define PRIu16 "hu"
-#define PRIu32 "u"
-#define PRIu64 __INTTYPE_PRI64__ "u"
-
-#define PRIx8  "hhx"
-#define PRIx16 "hx"
-#define PRIx32 "x"
-#define PRIx64 __INTTYPE_PRI64__ "x"
-
-#define PRIX8  "hhX"
-#define PRIX16 "hX"
-#define PRIX32 "X"
-#define PRIX64 __INTTYPE_PRI64__ "X"
-
-#define SCNd8  "hhd"
-#define SCNd16 "hd"
-#define SCNd32 "d"
-#define SCNd64 __INTTYPE_PRI64__ "d"
-
-#define SCNi8  "hhi"
-#define SCNi16 "hi"
-#define SCNi32 "i"
-#define SCNi64 __INTTYPE_PRI64__ "i"
-
-#define SCNo8  "hho"
-#define SCNo16 "ho"
-#define SCNo32 "o"
-#define SCNo64 __INTTYPE_PRI64__ "o"
-
-#define SCNu8  "hhu"
-#define SCNu16 "hu"
-#define SCNu32 "u"
-#define SCNu64 __INTTYPE_PRI64__ "u"
-
-#define SCNx8  "hhx"
-#define SCNx16 "hx"
-#define SCNx32 "x"
-#define SCNx64 __INTTYPE_PRI64__ "x"
-
-#define SCNX8  "hhX"
-#define SCNX16 "hX"
-#define SCNX32 "X"
-#define SCNX64 __INTTYPE_PRI64__ "X"
-
-#endif  /* __INTTYPES_H__ */
diff --git a/SDKs/darwin/usr/include/limits.h b/SDKs/darwin/usr/include/limits.h
deleted file mode 100644
index 5495a78..0000000
--- a/SDKs/darwin/usr/include/limits.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* ===-- limits.h - stub SDK header for compiler-rt -------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __LIMITS_H__
-#define __LIMITS_H__
-
-/* This is only here as a landing pad for the include_next from the compiler's
-   built-in limits.h. */
-
-#endif /* __LIMITS_H__ */
diff --git a/SDKs/darwin/usr/include/stdio.h b/SDKs/darwin/usr/include/stdio.h
deleted file mode 100644
index 1a8781f..0000000
--- a/SDKs/darwin/usr/include/stdio.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* ===-- stdio.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __STDIO_H__
-#define __STDIO_H__
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-typedef struct __sFILE FILE;
-typedef __SIZE_TYPE__ size_t;
-
-/* Determine the appropriate fdopen, fopen(), and fwrite() functions. */
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
-#  if defined(__i386)
-#    define __FDOPEN_NAME  "_fdopen$UNIX2003"
-#    define __FOPEN_NAME "_fopen$UNIX2003"
-#    define __FWRITE_NAME "_fwrite$UNIX2003"
-#  elif defined(__x86_64__)
-#    define __FDOPEN_NAME  "_fdopen"
-#    define __FOPEN_NAME "_fopen"
-#    define __FWRITE_NAME "_fwrite"
-#  elif defined(__arm) || defined(__arm64)
-#    define __FDOPEN_NAME  "_fdopen"
-#    define __FOPEN_NAME "_fopen"
-#    define __FWRITE_NAME "_fwrite"
-#  else
-#    error "unrecognized architecture for targeting OS X"
-#  endif
-#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
-#  if defined(__i386) || defined (__x86_64)
-#    define __FDOPEN_NAME  "_fdopen"
-#    define __FOPEN_NAME "_fopen"
-#    define __FWRITE_NAME "_fwrite"
-#  elif defined(__arm) || defined(__arm64)
-#    define __FDOPEN_NAME  "_fdopen"
-#    define __FOPEN_NAME "_fopen"
-#    define __FWRITE_NAME "_fwrite"
-#  else
-#    error "unrecognized architecture for targeting iOS"
-#  endif
-#else
-#  error "unrecognized architecture for targeting Darwin"
-#endif
-
-#    define stderr __stderrp
-extern FILE *__stderrp;
-
-#ifndef SEEK_SET
-#define	SEEK_SET	0	/* set file offset to offset */
-#endif
-#ifndef SEEK_CUR
-#define	SEEK_CUR	1	/* set file offset to current plus offset */
-#endif
-#ifndef SEEK_END
-#define	SEEK_END	2	/* set file offset to EOF plus offset */
-#endif
-
-int fclose(FILE *);
-int fflush(FILE *);
-FILE *fopen(const char * __restrict, const char * __restrict) __asm(__FOPEN_NAME);
-FILE *fdopen(int, const char *) __asm(__FDOPEN_NAME);
-int fprintf(FILE * __restrict, const char * __restrict, ...);
-int fputc(int, FILE *);
-size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict)
-  __asm(__FWRITE_NAME);
-size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
-long ftell(FILE *);
-int fseek(FILE *, long, int);
-int snprintf(char * __restrict, size_t, const char * __restrict, ...);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif /* __STDIO_H__ */
diff --git a/SDKs/darwin/usr/include/stdlib.h b/SDKs/darwin/usr/include/stdlib.h
deleted file mode 100644
index b6d3171..0000000
--- a/SDKs/darwin/usr/include/stdlib.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* ===-- stdlib.h - stub SDK header for compiler-rt -------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __STDLIB_H__
-#define __STDLIB_H__
-
-#define NULL ((void *)0)
-
-typedef __SIZE_TYPE__ size_t;
-
-void abort(void) __attribute__((__noreturn__));
-int atexit(void (*)(void));
-int atoi(const char *);
-void free(void *);
-char *getenv(const char *);
-void *malloc(size_t);
-void *realloc(void *, size_t);
-
-#endif /* __STDLIB_H__ */
diff --git a/SDKs/darwin/usr/include/string.h b/SDKs/darwin/usr/include/string.h
deleted file mode 100644
index 048fdba..0000000
--- a/SDKs/darwin/usr/include/string.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ===-- string.h - stub SDK header for compiler-rt -------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __STRING_H__
-#define __STRING_H__
-
-typedef __SIZE_TYPE__ size_t;
-
-int memcmp(const void *, const void *, size_t);
-void *memcpy(void *, const void *, size_t);
-void *memset(void *, int, size_t);
-char *strcat(char *, const char *);
-char *strcpy(char *, const char *);
-char *strdup(const char *);
-size_t strlen(const char *);
-char *strncpy(char *, const char *, size_t);
-
-/* Determine the appropriate strerror() function. */
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
-#  if defined(__i386)
-#    define __STRERROR_NAME  "_strerror$UNIX2003"
-#  elif defined(__x86_64__) || defined(__arm) || defined(__arm64)
-#    define __STRERROR_NAME  "_strerror"
-#  else
-#    error "unrecognized architecture for targeting OS X"
-#  endif
-#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
-#  if defined(__i386) || defined (__x86_64) || defined(__arm) || defined(__arm64)
-#    define __STRERROR_NAME  "_strerror"
-#  else
-#    error "unrecognized architecture for targeting iOS"
-#  endif
-#else
-#  error "unrecognized architecture for targeting Darwin"
-#endif
-
-char *strerror(int) __asm(__STRERROR_NAME);
-
-#endif /* __STRING_H__ */
diff --git a/SDKs/darwin/usr/include/sys/errno.h b/SDKs/darwin/usr/include/sys/errno.h
deleted file mode 100644
index 4befe38..0000000
--- a/SDKs/darwin/usr/include/sys/errno.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef _SYS_ERRNO_H_
-#define _SYS_ERRNO_H_
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-extern int *__error(void);
-#define errno (*__error())
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
diff --git a/SDKs/darwin/usr/include/sys/fcntl.h b/SDKs/darwin/usr/include/sys/fcntl.h
deleted file mode 100644
index 96b2438..0000000
--- a/SDKs/darwin/usr/include/sys/fcntl.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef _SYS_FCNTL_H_
-#define _SYS_FCNTL_H_
-
-/* Determine the appropriate open function. */
-#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
-#  if defined(__i386)
-#    define __OPEN_NAME  "_open$UNIX2003"
-#  elif defined(__x86_64__)
-#    define __OPEN_NAME  "_open"
-#  elif defined(__arm) || defined(__arm64)
-#    define __OPEN_NAME  "_open"
-#  else
-#    error "unrecognized architecture for targeting OS X"
-#  endif
-#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
-#  if defined(__i386) || defined (__x86_64)
-#    define __OPEN_NAME  "_open"
-#  elif defined(__arm) || defined(__arm64)
-#    define __OPEN_NAME  "_open"
-#  else
-#    error "unrecognized architecture for targeting iOS"
-#  endif
-#else
-#  error "unrecognized architecture for targeting Darwin"
-#endif
-
-#define O_RDONLY   0x0000    /* open for reading only */
-#define O_WRONLY   0x0001    /* open for writing only */
-#define O_RDWR     0x0002    /* open for reading and writing */
-#define O_ACCMODE  0x0003    /* mask for above modes */
-
-#define O_CREAT    0x0200    /* create if nonexistent */
-
-int open(const char *, int, ...) __asm(__OPEN_NAME);
-
-#endif /* !_SYS_FCNTL_H_ */
diff --git a/SDKs/darwin/usr/include/sys/mman.h b/SDKs/darwin/usr/include/sys/mman.h
deleted file mode 100644
index 84561f1..0000000
--- a/SDKs/darwin/usr/include/sys/mman.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ===-- mman.h - stub SDK header for compiler-rt ---------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __SYS_MMAN_H__
-#define __SYS_MMAN_H__
-
-typedef __SIZE_TYPE__ size_t;
-
-#define PROT_NONE     0x00
-#define PROT_READ     0x01
-#define PROT_WRITE    0x02
-#define PROT_EXEC     0x04
-
-#define MAP_SHARED    0x0001
-#define MAP_PRIVATE   0x0002
-
-#define MAP_FILE      0x0000
-#define MAP_ANON      0x1000
-
-#define MS_ASYNC      0x0001
-#define MS_INVALIDATE 0x0002
-#define MS_SYNC       0x0010
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd,
-           long long offset);
-int munmap(void *addr, size_t len);
-int msync(void *addr, size_t len, int flags);
-
-#endif /* __SYS_MMAN_H__ */
diff --git a/SDKs/darwin/usr/include/sys/stat.h b/SDKs/darwin/usr/include/sys/stat.h
deleted file mode 100644
index 6225f90..0000000
--- a/SDKs/darwin/usr/include/sys/stat.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ===-- stat.h - stub SDK header for compiler-rt ---------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __SYS_STAT_H__
-#define __SYS_STAT_H__
-
-typedef unsigned short uint16_t;
-typedef uint16_t mode_t;
-
-int mkdir(const char *, mode_t);
-
-#endif /* __SYS_STAT_H__ */
diff --git a/SDKs/darwin/usr/include/sys/types.h b/SDKs/darwin/usr/include/sys/types.h
deleted file mode 100644
index b425767..0000000
--- a/SDKs/darwin/usr/include/sys/types.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* ===-- types.h - stub SDK header for compiler-rt --------------------------===
- *
- *                     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 is a stub SDK header file. This file is not part of the interface of
- * this library nor an official version of the appropriate SDK header. It is
- * intended only to stub the features of this header required by compiler-rt.
- *
- * ===-----------------------------------------------------------------------===
- */
-
-#ifndef __SYS_TYPES_H__
-#define __SYS_TYPES_H__
-
-#endif /* __SYS_TYPES_H__ */
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index 0f6260a..aafccd4 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -43,7 +43,8 @@
 # add_compiler_rt_runtime(<name> <arch> {STATIC,SHARED}
 #                         SOURCES <source files>
 #                         CFLAGS <compile flags>
-#                         DEFS <compile definitions>)
+#                         DEFS <compile definitions>
+#                         OUTPUT_NAME <output library name>)
 macro(add_compiler_rt_runtime name arch type)
   if(CAN_TARGET_${arch})
     parse_arguments(LIB "SOURCES;CFLAGS;DEFS;OUTPUT_NAME" "" ${ARGN})
@@ -59,7 +60,10 @@
     set_target_properties(${name} PROPERTIES
       ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
       LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
-    if (LIB_OUTPUT_NAME)
+    if ("${LIB_OUTPUT_NAME}" STREQUAL "")
+      set_target_properties(${name} PROPERTIES
+        OUTPUT_NAME ${name}${COMPILER_RT_OS_SUFFIX})
+    else()
       set_target_properties(${name} PROPERTIES
         OUTPUT_NAME ${LIB_OUTPUT_NAME})
     endif()
@@ -138,6 +142,12 @@
 
   # gtest use a lot of stuff marked as deprecated on Windows.
   list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
+
+  # Visual Studio 2012 only supports up to 8 template parameters in
+  # std::tr1::tuple by default, but gtest requires 10
+  if(MSVC_VERSION EQUAL 1700)
+    list(APPEND COMPILER_RT_GTEST_CFLAGS -D_VARIADIC_MAX=10)
+  endif()
 endif()
 
 # Link objects into a single executable with COMPILER_RT_TEST_COMPILER,
diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake
index 2d1dd22..af3df8f 100644
--- a/cmake/Modules/CompilerRTCompile.cmake
+++ b/cmake/Modules/CompilerRTCompile.cmake
@@ -11,6 +11,9 @@
   if(NOT COMPILER_RT_STANDALONE_BUILD)
     list(APPEND SOURCE_DEPS clang)
   endif()
+  if (TARGET CompilerRTUnitTestCheckCxx)
+    list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
+  endif()
   string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
   if(is_cxx)
     string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
@@ -36,3 +39,43 @@
     MAIN_DEPENDENCY ${source}
     DEPENDS ${SOURCE_DEPS})
 endmacro()
+
+# On Darwin, there are no system-wide C++ headers and the just-built clang is
+# therefore not able to compile C++ files unless they are copied/symlinked into
+# ${LLVM_BINARY_DIR}/include/c++
+# The just-built clang is used to build compiler-rt unit tests. Let's detect
+# this before we try to build the tests and print out a suggestion how to fix
+# it.
+# On other platforms, this is currently not an issue.
+macro(clang_compiler_add_cxx_check)
+  if (APPLE)
+    set(CMD
+      "echo '#include <iostream>' | ${COMPILER_RT_TEST_COMPILER} -E -x c++ - > /dev/null"
+      "if [ $? != 0 ] "
+      "  then echo"
+      "  echo 'Your just-built clang cannot find C++ headers, which are needed to build and run compiler-rt tests.'"
+      "  echo 'You should copy or symlink your system C++ headers into ${LLVM_BINARY_DIR}/include/c++'"
+      "  if [ -d $(dirname $(dirname $(xcrun -f clang)))/include/c++ ]"
+      "    then echo 'e.g. with:'"
+      "    echo '  cp -r' $(dirname $(dirname $(xcrun -f clang)))/include/c++ '${LLVM_BINARY_DIR}/include/'"
+      "  elif [ -d $(dirname $(dirname $(xcrun -f clang)))/lib/c++ ]"
+      "    then echo 'e.g. with:'"
+      "    echo '  cp -r' $(dirname $(dirname $(xcrun -f clang)))/lib/c++ '${LLVM_BINARY_DIR}/include/'"
+      "  fi"
+      "  echo 'This can also be fixed by checking out the libcxx project from llvm.org and installing the headers'"
+      "  echo 'into your build directory:'"
+      "  echo '  cd ${LLVM_SOURCE_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
+      "  echo '  cd ${LLVM_BINARY_DIR} && make -C ${LLVM_SOURCE_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
+      "  echo"
+      "  false"
+      "fi"
+      )
+    add_custom_target(CompilerRTUnitTestCheckCxx
+      COMMAND bash -c "${CMD}"
+      COMMENT "Checking that just-built clang can find C++ headers..."
+      VERBATIM)
+    if (TARGET clang)
+      ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
+    endif()
+  endif()
+endmacro()
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index e22e775..ae59732 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -2,6 +2,7 @@
 # define a handy helper function for it. The compile flags setting in CMake
 # has serious issues that make its syntax challenging at best.
 function(set_target_compile_flags target)
+  set(argstring "")
   foreach(arg ${ARGN})
     set(argstring "${argstring} ${arg}")
   endforeach()
@@ -9,24 +10,13 @@
 endfunction()
 
 function(set_target_link_flags target)
+  set(argstring "")
   foreach(arg ${ARGN})
     set(argstring "${argstring} ${arg}")
   endforeach()
   set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
 endfunction()
 
-# Check if a given flag is present in a space-separated flag_string.
-# Store the result in out_var.
-function(find_flag_in_string flag_string flag out_var)
-  string(REPLACE " " ";" flag_list "${flag_string}")
-  list(FIND flag_list ${flag} flag_pos)
-  if(NOT flag_pos EQUAL -1)
-    set(${out_var} TRUE PARENT_SCOPE)
-  else()
-    set(${out_var} FALSE PARENT_SCOPE)
-  endif()
-endfunction()
-
 # Set the variable var_PYBOOL to True if var holds a true-ish string,
 # otherwise set it to False.
 macro(pythonize_bool var)
@@ -38,7 +28,7 @@
 endmacro()
 
 # Appends value to all lists in ARGN, if the condition is true.
-macro(append_if condition value)
+macro(append_list_if condition value)
   if(${condition})
     foreach(list ${ARGN})
       list(APPEND ${list} ${value})
@@ -56,6 +46,6 @@
 endmacro()
 
 macro(append_no_rtti_flag list)
-  append_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
-  append_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
+  append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
+  append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
 endmacro()
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 9902b44..90ab7fb 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -32,19 +32,227 @@
 check_cxx_compiler_flag(-Werror COMPILER_RT_HAS_WERROR_FLAG)
 check_cxx_compiler_flag("-Werror -Wframe-larger-than=512" COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG)
 check_cxx_compiler_flag("-Werror -Wglobal-constructors"   COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG)
-check_cxx_compiler_flag("-Werror -Wno-c99-extensions"     COMPILER_RT_HAS_WNO_C99_EXTENSIONS_FLAG)
-check_cxx_compiler_flag("-Werror -Wno-gnu"                COMPILER_RT_HAS_WNO_GNU_FLAG)
-check_cxx_compiler_flag("-Werror -Wno-non-virtual-dtor"   COMPILER_RT_HAS_WNO_NON_VIRTUAL_DTOR_FLAG)
-check_cxx_compiler_flag("-Werror -Wno-variadic-macros"    COMPILER_RT_HAS_WNO_VARIADIC_MACROS_FLAG)
+check_cxx_compiler_flag("-Werror -Wc99-extensions"     COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG)
+check_cxx_compiler_flag("-Werror -Wgnu"                COMPILER_RT_HAS_WGNU_FLAG)
+check_cxx_compiler_flag("-Werror -Wnon-virtual-dtor"   COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG)
+check_cxx_compiler_flag("-Werror -Wvariadic-macros"    COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG)
 
 check_cxx_compiler_flag(/W3 COMPILER_RT_HAS_W3_FLAG)
 check_cxx_compiler_flag(/WX COMPILER_RT_HAS_WX_FLAG)
+check_cxx_compiler_flag(/wd4146 COMPILER_RT_HAS_WD4146_FLAG)
+check_cxx_compiler_flag(/wd4291 COMPILER_RT_HAS_WD4291_FLAG)
+check_cxx_compiler_flag(/wd4391 COMPILER_RT_HAS_WD4391_FLAG)
 check_cxx_compiler_flag(/wd4722 COMPILER_RT_HAS_WD4722_FLAG)
+check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG)
 
 # Symbols.
 check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
 
 # Libraries.
-check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
+check_library_exists(c printf "" COMPILER_RT_HAS_LIBC)
 check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL)
+check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
 check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD)
+check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
+
+# Architectures.
+
+# List of all architectures we can target.
+set(COMPILER_RT_SUPPORTED_ARCH)
+
+# Try to compile a very simple source file to ensure we can target the given
+# platform. We use the results of these tests to build only the various target
+# runtime libraries supported by our current compilers cross-compiling
+# abilities.
+set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
+file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <limits>\nint main() {}\n")
+
+# test_target_arch(<arch> <target flags...>)
+# Sets the target flags for a given architecture and determines if this
+# architecture is supported by trying to build a simple file.
+macro(test_target_arch arch)
+  set(TARGET_${arch}_CFLAGS ${ARGN})
+  set(argstring "${CMAKE_EXE_LINKER_FLAGS}")
+  foreach(arg ${ARGN})
+    set(argstring "${argstring} ${arg}")
+  endforeach()
+  try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
+              COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
+              OUTPUT_VARIABLE TARGET_${arch}_OUTPUT
+              CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${argstring}")
+  if(${CAN_TARGET_${arch}})
+    list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+  elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "${arch}")
+    # Bail out if we cannot target the architecture we plan to test.
+    message(FATAL_ERROR "Cannot compile for ${arch}:\n${TARGET_${arch}_OUTPUT}")
+  endif()
+endmacro()
+
+# Add $arch as supported with no additional flags.
+macro(add_default_target_arch arch)
+  set(TARGET_${arch}_CFLAGS "")
+  set(CAN_TARGET_${arch} 1)
+  list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
+endmacro()
+
+macro(detect_target_arch)
+  check_symbol_exists(__arm__ "" __ARM)
+  check_symbol_exists(__aarch64__ "" __AARCH64)
+  check_symbol_exists(__x86_64__ "" __X86_64)
+  check_symbol_exists(__i686__ "" __I686)
+  check_symbol_exists(__i386__ "" __I386)
+  check_symbol_exists(__mips__ "" __MIPS)
+  check_symbol_exists(__mips64__ "" __MIPS64)
+  if(__ARM)
+    add_default_target_arch(arm)
+  elseif(__AARCH64)
+    add_default_target_arch(aarch64)
+  elseif(__X86_64)
+    add_default_target_arch(x86_64)
+  elseif(__I686)
+    add_default_target_arch(i686)
+  elseif(__I386)
+    add_default_target_arch(i386)
+  elseif(__MIPS64) # must be checked before __MIPS
+    add_default_target_arch(mips64)
+  elseif(__MIPS)
+    add_default_target_arch(mips)
+  endif()
+endmacro()
+
+# Generate the COMPILER_RT_SUPPORTED_ARCH list.
+if(ANDROID)
+  # Can't rely on LLVM_NATIVE_ARCH in cross-compilation.
+  # Examine compiler output instead.
+  detect_target_arch()
+  set(COMPILER_RT_OS_SUFFIX "-android")
+else()
+  if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
+    if (NOT MSVC)
+      test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
+    endif()
+    test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
+  elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
+    test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
+    test_target_arch(powerpc64le ${TARGET_64_BIT_CFLAGS})
+  elseif("${LLVM_NATIVE_ARCH}" STREQUAL "Mips")
+    if("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "mipsel|mips64el")
+      # regex for mipsel, mips64el
+      test_target_arch(mipsel ${TARGET_32_BIT_CFLAGS})
+      test_target_arch(mips64el ${TARGET_64_BIT_CFLAGS})
+    else()
+      test_target_arch(mips ${TARGET_32_BIT_CFLAGS})
+      test_target_arch(mips64 ${TARGET_64_BIT_CFLAGS})
+    endif()
+  elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "arm")
+    test_target_arch(arm "-march=armv7-a")
+  elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "aarch32")
+    test_target_arch(aarch32 "-march=armv8-a")
+  elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "aarch64")
+    test_target_arch(aarch64 "-march=aarch64")
+  endif()
+  set(COMPILER_RT_OS_SUFFIX "")
+endif()
+
+message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
+
+# Takes ${ARGN} and puts only supported architectures in @out_var list.
+function(filter_available_targets out_var)
+  set(archs)
+  foreach(arch ${ARGN})
+    list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
+    if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
+      list(APPEND archs ${arch})
+    endif()
+  endforeach()
+  set(${out_var} ${archs} PARENT_SCOPE)
+endfunction()
+
+# Arhcitectures supported by compiler-rt libraries.
+filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
+  x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mips64 mipsel mips64el)
+filter_available_targets(ASAN_SUPPORTED_ARCH
+  x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el)
+filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64)
+filter_available_targets(LSAN_SUPPORTED_ARCH x86_64)
+# LSan common files should be available on all architectures supported
+# by other sanitizers (even if they build into dummy object files).
+filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
+  ${SANITIZER_COMMON_SUPPORTED_ARCH})
+filter_available_targets(MSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
+filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64
+  mipsel mips64el aarch64 powerpc64 powerpc64le)
+filter_available_targets(TSAN_SUPPORTED_ARCH x86_64)
+filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel)
+
+if(ANDROID)
+  set(OS_NAME "Android")
+else()
+  set(OS_NAME "${CMAKE_SYSTEM_NAME}")
+endif()
+
+if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
+    (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD" OR
+    (OS_NAME MATCHES "Windows" AND MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)))
+  set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
+else()
+  set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH)
+  set(COMPILER_RT_HAS_ASAN TRUE)
+else()
+  set(COMPILER_RT_HAS_ASAN FALSE)
+endif()
+
+# TODO: Add builtins support.
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND DFSAN_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Linux")
+  set(COMPILER_RT_HAS_DFSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_DFSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+  set(COMPILER_RT_HAS_LSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_LSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_COMMON_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android")
+  set(COMPILER_RT_HAS_LSAN_COMMON TRUE)
+else()
+  set(COMPILER_RT_HAS_LSAN_COMMON FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Linux")
+  set(COMPILER_RT_HAS_MSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_MSAN FALSE)
+endif()
+
+if (PROFILE_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+  set(COMPILER_RT_HAS_PROFILE TRUE)
+else()
+  set(COMPILER_RT_HAS_PROFILE FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Linux|FreeBSD")
+  set(COMPILER_RT_HAS_TSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_TSAN FALSE)
+endif()
+
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
+  set(COMPILER_RT_HAS_UBSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_UBSAN FALSE)
+endif()
+
diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h
index 23fc178..4353914 100644
--- a/include/sanitizer/asan_interface.h
+++ b/include/sanitizer/asan_interface.h
@@ -55,13 +55,55 @@
   // Otherwise returns 0.
   int __asan_address_is_poisoned(void const volatile *addr);
 
-  // If at least on byte in [beg, beg+size) is poisoned, return the address
+  // If at least one byte in [beg, beg+size) is poisoned, return the address
   // of the first such byte. Otherwise return 0.
   void *__asan_region_is_poisoned(void *beg, size_t size);
 
   // Print the description of addr (useful when debugging in gdb).
   void __asan_describe_address(void *addr);
 
+  // Useful for calling from a debugger to get information about an ASan error.
+  // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+  int __asan_report_present();
+
+  // Useful for calling from a debugger to get information about an ASan error.
+  // If an error has been (or is being) reported, the following functions return
+  // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
+  // bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
+  void *__asan_get_report_pc();
+  void *__asan_get_report_bp();
+  void *__asan_get_report_sp();
+  void *__asan_get_report_address();
+  int __asan_get_report_access_type();
+  size_t __asan_get_report_access_size();
+  const char *__asan_get_report_description();
+
+  // Useful for calling from the debugger to get information about a pointer.
+  // Returns the category of the given pointer as a constant string.
+  // Possible return values are "global", "stack", "stack-fake", "heap",
+  // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+  // If global or stack, tries to also return the variable name, address and
+  // size. If heap, tries to return the chunk address and size. 'name' should
+  // point to an allocated buffer of size 'name_size'.
+  const char *__asan_locate_address(void *addr, char *name, size_t name_size,
+                                    void **region_address, size_t *region_size);
+
+  // Useful for calling from the debugger to get the allocation stack trace
+  // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+  // returns the number of stored frames or 0 on error.
+  size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
+                                int *thread_id);
+
+  // Useful for calling from the debugger to get the free stack trace
+  // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
+  // returns the number of stored frames or 0 on error.
+  size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
+                               int *thread_id);
+
+  // Useful for calling from the debugger to get the current shadow memory
+  // mapping.
+  void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
+
   // This is an internal function that is called to report an error.
   // However it is still a part of the interface because users may want to
   // set a breakpoint on this function in a debugger.
@@ -83,46 +125,6 @@
   // the program crashes before ASan report is printed.
   void __asan_on_error();
 
-  // Returns the estimated number of bytes that will be reserved by allocator
-  // for request of "size" bytes. If ASan allocator can't allocate that much
-  // memory, returns the maximal possible allocation size, otherwise returns
-  // "size".
-  /* DEPRECATED: Use __sanitizer_get_estimated_allocated_size instead. */
-  size_t __asan_get_estimated_allocated_size(size_t size);
-
-  // Returns 1 if p was returned by the ASan allocator and is not yet freed.
-  // Otherwise returns 0.
-  /* DEPRECATED: Use __sanitizer_get_ownership instead. */
-  int __asan_get_ownership(const void *p);
-
-  // Returns the number of bytes reserved for the pointer p.
-  // Requires (get_ownership(p) == true) or (p == 0).
-  /* DEPRECATED: Use __sanitizer_get_allocated_size instead. */
-  size_t __asan_get_allocated_size(const void *p);
-
-  // Number of bytes, allocated and not yet freed by the application.
-  /* DEPRECATED: Use __sanitizer_get_current_allocated_bytes instead. */
-  size_t __asan_get_current_allocated_bytes();
-
-  // Number of bytes, mmaped by asan allocator to fulfill allocation requests.
-  // Generally, for request of X bytes, allocator can reserve and add to free
-  // lists a large number of chunks of size X to use them for future requests.
-  // All these chunks count toward the heap size. Currently, allocator never
-  // releases memory to OS (instead, it just puts freed chunks to free lists).
-  /* DEPRECATED: Use __sanitizer_get_heap_size instead. */
-  size_t __asan_get_heap_size();
-
-  // Number of bytes, mmaped by asan allocator, which can be used to fulfill
-  // allocation requests. When a user program frees memory chunk, it can first
-  // fall into quarantine and will count toward __asan_get_free_bytes() later.
-  /* DEPRECATED: Use __sanitizer_get_free_bytes instead. */
-  size_t __asan_get_free_bytes();
-
-  // Number of bytes in unmapped pages, that are released to OS. Currently,
-  // always returns 0.
-  /* DEPRECATED: Use __sanitizer_get_unmapped_bytes instead. */
-  size_t __asan_get_unmapped_bytes();
-
   // Prints accumulated stats to stderr. Used for debugging.
   void __asan_print_accumulated_stats();
 
@@ -130,15 +132,6 @@
   // a string containing ASan runtime options. See asan_flags.h for details.
   const char* __asan_default_options();
 
-  // Malloc hooks that may be optionally provided by user.
-  // __asan_malloc_hook(ptr, size) is called immediately after
-  //   allocation of "size" bytes, which returned "ptr".
-  // __asan_free_hook(ptr) is called immediately before
-  //   deallocation of "ptr".
-  /* DEPRECATED: Use __sanitizer_malloc_hook / __sanitizer_free_hook instead. */
-  void __asan_malloc_hook(void *ptr, size_t size);
-  void __asan_free_hook(void *ptr);
-
   // The following 2 functions facilitate garbage collection in presence of
   // asan's fake stack.
 
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h
index 082a931..9cb5ad8 100644
--- a/include/sanitizer/common_interface_defs.h
+++ b/include/sanitizer/common_interface_defs.h
@@ -70,6 +70,9 @@
   // descriptor. Returns -1 on failure, or if coverage dumping is disabled.
   // This is intended for use by sandboxing code.
   intptr_t __sanitizer_maybe_open_cov_file(const char *name);
+  // Get the number of total unique covered entities (blocks, edges, calls).
+  // This can be useful for coverage-directed in-process fuzzers.
+  uintptr_t __sanitizer_get_total_unique_coverage();
 
   // Annotate the current state of a contiguous container, such as
   // std::vector, std::string or similar.
@@ -105,7 +108,7 @@
                                                  const void *end,
                                                  const void *old_mid,
                                                  const void *new_mid);
-  // Returns true if the contiguous container [beg, end) ir properly poisoned
+  // Returns true if the contiguous container [beg, end) is properly poisoned
   // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if
   //  - [beg, mid) is addressable,
   //  - [mid, end) is unaddressable.
diff --git a/include/sanitizer/dfsan_interface.h b/include/sanitizer/dfsan_interface.h
index bcd4ae0..79dbf2f 100644
--- a/include/sanitizer/dfsan_interface.h
+++ b/include/sanitizer/dfsan_interface.h
@@ -85,6 +85,12 @@
 /// callback executes.  Pass in NULL to remove any callback.
 void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
 
+/// Writes the labels currently used by the program to the given file
+/// descriptor. The lines of the output have the following format:
+///
+/// <label> <parent label 1> <parent label 2> <label description if any>
+void dfsan_dump_labels(int fd);
+
 #ifdef __cplusplus
 }  // extern "C"
 
diff --git a/include/sanitizer/msan_interface.h b/include/sanitizer/msan_interface.h
index f6a62be..5be5860 100644
--- a/include/sanitizer/msan_interface.h
+++ b/include/sanitizer/msan_interface.h
@@ -93,60 +93,6 @@
      Passing 0 will unset the callback. */
   void __msan_set_death_callback(void (*callback)(void));
 
-  /***********************************/
-  /* Allocator statistics interface. */
-
-  /* Returns the estimated number of bytes that will be reserved by allocator
-     for request of "size" bytes. If Msan allocator can't allocate that much
-     memory, returns the maximal possible allocation size, otherwise returns
-     "size". */
-  /* DEPRECATED: Use __sanitizer_get_estimated_allocated_size instead. */
-  size_t __msan_get_estimated_allocated_size(size_t size);
-
-  /* Returns true if p was returned by the Msan allocator and
-     is not yet freed. */
-  /* DEPRECATED: Use __sanitizer_get_ownership instead. */
-  int __msan_get_ownership(const volatile void *p);
-
-  /* Returns the number of bytes reserved for the pointer p.
-     Requires (get_ownership(p) == true) or (p == 0). */
-  /* DEPRECATED: Use __sanitizer_get_allocated_size instead. */
-  size_t __msan_get_allocated_size(const volatile void *p);
-
-  /* Number of bytes, allocated and not yet freed by the application. */
-  /* DEPRECATED: Use __sanitizer_get_current_allocated_bytes instead. */
-  size_t __msan_get_current_allocated_bytes();
-
-  /* Number of bytes, mmaped by msan allocator to fulfill allocation requests.
-     Generally, for request of X bytes, allocator can reserve and add to free
-     lists a large number of chunks of size X to use them for future requests.
-     All these chunks count toward the heap size. Currently, allocator never
-     releases memory to OS (instead, it just puts freed chunks to free
-     lists). */
-  /* DEPRECATED: Use __sanitizer_get_heap_size instead. */
-  size_t __msan_get_heap_size();
-
-  /* Number of bytes, mmaped by msan allocator, which can be used to fulfill
-     allocation requests. When a user program frees memory chunk, it can first
-     fall into quarantine and will count toward __msan_get_free_bytes()
-     later. */
-  /* DEPRECATED: Use __sanitizer_get_free_bytes instead. */
-  size_t __msan_get_free_bytes();
-
-  /* Number of bytes in unmapped pages, that are released to OS. Currently,
-     always returns 0. */
-  /* DEPRECATED: Use __sanitizer_get_unmapped_bytes instead. */
-  size_t __msan_get_unmapped_bytes();
-
-  /* Malloc hooks that may be optionally provided by user.
-     __msan_malloc_hook(ptr, size) is called immediately after
-       allocation of "size" bytes, which returned "ptr".
-     __msan_free_hook(ptr) is called immediately before
-       deallocation of "ptr". */
-  /* DEPRECATED: Use __sanitizer_malloc_hook / __sanitizer_free_hook instead. */
-  void __msan_malloc_hook(const volatile void *ptr, size_t size);
-  void __msan_free_hook(const volatile void *ptr);
-
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index fcde9a2..6929e68 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -3,37 +3,40 @@
 
 include(AddCompilerRT)
 include(SanitizerUtils)
-# Don't build sanitizers in the bootstrap build.
-if(NOT LLVM_USE_SANITIZER)
-  # AddressSanitizer is supported on Linux, FreeBSD and Mac OS X.
-  # 32-bit Windows support is experimental.
-  if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD")
-    set(SUPPORTS_BUILDING_ASAN TRUE)
-  elseif(CMAKE_SYSTEM_NAME MATCHES "Windows"
-         AND MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
-    set(SUPPORTS_BUILDING_ASAN TRUE)
-  else()
-    set(SUPPORTS_BUILDING_ASAN FALSE)
-  endif()
-  if(SUPPORTS_BUILDING_ASAN)
-    add_subdirectory(asan)
-    add_subdirectory(interception)
-    add_subdirectory(sanitizer_common)
-  endif()
-  if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD" AND NOT ANDROID)
-    # LSan, UBsan and profile can be built on Mac OS, FreeBSD and Linux.
-    add_subdirectory(lsan)
-    add_subdirectory(profile)
-    add_subdirectory(ubsan)
-  endif()
-  if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID)
-    # ThreadSanitizer and MemorySanitizer are supported on Linux only.
-    add_subdirectory(tsan)
-    add_subdirectory(tsan/dd)
-    add_subdirectory(msan)
-    add_subdirectory(msandr)
-    add_subdirectory(dfsan)
-  endif()
+
+if(COMPILER_RT_HAS_SANITIZER_COMMON)
+  add_subdirectory(interception)
+  add_subdirectory(sanitizer_common)
+endif()
+
+if(COMPILER_RT_HAS_ASAN)
+  add_subdirectory(asan)
 endif()
 
 add_subdirectory(builtins)
+
+if(COMPILER_RT_HAS_DFSAN)
+  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()
+
+if(COMPILER_RT_HAS_PROFILE)
+  add_subdirectory(profile)
+endif()
+
+if(COMPILER_RT_HAS_TSAN)
+  add_subdirectory(tsan)
+  add_subdirectory(tsan/dd)
+endif()
+
+if(COMPILER_RT_HAS_UBSAN)
+  add_subdirectory(ubsan)
+endif()
+
diff --git a/lib/asan/Android.mk b/lib/asan/Android.mk
index 3dd5959..322e07f 100644
--- a/lib/asan/Android.mk
+++ b/lib/asan/Android.mk
@@ -22,62 +22,66 @@
 ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
 
 asan_rtl_files := \
-	asan_activation.cc	\
-	asan_allocator2.cc	\
-	asan_fake_stack.cc \
-	asan_globals.cc	\
-	asan_interceptors.cc	\
-	asan_linux.cc \
-	asan_mac.cc \
-	asan_malloc_linux.cc \
-	asan_malloc_mac.cc \
-	asan_malloc_win.cc \
-	asan_new_delete.cc	\
-	asan_poisoning.cc	\
-	asan_posix.cc \
-	asan_report.cc	\
-	asan_rtl.cc \
-	asan_stack.cc	\
-	asan_stats.cc	\
-	asan_thread.cc	\
-	asan_win.cc \
-	../interception/interception_linux.cc \
-	../lsan/lsan_common.cc \
-	../lsan/lsan_common_linux.cc \
-	../sanitizer_common/sanitizer_allocator.cc \
-	../sanitizer_common/sanitizer_common.cc \
-	../sanitizer_common/sanitizer_common_libcdep.cc \
-	../sanitizer_common/sanitizer_coverage_libcdep.cc \
-	../sanitizer_common/sanitizer_coverage_mapping_libcdep.cc \
-	../sanitizer_common/sanitizer_deadlock_detector1.cc \
-	../sanitizer_common/sanitizer_deadlock_detector2.cc \
-	../sanitizer_common/sanitizer_flags.cc \
-	../sanitizer_common/sanitizer_libc.cc \
-	../sanitizer_common/sanitizer_libignore.cc \
-	../sanitizer_common/sanitizer_linux.cc \
-	../sanitizer_common/sanitizer_linux_libcdep.cc \
-	../sanitizer_common/sanitizer_mac.cc \
-	../sanitizer_common/sanitizer_persistent_allocator.cc \
-	../sanitizer_common/sanitizer_platform_limits_linux.cc \
-	../sanitizer_common/sanitizer_platform_limits_posix.cc \
-	../sanitizer_common/sanitizer_posix.cc \
-	../sanitizer_common/sanitizer_posix_libcdep.cc \
-	../sanitizer_common/sanitizer_printf.cc \
-	../sanitizer_common/sanitizer_procmaps_linux.cc \
-	../sanitizer_common/sanitizer_procmaps_mac.cc \
-	../sanitizer_common/sanitizer_stackdepot.cc \
-	../sanitizer_common/sanitizer_stacktrace.cc \
-	../sanitizer_common/sanitizer_stacktrace_libcdep.cc \
-	../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc \
-	../sanitizer_common/sanitizer_suppressions.cc \
-	../sanitizer_common/sanitizer_symbolizer.cc \
-	../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc \
-	../sanitizer_common/sanitizer_symbolizer_libcdep.cc \
-	../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc \
-	../sanitizer_common/sanitizer_symbolizer_win.cc \
-	../sanitizer_common/sanitizer_thread_registry.cc \
-	../sanitizer_common/sanitizer_tls_get_addr.cc \
-	../sanitizer_common/sanitizer_win.cc
+  asan_activation.cc \
+  asan_allocator2.cc \
+  asan_fake_stack.cc \
+  asan_globals.cc \
+  asan_interceptors.cc \
+  asan_linux.cc \
+  asan_mac.cc \
+  asan_malloc_linux.cc \
+  asan_malloc_mac.cc \
+  asan_malloc_win.cc \
+  asan_new_delete.cc \
+  asan_poisoning.cc \
+  asan_posix.cc \
+  asan_report.cc \
+  asan_rtl.cc \
+  asan_stack.cc \
+  asan_stats.cc \
+  asan_thread.cc \
+  asan_win.cc \
+  ../interception/interception_linux.cc \
+  ../lsan/lsan_common.cc \
+  ../lsan/lsan_common_linux.cc \
+  ../sanitizer_common/sanitizer_allocator.cc \
+  ../sanitizer_common/sanitizer_common.cc \
+  ../sanitizer_common/sanitizer_common_libcdep.cc \
+  ../sanitizer_common/sanitizer_coverage_libcdep.cc \
+  ../sanitizer_common/sanitizer_coverage_mapping_libcdep.cc \
+  ../sanitizer_common/sanitizer_deadlock_detector1.cc \
+  ../sanitizer_common/sanitizer_deadlock_detector2.cc \
+  ../sanitizer_common/sanitizer_flags.cc \
+  ../sanitizer_common/sanitizer_libc.cc \
+  ../sanitizer_common/sanitizer_libignore.cc \
+  ../sanitizer_common/sanitizer_linux.cc \
+  ../sanitizer_common/sanitizer_linux_libcdep.cc \
+  ../sanitizer_common/sanitizer_mac.cc \
+  ../sanitizer_common/sanitizer_persistent_allocator.cc \
+  ../sanitizer_common/sanitizer_platform_limits_linux.cc \
+  ../sanitizer_common/sanitizer_platform_limits_posix.cc \
+  ../sanitizer_common/sanitizer_posix.cc \
+  ../sanitizer_common/sanitizer_posix_libcdep.cc \
+  ../sanitizer_common/sanitizer_printf.cc \
+  ../sanitizer_common/sanitizer_procmaps_common.cc \
+  ../sanitizer_common/sanitizer_procmaps_freebsd.cc \
+  ../sanitizer_common/sanitizer_procmaps_linux.cc \
+  ../sanitizer_common/sanitizer_procmaps_mac.cc \
+  ../sanitizer_common/sanitizer_stackdepot.cc \
+  ../sanitizer_common/sanitizer_stacktrace.cc \
+  ../sanitizer_common/sanitizer_stacktrace_libcdep.cc \
+  ../sanitizer_common/sanitizer_stacktrace_printer.cc \
+  ../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc \
+  ../sanitizer_common/sanitizer_suppressions.cc \
+  ../sanitizer_common/sanitizer_symbolizer.cc \
+  ../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc \
+  ../sanitizer_common/sanitizer_symbolizer_libcdep.cc \
+  ../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc \
+  ../sanitizer_common/sanitizer_symbolizer_win.cc \
+  ../sanitizer_common/sanitizer_thread_registry.cc \
+  ../sanitizer_common/sanitizer_tls_get_addr.cc \
+  ../sanitizer_common/sanitizer_unwind_posix_libcdep.cc \
+  ../sanitizer_common/sanitizer_win.cc \
 
 asan_rtl_cflags := \
 	-fvisibility=hidden \
@@ -90,6 +94,7 @@
 	-Wno-non-virtual-dtor \
 	-Wno-sign-compare \
 	-Wno-unused-parameter \
+	-std=c++11
 
 asan_test_files := \
 	tests/asan_globals_test.cc \
@@ -181,7 +186,8 @@
     -DASAN_UAR=0 \
     -DASAN_HAS_BLACKLIST=1 \
     -DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
-    -DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV)
+    -DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV) \
+    -std=c++11
 LOCAL_SRC_FILES := tests/asan_noinst_test.cc tests/asan_test_main.cc
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CLANG := true
@@ -261,7 +267,8 @@
     -DASAN_UAR=0 \
     -DASAN_HAS_BLACKLIST=1 \
     -DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
-    -DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV)
+    -DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV) \
+    -std=c++11
 LOCAL_SRC_FILES := tests/asan_noinst_test.cc tests/asan_test_main.cc
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CLANG := true
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index b23a7a2..6251f06 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -1,15 +1,9 @@
 # Build for the AddressSanitizer runtime support library.
 
-if(APPLE)
-# Don't set rpath for the ASan libraries. Developers are encouraged to ship
-# their binaries together with the corresponding ASan runtime libraries,
-# so they'll anyway need to fix the rpath and the install name.
-set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
-endif()
-
 set(ASAN_SOURCES
   asan_allocator2.cc
   asan_activation.cc
+  asan_debugging.cc
   asan_fake_stack.cc
   asan_globals.cc
   asan_interceptors.cc
@@ -52,14 +46,20 @@
 
 set(ASAN_DYNAMIC_DEFINITIONS
   ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
+append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
 
 set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
-append_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
+append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
   -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
+append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
 
-set(ASAN_DYNAMIC_LIBS stdc++ m c)
-append_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
-append_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
+
+append_list_if(ANDROID log ASAN_DYNAMIC_LIBS)
 
 # Compile ASan sources into an object library.
 if(APPLE)
@@ -70,11 +70,6 @@
       CFLAGS ${ASAN_CFLAGS}
       DEFS ${ASAN_COMMON_DEFINITIONS})
   endforeach()
-elseif(ANDROID)
-  add_library(RTAsan.arm.android OBJECT ${ASAN_SOURCES} ${ASAN_CXX_SOURCES})
-  set_target_compile_flags(RTAsan.arm.android ${ASAN_CFLAGS})
-  set_property(TARGET RTAsan.arm.android APPEND PROPERTY
-    COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
 else()
   foreach(arch ${ASAN_SUPPORTED_ARCH})
     add_compiler_rt_object_library(RTAsan ${arch}
@@ -109,21 +104,6 @@
       DEFS ${ASAN_COMMON_DEFINITIONS})
     add_dependencies(asan clang_rt.asan_${os}_dynamic)
   endforeach()
-
-elseif(ANDROID)
-  add_library(clang_rt.asan-arm-android SHARED
-    $<TARGET_OBJECTS:RTAsan.arm.android>
-    $<TARGET_OBJECTS:RTInterception.arm.android>
-    $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
-  set_target_compile_flags(clang_rt.asan-arm-android
-    ${ASAN_CFLAGS})
-  set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY
-    COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
-  target_link_libraries(clang_rt.asan-arm-android dl log)
-  add_dependencies(asan clang_rt.asan-arm-android)
-  install(TARGETS clang_rt.asan-arm-android
-          ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
-          LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
 else()
   # Build separate libraries for each target.
   foreach(arch ${ASAN_SUPPORTED_ARCH})
@@ -131,7 +111,7 @@
       $<TARGET_OBJECTS:RTInterception.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
-    if (NOT WIN32)
+    if(NOT WIN32)
       # We can't build Leak Sanitizer on Windows yet.
       list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
            $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
@@ -158,8 +138,14 @@
         DEFS ${ASAN_COMMON_DEFINITIONS})
       add_dependencies(asan clang_rt.asan-preinit-${arch})
 
+      if (WIN32)
+         set(SHARED_ASAN_NAME clang_rt.asan_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
+      else()
+         set(SHARED_ASAN_NAME clang_rt.asan-${arch}${COMPILER_RT_OS_SUFFIX})
+      endif()
+
       add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
-        OUTPUT_NAME clang_rt.asan-${arch}
+        OUTPUT_NAME ${SHARED_ASAN_NAME}
         SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
                 ${ASAN_COMMON_RUNTIME_OBJECTS}
         CFLAGS ${ASAN_DYNAMIC_CFLAGS}
@@ -168,7 +154,7 @@
       add_dependencies(asan clang_rt.asan-dynamic-${arch})
     endif()
 
-    if (UNIX AND NOT ${arch} STREQUAL "i386")
+    if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686")
       add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch})
       add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
       add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
@@ -177,11 +163,17 @@
 
     if (WIN32)
       add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
-        SOURCES asan_dll_thunk.cc
+        SOURCES asan_win_dll_thunk.cc
                 $<TARGET_OBJECTS:RTInterception.${arch}>
         CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
         DEFS ${ASAN_COMMON_DEFINITIONS})
       add_dependencies(asan clang_rt.asan_dll_thunk-${arch})
+      add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk-${arch} ${arch}
+        STATIC
+        SOURCES asan_win_dynamic_runtime_thunk.cc
+        CFLAGS ${ASAN_CFLAGS} -DASAN_DYNAMIC_RUNTIME_THUNK -Zl
+        DEFS ${ASAN_COMMON_DEFINITIONS})
+      add_dependencies(asan clang_rt.asan_dynamic_runtime_thunk-${arch})
     endif()
   endforeach()
 endif()
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 6b2324a..6d3a992 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -45,8 +45,8 @@
   uptr AllocTid();
   uptr FreeTid();
   bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
-  void GetAllocStack(StackTrace *stack);
-  void GetFreeStack(StackTrace *stack);
+  StackTrace GetAllocStack();
+  StackTrace GetFreeStack();
   bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
     if (addr >= Beg() && (addr + access_size) <= End()) {
       *offset = addr - Beg();
@@ -139,18 +139,20 @@
   AsanThreadLocalMallocStorage() {}
 };
 
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
                     AllocType alloc_type);
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+                     AllocType alloc_type);
 
-void *asan_malloc(uptr size, StackTrace *stack);
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
-void *asan_realloc(void *p, uptr size, StackTrace *stack);
-void *asan_valloc(uptr size, StackTrace *stack);
-void *asan_pvalloc(uptr size, StackTrace *stack);
+void *asan_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                          StackTrace *stack);
+                        BufferedStackTrace *stack);
 uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
 
 uptr asan_mz_size(const void *ptr);
diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc
index f07b0f0..52bdcf6 100644
--- a/lib/asan/asan_allocator2.cc
+++ b/lib/asan/asan_allocator2.cc
@@ -168,23 +168,6 @@
     }
     return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
   }
-  // If we don't use stack depot, we store the alloc/free stack traces
-  // in the chunk itself.
-  u32 *AllocStackBeg() {
-    return (u32*)(Beg() - RZLog2Size(rz_log));
-  }
-  uptr AllocStackSize() {
-    CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
-    return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
-  }
-  u32 *FreeStackBeg() {
-    return (u32*)(Beg() + kChunkHeader2Size);
-  }
-  uptr FreeStackSize() {
-    if (user_requested_size < kChunkHeader2Size) return 0;
-    uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
-    return (available - kChunkHeader2Size) / sizeof(u32);
-  }
   bool AddrIsInside(uptr addr, bool locked_version = false) {
     return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
   }
@@ -199,20 +182,19 @@
 uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
 uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
 
-static void GetStackTraceFromId(u32 id, StackTrace *stack) {
+static StackTrace GetStackTraceFromId(u32 id) {
   CHECK(id);
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(id, &size);
-  CHECK(trace);
-  stack->CopyFrom(trace, size);
+  StackTrace res = StackDepotGet(id);
+  CHECK(res.trace);
+  return res;
 }
 
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
-  GetStackTraceFromId(chunk_->alloc_context_id, stack);
+StackTrace AsanChunkView::GetAllocStack() {
+  return GetStackTraceFromId(chunk_->alloc_context_id);
 }
 
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
-  GetStackTraceFromId(chunk_->free_context_id, stack);
+StackTrace AsanChunkView::GetFreeStack() {
+  return GetStackTraceFromId(chunk_->free_context_id);
 }
 
 struct QuarantineCallback;
@@ -280,7 +262,7 @@
   quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
 }
 
-static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
+static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
                       AllocType alloc_type, bool can_fill) {
   if (UNLIKELY(!asan_inited))
     AsanInitFromRtl();
@@ -372,7 +354,7 @@
     meta[1] = chunk_beg;
   }
 
-  m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
+  m->alloc_context_id = StackDepotPut(*stack);
 
   uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
   // Unpoison the bulk of the memory region.
@@ -408,15 +390,16 @@
   return res;
 }
 
-static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+static void ReportInvalidFree(void *ptr, u8 chunk_state,
+                              BufferedStackTrace *stack) {
   if (chunk_state == CHUNK_QUARANTINE)
     ReportDoubleFree((uptr)ptr, stack);
   else
     ReportFreeNotMalloced((uptr)ptr, stack);
 }
 
-static void AtomicallySetQuarantineFlag(AsanChunk *m,
-                                        void *ptr, StackTrace *stack) {
+static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+                                        BufferedStackTrace *stack) {
   u8 old_chunk_state = CHUNK_ALLOCATED;
   // Flip the chunk_state atomically to avoid race on double-free.
   if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
@@ -427,8 +410,8 @@
 
 // Expects the chunk to already be marked as quarantined by using
 // AtomicallySetQuarantineFlag.
-static void QuarantineChunk(AsanChunk *m, void *ptr,
-                            StackTrace *stack, AllocType alloc_type) {
+static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+                            AllocType alloc_type) {
   CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
 
   if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
@@ -440,7 +423,7 @@
     CHECK_EQ(m->free_tid, kInvalidTid);
   AsanThread *t = GetCurrentThread();
   m->free_tid = t ? t->tid() : 0;
-  m->free_context_id = StackDepotPut(stack->trace, stack->size);
+  m->free_context_id = StackDepotPut(*stack);
   // Poison the region.
   PoisonShadow(m->Beg(),
                RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -464,19 +447,25 @@
   }
 }
 
-static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
+static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
+                       AllocType alloc_type) {
   uptr p = reinterpret_cast<uptr>(ptr);
   if (p == 0) return;
 
   uptr chunk_beg = p - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+  if (delete_size && flags()->new_delete_type_mismatch &&
+      delete_size != m->UsedSize()) {
+    ReportNewDeleteSizeMismatch(p, delete_size, stack);
+  }
   ASAN_FREE_HOOK(ptr);
   // Must mark the chunk as quarantined before any changes to its metadata.
   AtomicallySetQuarantineFlag(m, ptr, stack);
   QuarantineChunk(m, ptr, stack, alloc_type);
 }
 
-static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
+static void *Reallocate(void *old_ptr, uptr new_size,
+                        BufferedStackTrace *stack) {
   CHECK(old_ptr && new_size);
   uptr p = reinterpret_cast<uptr>(old_ptr);
   uptr chunk_beg = p - kChunkHeaderSize;
@@ -496,7 +485,7 @@
     // If realloc() races with free(), we may start copying freed memory.
     // However, we will report racy double-free later anyway.
     REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
-    Deallocate(old_ptr, stack, FROM_MALLOC);
+    Deallocate(old_ptr, 0, stack, FROM_MALLOC);
   }
   return new_ptr;
 }
@@ -589,20 +578,25 @@
   allocator.PrintStats();
 }
 
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
                     AllocType alloc_type) {
   return Allocate(size, alignment, stack, alloc_type, true);
 }
 
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
-  Deallocate(ptr, stack, alloc_type);
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
+  Deallocate(ptr, 0, stack, alloc_type);
 }
 
-void *asan_malloc(uptr size, StackTrace *stack) {
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
+                     AllocType alloc_type) {
+  Deallocate(ptr, size, stack, alloc_type);
+}
+
+void *asan_malloc(uptr size, BufferedStackTrace *stack) {
   return Allocate(size, 8, stack, FROM_MALLOC, true);
 }
 
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
   if (CallocShouldReturnNullDueToOverflow(size, nmemb))
     return AllocatorReturnNull();
   void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
@@ -613,21 +607,21 @@
   return ptr;
 }
 
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
   if (p == 0)
     return Allocate(size, 8, stack, FROM_MALLOC, true);
   if (size == 0) {
-    Deallocate(p, stack, FROM_MALLOC);
+    Deallocate(p, 0, stack, FROM_MALLOC);
     return 0;
   }
   return Reallocate(p, size, stack);
 }
 
-void *asan_valloc(uptr size, StackTrace *stack) {
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
   return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
 }
 
-void *asan_pvalloc(uptr size, StackTrace *stack) {
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
   uptr PageSize = GetPageSizeCached();
   size = RoundUpTo(size, PageSize);
   if (size == 0) {
@@ -638,7 +632,7 @@
 }
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                        StackTrace *stack) {
+                        BufferedStackTrace *stack) {
   void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
   CHECK(IsAligned((uptr)ptr, alignment));
   *memptr = ptr;
@@ -764,17 +758,11 @@
 uptr __sanitizer_get_estimated_allocated_size(uptr size) {
   return size;
 }
-uptr __asan_get_estimated_allocated_size(uptr size) {
-  return __sanitizer_get_estimated_allocated_size(size);
-}
 
 int __sanitizer_get_ownership(const void *p) {
   uptr ptr = reinterpret_cast<uptr>(p);
   return (AllocationSize(ptr) > 0);
 }
-int __asan_get_ownership(const void *p) {
-  return __sanitizer_get_ownership(p);
-}
 
 uptr __sanitizer_get_allocated_size(const void *p) {
   if (p == 0) return 0;
@@ -787,23 +775,11 @@
   }
   return allocated_size;
 }
-uptr __asan_get_allocated_size(const void *p) {
-  return __sanitizer_get_allocated_size(p);
-}
 
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 // Provide default (no-op) implementation of malloc hooks.
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_malloc_hook(void *ptr, uptr size) {
-  (void)ptr;
-  (void)size;
-}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __asan_free_hook(void *ptr) {
-  (void)ptr;
-}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
 void __sanitizer_malloc_hook(void *ptr, uptr size) {
   (void)ptr;
   (void)size;
diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc
new file mode 100644
index 0000000..2b66dd5
--- /dev/null
+++ b/lib/asan/asan_debugging.cc
@@ -0,0 +1,141 @@
+//===-- asan_debugging.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 a part of AddressSanitizer, an address sanity checker.
+//
+// This file contains various functions that are generally useful to call when
+// using a debugger (LLDB, GDB).
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_flags.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+  descr->name[0] = 0;
+  descr->region_address = 0;
+  descr->region_size = 0;
+  descr->region_kind = "stack";
+
+  AsanThread::StackFrameAccess access;
+  if (!t->GetStackFrameAccessByAddr(addr, &access))
+    return;
+  InternalMmapVector<StackVarDescr> vars(16);
+  if (!ParseFrameDescription(access.frame_descr, &vars)) {
+    return;
+  }
+
+  for (uptr i = 0; i < vars.size(); i++) {
+    if (access.offset <= vars[i].beg + vars[i].size) {
+      internal_strncat(descr->name, vars[i].name_pos,
+                       Min(descr->name_size, vars[i].name_len));
+      descr->region_address = addr - (access.offset - vars[i].beg);
+      descr->region_size = vars[i].size;
+      return;
+    }
+  }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+  AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+  descr->name[0] = 0;
+  descr->region_address = 0;
+  descr->region_size = 0;
+
+  if (!chunk.IsValid()) {
+    descr->region_kind = "heap-invalid";
+    return;
+  }
+
+  descr->region_address = chunk.Beg();
+  descr->region_size = chunk.UsedSize();
+  descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+  if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+    return;
+  }
+  if (GetInfoForAddressIfGlobal(addr, descr)) {
+    return;
+  }
+  asanThreadRegistry().Lock();
+  AsanThread *thread = FindThreadByStackAddress(addr);
+  asanThreadRegistry().Unlock();
+  if (thread) {
+    GetInfoForStackVar(addr, descr, thread);
+    return;
+  }
+  GetInfoForHeapAddress(addr, descr);
+}
+
+uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
+                  bool alloc_stack) {
+  AsanChunkView chunk = FindHeapChunkByAddress(addr);
+  if (!chunk.IsValid()) return 0;
+
+  StackTrace stack(nullptr, 0);
+  if (alloc_stack) {
+    if (chunk.AllocTid() == kInvalidTid) return 0;
+    stack = chunk.GetAllocStack();
+    if (thread_id) *thread_id = chunk.AllocTid();
+  } else {
+    if (chunk.FreeTid() == kInvalidTid) return 0;
+    stack = chunk.GetFreeStack();
+    if (thread_id) *thread_id = chunk.FreeTid();
+  }
+
+  if (trace && size) {
+    size = Min(size, Min(stack.size, kStackTraceMax));
+    for (uptr i = 0; i < size; i++)
+      trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
+
+    return size;
+  }
+
+  return 0;
+}
+
+}  // namespace __asan
+
+using namespace __asan;
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+                                  uptr *region_address, uptr *region_size) {
+  AddressDescription descr = { name, name_size, 0, 0, 0 };
+  AsanLocateAddress(addr, &descr);
+  if (region_address) *region_address = descr.region_address;
+  if (region_size) *region_size = descr.region_size;
+  return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+  return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
+  return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
+  if (shadow_scale)
+    *shadow_scale = SHADOW_SCALE;
+  if (shadow_offset)
+    *shadow_offset = SHADOW_OFFSET;
+}
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 1139204..3df4dd3 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -52,18 +52,20 @@
   bool print_stats;
   bool print_legend;
   bool atexit;
-  bool disable_core;
   bool allow_reexec;
   bool print_full_thread_history;
   bool poison_heap;
   bool poison_partial;
+  bool poison_array_cookie;
   bool alloc_dealloc_mismatch;
+  bool new_delete_type_mismatch;
   bool strict_memcmp;
   bool strict_init_order;
   bool start_deactivated;
   int detect_invalid_pointer_pairs;
   bool detect_container_overflow;
   int detect_odr_violation;
+  bool dump_instruction_bytes;
 };
 
 extern Flags asan_flags_dont_use_directly;
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index a844201..be111d4 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -71,25 +71,64 @@
   }
 }
 
-static void ReportGlobal(const Global &g, const char *prefix) {
-  Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
-         prefix, &g, (void*)g.beg, g.size, g.size_with_redzone, g.name,
-         g.module_name, g.has_dynamic_init);
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+  if (addr >= g.beg + g.size_with_redzone) return false;
+  return true;
 }
 
-bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+static void ReportGlobal(const Global &g, const char *prefix) {
+  Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
+         prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
+         g.module_name, g.has_dynamic_init);
+  if (g.location) {
+    Report("  location (%p): name=%s[%p], %d %d\n", g.location,
+           g.location->filename, g.location->filename, g.location->line_no,
+           g.location->column_no);
+  }
+}
+
+static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
+                                      Global *output_global) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
   bool res = false;
   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
-    if (flags()->report_globals >= 2)
-      ReportGlobal(g, "Search");
-    res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    if (print) {
+      if (flags()->report_globals >= 2)
+        ReportGlobal(g, "Search");
+      res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    } else {
+      if (IsAddressNearGlobal(addr, g)) {
+        CHECK(output_global);
+        *output_global = g;
+        return true;
+      }
+    }
   }
   return res;
 }
 
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+  return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
+                                   /* output_global */ nullptr);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+  Global g = {};
+  if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
+    internal_strncpy(descr->name, g.name, descr->name_size);
+    descr->region_address = g.beg;
+    descr->region_size = g.size;
+    descr->region_kind = "global";
+    return true;
+  }
+  return false;
+}
+
 u32 FindRegistrationSite(const Global *g) {
   CHECK(global_registration_site_vector);
   for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
@@ -178,7 +217,7 @@
 void __asan_register_globals(__asan_global *globals, uptr n) {
   if (!flags()->report_globals) return;
   GET_STACK_TRACE_FATAL_HERE;
-  u32 stack_id = StackDepotPut(stack.trace, stack.size);
+  u32 stack_id = StackDepotPut(stack);
   BlockingMutexLock lock(&mu_for_globals);
   if (!global_registration_site_vector)
     global_registration_site_vector =
diff --git a/lib/asan/asan_init_version.h b/lib/asan/asan_init_version.h
index 88eb80f..77aea81 100644
--- a/lib/asan/asan_init_version.h
+++ b/lib/asan/asan_init_version.h
@@ -15,21 +15,16 @@
 #ifndef ASAN_INIT_VERSION_H
 #define ASAN_INIT_VERSION_H
 
-#include "sanitizer_common/sanitizer_internal_defs.h"
-
 extern "C" {
-  // This function should be called at the very beginning of the process,
-  // before any instrumented code is executed and before any call to malloc.
-  // Every time the ASan ABI changes we also change the version number in this
-  // name. Objects build with incompatible ASan ABI version
-  // will not link with run-time.
+  // Every time the ASan ABI changes we also change the version number in the
+  // __asan_init function name.  Objects built with incompatible ASan ABI
+  // versions will not link with run-time.
   // Changes between ABI versions:
   // v1=>v2: added 'module_name' to __asan_global
   // v2=>v3: stack frame description (created by the compiler)
   //         contains the function PC as the 3-rd field (see
   //         DescribeAddressIfStack).
   // v3=>v4: added '__asan_global_source_location' to __asan_global.
-  SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v4();
   #define __asan_init __asan_init_v4
   #define __asan_init_name "__asan_init_v4"
 }
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 4ae03ec..deac034 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -148,6 +148,7 @@
 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
 #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping()
 #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping()
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
 #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
@@ -221,8 +222,8 @@
 
 namespace __sanitizer {
 int real_sigaction(int signum, const void *act, void *oldact) {
-  return REAL(sigaction)(signum,
-                         (struct sigaction *)act, (struct sigaction *)oldact);
+  return REAL(sigaction)(signum, (const struct sigaction *)act,
+                         (struct sigaction *)oldact);
 }
 }  // namespace __sanitizer
 
@@ -295,37 +296,27 @@
 }
 #endif
 
-#if ASAN_INTERCEPT_MLOCKX
-// intercept mlock and friends.
-// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
-// All functions return 0 (success).
-static void MlockIsUnsupported() {
-  static bool printed = false;
-  if (printed) return;
-  printed = true;
-  VPrintf(1,
-          "INFO: AddressSanitizer ignores "
-          "mlock/mlockall/munlock/munlockall\n");
+#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, mlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
+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);
 }
 
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, mlockall, int flags) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, munlockall, void) {
-  MlockIsUnsupported();
-  return 0;
+#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
 
@@ -529,7 +520,7 @@
 }
 #endif
 
-INTERCEPTOR(uptr, strlen, const char *s) {
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
   if (UNLIKELY(!asan_inited)) return internal_strlen(s);
   // strlen is called from malloc_default_purgeable_zone()
   // in __asan::ReplaceSystemAlloc() on Mac.
@@ -537,15 +528,15 @@
     return REAL(strlen)(s);
   }
   ENSURE_ASAN_INITED();
-  uptr length = REAL(strlen)(s);
+  SIZE_T length = REAL(strlen)(s);
   if (flags()->replace_str) {
     ASAN_READ_RANGE(s, length + 1);
   }
   return length;
 }
 
-INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
-  uptr length = REAL(wcslen)(s);
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+  SIZE_T length = REAL(wcslen)(s);
   if (!asan_init_is_running) {
     ENSURE_ASAN_INITED();
     ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
@@ -587,7 +578,7 @@
     // We get this symbol by skipping leading blanks and optional +/- sign.
     while (IsSpace(*nptr)) nptr++;
     if (*nptr == '+' || *nptr == '-') nptr++;
-    *endptr = (char*)nptr;
+    *endptr = const_cast<char *>(nptr);
   }
   CHECK(*endptr >= nptr);
 }
@@ -728,6 +719,9 @@
 namespace __asan {
 void InitializeWindowsInterceptors() {
   ASAN_INTERCEPT_FUNC(CreateThread);
+  ASAN_INTERCEPT_FUNC(RaiseException);
+  ASAN_INTERCEPT_FUNC(_except_handler3);
+  ASAN_INTERCEPT_FUNC(_except_handler4);
 }
 
 }  // namespace __asan
@@ -775,14 +769,6 @@
   ASAN_INTERCEPT_FUNC(strtoll);
 #endif
 
-#if ASAN_INTERCEPT_MLOCKX
-  // Intercept mlock/munlock.
-  ASAN_INTERCEPT_FUNC(mlock);
-  ASAN_INTERCEPT_FUNC(munlock);
-  ASAN_INTERCEPT_FUNC(mlockall);
-  ASAN_INTERCEPT_FUNC(munlockall);
-#endif
-
   // Intecept signal- and jump-related functions.
   ASAN_INTERCEPT_FUNC(longjmp);
 #if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
@@ -805,7 +791,7 @@
 
   // Intercept exception handling functions.
 #if ASAN_INTERCEPT___CXA_THROW
-  INTERCEPT_FUNCTION(__cxa_throw);
+  ASAN_INTERCEPT_FUNC(__cxa_throw);
 #endif
 
   // Intercept threading-related functions
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index c5d1af0..ee3b82a 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -15,7 +15,7 @@
 #define ASAN_INTERCEPTORS_H
 
 #include "asan_internal.h"
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 
 // Use macro to describe if specific function should be
@@ -26,7 +26,6 @@
 # define ASAN_INTERCEPT_STRDUP 1
 # define ASAN_INTERCEPT_INDEX 1
 # define ASAN_INTERCEPT_PTHREAD_CREATE 1
-# define ASAN_INTERCEPT_MLOCKX 1
 # define ASAN_INTERCEPT_FORK 1
 #else
 # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
@@ -34,7 +33,6 @@
 # define ASAN_INTERCEPT_STRDUP 0
 # define ASAN_INTERCEPT_INDEX 0
 # define ASAN_INTERCEPT_PTHREAD_CREATE 0
-# define ASAN_INTERCEPT_MLOCKX 0
 # define ASAN_INTERCEPT_FORK 0
 #endif
 
@@ -86,7 +84,7 @@
 DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
 DECLARE_REAL(void*, memset, void *block, int c, uptr size)
 DECLARE_REAL(char*, strchr, const char *str, int c)
-DECLARE_REAL(uptr, strlen, const char *s)
+DECLARE_REAL(SIZE_T, strlen, const char *s)
 DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
 DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
 DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index 32629ea..edaf44d 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -22,6 +22,12 @@
 using __sanitizer::uptr;
 
 extern "C" {
+  // This function should be called at the very beginning of the process,
+  // before any instrumented code is executed and before any call to malloc.
+  // Please note that __asan_init is a macro that is replaced with
+  // __asan_init_vXXX at compile-time.
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
+
   // This structure is used to describe the source location of a place where
   // global was defined.
   struct __asan_global_source_location {
@@ -85,6 +91,39 @@
   void __asan_describe_address(uptr addr);
 
   SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_report_present();
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_pc();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_bp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_sp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_address();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_get_report_access_type();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_access_size();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_get_report_description();
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+                                     uptr *region_address, uptr *region_size);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
+                              u32 *thread_id);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
+                             u32 *thread_id);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
   void __asan_report_error(uptr pc, uptr bp, uptr sp,
                            uptr addr, int is_write, uptr access_size);
 
@@ -98,22 +137,6 @@
   SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
   /* OPTIONAL */ void __asan_on_error();
 
-  // ---------------------------
-  // FIXME: Replace these functions with __sanitizer equivalent.
-  SANITIZER_INTERFACE_ATTRIBUTE
-  uptr __asan_get_estimated_allocated_size(uptr size);
-  SANITIZER_INTERFACE_ATTRIBUTE int __asan_get_ownership(const void *p);
-  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
-  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
-  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
-  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
-  SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
-  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-  /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
-  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-  /* OPTIONAL */ void __asan_free_hook(void *ptr);
-  // ---------------------------
-
   SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
 
   SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
@@ -145,6 +168,15 @@
       void* __asan_memset(void *s, int c, uptr n);
   SANITIZER_INTERFACE_ATTRIBUTE
       void* __asan_memmove(void* dest, const void* src, uptr n);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_poison_cxx_array_cookie(uptr p);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_load_cxx_array_cookie(uptr *p);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_poison_intra_object_redzone(uptr p, uptr size);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
 }  // extern "C"
 
 #endif  // ASAN_INTERFACE_INTERNAL_H
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 0782789..f9f9243 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -45,10 +45,6 @@
 # endif
 #endif
 
-#ifndef ASAN_USE_PREINIT_ARRAY
-# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
-#endif
-
 #ifndef ASAN_DYNAMIC
 # ifdef PIC
 #  define ASAN_DYNAMIC 1
@@ -112,10 +108,8 @@
 // Add convenient macro for interface functions that may be represented as
 // weak hooks.
 #define ASAN_MALLOC_HOOK(ptr, size) \
-  if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size); \
   if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
 #define ASAN_FREE_HOOK(ptr) \
-  if (&__asan_free_hook) __asan_free_hook(ptr); \
   if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
 #define ASAN_ON_ERROR() \
   if (&__asan_on_error) __asan_on_error()
@@ -140,6 +134,8 @@
 const int kAsanStackUseAfterScopeMagic = 0xf8;
 const int kAsanGlobalRedzoneMagic = 0xf9;
 const int kAsanInternalHeapMagic = 0xfe;
+const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
 
 static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
 static const uptr kRetiredStackFrameMagic = 0x45E0360E;
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index ed7d9ce..4014357 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -114,7 +114,7 @@
       internal_strlen(dyld_insert_libraries) : 0;
   uptr fname_len = internal_strlen(info.dli_fname);
   if (!dyld_insert_libraries ||
-      !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
+      !REAL(strstr)(dyld_insert_libraries, StripModuleName(info.dli_fname))) {
     // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
     // library.
     char program_name[1024];
@@ -297,7 +297,7 @@
 // The caller retains control of the allocated context.
 extern "C"
 asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
-                                         StackTrace *stack) {
+                                         BufferedStackTrace *stack) {
   asan_block_context_t *asan_ctxt =
       (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
   asan_ctxt->block = ctxt;
diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc
index 077a50c..46a6a9d 100644
--- a/lib/asan/asan_malloc_linux.cc
+++ b/lib/asan/asan_malloc_linux.cc
@@ -23,45 +23,6 @@
 #include "asan_internal.h"
 #include "asan_stack.h"
 
-#if SANITIZER_ANDROID
-DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
-DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
-DECLARE_REAL_AND_INTERCEPTOR(uptr, malloc_usable_size, void *mem)
-
-struct MallocDebug {
-  void *(*malloc)(uptr bytes);
-  void (*free)(void *mem);
-  void *(*calloc)(uptr n_elements, uptr elem_size);
-  void *(*realloc)(void *oldMem, uptr bytes);
-  void *(*memalign)(uptr alignment, uptr bytes);
-  uptr (*malloc_usable_size)(void *mem);
-};
-
-ALIGNED(32) const MallocDebug asan_malloc_dispatch = {
-    WRAP(malloc),  WRAP(free),     WRAP(calloc),
-    WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
-
-namespace __asan {
-void ReplaceSystemMalloc() {
-  const MallocDebug** __libc_malloc_dispatch_p;
-  __libc_malloc_dispatch_p =
-      (const MallocDebug **)AsanDlSymNext("__libc_malloc_dispatch");
-  if (__libc_malloc_dispatch_p)
-    *__libc_malloc_dispatch_p = &asan_malloc_dispatch;
-}
-}  // namespace __asan
-
-#else  // SANITIZER_ANDROID
-
-namespace __asan {
-void ReplaceSystemMalloc() {
-}
-}  // namespace __asan
-#endif  // SANITIZER_ANDROID
-
 // ---------------------- Replacement functions ---------------- {{{1
 using namespace __asan;  // NOLINT
 
@@ -162,4 +123,64 @@
   __asan_print_accumulated_stats();
 }
 
+#if SANITIZER_ANDROID
+// Format of __libc_malloc_dispatch has changed in Android L.
+// While we are moving towards a solution that does not depend on bionic
+// internals, here is something to support both K* and L releases.
+struct MallocDebugK {
+  void *(*malloc)(uptr bytes);
+  void (*free)(void *mem);
+  void *(*calloc)(uptr n_elements, uptr elem_size);
+  void *(*realloc)(void *oldMem, uptr bytes);
+  void *(*memalign)(uptr alignment, uptr bytes);
+  uptr (*malloc_usable_size)(void *mem);
+};
+
+struct MallocDebugL {
+  void *(*calloc)(uptr n_elements, uptr elem_size);
+  void (*free)(void *mem);
+  fake_mallinfo (*mallinfo)(void);
+  void *(*malloc)(uptr bytes);
+  uptr (*malloc_usable_size)(void *mem);
+  void *(*memalign)(uptr alignment, uptr bytes);
+  int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
+  void* (*pvalloc)(uptr size);
+  void *(*realloc)(void *oldMem, uptr bytes);
+  void* (*valloc)(uptr size);
+};
+
+ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+    WRAP(malloc),  WRAP(free),     WRAP(calloc),
+    WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
+
+ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+    WRAP(calloc),         WRAP(free),               WRAP(mallinfo),
+    WRAP(malloc),         WRAP(malloc_usable_size), WRAP(memalign),
+    WRAP(posix_memalign), WRAP(pvalloc),            WRAP(realloc),
+    WRAP(valloc)};
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+  void **__libc_malloc_dispatch_p =
+      (void **)AsanDlSymNext("__libc_malloc_dispatch");
+  if (__libc_malloc_dispatch_p) {
+    // Decide on K vs L dispatch format by the presence of
+    // __libc_malloc_default_dispatch export in libc.
+    void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
+    if (default_dispatch_p)
+      *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
+    else
+      *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
+  }
+}
+}  // namespace __asan
+
+#else  // SANITIZER_ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+}  // namespace __asan
+#endif  // SANITIZER_ANDROID
+
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index b6d20d8..c99e312 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -19,75 +19,81 @@
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_stack.h"
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 
 #include <stddef.h>
 
-// ---------------------- Replacement functions ---------------- {{{1
 using namespace __asan;  // NOLINT
 
-// FIXME: Simply defining functions with the same signature in *.obj
-// files overrides the standard functions in *.lib
-// This works well for simple helloworld-like tests but might need to be
-// revisited in the future.
+// MT: Simply defining functions with the same signature in *.obj
+// files overrides the standard functions in the CRT.
+// MD: Memory allocation functions are defined in the CRT .dll,
+// so we have to intercept them before they are called for the first time.
+
+#if ASAN_DYNAMIC
+# define ALLOCATION_FUNCTION_ATTRIBUTE
+#else
+# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+#endif
 
 extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void free(void *ptr) {
   GET_STACK_TRACE_FREE;
   return asan_free(ptr, &stack, FROM_MALLOC);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
-void _free_dbg(void* ptr, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_dbg(void *ptr, int) {
   free(ptr);
 }
 
+ALLOCATION_FUNCTION_ATTRIBUTE
 void cfree(void *ptr) {
-  CHECK(!"cfree() should not be used on Windows?");
+  CHECK(!"cfree() should not be used on Windows");
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *malloc(size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_malloc(size, &stack);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _malloc_dbg(size_t size, int , const char*, int) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_dbg(size_t size, int, const char *, int) {
   return malloc(size);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *calloc(size_t nmemb, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_calloc(nmemb, size, &stack);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
-  return calloc(n, size);
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+  return calloc(nmemb, size);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
   return calloc(nmemb, size);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *realloc(void *ptr, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_realloc(ptr, size, &stack);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *_realloc_dbg(void *ptr, size_t size, int) {
   CHECK(!"_realloc_dbg should not exist!");
   return 0;
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
-void* _recalloc(void* p, size_t n, size_t elem_size) {
+ALLOCATION_FUNCTION_ATTRIBUTE
+void *_recalloc(void *p, size_t n, size_t elem_size) {
   if (!p)
     return calloc(n, elem_size);
   const size_t size = n * elem_size;
@@ -96,23 +102,23 @@
   return realloc(p, size);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 size_t _msize(void *ptr) {
   GET_CURRENT_PC_BP_SP;
   (void)sp;
   return asan_malloc_usable_size(ptr, pc, bp);
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *_expand(void *memblock, size_t size) {
   // _expand is used in realloc-like functions to resize the buffer if possible.
   // We don't want memory to stand still while resizing buffers, so return 0.
   return 0;
 }
 
-SANITIZER_INTERFACE_ATTRIBUTE
+ALLOCATION_FUNCTION_ATTRIBUTE
 void *_expand_dbg(void *memblock, size_t size) {
-  return 0;
+  return _expand(memblock, size);
 }
 
 // TODO(timurrrr): Might want to add support for _aligned_* allocation
@@ -133,37 +139,38 @@
 }
 }  // extern "C"
 
-using __interception::GetRealFunctionAddress;
-
-// We don't want to include "windows.h" in this file to avoid extra attributes
-// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
-extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
-                                        DWORD prot, DWORD *old_prot);
-const int PAGE_EXECUTE_READWRITE = 0x40;
-
 namespace __asan {
 void ReplaceSystemMalloc() {
-#if defined(_DLL)
-# ifdef _WIN64
-#  error ReplaceSystemMalloc was not tested on x64
-# endif
-  char *crt_malloc;
-  if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
-    // Replace malloc in the CRT dll with a jump to our malloc.
-    DWORD old_prot, unused;
-    CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
-    REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16);  // just in case.
+#if defined(ASAN_DYNAMIC)
+  // We don't check the result because CRT might not be used in the process.
+  __interception::OverrideFunction("free", (uptr)free);
+  __interception::OverrideFunction("malloc", (uptr)malloc);
+  __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
+  __interception::OverrideFunction("calloc", (uptr)calloc);
+  __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
+  __interception::OverrideFunction("realloc", (uptr)realloc);
+  __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
+  __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
+  __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
+  __interception::OverrideFunction("_msize", (uptr)_msize);
+  __interception::OverrideFunction("_expand", (uptr)_expand);
 
-    ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
-    crt_malloc[0] = 0xE9;  // jmp, should be followed by an offset.
-    REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
-
-    CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
-
-    // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
-  }
-
-  // FIXME: investigate whether anything else is needed.
+  // Override different versions of 'operator new' and 'operator delete'.
+  // No need to override the nothrow versions as they just wrap the throw
+  // versions.
+  // FIXME: Unfortunately, MSVC miscompiles the statements that take the
+  // addresses of the array versions of these operators,
+  // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
+  // We might want to try to work around this by [inline] assembly or compiling
+  // parts of the RTL with Clang.
+  void *(*op_new)(size_t sz) = operator new;
+  void (*op_delete)(void *p) = operator delete;
+  void *(*op_array_new)(size_t sz) = operator new[];
+  void (*op_array_delete)(void *p) = operator delete[];
+  __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
+  __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
+  __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
+  __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
 #endif
 }
 }  // namespace __asan
diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h
index 8acc99a..2746754 100644
--- a/lib/asan/asan_mapping.h
+++ b/lib/asan/asan_mapping.h
@@ -60,11 +60,11 @@
 // || `[0x00000000, 0x1fffffff]` || LowMem     ||
 //
 // Default Linux/MIPS mapping:
-// || `[0x2aaa8000, 0xffffffff]` || HighMem    ||
-// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
-// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap  ||
-// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow  ||
-// || `[0x00000000, 0x0aaa7fff]` || LowMem     ||
+// || `[0x2aaa0000, 0xffffffff]` || HighMem    ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap  ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow  ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem     ||
 //
 // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
 // || `[0x500000000000, 0x7fffffffffff]` || HighMem    ||
@@ -86,7 +86,8 @@
 static const u64 kDefaultShadowOffset64 = 1ULL << 44;
 static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000;  // < 2G.
 static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
-static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
+static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36;
 static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
 static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30;  // 0x40000000
 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46;  // 0x400000000000
@@ -116,6 +117,8 @@
 #    define SHADOW_OFFSET kFreeBSD_ShadowOffset64
 #  elif SANITIZER_MAC
 #   define SHADOW_OFFSET kDefaultShadowOffset64
+#  elif defined(__mips64)
+#   define SHADOW_OFFSET kMIPS64_ShadowOffset64
 #  else
 #   define SHADOW_OFFSET kDefaultShort64bitShadowOffset
 #  endif
diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc
index 86b9f28..e48bdaf 100644
--- a/lib/asan/asan_new_delete.cc
+++ b/lib/asan/asan_new_delete.cc
@@ -16,7 +16,7 @@
 #include "asan_internal.h"
 #include "asan_stack.h"
 
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 
 #include <stddef.h>
 
@@ -105,6 +105,16 @@
 void operator delete[](void *ptr, std::nothrow_t const&) {
   OPERATOR_DELETE_BODY(FROM_NEW_BR);
 }
+CXX_OPERATOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) throw() {
+  GET_STACK_TRACE_FREE;
+  asan_sized_free(ptr, size, &stack, FROM_NEW);
+}
+CXX_OPERATOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) throw() {
+  GET_STACK_TRACE_FREE;
+  asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
+}
 
 #else  // SANITIZER_MAC
 INTERCEPTOR(void, _ZdlPv, void *ptr) {
diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc
index b356e40..1c6e92f 100644
--- a/lib/asan/asan_poisoning.cc
+++ b/lib/asan/asan_poisoning.cc
@@ -61,6 +61,27 @@
     FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
 }
 
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+  uptr end = ptr + size;
+  if (common_flags()->verbosity) {
+    Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+           poison ? "" : "un", ptr, end, size);
+    if (common_flags()->verbosity >= 2)
+      PRINT_CURRENT_STACK();
+  }
+  CHECK(size);
+  CHECK_LE(size, 4096);
+  CHECK(IsAligned(end, SHADOW_GRANULARITY));
+  if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+    *(u8 *)MemToShadow(ptr) =
+        poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+    ptr |= SHADOW_GRANULARITY - 1;
+    ptr++;
+  }
+  for (; ptr < end; ptr += SHADOW_GRANULARITY)
+    *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
@@ -227,6 +248,36 @@
   *p = x;
 }
 
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_cxx_array_cookie(uptr p) {
+  if (SANITIZER_WORDSIZE != 64) return;
+  if (!flags()->poison_array_cookie) return;
+  uptr s = MEM_TO_SHADOW(p);
+  *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_load_cxx_array_cookie(uptr *p) {
+  if (SANITIZER_WORDSIZE != 64) return *p;
+  if (!flags()->poison_array_cookie) return *p;
+  uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
+  u8 sval = *reinterpret_cast<u8*>(s);
+  if (sval == kAsanArrayCookieMagic) return *p;
+  // If sval is not kAsanArrayCookieMagic it can only be freed memory,
+  // which means that we are going to get double-free. So, return 0 to avoid
+  // infinite loop of destructors. We don't want to report a double-free here
+  // though, so print a warning just in case.
+  // CHECK_EQ(sval, kAsanHeapFreeMagic);
+  if (sval == kAsanHeapFreeMagic) {
+    Report("AddressSanitizer: loaded array cookie from free-d memory; "
+           "expect a double-free report\n");
+    return 0;
+  }
+  // The cookie may remain unpoisoned if e.g. it comes from a custom
+  // operator new defined inside a class.
+  return *p;
+}
+
 // This is a simplified version of __asan_(un)poison_memory_region, which
 // assumes that left border of region to be poisoned is properly aligned.
 static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
@@ -345,6 +396,17 @@
       return 0;
   return 1;
 }
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+  AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+  AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
 // --- Implementation of LSan-specific functions --- {{{1
 namespace __lsan {
 bool WordIsPoisoned(uptr addr) {
diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h
index bd680ae..feda1a9 100644
--- a/lib/asan/asan_poisoning.h
+++ b/lib/asan/asan_poisoning.h
@@ -35,7 +35,6 @@
 ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
                                     u8 value) {
   DCHECK(flags()->poison_heap);
-  uptr PageSize = GetPageSizeCached();
   uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
   uptr shadow_end = MEM_TO_SHADOW(
       aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
@@ -48,8 +47,9 @@
       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
     REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
   } else {
-    uptr page_beg = RoundUpTo(shadow_beg, PageSize);
-    uptr page_end = RoundDownTo(shadow_end, PageSize);
+    uptr page_size = GetPageSizeCached();
+    uptr page_beg = RoundUpTo(shadow_beg, page_size);
+    uptr page_end = RoundDownTo(shadow_end, page_size);
 
     if (page_beg >= page_end) {
       REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 57c9581..c910e23 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -33,6 +33,7 @@
 namespace __asan {
 
 void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+  ScopedDeadlySignal signal_scope(GetCurrentThread());
   uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
   int code = (int)((siginfo_t*)siginfo)->si_code;
   // Write the first message using the bullet-proof write.
@@ -41,16 +42,42 @@
   GetPcSpBp(context, &pc, &sp, &bp);
 
   // Access at a reasonable offset above SP, or slightly below it (to account
-  // for x86_64 redzone, ARM push of multiple registers, etc) is probably a
-  // stack overflow.
+  // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+  // probably a stack overflow.
+  bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF;
+
+#if __powerpc__
+  // Large stack frames can be allocated with e.g.
+  //   lis r0,-10000
+  //   stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
+  // If the store faults then sp will not have been updated, so test above
+  // will not work, becase the fault address will be more than just "slightly"
+  // below sp.
+  if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) {
+    u32 inst = *(unsigned *)pc;
+    u32 ra = (inst >> 16) & 0x1F;
+    u32 opcd = inst >> 26;
+    u32 xo = (inst >> 1) & 0x3FF;
+    // Check for store-with-update to sp. The instructions we accept are:
+    //   stbu rs,d(ra)          stbux rs,ra,rb
+    //   sthu rs,d(ra)          sthux rs,ra,rb
+    //   stwu rs,d(ra)          stwux rs,ra,rb
+    //   stdu rs,ds(ra)         stdux rs,ra,rb
+    // where ra is r1 (the stack pointer).
+    if (ra == 1 &&
+        (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
+         (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
+      IsStackAccess = true;
+  }
+#endif // __powerpc__
+
   // We also check si_code to filter out SEGV caused by something else other
   // then hitting the guard page or unmapped memory, like, for example,
   // unaligned memory access.
-  if (addr + 128 > sp && addr < sp + 0xFFFF &&
-      (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
+  if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
     ReportStackOverflow(pc, sp, bp, context, addr);
   else
-    ReportSIGSEGV(pc, sp, bp, context, addr);
+    ReportSIGSEGV("SEGV", pc, sp, bp, context, addr);
 }
 
 // ---------------------- TSD ---------------- {{{1
diff --git a/lib/asan/asan_preinit.cc b/lib/asan/asan_preinit.cc
index 586f551..a3986d2 100644
--- a/lib/asan/asan_preinit.cc
+++ b/lib/asan/asan_preinit.cc
@@ -10,22 +10,16 @@
 // This file is a part of AddressSanitizer, an address sanity checker.
 //
 // Call __asan_init at the very early stage of process startup.
-// On Linux we use .preinit_array section (unless PIC macro is defined).
 //===----------------------------------------------------------------------===//
 #include "asan_internal.h"
 
-#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
-  // On Linux, we force __asan_init to be called before anyone else
-  // by placing it into .preinit_array section.
-  // FIXME: do we have anything like this on Mac?
+using namespace __asan;
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
   // The symbol is called __local_asan_preinit, because it's not intended to be
   // exported.
+  // This code linked into the main executable when -fsanitize=address is in
+  // the link flags. It can only use exported interface functions.
   __attribute__((section(".preinit_array"), used))
   void (*__local_asan_preinit)(void) = __asan_init;
-#elif SANITIZER_WINDOWS && defined(_DLL)
-  // On Windows, when using dynamic CRT (/MD), we can put a pointer
-  // to __asan_init into the global list of C initializers.
-  // See crt0dat.c in the CRT sources for the details.
-  #pragma section(".CRT$XIB", long, read)  // NOLINT
-  __declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
 #endif
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index e13d59f..2ca11a3 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -31,6 +31,19 @@
 static uptr error_message_buffer_pos = 0;
 static uptr error_message_buffer_size = 0;
 
+struct ReportData {
+  uptr pc;
+  uptr sp;
+  uptr bp;
+  uptr addr;
+  bool is_write;
+  uptr access_size;
+  const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
 void AppendToErrorMessageBuffer(const char *buffer) {
   if (error_message_buffer) {
     uptr length = internal_strlen(buffer);
@@ -59,6 +72,7 @@
     switch (byte) {
       case kAsanHeapLeftRedzoneMagic:
       case kAsanHeapRightRedzoneMagic:
+      case kAsanArrayCookieMagic:
         return Red();
       case kAsanHeapFreeMagic:
         return Magenta();
@@ -80,20 +94,31 @@
         return Red();
       case kAsanInternalHeapMagic:
         return Yellow();
+      case kAsanIntraObjectRedzone:
+        return Yellow();
       default:
         return Default();
     }
   }
   const char *EndShadowByte() { return Default(); }
+  const char *MemoryByte() { return Magenta(); }
+  const char *EndMemoryByte() { return Default(); }
 };
 
 // ---------------------- Helper functions ----------------------- {{{1
 
-static void PrintShadowByte(InternalScopedString *str, const char *before,
-                            u8 byte, const char *after = "\n") {
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+    u8 byte, bool in_shadow, const char *after = "\n") {
   Decorator d;
-  str->append("%s%s%x%x%s%s", before, d.ShadowByte(byte), byte >> 4, byte & 15,
-              d.EndShadowByte(), after);
+  str->append("%s%s%x%x%s%s", before,
+              in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
+              byte >> 4, byte & 15,
+              in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+    u8 byte, const char *after = "\n") {
+  PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
 }
 
 static void PrintShadowBytes(InternalScopedString *str, const char *before,
@@ -143,9 +168,29 @@
                   kAsanUserPoisonedMemoryMagic);
   PrintShadowByte(str, "  Container overflow:      ",
                   kAsanContiguousContainerOOBMagic);
+  PrintShadowByte(str, "  Array cookie:            ",
+                  kAsanArrayCookieMagic);
+  PrintShadowByte(str, "  Intra object redzone:    ",
+                  kAsanIntraObjectRedzone);
   PrintShadowByte(str, "  ASan internal:           ", kAsanInternalHeapMagic);
 }
 
+void MaybeDumpInstructionBytes(uptr pc) {
+  if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
+    return;
+  InternalScopedString str(1024);
+  str.append("First 16 instruction bytes at pc: ");
+  if (IsAccessibleMemoryRange(pc, 16)) {
+    for (int i = 0; i < 16; ++i) {
+      PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
+    }
+    str.append("\n");
+  } else {
+    str.append("unaccessible\n");
+  }
+  Report("%s", str.data());
+}
+
 static void PrintShadowMemoryForAddress(uptr addr) {
   if (!AddrIsInMem(addr)) return;
   uptr shadow_addr = MemToShadow(addr);
@@ -197,7 +242,7 @@
   else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
     should_demangle = true;
 
-  return should_demangle ? Symbolizer::Get()->Demangle(name) : name;
+  return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
 }
 
 // Check if the global is a zero-terminated ASCII string. If so, print it.
@@ -234,9 +279,7 @@
 
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
                                      const __asan_global &g) {
-  static const uptr kMinimalDistanceFromAnotherGlobal = 64;
-  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
-  if (addr >= g.beg + g.size_with_redzone) return false;
+  if (!IsAddressNearGlobal(addr, g)) return false;
   InternalScopedString str(4096);
   Decorator d;
   str.append("%s", d.Location());
@@ -262,21 +305,20 @@
   return true;
 }
 
-bool DescribeAddressIfShadow(uptr addr) {
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
   if (AddrIsInMem(addr))
     return false;
-  static const char kAddrInShadowReport[] =
-      "Address %p is located in the %s.\n";
-  if (AddrIsInShadowGap(addr)) {
-    Printf(kAddrInShadowReport, addr, "shadow gap area");
-    return true;
-  }
-  if (AddrIsInHighShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "high shadow area");
-    return true;
-  }
-  if (AddrIsInLowShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "low shadow area");
+  const char *area_type = nullptr;
+  if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+  else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+  else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+  if (area_type != nullptr) {
+    if (print) {
+      Printf("Address %p is located in the %s area.\n", addr, area_type);
+    } else {
+      CHECK(descr);
+      descr->region_kind = area_type;
+    }
     return true;
   }
   CHECK(0 && "Address is not in memory and not in shadow?");
@@ -303,16 +345,15 @@
   return ThreadNameWithParenthesis(t, buff, buff_len);
 }
 
-void PrintAccessAndVarIntersection(const char *var_name,
-                                   uptr var_beg, uptr var_size,
-                                   uptr addr, uptr access_size,
-                                   uptr prev_var_end, uptr next_var_beg) {
-  uptr var_end = var_beg + var_size;
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+                                          uptr access_size, uptr prev_var_end,
+                                          uptr next_var_beg) {
+  uptr var_end = var.beg + var.size;
   uptr addr_end = addr + access_size;
   const char *pos_descr = 0;
-  // If the variable [var_beg, var_end) is the nearest variable to the
+  // If the variable [var.beg, var_end) is the nearest variable to the
   // current memory access, indicate it in the log.
-  if (addr >= var_beg) {
+  if (addr >= var.beg) {
     if (addr_end <= var_end)
       pos_descr = "is inside";  // May happen if this is a use-after-return.
     else if (addr < var_end)
@@ -321,14 +362,20 @@
              next_var_beg - addr_end >= addr - var_end)
       pos_descr = "overflows";
   } else {
-    if (addr_end > var_beg)
+    if (addr_end > var.beg)
       pos_descr = "partially underflows";
     else if (addr >= prev_var_end &&
-             addr - prev_var_end >= var_beg - addr_end)
+             addr - prev_var_end >= var.beg - addr_end)
       pos_descr = "underflows";
   }
   InternalScopedString str(1024);
-  str.append("    [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+  str.append("    [%zd, %zd)", var.beg, var_end);
+  // Render variable name.
+  str.append(" '");
+  for (uptr i = 0; i < var.name_len; ++i) {
+    str.append("%c", var.name_pos[i]);
+  }
+  str.append("'");
   if (pos_descr) {
     Decorator d;
     // FIXME: we may want to also print the size of the access here,
@@ -341,41 +388,51 @@
   Printf("%s", str.data());
 }
 
-struct StackVarDescr {
-  uptr beg;
-  uptr size;
-  const char *name_pos;
-  uptr name_len;
-};
+bool ParseFrameDescription(const char *frame_descr,
+                           InternalMmapVector<StackVarDescr> *vars) {
+  CHECK(frame_descr);
+  char *p;
+  // This string is created by the compiler and has the following form:
+  // "n alloc_1 alloc_2 ... alloc_n"
+  // where alloc_i looks like "offset size len ObjectName".
+  uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
+  if (n_objects == 0)
+    return false;
+
+  for (uptr i = 0; i < n_objects; i++) {
+    uptr beg  = (uptr)internal_simple_strtoll(p, &p, 10);
+    uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
+    uptr len  = (uptr)internal_simple_strtoll(p, &p, 10);
+    if (beg == 0 || size == 0 || *p != ' ') {
+      return false;
+    }
+    p++;
+    StackVarDescr var = {beg, size, p, len};
+    vars->push_back(var);
+    p += len;
+  }
+
+  return true;
+}
 
 bool DescribeAddressIfStack(uptr addr, uptr access_size) {
   AsanThread *t = FindThreadByStackAddress(addr);
   if (!t) return false;
-  const uptr kBufSize = 4095;
-  char buf[kBufSize];
-  uptr offset = 0;
-  uptr frame_pc = 0;
-  char tname[128];
-  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
 
-#ifdef __powerpc64__
-  // On PowerPC64, the address of a function actually points to a
-  // three-doubleword data structure with the first field containing
-  // the address of the function's code.
-  frame_pc = *reinterpret_cast<uptr *>(frame_pc);
-#endif
-
-  // This string is created by the compiler and has the following form:
-  // "n alloc_1 alloc_2 ... alloc_n"
-  // where alloc_i looks like "offset size len ObjectName ".
-  CHECK(frame_descr);
   Decorator d;
+  char tname[128];
   Printf("%s", d.Location());
-  Printf("Address %p is located in stack of thread T%d%s "
-         "at offset %zu in frame\n",
-         addr, t->tid(),
-         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
-         offset);
+  Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+  // Try to fetch precise stack frame for this access.
+  AsanThread::StackFrameAccess access;
+  if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+    Printf("%s\n", d.EndLocation());
+    return true;
+  }
+  Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
   // Now we print the frame where the alloca has happened.
   // We print this frame as a stack trace with one element.
   // The symbolizer may print more than one frame if inlining was involved.
@@ -383,50 +440,42 @@
   // previously. That's unfortunate, but I have no better solution,
   // especially given that the alloca may be from entirely different place
   // (e.g. use-after-scope, or different thread's stack).
-  StackTrace alloca_stack;
-  alloca_stack.trace[0] = frame_pc + 16;
-  alloca_stack.size = 1;
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+  // On PowerPC64 ELFv1, the address of a function actually points to a
+  // three-doubleword data structure with the first field containing
+  // the address of the function's code.
+  access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+  access.frame_pc += 16;
   Printf("%s", d.EndLocation());
+  StackTrace alloca_stack(&access.frame_pc, 1);
   alloca_stack.Print();
+
+  InternalMmapVector<StackVarDescr> vars(16);
+  if (!ParseFrameDescription(access.frame_descr, &vars)) {
+    Printf("AddressSanitizer can't parse the stack frame "
+           "descriptor: |%s|\n", access.frame_descr);
+    // 'addr' is a stack address, so return true even if we can't parse frame
+    return true;
+  }
+  uptr n_objects = vars.size();
   // Report the number of stack objects.
-  char *p;
-  uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
-  CHECK_GT(n_objects, 0);
   Printf("  This frame has %zu object(s):\n", n_objects);
 
   // Report all objects in this frame.
-  InternalScopedBuffer<StackVarDescr> vars(n_objects);
   for (uptr i = 0; i < n_objects; i++) {
-    uptr beg, size;
-    uptr len;
-    beg  = (uptr)internal_simple_strtoll(p, &p, 10);
-    size = (uptr)internal_simple_strtoll(p, &p, 10);
-    len  = (uptr)internal_simple_strtoll(p, &p, 10);
-    if (beg == 0 || size == 0 || *p != ' ') {
-      Printf("AddressSanitizer can't parse the stack frame "
-                 "descriptor: |%s|\n", frame_descr);
-      break;
-    }
-    p++;
-    vars[i].beg = beg;
-    vars[i].size = size;
-    vars[i].name_pos = p;
-    vars[i].name_len = len;
-    p += len;
-  }
-  for (uptr i = 0; i < n_objects; i++) {
-    buf[0] = 0;
-    internal_strncat(buf, vars[i].name_pos,
-                     static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
     uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
     uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
-    PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size,
-                                  offset, access_size,
+    PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
                                   prev_var_end, next_var_beg);
   }
   Printf("HINT: this may be a false positive if your program uses "
-             "some custom stack unwind mechanism or swapcontext\n"
-             "      (longjmp and C++ exceptions *are* supported)\n");
+         "some custom stack unwind mechanism or swapcontext\n");
+  if (SANITIZER_WINDOWS)
+    Printf("      (longjmp, SEH and C++ exceptions *are* supported)\n");
+  else
+    Printf("      (longjmp and C++ exceptions *are* supported)\n");
+
   DescribeThread(t);
   return true;
 }
@@ -469,8 +518,7 @@
   asanThreadRegistry().CheckLocked();
   AsanThreadContext *alloc_thread =
       GetThreadContextByTidLocked(chunk.AllocTid());
-  StackTrace alloc_stack;
-  chunk.GetAllocStack(&alloc_stack);
+  StackTrace alloc_stack = chunk.GetAllocStack();
   char tname[128];
   Decorator d;
   AsanThreadContext *free_thread = 0;
@@ -480,8 +528,7 @@
            free_thread->tid,
            ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
            d.EndAllocation());
-    StackTrace free_stack;
-    chunk.GetFreeStack(&free_stack);
+    StackTrace free_stack = chunk.GetFreeStack();
     free_stack.Print();
     Printf("%spreviously allocated by thread T%d%s here:%s\n",
            d.Allocation(), alloc_thread->tid,
@@ -531,9 +578,7 @@
       " created by T%d%s here:\n", context->parent_tid,
       ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
   Printf("%s", str.data());
-  uptr stack_size;
-  const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
-  StackTrace::PrintStack(stack_trace, stack_size);
+  StackDepotGet(context->stack_id).Print();
   // Recursively described parent thread if needed.
   if (flags()->print_full_thread_history) {
     AsanThreadContext *parent_context =
@@ -548,14 +593,14 @@
 // immediately after printing error report.
 class ScopedInErrorReport {
  public:
-  ScopedInErrorReport() {
+  explicit ScopedInErrorReport(ReportData *report = nullptr) {
     static atomic_uint32_t num_calls;
     static u32 reporting_thread_tid;
     if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
       // Do not print more than one report, otherwise they will mix up.
       // Error reporting functions shouldn't return at this situation, as
       // they are defined as no-return.
-      Report("AddressSanitizer: while reporting a bug found another one."
+      Report("AddressSanitizer: while reporting a bug found another one. "
                  "Ignoring.\n");
       u32 current_tid = GetCurrentTidOrInvalid();
       if (current_tid != reporting_thread_tid) {
@@ -568,6 +613,8 @@
       // Die() to bypass any additional checks.
       internal__exit(flags()->exitcode);
     }
+    if (report) report_data = *report;
+    report_happened = true;
     ASAN_ON_ERROR();
     // Make sure the registry and sanitizer report mutexes are locked while
     // we're printing an error report.
@@ -602,8 +649,8 @@
   Printf("%s", d.Warning());
   Report(
       "ERROR: AddressSanitizer: stack-overflow on address %p"
-      " (pc %p sp %p bp %p T%d)\n",
-      (void *)addr, (void *)pc, (void *)sp, (void *)bp,
+      " (pc %p bp %p sp %p T%d)\n",
+      (void *)addr, (void *)pc, (void *)bp, (void *)sp,
       GetCurrentTidOrInvalid());
   Printf("%s", d.EndWarning());
   GET_STACK_TRACE_SIGNAL(pc, bp, context);
@@ -611,23 +658,28 @@
   ReportErrorSummary("stack-overflow", &stack);
 }
 
-void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
+void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
+                   void *context, uptr addr) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
   Report(
-      "ERROR: AddressSanitizer: SEGV on unknown address %p"
-      " (pc %p sp %p bp %p T%d)\n",
-      (void *)addr, (void *)pc, (void *)sp, (void *)bp,
+      "ERROR: AddressSanitizer: %s on unknown address %p"
+      " (pc %p bp %p sp %p T%d)\n",
+      description, (void *)addr, (void *)pc, (void *)bp, (void *)sp,
       GetCurrentTidOrInvalid());
+  if (pc < GetPageSizeCached()) {
+    Report("Hint: pc points to the zero page.\n");
+  }
   Printf("%s", d.EndWarning());
   GET_STACK_TRACE_SIGNAL(pc, bp, context);
   stack.Print();
+  MaybeDumpInstructionBytes(pc);
   Printf("AddressSanitizer can not provide additional info.\n");
   ReportErrorSummary("SEGV", &stack);
 }
 
-void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -645,7 +697,31 @@
   ReportErrorSummary("double-free", &stack);
 }
 
-void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
+void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+                                 BufferedStackTrace *free_stack) {
+  ScopedInErrorReport in_report;
+  Decorator d;
+  Printf("%s", d.Warning());
+  char tname[128];
+  u32 curr_tid = GetCurrentTidOrInvalid();
+  Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
+         "thread T%d%s:\n",
+         addr, curr_tid,
+         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
+  Printf("%s  object passed to delete has wrong type:\n", d.EndWarning());
+  Printf("  size of the allocated type:   %zd bytes;\n"
+         "  size of the deallocated type: %zd bytes.\n",
+         asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
+  CHECK_GT(free_stack->size, 0);
+  GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+  stack.Print();
+  DescribeHeapAddress(addr, 1);
+  ReportErrorSummary("new-delete-type-mismatch", &stack);
+  Report("HINT: if you don't care about these warnings you may set "
+         "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -662,7 +738,7 @@
   ReportErrorSummary("bad-free", &stack);
 }
 
-void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
                              AllocType alloc_type,
                              AllocType dealloc_type) {
   static const char *alloc_names[] =
@@ -685,7 +761,7 @@
          "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
 }
 
-void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -698,7 +774,8 @@
   ReportErrorSummary("bad-malloc_usable_size", stack);
 }
 
-void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+                                             BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -711,9 +788,10 @@
   ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
 }
 
-void ReportStringFunctionMemoryRangesOverlap(
-    const char *function, const char *offset1, uptr length1,
-    const char *offset2, uptr length2, StackTrace *stack) {
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+                                             const char *offset1, uptr length1,
+                                             const char *offset2, uptr length2,
+                                             BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   char bug_type[100];
@@ -730,7 +808,7 @@
 }
 
 void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
-                                      StackTrace *stack) {
+                                      BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   const char *bug_type = "negative-size-param";
@@ -744,7 +822,7 @@
 
 void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
                                                   uptr old_mid, uptr new_mid,
-                                                  StackTrace *stack) {
+                                                  BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Report("ERROR: AddressSanitizer: bad parameters to "
          "__sanitizer_annotate_contiguous_container:\n"
@@ -767,21 +845,23 @@
   InternalScopedString g1_loc(256), g2_loc(256);
   PrintGlobalLocation(&g1_loc, *g1);
   PrintGlobalLocation(&g2_loc, *g2);
-  Printf("  [1] size=%zd %s %s\n", g1->size, g1->name, g1_loc.data());
-  Printf("  [2] size=%zd %s %s\n", g2->size, g2->name, g2_loc.data());
+  Printf("  [1] size=%zd '%s' %s\n", g1->size,
+         MaybeDemangleGlobalName(g1->name), g1_loc.data());
+  Printf("  [2] size=%zd '%s' %s\n", g2->size,
+         MaybeDemangleGlobalName(g2->name), g2_loc.data());
   if (stack_id1 && stack_id2) {
     Printf("These globals were registered at these points:\n");
     Printf("  [1]:\n");
-    uptr stack_size;
-    const uptr *stack_trace = StackDepotGet(stack_id1, &stack_size);
-    StackTrace::PrintStack(stack_trace, stack_size);
+    StackDepotGet(stack_id1).Print();
     Printf("  [2]:\n");
-    stack_trace = StackDepotGet(stack_id2, &stack_size);
-    StackTrace::PrintStack(stack_trace, stack_size);
+    StackDepotGet(stack_id2).Print();
   }
   Report("HINT: if you don't care about these warnings you may set "
          "ASAN_OPTIONS=detect_odr_violation=0\n");
-  ReportErrorSummary("odr-violation", g1_loc.data(), 0, g1->name);
+  InternalScopedString error_msg(256);
+  error_msg.append("odr-violation: global '%s' at %s",
+                   MaybeDemangleGlobalName(g1->name), g1_loc.data());
+  ReportErrorSummary(error_msg.data());
 }
 
 // ----------------------- CheckForInvalidPointerPair ----------- {{{1
@@ -814,8 +894,8 @@
 }
 // ----------------------- Mac-specific reports ----------------- {{{1
 
-void WarnMacFreeUnallocated(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+                            BufferedStackTrace *stack) {
   // Just print a warning here.
   Printf("free_common(%p) -- attempting to free unallocated memory.\n"
              "AddressSanitizer is ignoring this error on Mac OS now.\n",
@@ -825,8 +905,8 @@
   DescribeHeapAddress(addr, 1);
 }
 
-void ReportMacMzReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+                               BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
              "This is an unrecoverable problem, exiting now.\n",
@@ -836,8 +916,8 @@
   DescribeHeapAddress(addr, 1);
 }
 
-void ReportMacCfReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+                               BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
              "This is an unrecoverable problem, exiting now.\n",
@@ -854,8 +934,6 @@
 
 void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
                          uptr access_size) {
-  ScopedInErrorReport in_report;
-
   // Determine the error type.
   const char *bug_descr = "unknown-crash";
   if (AddrIsInMem(addr)) {
@@ -869,6 +947,7 @@
     switch (*shadow_addr) {
       case kAsanHeapLeftRedzoneMagic:
       case kAsanHeapRightRedzoneMagic:
+      case kAsanArrayCookieMagic:
         bug_descr = "heap-buffer-overflow";
         break;
       case kAsanHeapFreeMagic:
@@ -900,12 +979,20 @@
       case kAsanGlobalRedzoneMagic:
         bug_descr = "global-buffer-overflow";
         break;
+      case kAsanIntraObjectRedzone:
+        bug_descr = "intra-object-overflow";
+        break;
     }
   }
+
+  ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+                        bug_descr };
+  ScopedInErrorReport in_report(&report);
+
   Decorator d;
   Printf("%s", d.Warning());
   Report("ERROR: AddressSanitizer: %s on address "
-             "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
+             "%p at pc %p bp %p sp %p\n",
              bug_descr, (void*)addr, pc, bp, sp);
   Printf("%s", d.EndWarning());
 
@@ -937,7 +1024,42 @@
 }
 
 void __asan_describe_address(uptr addr) {
+  // Thread registry must be locked while we're describing an address.
+  asanThreadRegistry().Lock();
   DescribeAddress(addr, 1);
+  asanThreadRegistry().Unlock();
+}
+
+int __asan_report_present() {
+  return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+  return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+  return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+  return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+  return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+  return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+  return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+  return report_data.description;
 }
 
 extern "C" {
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 374ebfb..fd65bad 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -18,13 +18,33 @@
 
 namespace __asan {
 
+struct StackVarDescr {
+  uptr beg;
+  uptr size;
+  const char *name_pos;
+  uptr name_len;
+};
+
+struct AddressDescription {
+  char *name;
+  uptr name_size;
+  uptr region_address;
+  uptr region_size;
+  const char *region_kind;
+};
+
 // The following functions prints address description depending
 // on the memory type (shadow/heap/stack/global).
 void DescribeHeapAddress(uptr addr, uptr access_size);
 bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
                                      const __asan_global &g);
-bool DescribeAddressIfShadow(uptr addr);
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+                             bool print = true);
+bool ParseFrameDescription(const char *frame_descr,
+                           InternalMmapVector<StackVarDescr> *vars);
 bool DescribeAddressIfStack(uptr addr, uptr access_size);
 // Determines memory type on its own.
 void DescribeAddress(uptr addr, uptr access_size);
@@ -34,36 +54,44 @@
 // Different kinds of error reports.
 void NORETURN
     ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
-void NORETURN
-    ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
-void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
+                            void *context, uptr addr);
+void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
+                                          BufferedStackTrace *free_stack);
+void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
                                       AllocType alloc_type,
                                       AllocType dealloc_type);
-void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
-                                             StackTrace *stack);
 void NORETURN
-ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack);
-void NORETURN ReportStringFunctionMemoryRangesOverlap(
-    const char *function, const char *offset1, uptr length1,
-    const char *offset2, uptr length2, StackTrace *stack);
+    ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
 void NORETURN
-ReportStringFunctionSizeOverflow(uptr offset, uptr size, StackTrace *stack);
+    ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+                                            BufferedStackTrace *stack);
 void NORETURN
-ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid,
-                                             uptr new_mid, StackTrace *stack);
+    ReportStringFunctionMemoryRangesOverlap(const char *function,
+                                            const char *offset1, uptr length1,
+                                            const char *offset2, uptr length2,
+                                            BufferedStackTrace *stack);
+void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+                                               BufferedStackTrace *stack);
+void NORETURN
+    ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+                                                 uptr old_mid, uptr new_mid,
+                                                 BufferedStackTrace *stack);
 
 void NORETURN
 ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                    const __asan_global *g2, u32 stack_id2);
 
 // Mac-specific errors and warnings.
-void WarnMacFreeUnallocated(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacMzReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacCfReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+                            BufferedStackTrace *stack);
+void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+                                        const char *zone_name,
+                                        BufferedStackTrace *stack);
+void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+                                        const char *zone_name,
+                                        BufferedStackTrace *stack);
 
 }  // namespace __asan
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 8f02257..f87d84f 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -67,7 +67,7 @@
   Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
          line, cond, (uptr)v1, (uptr)v2);
   // FIXME: check for infinite recursion without a thread-local counter here.
-  PRINT_CURRENT_STACK();
+  PRINT_CURRENT_STACK_CHECK();
   Die();
 }
 
@@ -173,11 +173,6 @@
       "If set, prints ASan exit stats even after program terminates "
       "successfully.");
 
-  ParseFlag(str, &f->disable_core, "disable_core",
-      "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
-      "dumping a 16T+ core file. "
-      "Ignored on OSes that don't dump core by default.");
-
   ParseFlag(str, &f->allow_reexec, "allow_reexec",
       "Allow the tool to re-exec the program. This may interfere badly with "
       "the debugger.");
@@ -191,6 +186,9 @@
       "Poison (or not) the heap memory on [de]allocation. Zero value is useful "
       "for benchmarking the allocator or instrumentator.");
 
+  ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie",
+      "Poison (or not) the array cookie after operator new[].");
+
   ParseFlag(str, &f->poison_partial, "poison_partial",
       "If true, poison partially addressable 8-byte aligned words "
       "(default=true). This flag affects heap and global buffers, but not "
@@ -198,6 +196,10 @@
 
   ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch",
       "Report errors on malloc/delete, new/free, new/delete[], etc.");
+
+  ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch",
+      "Report errors on mismatch betwen size of new and delete.");
+
   ParseFlag(str, &f->strict_memcmp, "strict_memcmp",
       "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
       "comparing p1 and p2.");
@@ -228,6 +230,9 @@
             "If >=2, detect violation of One-Definition-Rule (ODR); "
             "If ==1, detect ODR-violation only if the two variables "
             "have different sizes");
+
+  ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
+      "If true, dump 16 bytes starting at the instruction that caused SEGV");
 }
 
 void InitializeFlags(Flags *f, const char *env) {
@@ -264,22 +269,24 @@
   f->print_stats = false;
   f->print_legend = true;
   f->atexit = false;
-  f->disable_core = (SANITIZER_WORDSIZE == 64);
   f->allow_reexec = true;
   f->print_full_thread_history = true;
   f->poison_heap = true;
+  f->poison_array_cookie = true;
   f->poison_partial = true;
   // Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
   // https://code.google.com/p/address-sanitizer/issues/detail?id=131
   // https://code.google.com/p/address-sanitizer/issues/detail?id=309
   // TODO(glider,timurrrr): Fix known issues and enable this back.
   f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
+  f->new_delete_type_mismatch = true;
   f->strict_memcmp = true;
   f->strict_init_order = false;
   f->start_deactivated = false;
   f->detect_invalid_pointer_pairs = 0;
   f->detect_container_overflow = true;
   f->detect_odr_violation = 2;
+  f->dump_instruction_bytes = false;
 
   // Override from compile definition.
   ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
@@ -459,13 +466,6 @@
     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 18: __asan_get_allocated_size(0); break;
-    case 19: __asan_get_current_allocated_bytes(); break;
-    case 20: __asan_get_estimated_allocated_size(0); break;
-    case 21: __asan_get_free_bytes(); break;
-    case 22: __asan_get_heap_size(); break;
-    case 23: __asan_get_ownership(0); break;
-    case 24: __asan_get_unmapped_bytes(); 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;
@@ -609,7 +609,8 @@
   bool full_shadow_is_available =
       MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
 
-#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) &&                \
+    !ASAN_FIXED_MAPPING
   if (!full_shadow_is_available) {
     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
@@ -619,9 +620,7 @@
   if (common_flags()->verbosity)
     PrintAddressSpaceLayout();
 
-  if (flags()->disable_core) {
-    DisableCoreDumper();
-  }
+  DisableCoreDumperIfNecessary();
 
   if (full_shadow_is_available) {
     // mmap the low shadow plus at least one page at the left.
@@ -656,12 +655,8 @@
   AsanTSDInit(PlatformTSDDtor);
   InstallDeadlySignalHandlers(AsanOnSIGSEGV);
 
-  // Allocator should be initialized before starting external symbolizer, as
-  // fork() on Mac locks the allocator.
   InitializeAllocator();
 
-  Symbolizer::Init(common_flags()->external_symbolizer_path);
-
   // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
   // should be set to 1 prior to initializing the threads.
   asan_inited = 1;
@@ -690,7 +685,7 @@
   SanitizerInitializeUnwinder();
 
 #if CAN_SANITIZE_LEAKS
-  __lsan::InitCommonLsan();
+  __lsan::InitCommonLsan(false);
   if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
     Atexit(__lsan::DoLeakCheck);
   }
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index 032f729..8610ee4 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -25,8 +25,9 @@
 // The pc will be in the position 0 of the resulting stack trace.
 // The bp may refer to the current frame or to the caller's frame.
 ALWAYS_INLINE
-void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
-                                     uptr bp, void *context, bool fast) {
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+                                     uptr pc, uptr bp, void *context,
+                                     bool fast) {
 #if SANITIZER_WINDOWS
   stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
 #else
@@ -34,6 +35,10 @@
   stack->size = 0;
   if (LIKELY(asan_inited)) {
     if ((t = GetCurrentThread()) && !t->isUnwinding()) {
+      // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+      // yields the call stack of the signal's handler and not of the code
+      // that raised the signal (as it does on Linux).
+      if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
       uptr stack_top = t->stack_top();
       uptr stack_bottom = t->stack_bottom();
       ScopedUnwinding unwind_scope(t);
@@ -53,14 +58,14 @@
 // don't want stack trace to contain functions from ASan internals.
 
 #define GET_STACK_TRACE(max_size, fast)                                        \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   if (max_size <= 2) {                                                         \
     stack.size = max_size;                                                     \
     if (max_size > 0) {                                                        \
       stack.top_frame_bp = GET_CURRENT_FRAME();                                \
-      stack.trace[0] = StackTrace::GetCurrentPc();                             \
+      stack.trace_buffer[0] = StackTrace::GetCurrentPc();                      \
       if (max_size > 1)                                                        \
-        stack.trace[1] = GET_CALLER_PC();                                      \
+        stack.trace_buffer[1] = GET_CALLER_PC();                               \
     }                                                                          \
   } else {                                                                     \
     GetStackTraceWithPcBpAndContext(&stack, max_size,                          \
@@ -69,18 +74,21 @@
   }
 
 #define GET_STACK_TRACE_FATAL(pc, bp)                                          \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0,           \
                                   common_flags()->fast_unwind_on_fatal)
 
 #define GET_STACK_TRACE_SIGNAL(pc, bp, context)                                \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,     \
                                   common_flags()->fast_unwind_on_fatal)
 
 #define GET_STACK_TRACE_FATAL_HERE                                \
   GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
 
+#define GET_STACK_TRACE_CHECK_HERE                                \
+  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
 #define GET_STACK_TRACE_THREAD                                    \
   GET_STACK_TRACE(kStackTraceMax, true)
 
@@ -96,4 +104,10 @@
     stack.Print();              \
   }
 
+#define PRINT_CURRENT_STACK_CHECK() \
+  {                                 \
+    GET_STACK_TRACE_CHECK_HERE;     \
+    stack.Print();                  \
+  }
+
 #endif  // ASAN_STACK_H
diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc
index 0837bc8..a78b7b1 100644
--- a/lib/asan/asan_stats.cc
+++ b/lib/asan/asan_stats.cc
@@ -149,18 +149,12 @@
   // way we update accumulated stats.
   return (malloced > freed) ? malloced - freed : 1;
 }
-uptr __asan_get_current_allocated_bytes() {
-  return __sanitizer_get_current_allocated_bytes();
-}
 
 uptr __sanitizer_get_heap_size() {
   AsanStats stats;
   GetAccumulatedStats(&stats);
   return stats.mmaped - stats.munmaped;
 }
-uptr __asan_get_heap_size() {
-  return __sanitizer_get_heap_size();
-}
 
 uptr __sanitizer_get_free_bytes() {
   AsanStats stats;
@@ -175,16 +169,10 @@
   // way we update accumulated stats.
   return (total_free > total_used) ? total_free - total_used : 1;
 }
-uptr __asan_get_free_bytes() {
-  return __sanitizer_get_free_bytes();
-}
 
 uptr __sanitizer_get_unmapped_bytes() {
   return 0;
 }
-uptr __asan_get_unmapped_bytes() {
-  return __sanitizer_get_unmapped_bytes();
-}
 
 void __asan_print_accumulated_stats() {
   PrintAccumulatedStats();
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 48ff401..ce53bea 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -30,7 +30,7 @@
 void AsanThreadContext::OnCreated(void *arg) {
   CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
   if (args->stack)
-    stack_id = StackDepotPut(args->stack->trace, args->stack->size);
+    stack_id = StackDepotPut(*args->stack);
   thread = args->thread;
   thread->set_context(this);
 }
@@ -198,17 +198,18 @@
     PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
 }
 
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
-                                           uptr *frame_pc) {
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+                                           StackFrameAccess *access) {
   uptr bottom = 0;
   if (AddrIsInStack(addr)) {
     bottom = stack_bottom();
   } else if (has_fake_stack()) {
     bottom = fake_stack()->AddrIsInFakeStack(addr);
     CHECK(bottom);
-    *offset = addr - bottom;
-    *frame_pc = ((uptr*)bottom)[2];
-    return  (const char *)((uptr*)bottom)[1];
+    access->offset = addr - bottom;
+    access->frame_pc = ((uptr*)bottom)[2];
+    access->frame_descr = (const char *)((uptr*)bottom)[1];
+    return true;
   }
   uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
@@ -225,15 +226,15 @@
   }
 
   if (shadow_ptr < shadow_bottom) {
-    *offset = 0;
-    return "UNKNOWN";
+    return false;
   }
 
   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
   CHECK(ptr[0] == kCurrentStackFrameMagic);
-  *offset = addr - (uptr)ptr;
-  *frame_pc = ptr[2];
-  return (const char*)ptr[1];
+  access->offset = addr - (uptr)ptr;
+  access->frame_pc = ptr[2];
+  access->frame_descr = (const char*)ptr[1];
+  return true;
 }
 
 static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h
index 1bce25c..bf23728 100644
--- a/lib/asan/asan_thread.h
+++ b/lib/asan/asan_thread.h
@@ -71,7 +71,12 @@
   AsanThreadContext *context() { return context_; }
   void set_context(AsanThreadContext *context) { context_ = context; }
 
-  const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
+  struct StackFrameAccess {
+    uptr offset;
+    uptr frame_pc;
+    const char *frame_descr;
+  };
+  bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
 
   bool AddrIsInStack(uptr addr) {
     return addr >= stack_bottom_ && addr < stack_top_;
@@ -103,6 +108,10 @@
   bool isUnwinding() const { return unwinding_; }
   void setUnwinding(bool b) { unwinding_ = b; }
 
+  // True if we are in a deadly signal handler.
+  bool isInDeadlySignal() const { return in_deadly_signal_; }
+  void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
+
   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
   AsanStats &stats() { return stats_; }
 
@@ -128,6 +137,7 @@
   AsanThreadLocalMallocStorage malloc_storage_;
   AsanStats stats_;
   bool unwinding_;
+  bool in_deadly_signal_;
 };
 
 // ScopedUnwinding is a scope for stacktracing member of a context
@@ -142,6 +152,20 @@
   AsanThread *thread;
 };
 
+// ScopedDeadlySignal is a scope for handling deadly signals.
+class ScopedDeadlySignal {
+ public:
+  explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
+    if (thread) thread->setInDeadlySignal(true);
+  }
+  ~ScopedDeadlySignal() {
+    if (thread) thread->setInDeadlySignal(false);
+  }
+
+ private:
+  AsanThread *thread;
+};
+
 struct CreateThreadContextArgs {
   AsanThread *thread;
   StackTrace *stack;
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index da26e98..5303d1b 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -21,6 +21,7 @@
 
 #include "asan_interceptors.h"
 #include "asan_internal.h"
+#include "asan_report.h"
 #include "asan_thread.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_mutex.h"
@@ -70,7 +71,7 @@
   return 0;
 }
 
-void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); }
+void AsanCheckDynamicRTPrereqs() {}
 
 void AsanCheckIncompatibleRT() {}
 
@@ -86,6 +87,67 @@
   UNIMPLEMENTED();
 }
 
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+  EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+  CONTEXT *context = info->ContextRecord;
+  uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+  uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
+#else
+  uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
+#endif
+
+  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+      exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+    const char *description =
+        (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+            ? "access-violation"
+            : "in-page-error";
+    uptr access_addr = exception_record->ExceptionInformation[1];
+    ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
+  }
+
+  // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+  return default_seh_handler(info);
+}
+
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot.  Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module.  This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+  // We should only store the previous handler if it's not our own handler in
+  // order to avoid loops in the EH chain.
+  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+  if (prev_seh_handler != &SEHHandler)
+    default_seh_handler = prev_seh_handler;
+  return 0;
+}
+
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
+#pragma section(".CRT$XIZ", long, read)  // NOLINT
+static __declspec(allocate(".CRT$XIZ"))
+    int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+
 }  // namespace __asan
 
 #endif  // _WIN32
diff --git a/lib/asan/asan_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
similarity index 93%
rename from lib/asan/asan_dll_thunk.cc
rename to lib/asan/asan_win_dll_thunk.cc
index a3fbb27..b38a2d1 100644
--- a/lib/asan/asan_dll_thunk.cc
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -1,4 +1,4 @@
-//===-- asan_dll_thunk.cc -------------------------------------------------===//
+//===-- asan_win_dll_thunk.cc ---------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -21,7 +21,7 @@
 // simplifies the build procedure.
 #ifdef ASAN_DLL_THUNK
 #include "asan_init_version.h"
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 
 // ---------- Function interception helper functions and macros ----------- {{{1
 extern "C" {
@@ -75,7 +75,7 @@
 // Special case of hooks -- ASan own interface functions.  Those are only called
 // after __asan_init, thus an empty implementation is sufficient.
 #define INTERFACE_FUNCTION(name)                                               \
-  extern "C" void name() {                                                     \
+  extern "C" __declspec(noinline) void name() {                                \
     volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf;             \
     __debugbreak();                                                            \
   }                                                                            \
@@ -235,6 +235,20 @@
 INTERFACE_FUNCTION(__asan_report_load16)
 INTERFACE_FUNCTION(__asan_report_load_n)
 
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+
 INTERFACE_FUNCTION(__asan_memcpy);
 INTERFACE_FUNCTION(__asan_memset);
 INTERFACE_FUNCTION(__asan_memmove);
@@ -251,6 +265,9 @@
 INTERFACE_FUNCTION(__asan_poison_memory_region)
 INTERFACE_FUNCTION(__asan_unpoison_memory_region)
 
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+
 INTERFACE_FUNCTION(__asan_get_current_fake_stack)
 INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
 
@@ -307,6 +324,15 @@
 
 INTERCEPT_LIBRARY_FUNCTION(atoi);
 INTERCEPT_LIBRARY_FUNCTION(atol);
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+  __asan_handle_no_return();
+  return REAL(_except_handler4)(a, b, c, d);
+}
+
 INTERCEPT_LIBRARY_FUNCTION(frexp);
 INTERCEPT_LIBRARY_FUNCTION(longjmp);
 INTERCEPT_LIBRARY_FUNCTION(memchr);
@@ -330,6 +356,7 @@
 // is defined.
 void InterceptHooks() {
   INTERCEPT_HOOKS();
+  INTERCEPT_FUNCTION(_except_handler4);
 }
 
 // We want to call __asan_init before C/C++ initializers/constructors are
diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 0000000..3a4de7d
--- /dev/null
+++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,52 @@
+//===-- asan_win_uar_thunk.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 a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL RTL.
+//
+// This includes:
+//  - forwarding the detect_stack_use_after_return runtime option
+//  - installing a custom SEH handler
+//
+//===----------------------------------------------------------------------===//
+
+// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Using #ifdef rather than relying on Makefiles etc.
+// simplifies the build procedure.
+#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+
+// 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.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it.  Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// 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.
+int __asan_option_detect_stack_use_after_return =
+    __asan_should_detect_stack_use_after_return();
+
+// Set the ASan-specific SEH handler at the end of CRT initialization of each
+// module (see asan_win.cc for the details).
+//
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+#pragma section(".CRT$XIZ", long, read)  // NOLINT
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
+#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup
index 261e2c6..a620f51 100755
--- a/lib/asan/scripts/asan_device_setup
+++ b/lib/asan/scripts/asan_device_setup
@@ -1,4 +1,4 @@
-#!/bin/bash -e
+#!/bin/bash
 #===- lib/asan/scripts/asan_device_setup -----------------------------------===#
 #
 #                     The LLVM Compiler Infrastructure
@@ -10,6 +10,7 @@
 #
 #===------------------------------------------------------------------------===#
 
+set -e
 
 HERE="$(cd "$(dirname "$0")" && pwd)"
 
@@ -29,6 +30,21 @@
     exit 1
 }
 
+function get_device_arch { # OUTVAR
+    local _outvar=$1
+    local _ABI=$($ADB shell getprop ro.product.cpu.abi)
+    local _ARCH=
+    if [[ $_ABI == x86* ]]; then
+        _ARCH=i686
+    elif [[ $_ABI == armeabi* ]]; then
+        _ARCH=arm
+    else
+        echo "Unrecognized device ABI: $_ABI"
+        exit 1
+    fi
+    eval $_outvar=\$_ARCH
+}
+
 while [[ $# > 0 ]]; do
   case $1 in
     --revert)
@@ -70,16 +86,31 @@
     ADB="$ADB -s $device"
 fi
 
-ASAN_RT="libclang_rt.asan-arm-android.so"
+echo '>> Remounting /system rw'
+$ADB root
+$ADB wait-for-device
+$ADB remount
+$ADB wait-for-device
+
+get_device_arch ARCH
+echo "Target architecture: $ARCH"
+ASAN_RT="libclang_rt.asan-$ARCH-android.so"
 
 if [[ x$revert == xyes ]]; then
     echo '>> Uninstalling ASan'
-    $ADB root
-    $ADB wait-for-device
-    $ADB remount
-    $ADB shell mv /system/bin/app_process.real /system/bin/app_process
-    $ADB shell rm /system/bin/asanwrapper
-    $ADB shell rm /system/lib/$ASAN_RT
+
+    if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then
+        echo '>> Pre-L device detected.'
+        $ADB shell mv /system/bin/app_process.real /system/bin/app_process
+        $ADB shell rm /system/bin/asanwrapper
+        $ADB shell rm /system/lib/$ASAN_RT
+    else
+        $ADB shell rm /system/bin/app_process.wrap
+        $ADB shell rm /system/bin/asanwrapper
+        $ADB shell rm /system/lib/$ASAN_RT
+        $ADB shell rm /system/bin/app_process
+        $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+    fi
 
     echo '>> Restarting shell'
     $ADB shell stop
@@ -97,15 +128,15 @@
     ASAN_RT_PATH="$HERE"
 elif [[ $(basename "$HERE") == "bin" ]]; then
     # We could be in the toolchain's base directory.
-    # Consider ../lib, ../lib/asan and ../lib/clang/$VERSION/lib/linux.
-    P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
+    # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux.
+    P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
     if [[ -n "$P" ]]; then
         ASAN_RT_PATH="$(dirname "$P")"
     fi
 fi
 
 if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
-    echo "ASan runtime library not found"
+    echo ">> ASan runtime library not found"
     exit 1
 fi
 
@@ -114,28 +145,34 @@
 TMPDIR="$TMPDIRBASE/new"
 mkdir "$TMPDIROLD"
 
-echo '>> Remounting /system rw'
-$ADB root
-$ADB wait-for-device
-$ADB remount
-
-echo '>> Copying files from the device'
-$ADB pull /system/bin/app_process "$TMPDIROLD"
-$ADB pull /system/bin/app_process.real "$TMPDIROLD" || true
-$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true
-$ADB pull /system/lib/libclang_rt.asan-arm-android.so "$TMPDIROLD" || true
-cp -r "$TMPDIROLD" "$TMPDIR"
-
-if ! [[ -f "$TMPDIR/app_process" ]]; then
-    echo "app_process missing???"
-    exit 1
+RELEASE=$($ADB shell getprop ro.build.version.release)
+PRE_L=0
+if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
+    PRE_L=1
 fi
 
-if [[ -f "$TMPDIR/app_process.real" ]]; then
-    echo "app_process.real exists, updating the wrapper"
+if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then
+
+    if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then
+        echo '>> Old-style ASan installation detected. Reverting.'
+        $ADB shell mv /system/bin/app_process.real /system/bin/app_process
+    fi
+
+    echo '>> Pre-L device detected. Setting up app_process symlink.'
+    $ADB shell mv /system/bin/app_process /system/bin/app_process32
+    $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process
+fi
+
+echo '>> Copying files from the device'
+$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true
+$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true
+$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
+cp -r "$TMPDIROLD" "$TMPDIR"
+
+if [[ -f "$TMPDIR/app_process.wrap" ]]; then
+    echo ">> Previous installation detected"
 else
-    echo "app_process.real missing, new installation"
-    mv "$TMPDIR/app_process" "$TMPDIR/app_process.real"
+    echo ">> New installation"
 fi
 
 echo '>> Generating wrappers'
@@ -145,16 +182,22 @@
 # FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup,
 # which may or may not be a real bug (probably not).
 ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0
+
+# On Android-L not allowing user segv handler breaks some applications.
+if $ADB shell 'echo $LD_PRELOAD' | grep libsigchain.so >&/dev/null; then
+    ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
+fi
+
 if [[ x$extra_options != x ]] ; then
     ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
 fi
 
 # Zygote wrapper.
-cat <<EOF >"$TMPDIR/app_process"
-#!/system/bin/sh
+cat <<EOF >"$TMPDIR/app_process.wrap"
+#!/system/bin/sh-from-zygote
 ASAN_OPTIONS=$ASAN_OPTIONS \\
-LD_PRELOAD=libclang_rt.asan-arm-android.so \\
-exec /system/bin/app_process.real \$@
+LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\
+exec /system/bin/app_process32 \$@
 
 EOF
 
@@ -162,7 +205,7 @@
 # zygote).
 cat <<EOF >"$TMPDIR/asanwrapper"
 #!/system/bin/sh
-LD_PRELOAD=libclang_rt.asan-arm-android.so \\
+LD_PRELOAD=$ASAN_RT \\
 exec \$@
 
 EOF
@@ -170,18 +213,48 @@
 if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
     echo '>> Pushing files to the device'
     $ADB push "$TMPDIR/$ASAN_RT" /system/lib/
-    $ADB push "$TMPDIR/app_process" /system/bin/app_process
-    $ADB push "$TMPDIR/app_process.real" /system/bin/app_process.real
+    $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap
     $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper
+
+    $ADB shell rm /system/bin/app_process
+    $ADB shell ln -s /system/bin/app_process.wrap /system/bin/app_process
+
     $ADB shell chown root.shell \
-        /system/bin/app_process \
-        /system/bin/app_process.real \
+        /system/lib/"$ASAN_RT" \
+        /system/bin/app_process.wrap \
         /system/bin/asanwrapper
+    $ADB shell chmod 644 \
+        /system/lib/"$ASAN_RT"
     $ADB shell chmod 755 \
-        /system/bin/app_process \
-        /system/bin/app_process.real \
+        /system/bin/app_process.wrap \
         /system/bin/asanwrapper
 
+    # Make SELinux happy by keeping app_process wrapper and the shell
+    # it runs on in zygote domain.
+    ENFORCING=0
+    if $ADB shell getenforce | grep Enforcing >/dev/null; then
+        # Sometimes shell is not allowed to change file contexts.
+        # Temporarily switch to permissive.
+        ENFORCING=1
+        $ADB shell setenforce 0
+    fi
+
+    $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote
+
+    if [[ PRE_L -eq 1 ]]; then
+        CTX=u:object_r:system_file:s0
+    else
+        CTX=u:object_r:zygote_exec:s0
+    fi
+    $ADB shell chcon $CTX \
+        /system/bin/sh-from-zygote \
+        /system/bin/app_process.wrap \
+        /system/bin/app_process32
+
+    if [ $ENFORCING == 1 ]; then
+        $ADB shell setenforce 1
+    fi
+
     echo '>> Restarting shell (asynchronous)'
     $ADB shell stop
     $ADB shell start
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index a2f34f6..76de60a 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -7,6 +7,7 @@
 # License. See LICENSE.TXT for details.
 #
 #===------------------------------------------------------------------------===#
+import argparse
 import bisect
 import getopt
 import os
@@ -18,18 +19,26 @@
 
 symbolizers = {}
 DEBUG = False
-demangle = False;
-
+demangle = False
+binutils_prefix = None
+sysroot_path = None
+binary_name_filter = None
+fix_filename_patterns = None
+logfile = sys.stdin
 
 # FIXME: merge the code that calls fix_filename().
 def fix_filename(file_name):
-  for path_to_cut in sys.argv[1:]:
-    file_name = re.sub('.*' + path_to_cut, '', file_name)
+  if fix_filename_patterns:
+    for path_to_cut in fix_filename_patterns:
+      file_name = re.sub('.*' + path_to_cut, '', file_name)
   file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
   file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
   return file_name
 
-def GuessArch(addr):
+def sysroot_path_filter(binary_name):
+  return sysroot_path + binary_name
+
+def guess_arch(addr):
   # Guess which arch we're running. 10 = len('0x') + 8 hex digits.
   if len(addr) > 10:
     return 'x86_64'
@@ -60,7 +69,7 @@
   def __init__(self, symbolizer_path, addr):
     super(LLVMSymbolizer, self).__init__()
     self.symbolizer_path = symbolizer_path
-    self.default_arch = GuessArch(addr)
+    self.default_arch = guess_arch(addr)
     self.pipe = self.open_llvm_symbolizer()
 
   def open_llvm_symbolizer(self):
@@ -124,7 +133,10 @@
     self.pipe = self.open_addr2line()
 
   def open_addr2line(self):
-    cmd = ['addr2line', '-f']
+    addr2line_tool = 'addr2line'
+    if binutils_prefix:
+      addr2line_tool = binutils_prefix + addr2line_tool
+    cmd = [addr2line_tool, '-f']
     if demangle:
       cmd += ['--demangle']
     cmd += ['-e', self.binary]
@@ -182,7 +194,7 @@
   def __init__(self, addr, binary):
     super(DarwinSymbolizer, self).__init__()
     self.binary = binary
-    self.arch = GuessArch(addr)
+    self.arch = guess_arch(addr)
     self.open_atos()
 
   def open_atos(self):
@@ -328,9 +340,10 @@
     # E.g. in Chrome several binaries may share a single .dSYM.
     self.binary_name_filter = binary_name_filter
     self.system = os.uname()[0]
-    if self.system not in ['Linux', 'Darwin']:
+    if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
       raise Exception('Unknown system')
     self.llvm_symbolizer = None
+    self.frame_no = 0
 
   def symbolize_address(self, addr, binary, offset):
     # Initialize llvm-symbolizer lazily.
@@ -352,48 +365,77 @@
     assert result
     return result
 
-  def print_symbolized_lines(self, symbolized_lines):
+  def get_symbolized_lines(self, symbolized_lines):
     if not symbolized_lines:
-      print self.current_line
+      return [self.current_line]
     else:
+      result = []
       for symbolized_frame in symbolized_lines:
-        print '    #' + str(self.frame_no) + ' ' + symbolized_frame.rstrip()
+        result.append('    #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
         self.frame_no += 1
+      return result
 
-  def process_stdin(self):
+  def process_logfile(self):
     self.frame_no = 0
     while True:
-      line = sys.stdin.readline()
+      line = logfile.readline()
       if not line:
         break
-      self.current_line = line.rstrip()
-      #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
-      stack_trace_line_format = (
-          '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
-      match = re.match(stack_trace_line_format, line)
-      if not match:
-        print self.current_line
-        continue
-      if DEBUG:
-        print line
-      _, frameno_str, addr, binary, offset = match.groups()
-      if frameno_str == '0':
-        # Assume that frame #0 is the first frame of new stack trace.
-        self.frame_no = 0
-      original_binary = binary
-      if self.binary_name_filter:
-        binary = self.binary_name_filter(binary)
-      symbolized_line = self.symbolize_address(addr, binary, offset)
-      if not symbolized_line:
-        if original_binary != binary:
-          symbolized_line = self.symbolize_address(addr, binary, offset)
-      self.print_symbolized_lines(symbolized_line)
+      processed = self.process_line(line)
+      print '\n'.join(processed)
+
+  def process_line(self, line):
+    self.current_line = line.rstrip()
+    #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
+    stack_trace_line_format = (
+        '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
+    match = re.match(stack_trace_line_format, line)
+    if not match:
+      return [self.current_line]
+    if DEBUG:
+      print line
+    _, frameno_str, addr, binary, offset = match.groups()
+    if frameno_str == '0':
+      # Assume that frame #0 is the first frame of new stack trace.
+      self.frame_no = 0
+    original_binary = binary
+    if self.binary_name_filter:
+      binary = self.binary_name_filter(binary)
+    symbolized_line = self.symbolize_address(addr, binary, offset)
+    if not symbolized_line:
+      if original_binary != binary:
+        symbolized_line = self.symbolize_address(addr, binary, offset)
+    return self.get_symbolized_lines(symbolized_line)
 
 
 if __name__ == '__main__':
-  opts, args = getopt.getopt(sys.argv[1:], "d", ["demangle"])
-  for o, a in opts:
-    if o in ("-d", "--demangle"):
-      demangle = True;
-  loop = SymbolizationLoop()
-  loop.process_stdin()
+  parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+  description='ASan symbolization script',
+  epilog='''Example of use:
+  asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log''')
+  parser.add_argument('path_to_cut', nargs='*',
+    help='pattern to be cut from the result file path ')
+  parser.add_argument('-d','--demangle', action='store_true',
+    help='demangle function names')
+  parser.add_argument('-s', metavar='SYSROOT',
+    help='set path to sysroot for sanitized binaries')
+  parser.add_argument('-c', metavar='CROSS_COMPILE',
+    help='set prefix for binutils')
+  parser.add_argument('-l','--logfile', default=sys.stdin, type=argparse.FileType('r'),
+    help='set log file name to parse, default is stdin')
+  args = parser.parse_args()
+  if args.path_to_cut:
+    fix_filename_patterns = args.path_to_cut
+  if args.demangle:
+    demangle = True
+  if args.s:
+    binary_name_filter = sysroot_path_filter
+    sysroot_path = args.s
+  if args.c:
+    binutils_prefix = args.c
+  if args.logfile:
+    logfile = args.logfile
+  else:
+    logfile = sys.stdin
+  loop = SymbolizationLoop(binary_name_filter)
+  loop.process_logfile()
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index c6a7041..7b36371 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -31,7 +31,7 @@
   -O2
   -Wno-format
   -Werror=sign-compare)
-append_if(COMPILER_RT_HAS_WNO_VARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
 
 # -gline-tables-only must be enough for ASan, so use it if possible.
 if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
@@ -51,8 +51,10 @@
   ${ASAN_UNITTEST_COMMON_CFLAGS}
   -fsanitize=address
   "-fsanitize-blacklist=${ASAN_BLACKLIST_FILE}"
-  -mllvm -asan-instrument-assembly
 )
+if(CAN_TARGET_x86_64 OR CAN_TARGET_i386)
+  list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-instrument-assembly)
+endif()
 
 if(NOT MSVC)
   list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS --driver-mode=g++)
@@ -73,23 +75,29 @@
 
 set(ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS
   ${ASAN_UNITTEST_COMMON_LINKFLAGS})
-# On Android, we link with ASan runtime manually. On other platforms we depend
-# on Clang driver behavior, passing -fsanitize=address flag.
-if(NOT ANDROID)
-  list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
-endif()
+list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
 
 set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS
   ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}
   -shared-libasan)
 
+set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
+
 set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS})
-append_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS)
-append_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
-append_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS)
-append_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
+append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread
           ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS)
 
+# TODO(eugenis): move all -l flags above to _LIBS?
+set(ASAN_UNITTEST_NOINST_LIBS)
+append_list_if(ANDROID log ASAN_UNITTEST_NOINST_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
+
 # Compile source for the given architecture, using compiler
 # options in ${ARGN}, and add it to the object list.
 macro(asan_compile obj_list source arch kind)
@@ -198,7 +206,7 @@
       $<TARGET_OBJECTS:RTInterception.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
-    if(NOT MSVC)
+    if(NOT WIN32)
       list(APPEND ASAN_TEST_RUNTIME_OBJECTS
            $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
     endif()
@@ -233,7 +241,7 @@
   endif()
 endmacro()
 
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
   foreach(arch ${ASAN_SUPPORTED_ARCH})
     add_asan_tests_for_arch_and_kind(${arch} "-inline")
     add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
@@ -242,31 +250,31 @@
 endif()
 
 if(ANDROID)
-  # We assume that unit tests on Android are built in a build
-  # tree with fresh Clang as a host compiler.
-  
-  # Test w/o ASan instrumentation. Link it with ASan statically.
-  add_executable(AsanNoinstTest
-    $<TARGET_OBJECTS:RTAsan.arm.android>
-    $<TARGET_OBJECTS:RTInterception.arm.android>
-    $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>
-    ${COMPILER_RT_GTEST_SOURCE}
-    ${ASAN_NOINST_TEST_SOURCES})
-  set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
-  set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
-  target_link_libraries(AsanNoinstTest log)
+  foreach(arch ${ASAN_SUPPORTED_ARCH})
+    # Test w/o ASan instrumentation. Link it with ASan statically.
+    add_executable(AsanNoinstTest # FIXME: .arch?
+      $<TARGET_OBJECTS:RTAsan.${arch}>
+      $<TARGET_OBJECTS:RTInterception.${arch}>
+      $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+      ${COMPILER_RT_GTEST_SOURCE}
+      ${ASAN_NOINST_TEST_SOURCES})
+    set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
+    set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS})
+    target_link_libraries(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LIBS})
 
-  # Test with ASan instrumentation. Link with ASan dynamic runtime.
-  add_executable(AsanTest
-    ${COMPILER_RT_GTEST_SOURCE}
-    ${ASAN_INST_TEST_SOURCES})
-  set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
-  set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
-  target_link_libraries(AsanTest clang_rt.asan-arm-android)
+    # Test with ASan instrumentation. Link with ASan dynamic runtime.
+    add_executable(AsanTest
+      ${COMPILER_RT_GTEST_SOURCE}
+      ${ASAN_INST_TEST_SOURCES})
+    set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
+    set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+    target_link_libraries(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LIBS})
 
-  # Setup correct output directory and link flags.
-  set_target_properties(AsanNoinstTest AsanTest PROPERTIES
-    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-  # Add unit test to test suite.
-  add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+    # Setup correct output directory and link flags.
+    set_target_properties(AsanNoinstTest AsanTest PROPERTIES
+      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+    # Add unit tests to the test suite.
+    add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
+  endforeach()
 endif()
diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc
index 86f806d..1d8b04d 100644
--- a/lib/asan/tests/asan_asm_test.cc
+++ b/lib/asan/tests/asan_asm_test.cc
@@ -22,6 +22,7 @@
 
 template<typename T> void asm_write(T *ptr, T val);
 template<typename T> T asm_read(T *ptr);
+template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
 
 } // End of anonymous namespace
 
@@ -53,8 +54,17 @@
   return res;                                      \
 }
 
+#define DECLARE_ASM_REP_MOVS(Type, Movs)                                       \
+  template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) {   \
+    __asm__("rep " Movs " \n\t"                                                \
+            :                                                                  \
+            : "D"(dst), "S"(src), "c"(size)                                    \
+            : "rsi", "rdi", "rcx", "memory");                                  \
+  }
+
 DECLARE_ASM_WRITE(U8, "8", "movq", "r");
 DECLARE_ASM_READ(U8, "8", "movq", "=r");
+DECLARE_ASM_REP_MOVS(U8, "movsq");
 
 } // End of anonymous namespace
 
@@ -86,6 +96,14 @@
   return res;                                      \
 }
 
+#define DECLARE_ASM_REP_MOVS(Type, Movs)                                       \
+  template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) {   \
+    __asm__("rep " Movs " \n\t"                                                \
+            :                                                                  \
+            : "D"(dst), "S"(src), "c"(size)                                    \
+            : "esi", "edi", "ecx", "memory");                                  \
+  }
+
 } // End of anonymous namespace
 
 #endif  // defined(__i386__) && defined(__SSE2__)
@@ -104,6 +122,10 @@
 DECLARE_ASM_READ(U4, "4", "movl", "=r");
 DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
 
+DECLARE_ASM_REP_MOVS(U1, "movsb");
+DECLARE_ASM_REP_MOVS(U2, "movsw");
+DECLARE_ASM_REP_MOVS(U4, "movsl");
+
 template<typename T> void TestAsmWrite(const char *DeathPattern) {
   T *buf = new T;
   EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
@@ -157,6 +179,28 @@
   __asm__("movl %[r], (%[a])  \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
 }
 
+template <typename T>
+void TestAsmRepMovs(const char *DeathPatternRead,
+                    const char *DeathPatternWrite) {
+  T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
+  T dst_good[4] = {};
+  asm_rep_movs(dst_good, src_good, 4);
+  ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
+  ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
+  ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
+  ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
+
+  T dst_bad[3];
+  EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
+
+  T src_bad[3] = { 0x0, 0x1, 0x2 };
+  EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
+
+  T* dp = dst_bad + 4;
+  T* sp = src_bad + 4;
+  asm_rep_movs(dp, sp, 0);
+}
+
 } // End of anonymous namespace
 
 TEST(AddressSanitizer, asm_load_store) {
@@ -209,6 +253,15 @@
   ASSERT_EQ(0x1, r);
 }
 
+TEST(AddressSanitizer, asm_rep_movs) {
+  TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
+  TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
+  TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
+#if defined(__x86_64__)
+  TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
+#endif  // defined(__x86_64__)
+}
+
 #endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
 
 #endif // defined(__linux__)
diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc
index 7fae462..bb6af45 100644
--- a/lib/asan/tests/asan_noinst_test.cc
+++ b/lib/asan/tests/asan_noinst_test.cc
@@ -52,19 +52,19 @@
 
 static void MallocStress(size_t n) {
   u32 seed = my_rand();
-  StackTrace stack1;
-  stack1.trace[0] = 0xa123;
-  stack1.trace[1] = 0xa456;
+  BufferedStackTrace stack1;
+  stack1.trace_buffer[0] = 0xa123;
+  stack1.trace_buffer[1] = 0xa456;
   stack1.size = 2;
 
-  StackTrace stack2;
-  stack2.trace[0] = 0xb123;
-  stack2.trace[1] = 0xb456;
+  BufferedStackTrace stack2;
+  stack2.trace_buffer[0] = 0xb123;
+  stack2.trace_buffer[1] = 0xb456;
   stack2.size = 2;
 
-  StackTrace stack3;
-  stack3.trace[0] = 0xc123;
-  stack3.trace[1] = 0xc456;
+  BufferedStackTrace stack3;
+  stack3.trace_buffer[0] = 0xc123;
+  stack3.trace_buffer[1] = 0xc456;
   stack3.size = 2;
 
   std::vector<void *> vec;
@@ -140,8 +140,8 @@
 }
 
 TEST(AddressSanitizer, QuarantineTest) {
-  StackTrace stack;
-  stack.trace[0] = 0x890;
+  BufferedStackTrace stack;
+  stack.trace_buffer[0] = 0x890;
   stack.size = 1;
 
   const int size = 1024;
@@ -161,8 +161,8 @@
 void *ThreadedQuarantineTestWorker(void *unused) {
   (void)unused;
   u32 seed = my_rand();
-  StackTrace stack;
-  stack.trace[0] = 0x890;
+  BufferedStackTrace stack;
+  stack.trace_buffer[0] = 0x890;
   stack.size = 1;
 
   for (size_t i = 0; i < 1000; i++) {
@@ -188,8 +188,8 @@
 
 void *ThreadedOneSizeMallocStress(void *unused) {
   (void)unused;
-  StackTrace stack;
-  stack.trace[0] = 0x890;
+  BufferedStackTrace stack;
+  stack.trace_buffer[0] = 0x890;
   stack.size = 1;
   const size_t kNumMallocs = 1000;
   for (int iter = 0; iter < 1000; iter++) {
@@ -241,8 +241,8 @@
   uptr buggy_ptr;
 
   __asan_test_only_reported_buggy_pointer = &buggy_ptr;
-  StackTrace stack;
-  stack.trace[0] = 0x890;
+  BufferedStackTrace stack;
+  stack.trace_buffer[0] = 0x890;
   stack.size = 1;
 
   for (uptr len = 16; len <= 32; len++) {
diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc
index 3e96997..1cd2a08b 100644
--- a/lib/asan/tests/asan_str_test.cc
+++ b/lib/asan/tests/asan_str_test.cc
@@ -221,7 +221,8 @@
 
 TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
   RunStrChrTest(&strchr);
-#if !defined(_WIN32)  // no index() on Windows.
+// No index() on Windows and on Android L.
+#if !defined(_WIN32) && !defined(__ANDROID__)
   RunStrChrTest(&index);
 #endif
 }
@@ -498,15 +499,6 @@
   free(str);
 }
 
-void CallAtoi(const char *nptr) {
-  Ident(atoi(nptr));
-}
-void CallAtol(const char *nptr) {
-  Ident(atol(nptr));
-}
-void CallAtoll(const char *nptr) {
-  Ident(atoll(nptr));
-}
 typedef void(*PointerToCallAtoi)(const char*);
 
 void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
@@ -534,6 +526,15 @@
 }
 
 #if !defined(_WIN32)  // FIXME: Fix and enable on Windows.
+void CallAtoi(const char *nptr) {
+  Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+  Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+  Ident(atoll(nptr));
+}
 TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
   RunAtoiOOBTest(&CallAtoi);
   RunAtoiOOBTest(&CallAtol);
@@ -541,12 +542,6 @@
 }
 #endif
 
-void CallStrtol(const char *nptr, char **endptr, int base) {
-  Ident(strtol(nptr, endptr, base));
-}
-void CallStrtoll(const char *nptr, char **endptr, int base) {
-  Ident(strtoll(nptr, endptr, base));
-}
 typedef void(*PointerToCallStrtol)(const char*, char**, int);
 
 void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
@@ -590,6 +585,12 @@
 }
 
 #if !defined(_WIN32)  // FIXME: Fix and enable on Windows.
+void CallStrtol(const char *nptr, char **endptr, int base) {
+  Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+  Ident(strtoll(nptr, endptr, base));
+}
 TEST(AddressSanitizer, StrtollOOBTest) {
   RunStrtolOOBTest(&CallStrtoll);
 }
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 7760486..67bcbac 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -602,9 +602,9 @@
   siglongjmp(buf, 1);
 }
 
-#if !defined(__ANDROID__) && \
+#if !defined(__ANDROID__) && !defined(__arm__) && \
     !defined(__powerpc64__) && !defined(__powerpc__)
-// Does not work on Power:
+// Does not work on Power and ARM:
 // https://code.google.com/p/address-sanitizer/issues/detail?id=185
 TEST(AddressSanitizer, BuiltinLongJmpTest) {
   static jmp_buf buf;
@@ -615,7 +615,7 @@
   }
 }
 #endif  // !defined(__ANDROID__) && !defined(__powerpc64__) &&
-        // !defined(__powerpc__)
+        // !defined(__powerpc__) && !defined(__arm__)
 
 TEST(AddressSanitizer, UnderscopeLongJmpTest) {
   static jmp_buf buf;
@@ -832,7 +832,7 @@
   x[18]++;
   x[19]++;
 
-  delete x;
+  delete[] x;
   return res;
 }
 
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index bab3ce3..999faa8 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -163,6 +163,9 @@
   i386/umoddi3.S
   ${GENERIC_SOURCES})
 
+set(i686_SOURCES
+  ${i386_SOURCES})
+
 set(arm_SOURCES
   arm/adddf3vfp.S
   arm/addsf3vfp.S
@@ -250,14 +253,26 @@
 add_custom_target(builtins)
 
 if (NOT WIN32)
-  foreach(arch x86_64 i386 arm)
-    if(CAN_TARGET_${arch})
+  foreach (arch x86_64 i386 i686 arm)
+    if (CAN_TARGET_${arch})
+      # Filter out generic versions of routines that are re-implemented in
+      # architecture specific manner.  This prevents multiple definitions of the
+      # same symbols, making the symbol selection non-deterministic.
+      foreach (_file ${${arch}_SOURCES})
+        if (${_file} MATCHES ${arch}/*)
+          get_filename_component(_name ${_file} NAME)
+          string(REPLACE ".S" ".c" _cname "${_name}")
+          list(REMOVE_ITEM ${arch}_SOURCES ${_cname})
+        endif ()
+      endforeach ()
+
+      set_source_files_properties(${${arch}_SOURCES} PROPERTIES LANGUAGE C)
       add_compiler_rt_runtime(clang_rt.builtins-${arch} ${arch} STATIC
-        SOURCES ${${arch}_SOURCES}
-        CFLAGS "-std=c99")
+                              SOURCES ${${arch}_SOURCES}
+                              CFLAGS "-std=c99")
       add_dependencies(builtins clang_rt.builtins-${arch})
-    endif()
-  endforeach()
-endif()
+    endif ()
+  endforeach ()
+endif ()
 
 add_dependencies(compiler-rt builtins)
diff --git a/lib/builtins/addvdi3.c b/lib/builtins/addvdi3.c
index db45a27..0da3894 100644
--- a/lib/builtins/addvdi3.c
+++ b/lib/builtins/addvdi3.c
@@ -21,7 +21,7 @@
 COMPILER_RT_ABI di_int
 __addvdi3(di_int a, di_int b)
 {
-    di_int s = a + b;
+    di_int s = (du_int) a + (du_int) b;
     if (b >= 0)
     {
         if (s < a)
diff --git a/lib/builtins/addvsi3.c b/lib/builtins/addvsi3.c
index 81f515c..94ca726 100644
--- a/lib/builtins/addvsi3.c
+++ b/lib/builtins/addvsi3.c
@@ -21,7 +21,7 @@
 COMPILER_RT_ABI si_int
 __addvsi3(si_int a, si_int b)
 {
-    si_int s = a + b;
+    si_int s = (su_int) a + (su_int) b;
     if (b >= 0)
     {
         if (s < a)
diff --git a/lib/builtins/addvti3.c b/lib/builtins/addvti3.c
index 79b9611..c224de6 100644
--- a/lib/builtins/addvti3.c
+++ b/lib/builtins/addvti3.c
@@ -23,7 +23,7 @@
 COMPILER_RT_ABI ti_int
 __addvti3(ti_int a, ti_int b)
 {
-    ti_int s = a + b;
+    ti_int s = (tu_int) a + (tu_int) b;
     if (b >= 0)
     {
         if (s < a)
diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S
index c2e2ce9..86f3bba 100644
--- a/lib/builtins/arm/bswapdi2.S
+++ b/lib/builtins/arm/bswapdi2.S
@@ -21,7 +21,11 @@
 // Reverse all the bytes in a 64-bit integer.
 //
 	.p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
+#else
 DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
+#endif
 #if __ARM_ARCH < 6
     // before armv6 does not have "rev" instruction
     // r2 = rev(r0)
diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S
index ad09655..59ba815 100644
--- a/lib/builtins/arm/bswapsi2.S
+++ b/lib/builtins/arm/bswapsi2.S
@@ -21,7 +21,11 @@
 // Reverse all the bytes in a 32-bit integer.
 //
 	.p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
+#else
 DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
+#endif
 #if __ARM_ARCH < 6
     // before armv6 does not have "rev" instruction
  	eor	r1, r0, r0, ror #16
diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S
index bcea485..a55abac 100644
--- a/lib/builtins/arm/clzdi2.S
+++ b/lib/builtins/arm/clzdi2.S
@@ -21,7 +21,11 @@
 
 
 	.p2align	2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
+#else
 DEFINE_COMPILERRT_FUNCTION(__clzdi2)
+#endif
 #ifdef __ARM_FEATURE_CLZ
 #ifdef __ARMEB__
 	cmp	r0, 0
diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S
index f0240b0..1cd379b 100644
--- a/lib/builtins/arm/clzsi2.S
+++ b/lib/builtins/arm/clzsi2.S
@@ -20,7 +20,11 @@
 #endif
 
 	.p2align	2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
+#else
 DEFINE_COMPILERRT_FUNCTION(__clzsi2)
+#endif
 #ifdef __ARM_FEATURE_CLZ
 	clz	r0, r0
 	JMP(lr)
diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S
index 91bb2a5..646b9ab 100644
--- a/lib/builtins/arm/divmodsi4.S
+++ b/lib/builtins/arm/divmodsi4.S
@@ -27,8 +27,16 @@
 	.thumb
 #endif
 
+@ int __divmodsi4(int divident, int divisor, int *remainder)
+@   Calculate the quotient and remainder of the (signed) division.  The return
+@   value is the quotient, the remainder is placed in the variable.
+
 	.p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
+#else
 DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
 	tst     r1, r1
 	beq     LOCAL_LABEL(divzero)
diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S
index db47165..adf8f94 100644
--- a/lib/builtins/arm/divsi3.S
+++ b/lib/builtins/arm/divsi3.S
@@ -29,7 +29,15 @@
 	.p2align 3
 // Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
 DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
+
+@ int __divsi3(int divident, int divisor)
+@   Calculate and return the quotient of the (signed) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
+#else
 DEFINE_COMPILERRT_FUNCTION(__divsi3)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
    tst     r1,r1
    beq     LOCAL_LABEL(divzero)
diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S
index 7ed305e..295a227 100644
--- a/lib/builtins/arm/modsi3.S
+++ b/lib/builtins/arm/modsi3.S
@@ -26,8 +26,15 @@
 	.thumb
 #endif
 
+@ int __modsi3(int divident, int divisor)
+@   Calculate and return the remainder of the (signed) division.
+
 	.p2align 3
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
+#else
 DEFINE_COMPILERRT_FUNCTION(__modsi3)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
 	tst     r1, r1
 	beq     LOCAL_LABEL(divzero)
diff --git a/lib/builtins/arm/sync-ops.h b/lib/builtins/arm/sync-ops.h
index 87cc3c2..ee02c30 100644
--- a/lib/builtins/arm/sync-ops.h
+++ b/lib/builtins/arm/sync-ops.h
@@ -18,21 +18,24 @@
 #define SYNC_OP_4(op) \
         .p2align 2 ; \
         .thumb ; \
-        DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_ ## op) \
+        .syntax unified ; \
+        DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
         dmb ; \
         mov r12, r0 ; \
         LOCAL_LABEL(tryatomic_ ## op): \
         ldrex r0, [r12] ; \
         op(r2, r0, r1) ; \
         strex r3, r2, [r12] ; \
-        cbnz r3, LOCAL_LABEL(tryatomic_ ## op) ; \
+        cmp r3, #0 ; \
+        bne LOCAL_LABEL(tryatomic_ ## op) ; \
         dmb ; \
         bx lr
 
 #define SYNC_OP_8(op) \
         .p2align 2 ; \
         .thumb ; \
-        DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_ ## op) \
+        .syntax unified ; \
+        DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
         push {r4, r5, r6, lr} ; \
         dmb ; \
         mov r12, r0 ; \
@@ -40,7 +43,8 @@
         ldrexd r0, r1, [r12] ; \
         op(r4, r5, r0, r1, r2, r3) ; \
         strexd r6, r4, r5, [r12] ; \
-        cbnz r6, LOCAL_LABEL(tryatomic_ ## op) ; \
+        cmp r6, #0 ; \
+        bne LOCAL_LABEL(tryatomic_ ## op) ; \
         dmb ; \
         pop {r4, r5, r6, pc}
 
diff --git a/lib/builtins/arm/sync_fetch_and_add_8.S b/lib/builtins/arm/sync_fetch_and_add_8.S
index db59e05..5724bb1 100644
--- a/lib/builtins/arm/sync_fetch_and_add_8.S
+++ b/lib/builtins/arm/sync_fetch_and_add_8.S
@@ -14,9 +14,11 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define add_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     adds rD_LO, rN_LO, rM_LO ; \
     adc rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(add_8)
+#endif
 
diff --git a/lib/builtins/arm/sync_fetch_and_and_8.S b/lib/builtins/arm/sync_fetch_and_and_8.S
index 845c74f..a74163a 100644
--- a/lib/builtins/arm/sync_fetch_and_and_8.S
+++ b/lib/builtins/arm/sync_fetch_and_and_8.S
@@ -14,8 +14,10 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define and_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     and rD_LO, rN_LO, rM_LO ; \
     and rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(and_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_max_8.S b/lib/builtins/arm/sync_fetch_and_max_8.S
index 12dd46c..1eef2b2 100644
--- a/lib/builtins/arm/sync_fetch_and_max_8.S
+++ b/lib/builtins/arm/sync_fetch_and_max_8.S
@@ -14,6 +14,8 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define max_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI)         MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, gt)
 
 SYNC_OP_8(max_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_min_8.S b/lib/builtins/arm/sync_fetch_and_min_8.S
index 97af2aa..ad5cce0 100644
--- a/lib/builtins/arm/sync_fetch_and_min_8.S
+++ b/lib/builtins/arm/sync_fetch_and_min_8.S
@@ -14,6 +14,8 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define min_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI)         MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lt)
 
 SYNC_OP_8(min_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_nand_8.S b/lib/builtins/arm/sync_fetch_and_nand_8.S
index 80e8c00..a2c17c0 100644
--- a/lib/builtins/arm/sync_fetch_and_nand_8.S
+++ b/lib/builtins/arm/sync_fetch_and_nand_8.S
@@ -14,9 +14,11 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define nand_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     bic rD_LO, rN_LO, rM_LO ; \
     bic rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(nand_8)
+#endif
 
diff --git a/lib/builtins/arm/sync_fetch_and_or_8.S b/lib/builtins/arm/sync_fetch_and_or_8.S
index 0f77f02..87b940b 100644
--- a/lib/builtins/arm/sync_fetch_and_or_8.S
+++ b/lib/builtins/arm/sync_fetch_and_or_8.S
@@ -14,9 +14,11 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define or_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     orr rD_LO, rN_LO, rM_LO ; \
     orr rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(or_8)
+#endif
 
diff --git a/lib/builtins/arm/sync_fetch_and_sub_8.S b/lib/builtins/arm/sync_fetch_and_sub_8.S
index f4e1c4a..a8035a2 100644
--- a/lib/builtins/arm/sync_fetch_and_sub_8.S
+++ b/lib/builtins/arm/sync_fetch_and_sub_8.S
@@ -14,9 +14,11 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define sub_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     subs rD_LO, rN_LO, rM_LO ; \
     sbc rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(sub_8)
+#endif
 
diff --git a/lib/builtins/arm/sync_fetch_and_umax_8.S b/lib/builtins/arm/sync_fetch_and_umax_8.S
index 7716cfe..d9b7965 100644
--- a/lib/builtins/arm/sync_fetch_and_umax_8.S
+++ b/lib/builtins/arm/sync_fetch_and_umax_8.S
@@ -14,6 +14,8 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define umax_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI)         MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, hi)
 
 SYNC_OP_8(umax_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_umin_8.S b/lib/builtins/arm/sync_fetch_and_umin_8.S
index b099726..7bf5e23 100644
--- a/lib/builtins/arm/sync_fetch_and_umin_8.S
+++ b/lib/builtins/arm/sync_fetch_and_umin_8.S
@@ -14,6 +14,8 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define umin_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI)         MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, lo)
 
 SYNC_OP_8(umin_8)
+#endif
diff --git a/lib/builtins/arm/sync_fetch_and_xor_8.S b/lib/builtins/arm/sync_fetch_and_xor_8.S
index 91b6a4c..ea9aa6d 100644
--- a/lib/builtins/arm/sync_fetch_and_xor_8.S
+++ b/lib/builtins/arm/sync_fetch_and_xor_8.S
@@ -14,9 +14,11 @@
 
 #include "sync-ops.h"
 
+#if __ARM_ARCH_PROFILE != 'M'
 #define xor_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI) \
     eor rD_LO, rN_LO, rM_LO ; \
     eor rD_HI, rN_HI, rM_HI
 
 SYNC_OP_8(xor_8)
+#endif
 
diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S
index ddc8752..85b8493 100644
--- a/lib/builtins/arm/udivmodsi4.S
+++ b/lib/builtins/arm/udivmodsi4.S
@@ -17,8 +17,21 @@
 	.syntax unified
 	.text
 
+#if __ARM_ARCH_ISA_THUMB == 2
+	.thumb
+#endif
+
+@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
+@                           unsigned int *remainder)
+@   Calculate the quotient and remainder of the (unsigned) division.  The return
+@   value is the quotient, the remainder is placed in the variable.
+
 	.p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
+#else
 DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
 	tst     r1, r1
 	beq     LOCAL_LABEL(divby0)
@@ -42,6 +55,7 @@
 	 * r0 and (r1 << I) have the highest bit set in the same position.
 	 * At the time of JMP, ip := .Ldiv0block - 12 * I.
 	 * This depends on the fixed instruction size of block.
+	 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
 	 *
 	 * block(shift) implements the test-and-update-quotient core.
 	 * It assumes (r0 << shift) can be computed without overflow and
@@ -53,12 +67,20 @@
 	clz	r3, r1
 	/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
 	sub	r3, r3, ip
+#    if __ARM_ARCH_ISA_THUMB == 2
+	adr	ip, LOCAL_LABEL(div0block) + 1
+	sub	ip, ip, r3, lsl #1
+#    else
 	adr	ip, LOCAL_LABEL(div0block)
+#    endif
 	sub	ip, ip, r3, lsl #2
 	sub	ip, ip, r3, lsl #3
 	mov	r3, #0
 	bx	ip
 #  else
+#    if __ARM_ARCH_ISA_THUMB == 2
+#    error THUMB mode requires CLZ or UDIV
+#    endif
 	str	r4, [sp, #-8]!
 
 	mov	r4, r0
@@ -96,10 +118,11 @@
 
 #define	IMM	#
 
-#define block(shift) \
-	cmp	r0, r1, lsl IMM shift; \
-	addhs	r3, r3, IMM (1 << shift); \
-	subhs	r0, r0, r1, lsl IMM shift
+#define block(shift)                                                           \
+	cmp	r0, r1, lsl IMM shift;                                         \
+	ITT(hs);                                                               \
+	WIDE(addhs)	r3, r3, IMM (1 << shift);                              \
+	WIDE(subhs)	r0, r0, r1, lsl IMM shift
 
 	block(31)
 	block(30)
diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S
index 8fb1dca..165b2b5 100644
--- a/lib/builtins/arm/udivsi3.S
+++ b/lib/builtins/arm/udivsi3.S
@@ -17,21 +17,33 @@
 	.syntax unified
 	.text
 
+#if __ARM_ARCH_ISA_THUMB == 2
+	.thumb
+#endif
+
 	.p2align 2
 DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
+
+@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
+@   Calculate and return the quotient of the (unsigned) division.
+
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
+#else
 DEFINE_COMPILERRT_FUNCTION(__udivsi3)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
 	tst     r1, r1
 	beq     LOCAL_LABEL(divby0)
-	mov 	r3, r0
-	udiv	r0, r3, r1
-	mls 	r1, r0, r1, r3
+	udiv	r0, r0, r1
 	bx  	lr
 #else
 	cmp	r1, #1
 	bcc	LOCAL_LABEL(divby0)
+	IT(eq)
 	JMPc(lr, eq)
 	cmp	r0, r1
+	ITT(cc)
 	movcc	r0, #0
 	JMPc(lr, cc)
 	/*
@@ -43,6 +55,7 @@
 	 * r0 and (r1 << I) have the highest bit set in the same position.
 	 * At the time of JMP, ip := .Ldiv0block - 12 * I.
 	 * This depends on the fixed instruction size of block.
+	 * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
 	 *
 	 * block(shift) implements the test-and-update-quotient core.
 	 * It assumes (r0 << shift) can be computed without overflow and
@@ -54,12 +67,20 @@
 	clz	r3, r1
 	/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
 	sub	r3, r3, ip
+#    if __ARM_ARCH_ISA_THUMB == 2
+	adr	ip, LOCAL_LABEL(div0block) + 1
+	sub	ip, ip, r3, lsl #1
+#    else
 	adr	ip, LOCAL_LABEL(div0block)
+#    endif
 	sub	ip, ip, r3, lsl #2
 	sub	ip, ip, r3, lsl #3
 	mov	r3, #0
 	bx	ip
 #  else
+#    if __ARM_ARCH_ISA_THUMB == 2
+#    error THUMB mode requires CLZ or UDIV
+#    endif
 	mov	r2, r0
 	adr	ip, LOCAL_LABEL(div0block)
 
@@ -94,10 +115,11 @@
 
 #define	IMM	#
 
-#define block(shift) \
-	cmp	r0, r1, lsl IMM shift; \
-	addhs	r3, r3, IMM (1 << shift); \
-	subhs	r0, r0, r1, lsl IMM shift
+#define block(shift)                                                           \
+	cmp	r0, r1, lsl IMM shift;                                         \
+	ITT(hs);                                                               \
+	WIDE(addhs)	r3, r3, IMM (1 << shift);                              \
+	WIDE(subhs)	r0, r0, r1, lsl IMM shift
 
 	block(31)
 	block(30)
diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S
index 164646b..9e7a148 100644
--- a/lib/builtins/arm/umodsi3.S
+++ b/lib/builtins/arm/umodsi3.S
@@ -16,23 +16,33 @@
 
 	.syntax unified
 	.text
+#if __ARM_ARCH_ISA_THUMB == 2
+	.thumb
+#endif
+
+@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
+@   Calculate and return the remainder of the (unsigned) division.
 
 	.p2align 2
+#if __ARM_ARCH_ISA_THUMB == 2
+DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
+#else
 DEFINE_COMPILERRT_FUNCTION(__umodsi3)
+#endif
 #if __ARM_ARCH_EXT_IDIV__
 	tst     r1, r1
 	beq     LOCAL_LABEL(divby0)
-	mov 	r3, r0
-	udiv	r0, r3, r1
-	mls 	r1, r0, r1, r3
-	str 	r1, [r2]
+	udiv	r2, r0, r1
+	mls 	r0, r2, r1, r0
 	bx  	lr
 #else
 	cmp	r1, #1
 	bcc	LOCAL_LABEL(divby0)
+	ITT(eq)
 	moveq	r0, #0
 	JMPc(lr, eq)
 	cmp	r0, r1
+	IT(cc)
 	JMPc(lr, cc)
 	/*
 	 * Implement division using binary long division algorithm.
@@ -43,6 +53,7 @@
 	 * r0 and (r1 << I) have the highest bit set in the same position.
 	 * At the time of JMP, ip := .Ldiv0block - 8 * I.
 	 * This depends on the fixed instruction size of block.
+	 * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
 	 *
 	 * block(shift) implements the test-and-update-quotient core.
 	 * It assumes (r0 << shift) can be computed without overflow and
@@ -54,10 +65,18 @@
 	clz	r3, r1
 	/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
 	sub	r3, r3, ip
+#    if __ARM_ARCH_ISA_THUMB == 2
+	adr	ip, LOCAL_LABEL(div0block) + 1
+	sub	ip, ip, r3, lsl #1
+#    else
 	adr	ip, LOCAL_LABEL(div0block)
+#    endif
 	sub	ip, ip, r3, lsl #3
 	bx	ip
 #  else
+#    if __ARM_ARCH_ISA_THUMB == 2
+#    error THUMB mode requires CLZ or UDIV
+#    endif
 	mov	r2, r0
 	adr	ip, LOCAL_LABEL(div0block)
 
@@ -90,9 +109,10 @@
 
 #define	IMM	#
 
-#define block(shift) \
-	cmp	r0, r1, lsl IMM shift; \
-	subhs	r0, r0, r1, lsl IMM shift
+#define block(shift)                                                           \
+	cmp	r0, r1, lsl IMM shift;                                         \
+	IT(hs);                                                                \
+	WIDE(subhs)	r0, r0, r1, lsl IMM shift
 
 	block(31)
 	block(30)
diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h
index d415a5f..8688a9b 100644
--- a/lib/builtins/assembly.h
+++ b/lib/builtins/assembly.h
@@ -28,7 +28,9 @@
 // tell linker it can break up file at label boundaries
 #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
 #define SYMBOL_IS_FUNC(name)
+
 #elif defined(__ELF__)
+
 #define HIDDEN(name) .hidden name
 #define LOCAL_LABEL(name) .L_##name
 #define FILE_LEVEL_DIRECTIVE
@@ -37,45 +39,21 @@
 #else
 #define SYMBOL_IS_FUNC(name) .type name,@function
 #endif
-#else
+
+#else // !__APPLE__ && !__ELF__
+
 #define HIDDEN_DIRECTIVE(name)
 #define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
 #define SYMBOL_IS_FUNC(name)                                                   \
   .def name SEPARATOR                                                          \
     .scl 2 SEPARATOR                                                           \
     .type 32 SEPARATOR                                                         \
   .endef
-#define FILE_LEVEL_DIRECTIVE
+
 #endif
 
 #if defined(__arm__)
-#ifndef __ARM_ARCH
-#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) ||                     \
-    defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) ||                    \
-    defined(__ARM_ARCH_7EM__)
-#define __ARM_ARCH 7
-#endif
-#endif
-
-#ifndef __ARM_ARCH
-#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) ||                     \
-    defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) ||                    \
-    defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6ZM__)
-#define __ARM_ARCH 6
-#endif
-#endif
-
-#ifndef __ARM_ARCH
-#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) ||                     \
-    defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
-#define __ARM_ARCH 5
-#endif
-#endif
-
-#ifndef __ARM_ARCH
-#define __ARM_ARCH 4
-#endif
-
 #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
 #define ARM_HAS_BX
 #endif
@@ -91,6 +69,20 @@
 #define JMP(r) mov pc, r
 #define JMPc(r, c) mov##c pc, r
 #endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define IT(cond)  it cond
+#define ITT(cond) itt cond
+#else
+#define IT(cond)
+#define ITT(cond)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
 #endif
 
 #define GLUE2(a, b) a##b
@@ -111,6 +103,14 @@
   DECLARE_SYMBOL_VISIBILITY(name)                                              \
   SYMBOL_NAME(name):
 
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name)                                 \
+  FILE_LEVEL_DIRECTIVE SEPARATOR                                               \
+  .globl SYMBOL_NAME(name) SEPARATOR                                           \
+  SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
+  DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR                                    \
+  .thumb_func SEPARATOR                                                        \
+  SYMBOL_NAME(name):
+
 #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name)                               \
   FILE_LEVEL_DIRECTIVE SEPARATOR                                               \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c
index 66f9fcc..86e68af 100644
--- a/lib/builtins/clear_cache.c
+++ b/lib/builtins/clear_cache.c
@@ -32,9 +32,7 @@
  * specified range.
  */
 
-COMPILER_RT_EXPORT void
-__clear_cache(void* start, void* end)
-{
+void __clear_cache(void *start, void *end) {
 #if __i386__ || __x86_64__
 /*
  * Intel processors have a unified instruction and data cache
diff --git a/lib/builtins/i386/floatdidf.S b/lib/builtins/i386/floatdidf.S
index 5c45ee9..f4f5d01 100644
--- a/lib/builtins/i386/floatdidf.S
+++ b/lib/builtins/i386/floatdidf.S
@@ -7,12 +7,21 @@
 
 #ifdef __i386__
 
-#ifndef __ELF__
-.const
+#if defined(__APPLE__)
+	.const
+#elif defined(__ELF__)
+	.section .rodata
+#else
+	.section .rdata,"rd"
 #endif
-.balign 4
-twop52: .quad 0x4330000000000000
-twop32: .quad 0x41f0000000000000
+
+	.balign 16
+twop52:
+	.quad 0x4330000000000000
+
+	.balign 16
+twop32:
+	.quad 0x41f0000000000000
 
 #define REL_ADDR(_a)	(_a)-0b(%eax)
 
diff --git a/lib/builtins/i386/floatundidf.S b/lib/builtins/i386/floatundidf.S
index b006278..676fed0 100644
--- a/lib/builtins/i386/floatundidf.S
+++ b/lib/builtins/i386/floatundidf.S
@@ -17,14 +17,25 @@
 
 #ifdef __i386__
 
-#ifndef __ELF__
-.const
+#if defined(__APPLE__)
+	.const
+#elif defined(__ELF__)
+	.section .rodata
+#else
+	.section .rdata,"rd"
 #endif
-.balign 4
-twop52: .quad 0x4330000000000000
+
+	.balign 16
+twop52:
+	.quad 0x4330000000000000
+
+	.balign 16
 twop84_plus_twop52:
-		.quad 0x4530000000100000
-twop84: .quad 0x4530000000000000
+	.quad 0x4530000000100000
+
+	.balign 16
+twop84:
+	.quad 0x4530000000000000
 
 #define REL_ADDR(_a)	(_a)-0b(%eax)
 
diff --git a/lib/builtins/i386/floatundisf.S b/lib/builtins/i386/floatundisf.S
index 8984627..5b81620 100644
--- a/lib/builtins/i386/floatundisf.S
+++ b/lib/builtins/i386/floatundisf.S
@@ -52,15 +52,27 @@
 
 #ifdef __i386__
 
-#ifndef __ELF__
-.const
+#if defined(__APPLE__)
+	.const
+#elif defined(__ELF__)
+	.section .rodata
+#else
+	.section .rdata,"rd"
 #endif
-.balign 8
-twop52: .quad 0x4330000000000000
-		.quad 0x0000000000000fff
-sticky: .quad 0x0000000000000000
-		.long 0x00000012
-twelve:	.long 0x00000000
+
+	.balign 16
+twop52:
+	.quad 0x4330000000000000
+	.quad 0x0000000000000fff
+
+	.balign 16
+sticky:
+	.quad 0x0000000000000000
+	.long 0x00000012
+
+	.balign 16
+twelve:
+	.long 0x00000000
 
 #define			TWOp52			twop52-0b(%ecx)
 #define			STICKY			sticky-0b(%ecx,%eax,8)
diff --git a/lib/builtins/i386/floatundixf.S b/lib/builtins/i386/floatundixf.S
index 9d2f31f..d60ad7d 100644
--- a/lib/builtins/i386/floatundixf.S
+++ b/lib/builtins/i386/floatundixf.S
@@ -7,14 +7,25 @@
 
 #ifdef __i386__
 
-#ifndef __ELF__
-.const
+#if defined(__APPLE__)
+	.const
+#elif defined(__ELF__)
+	.section .rodata
+#else
+	.section .rdata,"rd"
 #endif
-.balign 4
-twop52: .quad 0x4330000000000000
+
+	.balign 16
+twop52:
+	.quad 0x4330000000000000
+
+	.balign 16
 twop84_plus_twop52_neg:
-		.quad 0xc530000000100000
-twop84: .quad 0x4530000000000000
+	.quad 0xc530000000100000
+
+	.balign 16
+twop84:
+	.quad 0x4530000000000000
 
 #define REL_ADDR(_a)	(_a)-0b(%eax)
 
diff --git a/lib/builtins/int_endianness.h b/lib/builtins/int_endianness.h
index c465a98..4b35bde 100644
--- a/lib/builtins/int_endianness.h
+++ b/lib/builtins/int_endianness.h
@@ -33,7 +33,8 @@
 
 /* .. */
 
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) ||   \
+    defined(__minix)
 #include <sys/endian.h>
 
 #if _BYTE_ORDER == _BIG_ENDIAN
@@ -61,7 +62,8 @@
 
 /* .. */
 
-/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */
+/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+ * compiler (at least with GCC) */
 #if defined(__APPLE__) || defined(__ellcc__ )
 
 #ifdef __BIG_ENDIAN__
@@ -83,15 +85,14 @@
 /* .. */
 
 #if defined(__linux__)
-#include <endian.h>
 
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 #define _YUGA_LITTLE_ENDIAN 0
 #define _YUGA_BIG_ENDIAN    1
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 #define _YUGA_LITTLE_ENDIAN 1
 #define _YUGA_BIG_ENDIAN    0
-#endif /* __BYTE_ORDER */
+#endif /* __BYTE_ORDER__ */
 
 #endif /* GNU/Linux */
 
diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h
index 75ab975..ff314da 100644
--- a/lib/builtins/int_lib.h
+++ b/lib/builtins/int_lib.h
@@ -22,19 +22,13 @@
 
 /* ABI macro definitions */
 
-/*
- * TODO define this appropriately for targets that require explicit export
- * declarations (i.e. Windows)
- */
-#define COMPILER_RT_EXPORT
-
 #if __ARM_EABI__
 # define ARM_EABI_FNALIAS(aeabi_name, name)         \
   void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
-# define COMPILER_RT_ABI COMPILER_RT_EXPORT __attribute__((pcs("aapcs")))
+# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
 #else
 # define ARM_EABI_FNALIAS(aeabi_name, name)
-# define COMPILER_RT_ABI COMPILER_RT_EXPORT
+# define COMPILER_RT_ABI
 #endif
 
 #if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
diff --git a/lib/builtins/subvdi3.c b/lib/builtins/subvdi3.c
index 0f1f924..71fc70f 100644
--- a/lib/builtins/subvdi3.c
+++ b/lib/builtins/subvdi3.c
@@ -21,7 +21,7 @@
 COMPILER_RT_ABI di_int
 __subvdi3(di_int a, di_int b)
 {
-    di_int s = a - b;
+    di_int s = (du_int) a - (du_int) b;
     if (b >= 0)
     {
         if (s > a)
diff --git a/lib/builtins/subvsi3.c b/lib/builtins/subvsi3.c
index ec4594c..e6c0fb6 100644
--- a/lib/builtins/subvsi3.c
+++ b/lib/builtins/subvsi3.c
@@ -21,7 +21,7 @@
 COMPILER_RT_ABI si_int
 __subvsi3(si_int a, si_int b)
 {
-    si_int s = a - b;
+    si_int s = (su_int) a - (su_int) b;
     if (b >= 0)
     {
         if (s > a)
diff --git a/lib/builtins/subvti3.c b/lib/builtins/subvti3.c
index 8f11714..a6804d2 100644
--- a/lib/builtins/subvti3.c
+++ b/lib/builtins/subvti3.c
@@ -23,7 +23,7 @@
 COMPILER_RT_ABI ti_int
 __subvti3(ti_int a, ti_int b)
 {
-    ti_int s = a - b;
+    ti_int s = (tu_int) a - (tu_int) b;
     if (b >= 0)
     {
         if (s > a)
diff --git a/lib/builtins/x86_64/floatundidf.S b/lib/builtins/x86_64/floatundidf.S
index 7c94231..d54b974 100644
--- a/lib/builtins/x86_64/floatundidf.S
+++ b/lib/builtins/x86_64/floatundidf.S
@@ -20,15 +20,20 @@
 #if defined(__APPLE__)
 	.const
 #elif defined(__ELF__)
-	.rodata
+	.section .rodata
 #else
 	.section .rdata,"rd"
 #endif
-	.balign 4
+
+	.balign 16
 twop52:
 	.quad 0x4330000000000000
+
+	.balign 16
 twop84_plus_twop52:
 	.quad 0x4530000000100000
+
+	.balign 16
 twop84:
 	.quad 0x4530000000000000
 
diff --git a/lib/builtins/x86_64/floatundisf.S b/lib/builtins/x86_64/floatundisf.S
index c840913..e41f118 100644
--- a/lib/builtins/x86_64/floatundisf.S
+++ b/lib/builtins/x86_64/floatundisf.S
@@ -10,10 +10,12 @@
 #if defined(__APPLE__)
 	.literal4
 #elif defined(__ELF__)
-	.rodata
+	.section .rodata
 #else
 	.section .rdata,"rd"
 #endif
+
+	.balign 16
 two:
 	.single 2.0
 
diff --git a/lib/builtins/x86_64/floatundixf.S b/lib/builtins/x86_64/floatundixf.S
index 6603935..91bdc8a 100644
--- a/lib/builtins/x86_64/floatundixf.S
+++ b/lib/builtins/x86_64/floatundixf.S
@@ -10,11 +10,12 @@
 #if defined(__APPLE__)
 	.const
 #elif defined(__ELF__)
-	.rodata
+	.section .rodata
 #else
 	.section .rdata,"rd"
 #endif
-	.balign 4
+
+	.balign 16
 twop64:
 	.quad 0x43f0000000000000
 
diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt
index bb73d29..daad07f 100644
--- a/lib/dfsan/CMakeLists.txt
+++ b/lib/dfsan/CMakeLists.txt
@@ -7,14 +7,14 @@
   dfsan_interceptors.cc)
 set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 # Prevent clang from generating libc calls.
-append_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
 
 # Static runtime library.
 add_custom_target(dfsan)
 set(arch "x86_64")
 if(CAN_TARGET_${arch})
   set(DFSAN_CFLAGS ${DFSAN_COMMON_CFLAGS})
-  append_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS)
+  append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS)
   add_compiler_rt_runtime(clang_rt.dfsan-${arch} ${arch} STATIC
     SOURCES ${DFSAN_RTL_SOURCES}
             $<TARGET_OBJECTS:RTInterception.${arch}>
@@ -39,9 +39,9 @@
                    VERBATIM
                    COMMAND
                      cat ${CMAKE_CURRENT_SOURCE_DIR}/done_abilist.txt
-                         ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1204_abilist.txt
+                         ${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1404_abilist.txt
                          > ${dfsan_abilist_filename}
-                   DEPENDS done_abilist.txt libc_ubuntu1204_abilist.txt)
+                   DEPENDS done_abilist.txt libc_ubuntu1404_abilist.txt)
 add_dependencies(dfsan dfsan_abilist)
 install(FILES ${dfsan_abilist_filename}
         DESTINATION ${COMPILER_RT_INSTALL_PATH})
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index 076ec58..dcc52b1 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -74,6 +74,14 @@
   return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2];
 }
 
+// Checks we do not run out of labels.
+static void dfsan_check_label(dfsan_label label) {
+  if (label == kInitializingLabel) {
+    Report("FATAL: DataFlowSanitizer: out of labels\n");
+    Die();
+  }
+}
+
 // Resolves the union of two unequal labels.  Nonequality is a precondition for
 // this function (the instrumentation pass inlines the equality test).
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
@@ -106,7 +114,7 @@
     } else {
       label =
         atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
-      CHECK_NE(label, kInitializingLabel);
+      dfsan_check_label(label);
       __dfsan_label_info[label].l1 = l1;
       __dfsan_label_info[label].l2 = l2;
     }
@@ -147,6 +155,15 @@
     Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
 }
 
+// Indirect call to an uninstrumented vararg function. We don't have a way of
+// handling these at the moment.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__dfsan_vararg_wrapper(const char *fname) {
+  Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
+         "function %s\n", fname);
+  Die();
+}
+
 // Like __dfsan_union, but for use from the client or custom functions.  Hence
 // the equality comparison is done here before calling __dfsan_union.
 SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
@@ -160,7 +177,7 @@
 dfsan_label dfsan_create_label(const char *desc, void *userdata) {
   dfsan_label label =
     atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1;
-  CHECK_NE(label, kInitializingLabel);
+  dfsan_check_label(label);
   __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0;
   __dfsan_label_info[label].desc = desc;
   __dfsan_label_info[label].userdata = userdata;
@@ -169,8 +186,20 @@
 
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
 void __dfsan_set_label(dfsan_label label, void *addr, uptr size) {
-  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
+  for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) {
+    // Don't write the label if it is already the value we need it to be.
+    // In a program where most addresses are not labeled, it is common that
+    // a page of shadow memory is entirely zeroed.  The Linux copy-on-write
+    // implementation will share all of the zeroed pages, making a copy of a
+    // page when any value is written.  The un-sharing will happen even if
+    // the value written does not change the value in memory.  Avoiding the
+    // write when both |label| and |*labelp| are zero dramatically reduces
+    // the amount of real memory used by large programs.
+    if (label == *labelp)
+      continue;
+
     *labelp = label;
+  }
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -238,14 +267,50 @@
   return static_cast<uptr>(max_label_allocated);
 }
 
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+dfsan_dump_labels(int fd) {
+  dfsan_label last_label =
+      atomic_load(&__dfsan_last_label, memory_order_relaxed);
+
+  for (uptr l = 1; l <= last_label; ++l) {
+    char buf[64];
+    internal_snprintf(buf, sizeof(buf), "%u %u %u ", l,
+                      __dfsan_label_info[l].l1, __dfsan_label_info[l].l2);
+    internal_write(fd, buf, internal_strlen(buf));
+    if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) {
+      internal_write(fd, __dfsan_label_info[l].desc,
+                     internal_strlen(__dfsan_label_info[l].desc));
+    }
+    internal_write(fd, "\n", 1);
+  }
+}
+
 static void InitializeFlags(Flags &f, const char *env) {
   f.warn_unimplemented = true;
   f.warn_nonzero_labels = false;
   f.strict_data_dependencies = true;
+  f.dump_labels_at_exit = "";
 
   ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented", "");
   ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels", "");
   ParseFlag(env, &f.strict_data_dependencies, "strict_data_dependencies", "");
+  ParseFlag(env, &f.dump_labels_at_exit, "dump_labels_at_exit", "");
+}
+
+static void dfsan_fini() {
+  if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) {
+    fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */);
+    if (fd == kInvalidFd) {
+      Report("WARNING: DataFlowSanitizer: unable to open output file %s\n",
+             flags().dump_labels_at_exit);
+      return;
+    }
+
+    Report("INFO: DataFlowSanitizer: dumping labels to %s\n",
+           flags().dump_labels_at_exit);
+    dfsan_dump_labels(fd);
+    internal_close(fd);
+  }
 }
 
 #ifdef DFSAN_NOLIBC
@@ -267,9 +332,16 @@
   InitializeFlags(flags(), GetEnv("DFSAN_OPTIONS"));
 
   InitializeInterceptors();
+
+  // Register the fini callback to run when the program terminates successfully
+  // or it is killed by the runtime.
+  Atexit(dfsan_fini);
+  SetDieCallback(dfsan_fini);
+
+  __dfsan_label_info[kInitializingLabel].desc = "<init label>";
 }
 
-#ifndef DFSAN_NOLIBC
+#if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY
 __attribute__((section(".preinit_array"), used))
 static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init;
 #endif
diff --git a/lib/dfsan/dfsan.h b/lib/dfsan/dfsan.h
index ffa98d8..1b6c150 100644
--- a/lib/dfsan/dfsan.h
+++ b/lib/dfsan/dfsan.h
@@ -61,6 +61,8 @@
   // comparison might be data-dependent on the content of the strings). This
   // applies only to the custom functions defined in 'custom.c'.
   bool strict_data_dependencies;
+  // The path of the file where to dump the labels when the program terminates.
+  const char* dump_labels_at_exit;
 };
 
 extern Flags flags_data;
diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc
index d06a003..839a399 100644
--- a/lib/dfsan/dfsan_custom.cc
+++ b/lib/dfsan/dfsan_custom.cc
@@ -12,12 +12,14 @@
 // This file defines the custom functions listed in done_abilist.txt.
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_linux.h"
 
 #include "dfsan/dfsan.h"
 
 #include <arpa/inet.h>
+#include <assert.h>
 #include <ctype.h>
 #include <dlfcn.h>
 #include <link.h>
@@ -26,6 +28,8 @@
 #include <pwd.h>
 #include <sched.h>
 #include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -211,8 +215,9 @@
 
 
 static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
-  dfsan_label *sdest = shadow_for(dest), *ssrc = shadow_for((void *)src);
-  internal_memcpy((void *)sdest, (void *)ssrc, n * sizeof(dfsan_label));
+  dfsan_label *sdest = shadow_for(dest);
+  const dfsan_label *ssrc = shadow_for(src);
+  internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
   return internal_memcpy(dest, src, n);
 }
 
@@ -361,9 +366,11 @@
 int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
   dfsan_set_label(0, *info);
-  dfsan_set_label(0, (void *)info->dlpi_name, strlen(info->dlpi_name) + 1);
-  dfsan_set_label(0, (void *)info->dlpi_phdr,
-                  sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
+  dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
+                  strlen(info->dlpi_name) + 1);
+  dfsan_set_label(
+      0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
+      sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
   dfsan_label ret_label;
   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
                                    0, &ret_label);
@@ -839,4 +846,279 @@
   *ret_label = 0;
   return write(fd, buf, count);
 }
+
+// Type used to extract a dfsan_label with va_arg()
+typedef int dfsan_label_va;
+
+// A chunk of data representing the output of formatting either a constant
+// string or a single format directive.
+struct Chunk {
+  // Address of the beginning of the formatted string
+  const char *ptr;
+  // Size of the formatted string
+  size_t size;
+
+  // Type of DFSan label (depends on the format directive)
+  enum {
+    // Constant string, no argument and thus no label
+    NONE = 0,
+    // Label for an argument of '%n'
+    IGNORED,
+    // Label for a '%s' argument
+    STRING,
+    // Label for any other type of argument
+    NUMERIC,
+  } label_type;
+
+  // Value of the argument (if label_type == STRING)
+  const char *arg;
+};
+
+// Formats the input. The output is stored in 'str' starting from offset
+// 'off'. The format directive is represented by the first 'format_size' bytes
+// of 'format'. If 'has_size' is true, 'size' bounds the number of output
+// bytes. Returns the return value of the vsnprintf call used to format the
+// input.
+static int format_chunk(char *str, size_t off, bool has_size, size_t size,
+                        const char *format, size_t format_size, ...) {
+  char *chunk_format = (char *) malloc(format_size + 1);
+  assert(chunk_format);
+  internal_memcpy(chunk_format, format, format_size);
+  chunk_format[format_size] = '\0';
+
+  va_list ap;
+  va_start(ap, format_size);
+  int r = 0;
+  if (has_size) {
+    r = vsnprintf(str + off, off < size ? size - off : 0, chunk_format, ap);
+  } else {
+    r = vsprintf(str + off, chunk_format, ap);
+  }
+  va_end(ap);
+
+  free(chunk_format);
+  return r;
+}
+
+// Formats the input and propagates the input labels to the output. The output
+// is stored in 'str'. If 'has_size' is true, 'size' bounds the number of
+// output bytes. 'format' and 'ap' are the format string and the list of
+// arguments for formatting. Returns the return value vsnprintf would return.
+//
+// The function tokenizes the format string in chunks representing either a
+// constant string or a single format directive (e.g., '%.3f') and formats each
+// chunk independently into the output string. This approach allows to figure
+// out which bytes of the output string depends on which argument and thus to
+// propagate labels more precisely.
+static int format_buffer(char *str, bool has_size, size_t size,
+                         const char *format, dfsan_label *va_labels,
+                         dfsan_label *ret_label, va_list ap) {
+  InternalMmapVector<Chunk> chunks(8);
+  size_t off = 0;
+
+  while (*format) {
+    chunks.push_back(Chunk());
+    Chunk& chunk = chunks.back();
+    chunk.ptr = str + off;
+    chunk.arg = nullptr;
+
+    int status = 0;
+
+    if (*format != '%') {
+      // Ordinary character. Consume all the characters until a '%' or the end
+      // of the string.
+      size_t format_size = 0;
+      for (; *format && *format != '%'; ++format, ++format_size) {}
+      status = format_chunk(str, off, has_size, size, format - format_size,
+                            format_size);
+      chunk.label_type = Chunk::NONE;
+    } else {
+      // Conversion directive. Consume all the characters until a conversion
+      // specifier or the end of the string.
+      bool end_format = false;
+#define FORMAT_CHUNK(t)                                                  \
+      format_chunk(str, off, has_size, size, format - format_size,  \
+                   format_size + 1, va_arg(ap, t))
+
+      for (size_t format_size = 1; *++format && !end_format; ++format_size) {
+        switch (*format) {
+          case 'd':
+          case 'i':
+          case 'o':
+          case 'u':
+          case 'x':
+          case 'X':
+            switch (*(format - 1)) {
+              case 'h':
+                // Also covers the 'hh' case (since the size of the arg is still
+                // an int).
+                status = FORMAT_CHUNK(int);
+                break;
+              case 'l':
+                if (format_size >= 2 && *(format - 2) == 'l') {
+                  status = FORMAT_CHUNK(long long int);
+                } else {
+                  status = FORMAT_CHUNK(long int);
+                }
+                break;
+              case 'q':
+                status = FORMAT_CHUNK(long long int);
+                break;
+              case 'j':
+                status = FORMAT_CHUNK(intmax_t);
+                break;
+              case 'z':
+                status = FORMAT_CHUNK(size_t);
+                break;
+              case 't':
+                status = FORMAT_CHUNK(size_t);
+                break;
+              default:
+                status = FORMAT_CHUNK(int);
+            }
+            chunk.label_type = Chunk::NUMERIC;
+            end_format = true;
+            break;
+
+          case 'a':
+          case 'A':
+          case 'e':
+          case 'E':
+          case 'f':
+          case 'F':
+          case 'g':
+          case 'G':
+            if (*(format - 1) == 'L') {
+              status = FORMAT_CHUNK(long double);
+            } else {
+              status = FORMAT_CHUNK(double);
+            }
+            chunk.label_type = Chunk::NUMERIC;
+            end_format = true;
+            break;
+
+          case 'c':
+            status = FORMAT_CHUNK(int);
+            chunk.label_type = Chunk::NUMERIC;
+            end_format = true;
+            break;
+
+          case 's':
+            chunk.arg = va_arg(ap, char *);
+            status =
+                format_chunk(str, off, has_size, size,
+                             format - format_size, format_size + 1,
+                             chunk.arg);
+            chunk.label_type = Chunk::STRING;
+            end_format = true;
+            break;
+
+          case 'p':
+            status = FORMAT_CHUNK(void *);
+            chunk.label_type = Chunk::NUMERIC;
+            end_format = true;
+            break;
+
+          case 'n':
+            *(va_arg(ap, int *)) = (int)off;
+            chunk.label_type = Chunk::IGNORED;
+            end_format = true;
+            break;
+
+          case '%':
+            status = format_chunk(str, off, has_size, size,
+                                  format - format_size, format_size + 1);
+            chunk.label_type = Chunk::NONE;
+            end_format = true;
+            break;
+
+          default:
+            break;
+        }
+      }
+#undef FORMAT_CHUNK
+    }
+
+    if (status < 0) {
+      return status;
+    }
+
+    // A return value of {v,}snprintf of size or more means that the output was
+    // truncated.
+    if (has_size) {
+      if (off < size) {
+        size_t ustatus = (size_t) status;
+        chunk.size = ustatus >= (size - off) ?
+            ustatus - (size - off) : ustatus;
+      } else {
+        chunk.size = 0;
+      }
+    } else {
+      chunk.size = status;
+    }
+    off += status;
+  }
+
+  // TODO(martignlo): Decide how to combine labels (e.g., whether to ignore or
+  // not the label of the format string).
+
+  // Label each output chunk according to the label supplied as argument to the
+  // function. We need to go through all the chunks and arguments even if the
+  // string was only partially printed ({v,}snprintf case).
+  for (size_t i = 0; i < chunks.size(); ++i) {
+    const Chunk& chunk = chunks[i];
+    void *chunk_ptr = const_cast<char *>(chunk.ptr);
+
+    switch (chunk.label_type) {
+      case Chunk::NONE:
+        dfsan_set_label(0, chunk_ptr, chunk.size);
+        break;
+      case Chunk::IGNORED:
+        va_labels++;
+        dfsan_set_label(0, chunk_ptr, chunk.size);
+        break;
+      case Chunk::NUMERIC: {
+        dfsan_label label = *va_labels++;
+        dfsan_set_label(label, chunk_ptr, chunk.size);
+        break;
+      }
+      case Chunk::STRING: {
+        // Consume the label of the pointer to the string
+        va_labels++;
+        internal_memcpy(shadow_for(chunk_ptr),
+                        shadow_for(chunk.arg),
+                        sizeof(dfsan_label) * (strlen(chunk.arg)));
+        break;
+      }
+    }
+  }
+
+  *ret_label = 0;
+
+  // Number of bytes written in total.
+  return off;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
+                   dfsan_label format_label, dfsan_label *va_labels,
+                   dfsan_label *ret_label, ...) {
+  va_list ap;
+  va_start(ap, ret_label);
+  int ret = format_buffer(str, false, 0, format, va_labels, ret_label, ap);
+  va_end(ap);
+  return ret;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfsw_snprintf(char *str, size_t size, const char *format,
+                    dfsan_label str_label, dfsan_label size_label,
+                    dfsan_label format_label, dfsan_label *va_labels,
+                    dfsan_label *ret_label, ...) {
+  va_list ap;
+  va_start(ap, ret_label);
+  int ret = format_buffer(str, true, size, format, va_labels, ret_label, ap);
+  va_end(ap);
+  return ret;
+}
 }
diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt
index 44507bf..15c6d1b 100644
--- a/lib/dfsan/done_abilist.txt
+++ b/lib/dfsan/done_abilist.txt
@@ -208,9 +208,11 @@
 fun:sigaction=custom
 fun:gettimeofday=custom
 
+# sprintf-like
+fun:sprintf=custom
+fun:snprintf=custom
+
 # TODO: custom
-fun:snprintf=discard
-fun:vsnprintf=discard
 fun:asprintf=discard
 fun:qsort=discard
 
@@ -235,3 +237,24 @@
 
 # Functions that take a callback (wrap the callback manually).
 fun:pthread_create=custom
+
+###############################################################################
+# libffi/libgo
+###############################################################################
+# Functions that are written in asm or are called from asm.
+fun:ffi_call_unix64=uninstrumented
+fun:ffi_call_unix64=discard
+fun:ffi_closure_unix64_inner=uninstrumented
+fun:ffi_closure_unix64_inner=discard
+fun:ffi_closure_unix64=uninstrumented
+fun:ffi_closure_unix64=discard
+fun:__go_get_closure=uninstrumented
+fun:__go_get_closure=discard
+fun:__go_makefunc_can_recover=uninstrumented
+fun:__go_makefunc_can_recover=discard
+fun:__go_makefunc_returning=uninstrumented
+fun:__go_makefunc_returning=discard
+fun:reflect.MakeFuncStubGo=uninstrumented
+fun:reflect.MakeFuncStubGo=discard
+fun:reflect.makeFuncStub=uninstrumented
+fun:reflect.makeFuncStub=discard
diff --git a/lib/dfsan/libc_ubuntu1204_abilist.txt b/lib/dfsan/libc_ubuntu1404_abilist.txt
similarity index 90%
rename from lib/dfsan/libc_ubuntu1204_abilist.txt
rename to lib/dfsan/libc_ubuntu1404_abilist.txt
index 5fc8194..a1ea0a0 100644
--- a/lib/dfsan/libc_ubuntu1204_abilist.txt
+++ b/lib/dfsan/libc_ubuntu1404_abilist.txt
@@ -123,83 +123,6 @@
 fun:_IO_wfile_xsputn=uninstrumented
 fun:_IO_wmarker_delta=uninstrumented
 fun:_IO_wsetb=uninstrumented
-fun:_L_cond_lock_1021=uninstrumented
-fun:_L_cond_lock_874=uninstrumented
-fun:_L_cond_lock_918=uninstrumented
-fun:_L_lock_1006=uninstrumented
-fun:_L_lock_125=uninstrumented
-fun:_L_lock_1281=uninstrumented
-fun:_L_lock_13=uninstrumented
-fun:_L_lock_133=uninstrumented
-fun:_L_lock_1392=uninstrumented
-fun:_L_lock_175=uninstrumented
-fun:_L_lock_19=uninstrumented
-fun:_L_lock_2009=uninstrumented
-fun:_L_lock_21=uninstrumented
-fun:_L_lock_211=uninstrumented
-fun:_L_lock_2143=uninstrumented
-fun:_L_lock_227=uninstrumented
-fun:_L_lock_23=uninstrumented
-fun:_L_lock_2338=uninstrumented
-fun:_L_lock_26=uninstrumented
-fun:_L_lock_29=uninstrumented
-fun:_L_lock_3116=uninstrumented
-fun:_L_lock_32=uninstrumented
-fun:_L_lock_3335=uninstrumented
-fun:_L_lock_34=uninstrumented
-fun:_L_lock_37=uninstrumented
-fun:_L_lock_40=uninstrumented
-fun:_L_lock_4016=uninstrumented
-fun:_L_lock_4410=uninstrumented
-fun:_L_lock_451=uninstrumented
-fun:_L_lock_4590=uninstrumented
-fun:_L_lock_466=uninstrumented
-fun:_L_lock_641=uninstrumented
-fun:_L_lock_858=uninstrumented
-fun:_L_lock_903=uninstrumented
-fun:_L_robust_cond_lock_164=uninstrumented
-fun:_L_robust_lock_160=uninstrumented
-fun:_L_robust_timedlock_361=uninstrumented
-fun:_L_robust_unlock_189=uninstrumented
-fun:_L_timedlock_1043=uninstrumented
-fun:_L_timedlock_108=uninstrumented
-fun:_L_timedlock_292=uninstrumented
-fun:_L_unlock_114=uninstrumented
-fun:_L_unlock_1157=uninstrumented
-fun:_L_unlock_1355=uninstrumented
-fun:_L_unlock_137=uninstrumented
-fun:_L_unlock_157=uninstrumented
-fun:_L_unlock_16=uninstrumented
-fun:_L_unlock_170=uninstrumented
-fun:_L_unlock_174=uninstrumented
-fun:_L_unlock_177=uninstrumented
-fun:_L_unlock_1946=uninstrumented
-fun:_L_unlock_197=uninstrumented
-fun:_L_unlock_2117=uninstrumented
-fun:_L_unlock_2318=uninstrumented
-fun:_L_unlock_2384=uninstrumented
-fun:_L_unlock_27=uninstrumented
-fun:_L_unlock_3119=uninstrumented
-fun:_L_unlock_312=uninstrumented
-fun:_L_unlock_3464=uninstrumented
-fun:_L_unlock_37=uninstrumented
-fun:_L_unlock_3744=uninstrumented
-fun:_L_unlock_4037=uninstrumented
-fun:_L_unlock_43=uninstrumented
-fun:_L_unlock_4353=uninstrumented
-fun:_L_unlock_4432=uninstrumented
-fun:_L_unlock_4525=uninstrumented
-fun:_L_unlock_4619=uninstrumented
-fun:_L_unlock_494=uninstrumented
-fun:_L_unlock_54=uninstrumented
-fun:_L_unlock_544=uninstrumented
-fun:_L_unlock_61=uninstrumented
-fun:_L_unlock_62=uninstrumented
-fun:_L_unlock_64=uninstrumented
-fun:_L_unlock_644=uninstrumented
-fun:_L_unlock_698=uninstrumented
-fun:_L_unlock_708=uninstrumented
-fun:_L_unlock_88=uninstrumented
 fun:_Unwind_Backtrace=uninstrumented
 fun:_Unwind_DeleteException=uninstrumented
 fun:_Unwind_FindEnclosingFunction=uninstrumented
@@ -218,18 +141,9 @@
 fun:_Unwind_Resume_or_Rethrow=uninstrumented
 fun:_Unwind_SetGR=uninstrumented
 fun:_Unwind_SetIP=uninstrumented
-fun:__GI___nptl_create_event=uninstrumented
-fun:__GI___nptl_death_event=uninstrumented
-fun:__GI___pthread_cleanup_upto=uninstrumented
-fun:__GI___pthread_register_cancel=uninstrumented
-fun:__GI___pthread_unregister_cancel=uninstrumented
-fun:__GI___pthread_unwind=uninstrumented
-fun:__GI___pthread_unwind_next=uninstrumented
 fun:__absvdi2=uninstrumented
 fun:__absvsi2=uninstrumented
 fun:__absvti2=uninstrumented
-fun:__accept=uninstrumented
-fun:__accept_nocancel=uninstrumented
 fun:__acos_finite=uninstrumented
 fun:__acosf_finite=uninstrumented
 fun:__acosh_finite=uninstrumented
@@ -602,27 +516,31 @@
 fun:__bswapdi2=uninstrumented
 fun:__bswapsi2=uninstrumented
 fun:__bzero=uninstrumented
+fun:__call_tls_dtors=uninstrumented
 fun:__chk_fail=uninstrumented
 fun:__clear_cache=uninstrumented
+fun:__clock_getcpuclockid=uninstrumented
+fun:__clock_getres=uninstrumented
+fun:__clock_gettime=uninstrumented
+fun:__clock_nanosleep=uninstrumented
+fun:__clock_settime=uninstrumented
 fun:__clog10=uninstrumented
 fun:__clog10f=uninstrumented
 fun:__clog10l=uninstrumented
 fun:__clone=uninstrumented
 fun:__close=uninstrumented
-fun:__close_nocancel=uninstrumented
+fun:__clrsbdi2=uninstrumented
+fun:__clrsbti2=uninstrumented
 fun:__clzdi2=uninstrumented
 fun:__clzti2=uninstrumented
 fun:__cmpti2=uninstrumented
 fun:__cmsg_nxthdr=uninstrumented
-fun:__condvar_cleanup1=uninstrumented
-fun:__condvar_cleanup2=uninstrumented
 fun:__confstr_chk=uninstrumented
 fun:__connect=uninstrumented
-fun:__connect_internal=uninstrumented
-fun:__connect_nocancel=uninstrumented
 fun:__cosh_finite=uninstrumented
 fun:__coshf_finite=uninstrumented
 fun:__coshl_finite=uninstrumented
+fun:__cpu_indicator_init=uninstrumented
 fun:__create_ib_request=uninstrumented
 fun:__ctype_b_loc=uninstrumented
 fun:__ctype_get_mb_cur_max=uninstrumented
@@ -634,15 +552,14 @@
 fun:__cxa_at_quick_exit=uninstrumented
 fun:__cxa_atexit=uninstrumented
 fun:__cxa_finalize=uninstrumented
+fun:__cxa_thread_atexit_impl=uninstrumented
 fun:__cyg_profile_func_enter=uninstrumented
 fun:__cyg_profile_func_exit=uninstrumented
 fun:__dcgettext=uninstrumented
-fun:__deallocate_stack=uninstrumented
 fun:__default_morecore=uninstrumented
 fun:__deregister_frame=uninstrumented
 fun:__deregister_frame_info=uninstrumented
 fun:__deregister_frame_info_bases=uninstrumented
-fun:__determine_cpumask_size=uninstrumented
 fun:__dfp_clear_except=uninstrumented
 fun:__dfp_get_round=uninstrumented
 fun:__dfp_raise_except=uninstrumented
@@ -659,13 +576,10 @@
 fun:__dn_count_labels=uninstrumented
 fun:__dn_expand=uninstrumented
 fun:__dn_skipname=uninstrumented
-fun:__do_global_ctors_aux=uninstrumented
-fun:__do_global_dtors_aux=uninstrumented
 fun:__do_niscall3=uninstrumented
 fun:__dprintf_chk=uninstrumented
 fun:__dup2=uninstrumented
 fun:__duplocale=uninstrumented
-fun:__dyn_pthread_atfork=uninstrumented
 fun:__emutls_get_address=uninstrumented
 fun:__emutls_register_common=uninstrumented
 fun:__enable_execute_stack=uninstrumented
@@ -687,7 +601,6 @@
 fun:__extendxftf2=uninstrumented
 fun:__fbufsize=uninstrumented
 fun:__fcntl=uninstrumented
-fun:__fcntl_nocancel=uninstrumented
 fun:__fdelt_chk=uninstrumented
 fun:__fdelt_warn=uninstrumented
 fun:__fentry__=uninstrumented
@@ -698,8 +611,6 @@
 fun:__fgets_unlocked_chk=uninstrumented
 fun:__fgetws_chk=uninstrumented
 fun:__fgetws_unlocked_chk=uninstrumented
-fun:__find_in_stack_list=uninstrumented
-fun:__find_thread_by_id=uninstrumented
 fun:__finite=uninstrumented
 fun:__finitef=uninstrumented
 fun:__finitel=uninstrumented
@@ -731,7 +642,6 @@
 fun:__floatuntisf=uninstrumented
 fun:__floatuntitf=uninstrumented
 fun:__floatuntixf=uninstrumented
-fun:__flockfile=uninstrumented
 fun:__fmod_finite=uninstrumented
 fun:__fmodf_finite=uninstrumented
 fun:__fmodl_finite=uninstrumented
@@ -752,14 +662,9 @@
 fun:__freadable=uninstrumented
 fun:__freading=uninstrumented
 fun:__free_fdresult=uninstrumented
-fun:__free_stacks=uninstrumented
-fun:__free_tcb=uninstrumented
 fun:__freelocale=uninstrumented
 fun:__fsetlocking=uninstrumented
 fun:__fstat=uninstrumented
-fun:__fsync_nocancel=uninstrumented
-fun:__ftrylockfile=uninstrumented
-fun:__funlockfile=uninstrumented
 fun:__fwprintf_chk=uninstrumented
 fun:__fwritable=uninstrumented
 fun:__fwriting=uninstrumented
@@ -781,6 +686,7 @@
 fun:__generic_morestack_set_initial_sp=uninstrumented
 fun:__generic_releasestack=uninstrumented
 fun:__get_cpu_features=uninstrumented
+fun:__getauxval=uninstrumented
 fun:__getcwd_chk=uninstrumented
 fun:__getdelim=uninstrumented
 fun:__getdomainname_chk=uninstrumented
@@ -802,7 +708,6 @@
 fun:__hypot_finite=uninstrumented
 fun:__hypotf_finite=uninstrumented
 fun:__hypotl_finite=uninstrumented
-fun:__init_sched_fifo_prio=uninstrumented
 fun:__internal_endnetgrent=uninstrumented
 fun:__internal_getnetgrent_r=uninstrumented
 fun:__internal_setnetgrent=uninstrumented
@@ -835,6 +740,9 @@
 fun:__isoc99_wscanf=uninstrumented
 fun:__isprint_l=uninstrumented
 fun:__ispunct_l=uninstrumented
+fun:__issignaling=uninstrumented
+fun:__issignalingf=uninstrumented
+fun:__issignalingl=uninstrumented
 fun:__isspace_l=uninstrumented
 fun:__isupper_l=uninstrumented
 fun:__iswalnum_l=uninstrumented
@@ -866,14 +774,11 @@
 fun:__lgamma_r_finite=uninstrumented
 fun:__lgammaf_r_finite=uninstrumented
 fun:__lgammal_r_finite=uninstrumented
-fun:__libc_accept=uninstrumented
 fun:__libc_alloca_cutoff=uninstrumented
 fun:__libc_allocate_rtsig=uninstrumented
 fun:__libc_allocate_rtsig_private=uninstrumented
 fun:__libc_calloc=uninstrumented
 fun:__libc_clntudp_bufcreate=uninstrumented
-fun:__libc_close=uninstrumented
-fun:__libc_connect=uninstrumented
 fun:__libc_csu_fini=uninstrumented
 fun:__libc_csu_init=uninstrumented
 fun:__libc_current_sigrtmax=uninstrumented
@@ -885,62 +790,30 @@
 fun:__libc_dlopen_mode=uninstrumented
 fun:__libc_dlsym=uninstrumented
 fun:__libc_fatal=uninstrumented
-fun:__libc_fcntl=uninstrumented
 fun:__libc_fork=uninstrumented
 fun:__libc_free=uninstrumented
 fun:__libc_freeres=uninstrumented
-fun:__libc_fsync=uninstrumented
+fun:__libc_ifunc_impl_list=uninstrumented
 fun:__libc_init_first=uninstrumented
 fun:__libc_longjmp=uninstrumented
-fun:__libc_lseek=uninstrumented
-fun:__libc_lseek64=uninstrumented
 fun:__libc_mallinfo=uninstrumented
 fun:__libc_malloc=uninstrumented
 fun:__libc_mallopt=uninstrumented
 fun:__libc_memalign=uninstrumented
-fun:__libc_msync=uninstrumented
-fun:__libc_nanosleep=uninstrumented
-fun:__libc_open=uninstrumented
-fun:__libc_pause=uninstrumented
-fun:__libc_pread=uninstrumented
-fun:__libc_pread64=uninstrumented
 fun:__libc_pthread_init=uninstrumented
 fun:__libc_pvalloc=uninstrumented
 fun:__libc_pwrite=uninstrumented
-fun:__libc_pwrite64=uninstrumented
-fun:__libc_read=uninstrumented
 fun:__libc_realloc=uninstrumented
-fun:__libc_recv=uninstrumented
-fun:__libc_recvfrom=uninstrumented
-fun:__libc_recvmsg=uninstrumented
 fun:__libc_res_nquery=uninstrumented
 fun:__libc_res_nsearch=uninstrumented
 fun:__libc_rpc_getport=uninstrumented
 fun:__libc_sa_len=uninstrumented
-fun:__libc_send=uninstrumented
-fun:__libc_sendmsg=uninstrumented
-fun:__libc_sendto=uninstrumented
-fun:__libc_sigaction=uninstrumented
+fun:__libc_secure_getenv=uninstrumented
 fun:__libc_siglongjmp=uninstrumented
-fun:__libc_sigsuspend=uninstrumented
-fun:__libc_sigwait=uninstrumented
 fun:__libc_start_main=uninstrumented
 fun:__libc_system=uninstrumented
-fun:__libc_tcdrain=uninstrumented
 fun:__libc_thread_freeres=uninstrumented
 fun:__libc_valloc=uninstrumented
-fun:__libc_wait=uninstrumented
-fun:__libc_waitpid=uninstrumented
-fun:__libc_write=uninstrumented
-fun:__lll_lock_wait=uninstrumented
-fun:__lll_lock_wait_private=uninstrumented
-fun:__lll_robust_lock_wait=uninstrumented
-fun:__lll_robust_timedlock_wait=uninstrumented
-fun:__lll_timedlock_wait=uninstrumented
-fun:__lll_timedwait_tid=uninstrumented
-fun:__lll_unlock_wake=uninstrumented
-fun:__lll_unlock_wake_private=uninstrumented
-fun:__llseek=uninstrumented
 fun:__loc_aton=uninstrumented
 fun:__loc_ntoa=uninstrumented
 fun:__log10_finite=uninstrumented
@@ -954,14 +827,12 @@
 fun:__logl_finite=uninstrumented
 fun:__longjmp_chk=uninstrumented
 fun:__lseek=uninstrumented
-fun:__lseek64=uninstrumented
-fun:__lseek_nocancel=uninstrumented
 fun:__lshrti3=uninstrumented
 fun:__lstat=uninstrumented
 fun:__lttf2=uninstrumented
 fun:__lxstat=uninstrumented
 fun:__lxstat64=uninstrumented
-fun:__make_stacks_executable=uninstrumented
+fun:__madvise=uninstrumented
 fun:__mbrlen=uninstrumented
 fun:__mbrtowc=uninstrumented
 fun:__mbsnrtowcs_chk=uninstrumented
@@ -974,23 +845,22 @@
 fun:__mempcpy_small=uninstrumented
 fun:__memset_chk=uninstrumented
 fun:__mknod=uninstrumented
+fun:__mktemp=uninstrumented
 fun:__modti3=uninstrumented
 fun:__monstartup=uninstrumented
 fun:__morestack=uninstrumented
 fun:__morestack_allocate_stack_space=uninstrumented
 fun:__morestack_block_signals=uninstrumented
 fun:__morestack_fail=uninstrumented
+fun:__morestack_get_guard=uninstrumented
 fun:__morestack_large_model=uninstrumented
 fun:__morestack_load_mmap=uninstrumented
+fun:__morestack_make_guard=uninstrumented
 fun:__morestack_non_split=uninstrumented
 fun:__morestack_release_segments=uninstrumented
+fun:__morestack_set_guard=uninstrumented
 fun:__morestack_unblock_signals=uninstrumented
 fun:__mq_open_2=uninstrumented
-fun:__msgrcv=uninstrumented
-fun:__msgrcv_nocancel=uninstrumented
-fun:__msgsnd=uninstrumented
-fun:__msgsnd_nocancel=uninstrumented
-fun:__msync_nocancel=uninstrumented
 fun:__muldc3=uninstrumented
 fun:__mulsc3=uninstrumented
 fun:__multc3=uninstrumented
@@ -1001,16 +871,12 @@
 fun:__mulvti3=uninstrumented
 fun:__mulxc3=uninstrumented
 fun:__nanosleep=uninstrumented
-fun:__nanosleep_nocancel=uninstrumented
 fun:__negtf2=uninstrumented
 fun:__negti2=uninstrumented
 fun:__negvdi2=uninstrumented
 fun:__negvsi2=uninstrumented
 fun:__negvti2=uninstrumented
 fun:__netf2=uninstrumented
-fun:__new_sem_destroy=uninstrumented
-fun:__new_sem_getvalue=uninstrumented
-fun:__new_sem_init=uninstrumented
 fun:__newlocale=uninstrumented
 fun:__nis_default_access=uninstrumented
 fun:__nis_default_group=uninstrumented
@@ -1023,12 +889,6 @@
 fun:__nisbind_destroy=uninstrumented
 fun:__nisbind_next=uninstrumented
 fun:__nl_langinfo_l=uninstrumented
-fun:__nptl_create_event=uninstrumented
-fun:__nptl_deallocate_tsd=uninstrumented
-fun:__nptl_death_event=uninstrumented
-fun:__nptl_main=uninstrumented
-fun:__nptl_set_robust=uninstrumented
-fun:__nptl_setxid=uninstrumented
 fun:__ns_get16=uninstrumented
 fun:__ns_get32=uninstrumented
 fun:__ns_name_ntop=uninstrumented
@@ -1055,7 +915,6 @@
 fun:__open64_2=uninstrumented
 fun:__open_2=uninstrumented
 fun:__open_catalog=uninstrumented
-fun:__open_nocancel=uninstrumented
 fun:__openat64_2=uninstrumented
 fun:__openat_2=uninstrumented
 fun:__overflow=uninstrumented
@@ -1072,9 +931,9 @@
 fun:__p_type=uninstrumented
 fun:__paritydi2=uninstrumented
 fun:__parityti2=uninstrumented
-fun:__pause_nocancel=uninstrumented
 fun:__pipe=uninstrumented
 fun:__poll=uninstrumented
+fun:__poll_chk=uninstrumented
 fun:__popcountdi2=uninstrumented
 fun:__popcountti2=uninstrumented
 fun:__posix_getopt=uninstrumented
@@ -1085,121 +944,41 @@
 fun:__powitf2=uninstrumented
 fun:__powixf2=uninstrumented
 fun:__powl_finite=uninstrumented
-fun:__pread=uninstrumented
+fun:__ppoll_chk=uninstrumented
 fun:__pread64=uninstrumented
 fun:__pread64_chk=uninstrumented
 fun:__pread_chk=uninstrumented
-fun:__pread_nocancel=uninstrumented
 fun:__prepare_niscall=uninstrumented
 fun:__printf_chk=uninstrumented
 fun:__printf_fp=uninstrumented
 fun:__profile_frequency=uninstrumented
 fun:__pthread_atfork=uninstrumented
-fun:__pthread_attr_destroy=uninstrumented
-fun:__pthread_attr_getaffinity_new=uninstrumented
-fun:__pthread_attr_getaffinity_old=uninstrumented
-fun:__pthread_attr_getdetachstate=uninstrumented
-fun:__pthread_attr_getinheritsched=uninstrumented
-fun:__pthread_attr_getschedparam=uninstrumented
-fun:__pthread_attr_getschedpolicy=uninstrumented
-fun:__pthread_attr_getscope=uninstrumented
-fun:__pthread_attr_getstack=uninstrumented
-fun:__pthread_attr_getstackaddr=uninstrumented
-fun:__pthread_attr_getstacksize=uninstrumented
-fun:__pthread_attr_init_2_1=uninstrumented
-fun:__pthread_attr_setaffinity_new=uninstrumented
-fun:__pthread_attr_setaffinity_old=uninstrumented
-fun:__pthread_attr_setdetachstate=uninstrumented
-fun:__pthread_attr_setinheritsched=uninstrumented
-fun:__pthread_attr_setschedparam=uninstrumented
-fun:__pthread_attr_setschedpolicy=uninstrumented
-fun:__pthread_attr_setscope=uninstrumented
-fun:__pthread_attr_setstack=uninstrumented
-fun:__pthread_attr_setstackaddr=uninstrumented
-fun:__pthread_attr_setstacksize=uninstrumented
-fun:__pthread_cleanup_pop=uninstrumented
-fun:__pthread_cleanup_pop_restore=uninstrumented
-fun:__pthread_cleanup_push=uninstrumented
-fun:__pthread_cleanup_push_defer=uninstrumented
 fun:__pthread_cleanup_routine=uninstrumented
-fun:__pthread_cleanup_upto=uninstrumented
 fun:__pthread_clock_gettime=uninstrumented
 fun:__pthread_clock_settime=uninstrumented
-fun:__pthread_cond_broadcast=uninstrumented
-fun:__pthread_cond_broadcast_2_0=uninstrumented
-fun:__pthread_cond_destroy=uninstrumented
-fun:__pthread_cond_destroy_2_0=uninstrumented
-fun:__pthread_cond_init=uninstrumented
-fun:__pthread_cond_init_2_0=uninstrumented
-fun:__pthread_cond_signal=uninstrumented
-fun:__pthread_cond_signal_2_0=uninstrumented
-fun:__pthread_cond_timedwait=uninstrumented
-fun:__pthread_cond_timedwait_2_0=uninstrumented
-fun:__pthread_cond_wait=uninstrumented
-fun:__pthread_cond_wait_2_0=uninstrumented
-fun:__pthread_condattr_destroy=uninstrumented
-fun:__pthread_condattr_init=uninstrumented
-fun:__pthread_create_2_1=uninstrumented
-fun:__pthread_current_priority=uninstrumented
-fun:__pthread_disable_asynccancel=uninstrumented
-fun:__pthread_enable_asynccancel=uninstrumented
-fun:__pthread_equal=uninstrumented
-fun:__pthread_exit=uninstrumented
 fun:__pthread_get_minstack=uninstrumented
-fun:__pthread_getaffinity_new=uninstrumented
-fun:__pthread_getaffinity_np=uninstrumented
-fun:__pthread_getaffinity_old=uninstrumented
-fun:__pthread_getschedparam=uninstrumented
 fun:__pthread_getspecific=uninstrumented
-fun:__pthread_getspecific_internal=uninstrumented
-fun:__pthread_init_static_tls=uninstrumented
 fun:__pthread_initialize_minimal=uninstrumented
-fun:__pthread_initialize_minimal_internal=uninstrumented
 fun:__pthread_key_create=uninstrumented
-fun:__pthread_key_create_internal=uninstrumented
-fun:__pthread_kill=uninstrumented
-fun:__pthread_kill_other_threads_np=uninstrumented
-fun:__pthread_mutex_cond_lock=uninstrumented
-fun:__pthread_mutex_cond_lock_adjust=uninstrumented
-fun:__pthread_mutex_cond_lock_full=uninstrumented
 fun:__pthread_mutex_destroy=uninstrumented
-fun:__pthread_mutex_destroy_internal=uninstrumented
 fun:__pthread_mutex_init=uninstrumented
-fun:__pthread_mutex_init_internal=uninstrumented
 fun:__pthread_mutex_lock=uninstrumented
-fun:__pthread_mutex_lock_full=uninstrumented
-fun:__pthread_mutex_lock_internal=uninstrumented
 fun:__pthread_mutex_trylock=uninstrumented
 fun:__pthread_mutex_unlock=uninstrumented
-fun:__pthread_mutex_unlock_full=uninstrumented
-fun:__pthread_mutex_unlock_internal=uninstrumented
-fun:__pthread_mutex_unlock_usercnt=uninstrumented
 fun:__pthread_mutexattr_destroy=uninstrumented
 fun:__pthread_mutexattr_init=uninstrumented
 fun:__pthread_mutexattr_settype=uninstrumented
 fun:__pthread_once=uninstrumented
-fun:__pthread_once_internal=uninstrumented
 fun:__pthread_register_cancel=uninstrumented
 fun:__pthread_register_cancel_defer=uninstrumented
 fun:__pthread_rwlock_destroy=uninstrumented
 fun:__pthread_rwlock_init=uninstrumented
 fun:__pthread_rwlock_rdlock=uninstrumented
-fun:__pthread_rwlock_rdlock_internal=uninstrumented
 fun:__pthread_rwlock_tryrdlock=uninstrumented
 fun:__pthread_rwlock_trywrlock=uninstrumented
 fun:__pthread_rwlock_unlock=uninstrumented
-fun:__pthread_rwlock_unlock_internal=uninstrumented
 fun:__pthread_rwlock_wrlock=uninstrumented
-fun:__pthread_rwlock_wrlock_internal=uninstrumented
-fun:__pthread_self=uninstrumented
-fun:__pthread_setaffinity_new=uninstrumented
-fun:__pthread_setaffinity_old=uninstrumented
-fun:__pthread_setcancelstate=uninstrumented
-fun:__pthread_setcanceltype=uninstrumented
-fun:__pthread_setschedparam=uninstrumented
 fun:__pthread_setspecific=uninstrumented
-fun:__pthread_setspecific_internal=uninstrumented
-fun:__pthread_tpp_change_priority=uninstrumented
 fun:__pthread_unregister_cancel=uninstrumented
 fun:__pthread_unregister_cancel_restore=uninstrumented
 fun:__pthread_unwind=uninstrumented
@@ -1207,24 +986,15 @@
 fun:__ptsname_r_chk=uninstrumented
 fun:__putlong=uninstrumented
 fun:__putshort=uninstrumented
-fun:__pwrite=uninstrumented
 fun:__pwrite64=uninstrumented
-fun:__pwrite_nocancel=uninstrumented
 fun:__rawmemchr=uninstrumented
 fun:__read=uninstrumented
 fun:__read_chk=uninstrumented
-fun:__read_nocancel=uninstrumented
 fun:__readlink_chk=uninstrumented
 fun:__readlinkat_chk=uninstrumented
 fun:__realpath_chk=uninstrumented
-fun:__reclaim_stacks=uninstrumented
-fun:__recv=uninstrumented
 fun:__recv_chk=uninstrumented
-fun:__recvfrom=uninstrumented
 fun:__recvfrom_chk=uninstrumented
-fun:__recvfrom_nocancel=uninstrumented
-fun:__recvmsg=uninstrumented
-fun:__recvmsg_nocancel=uninstrumented
 fun:__register_atfork=uninstrumented
 fun:__register_frame=uninstrumented
 fun:__register_frame_info=uninstrumented
@@ -1261,7 +1031,6 @@
 fun:__res_search=uninstrumented
 fun:__res_send=uninstrumented
 fun:__res_state=uninstrumented
-fun:__restore_rt=uninstrumented
 fun:__rpc_thread_createerr=uninstrumented
 fun:__rpc_thread_svc_fdset=uninstrumented
 fun:__rpc_thread_svc_max_pollfd=uninstrumented
@@ -1281,14 +1050,11 @@
 fun:__sched_yield=uninstrumented
 fun:__secure_getenv=uninstrumented
 fun:__select=uninstrumented
-fun:__sem_search=uninstrumented
 fun:__send=uninstrumented
-fun:__sendmsg=uninstrumented
-fun:__sendmsg_nocancel=uninstrumented
-fun:__sendto=uninstrumented
-fun:__sendto_nocancel=uninstrumented
+fun:__sendmmsg=uninstrumented
 fun:__setmntent=uninstrumented
 fun:__setpgid=uninstrumented
+fun:__sfp_handle_exceptions=uninstrumented
 fun:__sigaction=uninstrumented
 fun:__sigaddset=uninstrumented
 fun:__sigdelset=uninstrumented
@@ -1299,13 +1065,19 @@
 fun:__sigpause=uninstrumented
 fun:__sigsetjmp=uninstrumented
 fun:__sigsuspend=uninstrumented
-fun:__sigsuspend_nocancel=uninstrumented
-fun:__sigwait=uninstrumented
 fun:__sinh_finite=uninstrumented
 fun:__sinhf_finite=uninstrumented
 fun:__sinhl_finite=uninstrumented
 fun:__snprintf_chk=uninstrumented
+fun:__splitstack_block_signals=uninstrumented
+fun:__splitstack_block_signals_context=uninstrumented
 fun:__splitstack_find=uninstrumented
+fun:__splitstack_find_context=uninstrumented
+fun:__splitstack_getcontext=uninstrumented
+fun:__splitstack_makecontext=uninstrumented
+fun:__splitstack_releasecontext=uninstrumented
+fun:__splitstack_resetcontext=uninstrumented
+fun:__splitstack_setcontext=uninstrumented
 fun:__sprintf_chk=uninstrumented
 fun:__sqrt_finite=uninstrumented
 fun:__sqrtf_finite=uninstrumented
@@ -1397,7 +1169,6 @@
 fun:__umodti3=uninstrumented
 fun:__underflow=uninstrumented
 fun:__unordtf2=uninstrumented
-fun:__unwind_freeres=uninstrumented
 fun:__uselocale=uninstrumented
 fun:__vasprintf_chk=uninstrumented
 fun:__vdprintf_chk=uninstrumented
@@ -1414,7 +1185,6 @@
 fun:__vsyslog_chk=uninstrumented
 fun:__vwprintf_chk=uninstrumented
 fun:__wait=uninstrumented
-fun:__wait_lookup_done=uninstrumented
 fun:__waitpid=uninstrumented
 fun:__warn_memset_zero_len=uninstrumented
 fun:__wcpcpy_chk=uninstrumented
@@ -1449,7 +1219,6 @@
 fun:__wctomb_chk=uninstrumented
 fun:__wctrans_l=uninstrumented
 fun:__wctype_l=uninstrumented
-fun:__where_is_shmfs=uninstrumented
 fun:__wmemcpy_chk=uninstrumented
 fun:__wmemmove_chk=uninstrumented
 fun:__wmempcpy_chk=uninstrumented
@@ -1458,7 +1227,6 @@
 fun:__wprintf_chk=uninstrumented
 fun:__wrap_pthread_create=uninstrumented
 fun:__write=uninstrumented
-fun:__write_nocancel=uninstrumented
 fun:__wuflow=uninstrumented
 fun:__wunderflow=uninstrumented
 fun:__xmknod=uninstrumented
@@ -1484,6 +1252,7 @@
 fun:_dl_allocate_tls_init=uninstrumented
 fun:_dl_deallocate_tls=uninstrumented
 fun:_dl_debug_state=uninstrumented
+fun:_dl_find_dso_for_object=uninstrumented
 fun:_dl_get_tls_static_info=uninstrumented
 fun:_dl_make_stack_executable=uninstrumented
 fun:_dl_mcount=uninstrumented
@@ -1494,7 +1263,6 @@
 fun:_dl_tls_setup=uninstrumented
 fun:_dl_vsym=uninstrumented
 fun:_exit=uninstrumented
-fun:_fini=uninstrumented
 fun:_flushlbf=uninstrumented
 fun:_gethtbyaddr=uninstrumented
 fun:_gethtbyname=uninstrumented
@@ -1502,7 +1270,6 @@
 fun:_gethtent=uninstrumented
 fun:_getlong=uninstrumented
 fun:_getshort=uninstrumented
-fun:_init=uninstrumented
 fun:_longjmp=uninstrumented
 fun:_mcleanup=uninstrumented
 fun:_mcount=uninstrumented
@@ -1542,7 +1309,6 @@
 fun:acoshf=uninstrumented
 fun:acoshl=uninstrumented
 fun:acosl=uninstrumented
-fun:add_and_round.constprop.0=uninstrumented
 fun:addmntent=uninstrumented
 fun:addseverity=uninstrumented
 fun:adjtime=uninstrumented
@@ -1564,6 +1330,7 @@
 fun:aio_write=uninstrumented
 fun:aio_write64=uninstrumented
 fun:alarm=uninstrumented
+fun:aligned_alloc=uninstrumented
 fun:alphasort=uninstrumented
 fun:alphasort64=uninstrumented
 fun:arch_prctl=uninstrumented
@@ -1622,7 +1389,6 @@
 fun:bcmp=uninstrumented
 fun:bcopy=uninstrumented
 fun:bdflush=uninstrumented
-fun:bid128_ext_fma=uninstrumented
 fun:bind=uninstrumented
 fun:bind_textdomain_codeset=uninstrumented
 fun:bindresvport=uninstrumented
@@ -1632,6 +1398,8 @@
 fun:bsearch=uninstrumented
 fun:btowc=uninstrumented
 fun:bzero=uninstrumented
+fun:c16rtomb=uninstrumented
+fun:c32rtomb=uninstrumented
 fun:cabs=uninstrumented
 fun:cabsf=uninstrumented
 fun:cabsl=uninstrumented
@@ -1688,7 +1456,6 @@
 fun:cfsetospeed=uninstrumented
 fun:cfsetspeed=uninstrumented
 fun:chdir=uninstrumented
-fun:check_add_mapping=uninstrumented
 fun:chflags=uninstrumented
 fun:chmod=uninstrumented
 fun:chown=uninstrumented
@@ -1696,8 +1463,6 @@
 fun:cimag=uninstrumented
 fun:cimagf=uninstrumented
 fun:cimagl=uninstrumented
-fun:cleanup=uninstrumented
-fun:clear_once_control=uninstrumented
 fun:clearenv=uninstrumented
 fun:clearerr=uninstrumented
 fun:clearerr_unlocked=uninstrumented
@@ -1756,7 +1521,6 @@
 fun:creall=uninstrumented
 fun:creat=uninstrumented
 fun:creat64=uninstrumented
-fun:create_key=uninstrumented
 fun:create_module=uninstrumented
 fun:crypt=uninstrumented
 fun:crypt_r=uninstrumented
@@ -1800,8 +1564,6 @@
 fun:dlsym=uninstrumented
 fun:dlvsym=uninstrumented
 fun:dngettext=uninstrumented
-fun:do_clone.constprop.4=uninstrumented
-fun:do_sigwait=uninstrumented
 fun:dprintf=uninstrumented
 fun:drand48=uninstrumented
 fun:drand48_r=uninstrumented
@@ -2002,12 +1764,9 @@
 fun:fputwc_unlocked=uninstrumented
 fun:fputws=uninstrumented
 fun:fputws_unlocked=uninstrumented
-fun:frame_dummy=uninstrumented
 fun:fread=uninstrumented
 fun:fread_unlocked=uninstrumented
 fun:free=uninstrumented
-fun:free_dynamic_blocks=uninstrumented
-fun:free_segments=uninstrumented
 fun:freeaddrinfo=uninstrumented
 fun:freeifaddrs=uninstrumented
 fun:freelocale=uninstrumented
@@ -2065,7 +1824,6 @@
 fun:gammaf=uninstrumented
 fun:gammal=uninstrumented
 fun:gcvt=uninstrumented
-fun:get_BID128.constprop.5=uninstrumented
 fun:get_avphys_pages=uninstrumented
 fun:get_current_dir_name=uninstrumented
 fun:get_kernel_syms=uninstrumented
@@ -2079,6 +1837,7 @@
 fun:getaliasbyname_r=uninstrumented
 fun:getaliasent=uninstrumented
 fun:getaliasent_r=uninstrumented
+fun:getauxval=uninstrumented
 fun:getc=uninstrumented
 fun:getc_unlocked=uninstrumented
 fun:getchar=uninstrumented
@@ -2492,6 +2251,8 @@
 fun:matherr=uninstrumented
 fun:mblen=uninstrumented
 fun:mbrlen=uninstrumented
+fun:mbrtoc16=uninstrumented
+fun:mbrtoc32=uninstrumented
 fun:mbrtowc=uninstrumented
 fun:mbsinit=uninstrumented
 fun:mbsnrtowcs=uninstrumented
@@ -2653,9 +2414,6 @@
 fun:nis_write_obj=uninstrumented
 fun:nl_langinfo=uninstrumented
 fun:nl_langinfo_l=uninstrumented
-fun:nop=uninstrumented
-fun:nptl_freeres=uninstrumented
-fun:nr_digits256=uninstrumented
 fun:nrand48=uninstrumented
 fun:nrand48_r=uninstrumented
 fun:ns_datetosecs=uninstrumented
@@ -2802,7 +2560,6 @@
 fun:pthread_barrierattr_init=uninstrumented
 fun:pthread_barrierattr_setpshared=uninstrumented
 fun:pthread_cancel=uninstrumented
-fun:pthread_cancel_init=uninstrumented
 fun:pthread_cond_broadcast=uninstrumented
 fun:pthread_cond_destroy=uninstrumented
 fun:pthread_cond_init=uninstrumented
@@ -2820,6 +2577,7 @@
 fun:pthread_equal=uninstrumented
 fun:pthread_exit=uninstrumented
 fun:pthread_getaffinity_np=uninstrumented
+fun:pthread_getattr_default_np=uninstrumented
 fun:pthread_getattr_np=uninstrumented
 fun:pthread_getconcurrency=uninstrumented
 fun:pthread_getcpuclockid=uninstrumented
@@ -2875,6 +2633,7 @@
 fun:pthread_rwlockattr_setpshared=uninstrumented
 fun:pthread_self=uninstrumented
 fun:pthread_setaffinity_np=uninstrumented
+fun:pthread_setattr_default_np=uninstrumented
 fun:pthread_setcancelstate=uninstrumented
 fun:pthread_setcanceltype=uninstrumented
 fun:pthread_setconcurrency=uninstrumented
@@ -3003,7 +2762,6 @@
 fun:rmdir=uninstrumented
 fun:round=uninstrumented
 fun:roundf=uninstrumented
-fun:rounding_correction.constprop.1=uninstrumented
 fun:roundl=uninstrumented
 fun:rpmatch=uninstrumented
 fun:rresvport=uninstrumented
@@ -3038,6 +2796,7 @@
 fun:sched_setparam=uninstrumented
 fun:sched_setscheduler=uninstrumented
 fun:sched_yield=uninstrumented
+fun:secure_getenv=uninstrumented
 fun:seed48=uninstrumented
 fun:seed48_r=uninstrumented
 fun:seekdir=uninstrumented
@@ -3049,12 +2808,9 @@
 fun:sem_open=uninstrumented
 fun:sem_post=uninstrumented
 fun:sem_timedwait=uninstrumented
-fun:sem_timedwait_cleanup=uninstrumented
-fun:sem_timedwait_cleanup2=uninstrumented
 fun:sem_trywait=uninstrumented
 fun:sem_unlink=uninstrumented
 fun:sem_wait=uninstrumented
-fun:sem_wait_cleanup=uninstrumented
 fun:semctl=uninstrumented
 fun:semget=uninstrumented
 fun:semop=uninstrumented
@@ -3123,7 +2879,6 @@
 fun:setutxent=uninstrumented
 fun:setvbuf=uninstrumented
 fun:setxattr=uninstrumented
-fun:setxid_mark_thread.isra.1=uninstrumented
 fun:sgetsgent=uninstrumented
 fun:sgetsgent_r=uninstrumented
 fun:sgetspent=uninstrumented
@@ -3140,12 +2895,10 @@
 fun:sigaltstack=uninstrumented
 fun:sigandset=uninstrumented
 fun:sigblock=uninstrumented
-fun:sigcancel_handler=uninstrumented
 fun:sigdelset=uninstrumented
 fun:sigemptyset=uninstrumented
 fun:sigfillset=uninstrumented
 fun:siggetmask=uninstrumented
-fun:sighandler_setxid=uninstrumented
 fun:sighold=uninstrumented
 fun:sigignore=uninstrumented
 fun:siginterrupt=uninstrumented
@@ -3200,8 +2953,6 @@
 fun:sscanf=uninstrumented
 fun:ssignal=uninstrumented
 fun:sstk=uninstrumented
-fun:stack_split_initialize_thread=uninstrumented
-fun:start_thread=uninstrumented
 fun:stat=uninstrumented
 fun:stat64=uninstrumented
 fun:statfs=uninstrumented
@@ -3272,7 +3023,6 @@
 fun:strxfrm=uninstrumented
 fun:strxfrm_l=uninstrumented
 fun:stty=uninstrumented
-fun:sub256=uninstrumented
 fun:svc_exit=uninstrumented
 fun:svc_getreq=uninstrumented
 fun:svc_getreq_common=uninstrumented
@@ -3392,6 +3142,7 @@
 fun:timerfd_gettime=uninstrumented
 fun:timerfd_settime=uninstrumented
 fun:times=uninstrumented
+fun:timespec_get=uninstrumented
 fun:tmpfile=uninstrumented
 fun:tmpfile64=uninstrumented
 fun:tmpnam=uninstrumented
@@ -3433,8 +3184,6 @@
 fun:unlockpt=uninstrumented
 fun:unsetenv=uninstrumented
 fun:unshare=uninstrumented
-fun:unwind_cleanup=uninstrumented
-fun:unwind_stop=uninstrumented
 fun:updwtmp=uninstrumented
 fun:updwtmpx=uninstrumented
 fun:uselib=uninstrumented
@@ -3480,7 +3229,6 @@
 fun:wait4=uninstrumented
 fun:waitid=uninstrumented
 fun:waitpid=uninstrumented
-fun:walker=uninstrumented
 fun:warn=uninstrumented
 fun:warnx=uninstrumented
 fun:wcpcpy=uninstrumented
diff --git a/lib/dfsan/scripts/build-libc-list.py b/lib/dfsan/scripts/build-libc-list.py
index eb4c619..eddb6c0 100755
--- a/lib/dfsan/scripts/build-libc-list.py
+++ b/lib/dfsan/scripts/build-libc-list.py
@@ -26,6 +26,7 @@
     raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
   for line in readelf:
     if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
+       line[39:44] != 'LOCAL' and \
        line[55:58] != 'UND':
       function_name = line[59:].split('@')[0]
       functions.append(function_name)
diff --git a/lib/dfsan/scripts/check_custom_wrappers.sh b/lib/dfsan/scripts/check_custom_wrappers.sh
index 87e8a09..50bc85d 100755
--- a/lib/dfsan/scripts/check_custom_wrappers.sh
+++ b/lib/dfsan/scripts/check_custom_wrappers.sh
@@ -1,26 +1,28 @@
-#!/usr/bin/env bash
+#!/bin/sh
 
 DFSAN_DIR=$(dirname "$0")/../
-DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.c
+DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
 DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
 DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
 
 DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
 ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
+DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
 
 on_exit() {
   rm -f ${DIFFOUT} 2> /dev/null
   rm -f ${ERRORLOG} 2> /dev/null
+  rm -f ${DIFF_A} 2> /dev/null
+  rm -f ${DIFF_B} 2> /dev/null
 }
 
 trap on_exit EXIT
-
-diff -u \
-  <(grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} | grep -v "dfsan_get_label" \
-    | sed "s/^fun:\(.*\)=custom.*/\1/" | sort ) \
-  <(grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
-    | sed "s/.*__dfsw_\(.*\)(.*/\1/" \
-    | sort) > ${DIFFOUT}
+grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} | grep -v "dfsan_get_label" \
+  | sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
+grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
+  | sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
 if [ $? -ne 0 ]
 then
   echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
@@ -28,13 +30,11 @@
   cat ${DIFFOUT} >> ${ERRORLOG}
 fi
 
-diff -u \
-  <(grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
-    | sed "s/.*__dfsw_\([^(]*\).*/\1/" \
-    | sort) \
-  <(grep -E "^\\s*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
-    | sed "s/.*test_\(.*\)();/\1/" \
-    | sort) > ${DIFFOUT}
+grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
+  | sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
+grep -E "^\\s*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
+  | sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
+diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
 if [ $? -ne 0 ]
 then
   echo -n "The following differences between the implemented " >> ${ERRORLOG}
@@ -42,7 +42,7 @@
   cat ${DIFFOUT} >> ${ERRORLOG}
 fi
 
-if [[ -s ${ERRORLOG} ]]
+if [ -s ${ERRORLOG} ]
 then
   cat ${ERRORLOG}
   exit 1
diff --git a/lib/interception/CMakeLists.txt b/lib/interception/CMakeLists.txt
index cf8b3b4..b77f2d1 100644
--- a/lib/interception/CMakeLists.txt
+++ b/lib/interception/CMakeLists.txt
@@ -20,10 +20,6 @@
       SOURCES ${INTERCEPTION_SOURCES}
       CFLAGS ${INTERCEPTION_CFLAGS})
   endforeach()
-elseif(ANDROID)
-  add_library(RTInterception.arm.android OBJECT ${INTERCEPTION_SOURCES})
-  set_target_compile_flags(RTInterception.arm.android
-    ${INTERCEPTION_CFLAGS})
 else()
   # Otherwise, build separate libraries for each target.
   foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
diff --git a/lib/interception/interception.h b/lib/interception/interception.h
index 743c88d..5257325 100644
--- a/lib/interception/interception.h
+++ b/lib/interception/interception.h
@@ -122,15 +122,9 @@
 # define DECLARE_WRAPPER(ret_type, func, ...)
 
 #elif defined(_WIN32)
-# if defined(_DLL)  // DLL CRT
-#  define WRAP(x) x
-#  define WRAPPER_NAME(x) #x
-#  define INTERCEPTOR_ATTRIBUTE
-# else  // Static CRT
-#  define WRAP(x) __asan_wrap_##x
-#  define WRAPPER_NAME(x) "__asan_wrap_"#x
-#  define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
-# endif
+# define WRAP(x) __asan_wrap_##x
+# define WRAPPER_NAME(x) "__asan_wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
 # define DECLARE_WRAPPER(ret_type, func, ...) \
     extern "C" ret_type func(__VA_ARGS__);
 # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc
index 9eabe52..cd241c3 100644
--- a/lib/interception/interception_win.cc
+++ b/lib/interception/interception_win.cc
@@ -19,20 +19,6 @@
 
 namespace __interception {
 
-bool GetRealFunctionAddress(const char *func_name, uptr *func_addr) {
-  const char *DLLS[] = {
-    "msvcr80.dll",
-    "msvcr90.dll",
-    "kernel32.dll",
-    NULL
-  };
-  *func_addr = 0;
-  for (size_t i = 0; *func_addr == 0 && DLLS[i]; ++i) {
-    *func_addr = (uptr)GetProcAddress(GetModuleHandleA(DLLS[i]), func_name);
-  }
-  return (*func_addr != 0);
-}
-
 // FIXME: internal_str* and internal_mem* functions should be moved from the
 // ASan sources into interception/.
 
@@ -110,9 +96,11 @@
       case 0x458B:  // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
       case 0x5D8B:  // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
       case 0xEC83:  // 83 EC XX = sub esp, XX
+      case 0x75FF:  // FF 75 XX = push dword ptr [ebp+XXh]
         cursor += 3;
         continue;
       case 0xC1F7:  // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
+      case 0x25FF:  // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
         cursor += 6;
         continue;
       case 0x3D83:  // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
@@ -193,6 +181,36 @@
   return true;
 }
 
+static const void **InterestingDLLsAvailable() {
+  const char *InterestingDLLs[] = {"kernel32.dll",
+                                   "msvcr110.dll", // VS2012
+                                   "msvcr120.dll", // VS2013
+                                   NULL};
+  static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
+  if (!result[0]) {
+    for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
+      if (HMODULE h = GetModuleHandleA(InterestingDLLs[i]))
+        result[j++] = (void *)h;
+    }
+  }
+  return (const void **)&result[0];
+}
+
+static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
+  *func_addr = 0;
+  const void **DLLs = InterestingDLLsAvailable();
+  for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
+    *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name);
+  return (*func_addr != 0);
+}
+
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
+  uptr orig_func;
+  if (!GetFunctionAddressInDLLs(name, &orig_func))
+    return false;
+  return OverrideFunction(orig_func, new_func, orig_old_func);
+}
+
 }  // namespace __interception
 
 #endif  // _WIN32
diff --git a/lib/interception/interception_win.h b/lib/interception/interception_win.h
index f2727c9..ba768a7 100644
--- a/lib/interception/interception_win.h
+++ b/lib/interception/interception_win.h
@@ -22,27 +22,29 @@
 #define INTERCEPTION_WIN_H
 
 namespace __interception {
-// returns true if a function with the given name was found.
-bool GetRealFunctionAddress(const char *func_name, uptr *func_addr);
+// All the functions in the OverrideFunction() family return true on success,
+// false on failure (including "couldn't find the function").
 
-// returns true if the old function existed, false on failure.
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
+// Overrides a function by its address.
+bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0);
+
+// Overrides a function in a system DLL or DLL CRT by its exported name.
+bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
 }  // namespace __interception
 
-#if defined(_DLL)
-# define INTERCEPT_FUNCTION_WIN(func) \
-    ::__interception::GetRealFunctionAddress( \
-        #func, (::__interception::uptr*)&REAL(func))
+#if defined(INTERCEPTION_DYNAMIC_CRT)
+#define INTERCEPT_FUNCTION_WIN(func)                                           \
+  ::__interception::OverrideFunction(#func,                                    \
+                                     (::__interception::uptr)WRAP(func),       \
+                                     (::__interception::uptr *)&REAL(func))
 #else
-# define INTERCEPT_FUNCTION_WIN(func) \
-    ::__interception::OverrideFunction( \
-        (::__interception::uptr)func, \
-        (::__interception::uptr)WRAP(func), \
-        (::__interception::uptr*)&REAL(func))
+#define INTERCEPT_FUNCTION_WIN(func)                                           \
+  ::__interception::OverrideFunction((::__interception::uptr)func,             \
+                                     (::__interception::uptr)WRAP(func),       \
+                                     (::__interception::uptr *)&REAL(func))
 #endif
 
-#define INTERCEPT_FUNCTION_VER_WIN(func, symver) \
-    INTERCEPT_FUNCTION_WIN(func)
+#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
 
 #endif  // INTERCEPTION_WIN_H
 #endif  // _WIN32
diff --git a/lib/lsan/CMakeLists.txt b/lib/lsan/CMakeLists.txt
index 82e9aa7..2ea765d 100644
--- a/lib/lsan/CMakeLists.txt
+++ b/lib/lsan/CMakeLists.txt
@@ -16,11 +16,6 @@
 
 set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
-# The common files need to build on every arch supported by ASan.
-# (Even if they build into dummy object files.)
-filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
-  x86_64 i386 powerpc64 arm aarch64 mips)
-
 add_custom_target(lsan)
 
 if(APPLE)
@@ -30,7 +25,7 @@
       SOURCES ${LSAN_COMMON_SOURCES}
       CFLAGS ${LSAN_CFLAGS})
   endforeach()
-elseif(NOT ANDROID)
+else()
   foreach(arch ${LSAN_COMMON_SUPPORTED_ARCH})
     add_compiler_rt_object_library(RTLSanCommon ${arch}
       SOURCES ${LSAN_COMMON_SOURCES}
diff --git a/lib/lsan/lsan.cc b/lib/lsan/lsan.cc
index 1b30b4f..1598fca 100644
--- a/lib/lsan/lsan.cc
+++ b/lib/lsan/lsan.cc
@@ -25,16 +25,6 @@
 
 namespace __lsan {
 
-static void InitializeCommonFlags() {
-  CommonFlags *cf = common_flags();
-  SetCommonFlagsDefaults(cf);
-  cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
-  cf->malloc_context_size = 30;
-  cf->detect_leaks = true;
-
-  ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS"));
-}
-
 ///// Interface to the common LSan module. /////
 bool WordIsPoisoned(uptr addr) {
   return false;
@@ -50,7 +40,7 @@
     return;
   lsan_init_is_running = true;
   SanitizerToolName = "LeakSanitizer";
-  InitializeCommonFlags();
+  InitCommonLsan(true);
   InitializeAllocator();
   InitTlsSize();
   InitializeInterceptors();
@@ -60,12 +50,14 @@
   ThreadStart(tid, GetTid());
   SetCurrentThread(tid);
 
-  Symbolizer::Init(common_flags()->external_symbolizer_path);
-
-  InitCommonLsan();
   if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
     Atexit(DoLeakCheck);
   lsan_inited = true;
   lsan_init_is_running = false;
 }
 
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+  GET_STACK_TRACE_FATAL;
+  stack.Print();
+}
diff --git a/lib/lsan/lsan.h b/lib/lsan/lsan.h
index 3e7f76b..53783cd 100644
--- a/lib/lsan/lsan.h
+++ b/lib/lsan/lsan.h
@@ -15,6 +15,26 @@
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 
+#define GET_STACK_TRACE(max_size, fast)                                        \
+  BufferedStackTrace stack;                                                    \
+  {                                                                            \
+    uptr stack_top = 0, stack_bottom = 0;                                      \
+    ThreadContext *t;                                                          \
+    if (fast && (t = CurrentThreadContext())) {                                \
+      stack_top = t->stack_end();                                              \
+      stack_bottom = t->stack_begin();                                         \
+    }                                                                          \
+    stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),    \
+                 /* context */ 0, stack_top, stack_bottom, fast);              \
+  }
+
+#define GET_STACK_TRACE_FATAL \
+  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_MALLOC                                      \
+  GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
+                  common_flags()->fast_unwind_on_malloc)
+
 namespace __lsan {
 
 void InitializeInterceptors();
diff --git a/lib/lsan/lsan_allocator.cc b/lib/lsan/lsan_allocator.cc
index 2340a12..8be2a2a 100644
--- a/lib/lsan/lsan_allocator.cc
+++ b/lib/lsan/lsan_allocator.cc
@@ -15,6 +15,7 @@
 #include "lsan_allocator.h"
 
 #include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
@@ -53,7 +54,7 @@
   allocator.SwallowCache(&cache);
 }
 
-static ChunkMetadata *Metadata(void *p) {
+static ChunkMetadata *Metadata(const void *p) {
   return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
 }
 
@@ -62,7 +63,7 @@
   ChunkMetadata *m = Metadata(p);
   CHECK(m);
   m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
-  m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
+  m->stack_trace_id = StackDepotPut(stack);
   m->requested_size = size;
   atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
 }
@@ -87,10 +88,12 @@
   if (cleared && allocator.FromPrimary(p))
     memset(p, 0, size);
   RegisterAllocation(stack, p, size);
+  if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
   return p;
 }
 
 void Deallocate(void *p) {
+  if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
   RegisterDeallocation(p);
   allocator.Deallocate(&cache, p);
 }
@@ -113,7 +116,7 @@
   *end = *begin + sizeof(cache);
 }
 
-uptr GetMallocUsableSize(void *p) {
+uptr GetMallocUsableSize(const void *p) {
   ChunkMetadata *m = Metadata(p);
   if (!m) return 0;
   return m->requested_size;
@@ -200,3 +203,38 @@
   }
 }
 }  // namespace __lsan
+
+using namespace __lsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_current_allocated_bytes() {
+  uptr stats[AllocatorStatCount];
+  allocator.GetStats(stats);
+  return stats[AllocatorStatAllocated];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_heap_size() {
+  uptr stats[AllocatorStatCount];
+  allocator.GetStats(stats);
+  return stats[AllocatorStatMapped];
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_free_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_unmapped_bytes() { return 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_allocated_size(const void *p) {
+  return GetMallocUsableSize(p);
+}
+}  // extern "C"
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
index 00c55ae..f564601 100644
--- a/lib/lsan/lsan_allocator.h
+++ b/lib/lsan/lsan_allocator.h
@@ -25,7 +25,7 @@
 void Deallocate(void *p);
 void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
                  uptr alignment);
-uptr GetMallocUsableSize(void *p);
+uptr GetMallocUsableSize(const void *p);
 
 template<typename Callable>
 void ForEachChunk(const Callable &callback);
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 92da6b0..746244c 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -36,15 +36,13 @@
 
 Flags lsan_flags;
 
-static void InitializeFlags() {
+static void InitializeFlags(bool standalone) {
   Flags *f = flags();
   // Default values.
   f->report_objects = false;
   f->resolution = 0;
   f->max_leaks = 0;
   f->exitcode = 23;
-  f->print_suppressions = true;
-  f->suppressions="";
   f->use_registers = true;
   f->use_globals = true;
   f->use_stacks = true;
@@ -72,9 +70,18 @@
     ParseFlag(options, &f->log_pointers, "log_pointers", "");
     ParseFlag(options, &f->log_threads, "log_threads", "");
     ParseFlag(options, &f->exitcode, "exitcode", "");
-    ParseFlag(options, &f->print_suppressions, "print_suppressions", "");
-    ParseFlag(options, &f->suppressions, "suppressions", "");
   }
+
+  // Set defaults for common flags (only in standalone mode) and parse
+  // them from LSAN_OPTIONS.
+  CommonFlags *cf = common_flags();
+  if (standalone) {
+    SetCommonFlagsDefaults(cf);
+    cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
+    cf->malloc_context_size = 30;
+    cf->detect_leaks = true;
+  }
+  ParseCommonFlagsFromString(cf, options);
 }
 
 #define LOG_POINTERS(...)                           \
@@ -87,24 +94,14 @@
     if (flags()->log_threads) Report(__VA_ARGS__); \
   } while (0);
 
-SuppressionContext *suppression_ctx;
+static bool suppressions_inited = false;
 
 void InitializeSuppressions() {
-  CHECK(!suppression_ctx);
-  ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
-  suppression_ctx = new(placeholder) SuppressionContext;
-  char *suppressions_from_file;
-  uptr buffer_size;
-  if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file,
-                       &buffer_size, 1 << 26 /* max_len */))
-    suppression_ctx->Parse(suppressions_from_file);
-  if (flags()->suppressions[0] && !buffer_size) {
-    Printf("LeakSanitizer: failed to read suppressions file '%s'\n",
-           flags()->suppressions);
-    Die();
-  }
+  CHECK(!suppressions_inited);
+  SuppressionContext::InitIfNecessary();
   if (&__lsan_default_suppressions)
-    suppression_ctx->Parse(__lsan_default_suppressions());
+    SuppressionContext::Get()->Parse(__lsan_default_suppressions());
+  suppressions_inited = true;
 }
 
 struct RootRegion {
@@ -120,8 +117,8 @@
   root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
 }
 
-void InitCommonLsan() {
-  InitializeFlags();
+void InitCommonLsan(bool standalone) {
+  InitializeFlags(standalone);
   InitializeRootRegions();
   if (common_flags()->detect_leaks) {
     // Initialization which can fail or print warnings should only be done if
@@ -358,9 +355,7 @@
 
 static void PrintStackTraceById(u32 stack_trace_id) {
   CHECK(stack_trace_id);
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(stack_trace_id, &size);
-  StackTrace::PrintStack(trace, size);
+  StackDepotGet(stack_trace_id).Print();
 }
 
 // ForEachChunk callback. Aggregates information about unreachable chunks into
@@ -375,10 +370,9 @@
     uptr resolution = flags()->resolution;
     u32 stack_trace_id = 0;
     if (resolution > 0) {
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
-      size = Min(size, resolution);
-      stack_trace_id = StackDepotPut(trace, size);
+      StackTrace stack = StackDepotGet(m.stack_trace_id());
+      stack.size = Min(stack.size, resolution);
+      stack_trace_id = StackDepotPut(stack);
     } else {
       stack_trace_id = m.stack_trace_id();
     }
@@ -389,7 +383,7 @@
 
 static void PrintMatchedSuppressions() {
   InternalMmapVector<Suppression *> matched(1);
-  suppression_ctx->GetMatched(&matched);
+  SuppressionContext::Get()->GetMatched(&matched);
   if (!matched.size())
     return;
   const char *line = "-----------------------------------------------------";
@@ -450,12 +444,15 @@
     Printf("%s", d.End());
     param.leak_report.ReportTopLeaks(flags()->max_leaks);
   }
-  if (flags()->print_suppressions)
+  if (common_flags()->print_suppressions)
     PrintMatchedSuppressions();
   if (unsuppressed_count > 0) {
     param.leak_report.PrintSummary();
-    if (flags()->exitcode)
+    if (flags()->exitcode) {
+      if (common_flags()->coverage)
+        __sanitizer_cov_dump();
       internal__exit(flags()->exitcode);
+    }
   }
 }
 
@@ -465,31 +462,32 @@
   // Suppress by module name.
   const char *module_name;
   uptr module_offset;
-  if (Symbolizer::Get()->GetModuleNameAndOffsetForPC(addr, &module_name,
-                                                     &module_offset) &&
-      suppression_ctx->Match(module_name, SuppressionLeak, &s))
+  if (Symbolizer::GetOrInit()
+          ->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) &&
+      SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s))
     return s;
 
   // Suppress by file or function name.
   static const uptr kMaxAddrFrames = 16;
   InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
   for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo();
-  uptr addr_frames_num = Symbolizer::Get()->SymbolizePC(
+  uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
       addr, addr_frames.data(), kMaxAddrFrames);
   for (uptr i = 0; i < addr_frames_num; i++) {
-    if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
-        suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s))
+    if (SuppressionContext::Get()->Match(addr_frames[i].function,
+                                         SuppressionLeak, &s) ||
+        SuppressionContext::Get()->Match(addr_frames[i].file, SuppressionLeak,
+                                         &s))
       return s;
   }
   return 0;
 }
 
 static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(stack_trace_id, &size);
-  for (uptr i = 0; i < size; i++) {
-    Suppression *s =
-        GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i]));
+  StackTrace stack = StackDepotGet(stack_trace_id);
+  for (uptr i = 0; i < stack.size; i++) {
+    Suppression *s = GetSuppressionForAddr(
+        StackTrace::GetPreviousInstructionPc(stack.trace[i]));
     if (s) return s;
   }
   return 0;
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index c0f12e6..86ff12d 100644
--- a/lib/lsan/lsan_common.h
+++ b/lib/lsan/lsan_common.h
@@ -51,10 +51,6 @@
   int max_leaks;
   // If nonzero kill the process with this exit code upon finding leaks.
   int exitcode;
-  // Print matched suppressions after leak checking.
-  bool print_suppressions;
-  // Suppressions file name.
-  const char* suppressions;
 
   // Flags controlling the root set of reachable memory.
   // Global variables (.data and .bss).
@@ -135,7 +131,7 @@
 };
 
 // Functions called from the parent tool.
-void InitCommonLsan();
+void InitCommonLsan(bool standalone);
 void DoLeakCheck();
 bool DisabledInThisThread();
 
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
index faa24d7..ba51868 100644
--- a/lib/lsan/lsan_common_linux.cc
+++ b/lib/lsan/lsan_common_linux.cc
@@ -94,11 +94,10 @@
 
 static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
   CHECK(stack_id);
-  uptr size = 0;
-  const uptr *trace = map->Get(stack_id, &size);
+  StackTrace stack = map->Get(stack_id);
   // The top frame is our malloc/calloc/etc. The next frame is the caller.
-  if (size >= 2)
-    return trace[1];
+  if (stack.size >= 2)
+    return stack.trace[1];
   return 0;
 }
 
diff --git a/lib/lsan/lsan_interceptors.cc b/lib/lsan/lsan_interceptors.cc
index ad8ca90..b01bbf8 100644
--- a/lib/lsan/lsan_interceptors.cc
+++ b/lib/lsan/lsan_interceptors.cc
@@ -12,11 +12,11 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "interception/interception.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_interception.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
@@ -34,21 +34,6 @@
 int pthread_setspecific(unsigned key, const void *v);
 }
 
-#define GET_STACK_TRACE                                              \
-  StackTrace stack;                                                  \
-  {                                                                  \
-    uptr stack_top = 0, stack_bottom = 0;                            \
-    ThreadContext *t;                                                \
-    bool fast = common_flags()->fast_unwind_on_malloc;               \
-    if (fast && (t = CurrentThreadContext())) {                      \
-      stack_top = t->stack_end();                                    \
-      stack_bottom = t->stack_begin();                               \
-    }                                                                \
-    stack.Unwind(__sanitizer::common_flags()->malloc_context_size,   \
-                 StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), 0, \
-                 stack_top, stack_bottom, fast);                     \
-  }
-
 #define ENSURE_LSAN_INITED do {   \
   CHECK(!lsan_init_is_running);   \
   if (!lsan_inited)               \
@@ -65,7 +50,7 @@
 
 INTERCEPTOR(void*, malloc, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   return Allocate(stack, size, 1, kAlwaysClearMemory);
 }
 
@@ -88,32 +73,32 @@
   }
   if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   size *= nmemb;
   return Allocate(stack, size, 1, true);
 }
 
 INTERCEPTOR(void*, realloc, void *q, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   return Reallocate(stack, q, size, 1);
 }
 
 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   return Allocate(stack, size, alignment, kAlwaysClearMemory);
 }
 
 INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   return Allocate(stack, size, alignment, kAlwaysClearMemory);
 }
 
 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
   // FIXME: Return ENOMEM if user requested more than max alloc size.
   return 0;
@@ -121,7 +106,7 @@
 
 INTERCEPTOR(void*, valloc, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   if (size == 0)
     size = GetPageSizeCached();
   return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
@@ -148,7 +133,7 @@
 
 INTERCEPTOR(void*, pvalloc, uptr size) {
   ENSURE_LSAN_INITED;
-  GET_STACK_TRACE;
+  GET_STACK_TRACE_MALLOC;
   uptr PageSize = GetPageSizeCached();
   size = RoundUpTo(size, PageSize);
   if (size == 0) {
@@ -162,7 +147,7 @@
 
 #define OPERATOR_NEW_BODY                              \
   ENSURE_LSAN_INITED;                                  \
-  GET_STACK_TRACE;                                     \
+  GET_STACK_TRACE_MALLOC;                              \
   return Allocate(stack, size, 1, kAlwaysClearMemory);
 
 INTERCEPTOR_ATTRIBUTE
diff --git a/lib/lsan/lsan_preinit.cc b/lib/lsan/lsan_preinit.cc
index e663951..5a19095 100644
--- a/lib/lsan/lsan_preinit.cc
+++ b/lib/lsan/lsan_preinit.cc
@@ -14,11 +14,7 @@
 
 #include "lsan.h"
 
-#ifndef LSAN_USE_PREINIT_ARRAY
-#define LSAN_USE_PREINIT_ARRAY 1
-#endif
-
-#if LSAN_USE_PREINIT_ARRAY && !defined(PIC)
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
   // We force __lsan_init to be called before anyone else by placing it into
   // .preinit_array section.
   __attribute__((section(".preinit_array"), used))
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 4d69a25..90d9fac 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -14,16 +14,15 @@
 
 set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 append_no_rtti_flag(MSAN_RTL_CFLAGS)
-append_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
 # Prevent clang from generating libc calls.
-append_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
 
 set(MSAN_RUNTIME_LIBRARIES)
 
 # Static runtime library.
 add_custom_target(msan)
-set(arch "x86_64")
-if(CAN_TARGET_${arch})
+foreach(arch ${MSAN_SUPPORTED_ARCH})
   add_compiler_rt_runtime(clang_rt.msan-${arch} ${arch} STATIC
     SOURCES ${MSAN_RTL_SOURCES}
             $<TARGET_OBJECTS:RTInterception.${arch}>
@@ -36,7 +35,7 @@
     add_sanitizer_rt_symbols(clang_rt.msan-${arch} msan.syms.extra)
     add_dependencies(msan clang_rt.msan-${arch}-symbols)
   endif()
-endif()
+endforeach()
 
 add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
 add_dependencies(msan msan_blacklist)
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index fd7fdbb..09622c4 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -34,27 +34,25 @@
 static THREADLOCAL int msan_expect_umr = 0;
 static THREADLOCAL int msan_expected_umr_found = 0;
 
-static bool msan_running_under_dr;
-
 // Function argument shadow. Each argument starts at the next available 8-byte
 // aligned address.
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
 
 // Function argument origin. Each argument starts at the same offset as the
 // corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
 // would break compatibility with older prebuilt binaries.
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSizeInWords];
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
 THREADLOCAL u32 __msan_retval_origin_tls;
 
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
 THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
@@ -63,7 +61,6 @@
 THREADLOCAL u32 __msan_origin_tls;
 
 static THREADLOCAL int is_in_symbolizer;
-static THREADLOCAL int is_in_loader;
 
 extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
 
@@ -79,14 +76,6 @@
 void ExitSymbolizer()  { --is_in_symbolizer; }
 bool IsInSymbolizer() { return is_in_symbolizer; }
 
-void EnterLoader() { ++is_in_loader; }
-void ExitLoader()  { --is_in_loader; }
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader() { return is_in_loader; }
-}
-
 static Flags msan_flags;
 
 Flags *flags() {
@@ -187,7 +176,7 @@
   ParseFlagsFromString(f, options);
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
                    bool request_fast_unwind) {
   MsanThread *t = GetCurrentThread();
   if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
@@ -280,16 +269,19 @@
     }
   }
 
-  StackDepotHandle h = StackDepotPut_WithHandle(stack->trace, stack->size);
+  StackDepotHandle h = StackDepotPut_WithHandle(*stack);
   if (!h.valid()) return id;
-  int use_count = h.use_count();
-  if (use_count > flags()->origin_history_per_stack_limit)
-    return id;
+
+  if (flags()->origin_history_per_stack_limit > 0) {
+    int use_count = h.use_count();
+    if (use_count > flags()->origin_history_per_stack_limit) return id;
+  }
 
   u32 chained_id;
   bool inserted = ChainedOriginDepotPut(h.id(), o.id(), &chained_id);
 
-  if (inserted) h.inc_use_count_unsafe();
+  if (inserted && flags()->origin_history_per_stack_limit > 0)
+    h.inc_use_count_unsafe();
 
   return Origin(chained_id, depth).raw_id();
 }
@@ -377,6 +369,7 @@
 
   if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
     ReplaceOperatorsNewAndDelete();
+  DisableCoreDumperIfNecessary();
   if (StackSizeIsUnlimited()) {
     VPrintf(1, "Unlimited stack, doing reexec\n");
     // A reasonably large stack size. It is bigger than the usual 8Mb, because,
@@ -390,7 +383,7 @@
   __msan_clear_on_return();
   if (__msan_get_track_origins())
     VPrintf(1, "msan_track_origins\n");
-  if (!InitShadow(/* prot1 */ !msan_running_under_dr, /* prot2 */ true,
+  if (!InitShadow(/* prot1 */ true, /* prot2 */ true,
                   /* map_shadow */ true, __msan_get_track_origins())) {
     Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
     Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
@@ -401,8 +394,7 @@
     Die();
   }
 
-  Symbolizer::Init(common_flags()->external_symbolizer_path);
-  Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+  Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
 
   MsanTSDInit(MsanTSDDtor);
 
@@ -482,7 +474,7 @@
   (void)sp;
   ReportUMRInsideAddressRange(__func__, x, size, offset);
   __msan::PrintWarningWithOrigin(pc, bp,
-                                 __msan_get_origin(((char *)x) + offset));
+                                 __msan_get_origin(((const char *)x) + offset));
   if (__msan::flags()->halt_on_error) {
     Printf("Exiting\n");
     Die();
@@ -495,40 +487,13 @@
   return old;
 }
 
-int  __msan_has_dynamic_component() {
-  return msan_running_under_dr;
-}
+int __msan_has_dynamic_component() { return false; }
 
 NOINLINE
 void __msan_clear_on_return() {
   __msan_param_tls[0] = 0;
 }
 
-static void* get_tls_base() {
-  u64 p;
-  asm("mov %%fs:0, %0"
-      : "=r"(p) ::);
-  return (void*)p;
-}
-
-int __msan_get_retval_tls_offset() {
-  // volatile here is needed to avoid UB, because the compiler thinks that we
-  // are doing address arithmetics on unrelated pointers, and takes some
-  // shortcuts
-  volatile sptr retval_tls_p = (sptr)&__msan_retval_tls;
-  volatile sptr tls_base_p = (sptr)get_tls_base();
-  return retval_tls_p - tls_base_p;
-}
-
-int __msan_get_param_tls_offset() {
-  // volatile here is needed to avoid UB, because the compiler thinks that we
-  // are doing address arithmetics on unrelated pointers, and takes some
-  // shortcuts
-  volatile sptr param_tls_p = (sptr)&__msan_param_tls;
-  volatile sptr tls_base_p = (sptr)get_tls_base();
-  return param_tls_p - tls_base_p;
-}
-
 void __msan_partial_poison(const void* data, void* shadow, uptr size) {
   internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
 }
@@ -562,11 +527,11 @@
 // 'descr' is created at compile time and contains '----' in the beginning.
 // When we see descr for the first time we replace '----' with a uniq id
 // and set the origin to (id | (31-th bit)).
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
   __msan_set_alloca_origin4(a, size, descr, 0);
 }
 
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
   static const u32 dash = '-';
   static const u32 first_timer =
       dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -654,18 +619,6 @@
   death_callback = callback;
 }
 
-void *__msan_wrap_indirect_call(void *target) {
-  return IndirectExternCall(target);
-}
-
-void __msan_dr_is_initialized() {
-  msan_running_under_dr = true;
-}
-
-void __msan_set_indirect_call_wrapper(uptr wrapper) {
-  SetIndirectCallWrapper(wrapper);
-}
-
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index 05a8c47..aed8738 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,15 +25,25 @@
 # define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
 #endif
 
+#if defined(__mips64)
+#define MEM_TO_SHADOW(mem)       (((uptr)mem) & ~0x4000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x2000000000ULL)
+#define MEM_TO_ORIGIN(mem)       (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
+#define MEM_IS_APP(mem)          ((uptr)mem >= 0xe000000000ULL)
+#define MEM_IS_SHADOW(mem) \
+  ((uptr)mem >= 0xa000000000ULL && (uptr)mem <= 0xc000000000ULL)
+#elif defined(__x86_64__)
 #define MEM_TO_SHADOW(mem)       (((uptr)mem) & ~0x400000000000ULL)
 #define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x200000000000ULL)
 #define MEM_TO_ORIGIN(mem)       (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
 #define MEM_IS_APP(mem)          ((uptr)mem >= 0x600000000000ULL)
 #define MEM_IS_SHADOW(mem) \
   ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
+#endif
 
-const int kMsanParamTlsSizeInWords = 100;
-const int kMsanRetvalTlsSizeInWords = 100;
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
 
 namespace __msan {
 extern int msan_inited;
@@ -64,14 +74,11 @@
   ~SymbolizerScope() { ExitSymbolizer(); }
 };
 
-void EnterLoader();
-void ExitLoader();
-
 void MsanDie();
 void PrintWarning(uptr pc, uptr bp);
 void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
                    bool request_fast_unwind);
 
 void ReportUMR(StackTrace *stack, u32 origin);
@@ -96,27 +103,24 @@
 // the previous origin id.
 u32 ChainOrigin(u32 id, StackTrace *stack);
 
-#define GET_MALLOC_STACK_TRACE                                     \
-  StackTrace stack;                                                \
-  stack.size = 0;                                                  \
-  if (__msan_get_track_origins() && msan_inited)                   \
-    GetStackTrace(&stack, common_flags()->malloc_context_size,     \
-        StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),           \
-        common_flags()->fast_unwind_on_malloc)
-
-#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                  \
-  StackTrace stack;                                          \
-  stack.size = 0;                                            \
-  if (__msan_get_track_origins() > 1 && msan_inited)         \
-  GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+#define GET_MALLOC_STACK_TRACE                                                 \
+  BufferedStackTrace stack;                                                    \
+  if (__msan_get_track_origins() && msan_inited)                               \
+  GetStackTrace(&stack, common_flags()->malloc_context_size,                   \
+                StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),               \
                 common_flags()->fast_unwind_on_malloc)
 
-#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)       \
-  StackTrace stack;                               \
-  stack.size = 0;                                 \
-  if (msan_inited)                                \
-    GetStackTrace(&stack, kStackTraceMax, pc, bp, \
-                  common_flags()->fast_unwind_on_fatal)
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                                    \
+  BufferedStackTrace stack;                                                    \
+  if (__msan_get_track_origins() > 1 && msan_inited)                           \
+  GetStackTrace(&stack, flags()->store_context_size, pc, bp,                   \
+                common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)                                    \
+  BufferedStackTrace stack;                                                    \
+  if (msan_inited)                                                             \
+  GetStackTrace(&stack, kStackTraceMax, pc, bp,                                \
+                common_flags()->fast_unwind_on_fatal)
 
 #define GET_STORE_STACK_TRACE \
   GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
@@ -141,10 +145,8 @@
 }  // namespace __msan
 
 #define MSAN_MALLOC_HOOK(ptr, size) \
-  if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size); \
   if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
 #define MSAN_FREE_HOOK(ptr) \
-  if (&__msan_free_hook) __msan_free_hook(ptr); \
   if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
 
 #endif  // MSAN_H
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index fb1788f..aa1ea1d 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -40,14 +40,26 @@
   }
 };
 
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize   = 0x80000000000;  // 8T.
-static const uptr kMetadataSize  = sizeof(Metadata);
-static const uptr kMaxAllowedMallocSize = 8UL << 30;
+#if defined(__mips64)
+  static const uptr kMaxAllowedMallocSize = 2UL << 30;
+  static const uptr kRegionSizeLog = 20;
+  static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+  typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+  typedef CompactSizeClassMap SizeClassMap;
 
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+  typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+                               SizeClassMap, kRegionSizeLog, ByteMap,
+                               MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__x86_64__)
+  static const uptr kAllocatorSpace = 0x600000000000ULL;
+  static const uptr kAllocatorSize   = 0x80000000000;  // 8T.
+  static const uptr kMetadataSize  = sizeof(Metadata);
+  static const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+  typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
                              DefaultSizeClassMap,
                              MsanMapUnmapCallback> PrimaryAllocator;
+#endif
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
 typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
@@ -102,7 +114,7 @@
   } else if (flags()->poison_in_malloc) {
     __msan_poison(allocated, size);
     if (__msan_get_track_origins()) {
-      u32 stack_id = StackDepotPut(stack->trace, stack->size);
+      u32 stack_id = StackDepotPut(*stack);
       CHECK(stack_id);
       u32 id;
       ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
@@ -125,7 +137,7 @@
   if (flags()->poison_in_free) {
     __msan_poison(p, size);
     if (__msan_get_track_origins()) {
-      u32 stack_id = StackDepotPut(stack->trace, stack->size);
+      u32 stack_id = StackDepotPut(*stack);
       CHECK(stack_id);
       u32 id;
       ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
@@ -188,40 +200,19 @@
   allocator.GetStats(stats);
   return stats[AllocatorStatAllocated];
 }
-uptr __msan_get_current_allocated_bytes() {
-  return __sanitizer_get_current_allocated_bytes();
-}
 
 uptr __sanitizer_get_heap_size() {
   uptr stats[AllocatorStatCount];
   allocator.GetStats(stats);
   return stats[AllocatorStatMapped];
 }
-uptr __msan_get_heap_size() {
-  return __sanitizer_get_heap_size();
-}
 
 uptr __sanitizer_get_free_bytes() { return 1; }
-uptr __msan_get_free_bytes() {
-  return __sanitizer_get_free_bytes();
-}
 
 uptr __sanitizer_get_unmapped_bytes() { return 1; }
-uptr __msan_get_unmapped_bytes() {
-  return __sanitizer_get_unmapped_bytes();
-}
 
 uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
-uptr __msan_get_estimated_allocated_size(uptr size) {
-  return __sanitizer_get_estimated_allocated_size(size);
-}
 
 int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
-int __msan_get_ownership(const void *p) {
-  return __sanitizer_get_ownership(p);
-}
 
 uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
-uptr __msan_get_allocated_size(const void *p) {
-  return __sanitizer_get_allocated_size(p);
-}
diff --git a/lib/msan/msan_chained_origin_depot.cc b/lib/msan/msan_chained_origin_depot.cc
index faf0461..f3fb3c8 100644
--- a/lib/msan/msan_chained_origin_depot.cc
+++ b/lib/msan/msan_chained_origin_depot.cc
@@ -19,31 +19,6 @@
 struct ChainedOriginDepotDesc {
   u32 here_id;
   u32 prev_id;
-  u32 hash() const {
-    const u32 m = 0x5bd1e995;
-    const u32 seed = 0x9747b28c;
-    const u32 r = 24;
-    u32 h = seed;
-    u32 k = here_id;
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-
-    k = prev_id;
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-    return h;
-  }
-  bool is_valid() { return true; }
 };
 
 struct ChainedOriginDepotNode {
@@ -59,6 +34,44 @@
   static uptr storage_size(const args_type &args) {
     return sizeof(ChainedOriginDepotNode);
   }
+  /* This is murmur2 hash for the 64->32 bit case.
+     It does not behave all that well because the keys have a very biased
+     distribution (I've seen 7-element buckets with the table only 14% full).
+
+     here_id is built of
+     * (1 bits) Reserved, zero.
+     * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+     * (23 bits) Sequential number (each part has each own sequence).
+
+     prev_id has either the same distribution as here_id (but with 3:8:21)
+     split, or one of two reserved values (-1) or (-2). Either case can
+     dominate depending on the workload.
+  */
+  static u32 hash(const args_type &args) {
+    const u32 m = 0x5bd1e995;
+    const u32 seed = 0x9747b28c;
+    const u32 r = 24;
+    u32 h = seed;
+    u32 k = args.here_id;
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+    h *= m;
+    h ^= k;
+
+    k = args.prev_id;
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+    h *= m;
+    h ^= k;
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+    return h;
+  }
+  static bool is_valid(const args_type &args) { return true; }
   void store(const args_type &args, u32 other_hash) {
     here_id = args.here_id;
     prev_id = args.prev_id;
@@ -103,4 +116,12 @@
   return desc.here_id;
 }
 
+void ChainedOriginDepotLockAll() {
+  chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+  chainedOriginDepot.UnlockAll();
+}
+
 }  // namespace __msan
diff --git a/lib/msan/msan_chained_origin_depot.h b/lib/msan/msan_chained_origin_depot.h
index db427b0..f7a71ce 100644
--- a/lib/msan/msan_chained_origin_depot.h
+++ b/lib/msan/msan_chained_origin_depot.h
@@ -21,6 +21,9 @@
 // Retrieves a stored stack trace by the id.
 u32 ChainedOriginDepotGet(u32 id, u32 *other);
 
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
 }  // namespace __msan
 
 #endif  // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 3394690..aa6b1ff 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -15,6 +15,7 @@
 // sanitizer_common/sanitizer_common_interceptors.h
 //===----------------------------------------------------------------------===//
 
+#include "interception/interception.h"
 #include "msan.h"
 #include "msan_chained_origin_depot.h"
 #include "msan_origin.h"
@@ -25,7 +26,6 @@
 #include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_interception.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_linux.h"
@@ -64,21 +64,22 @@
 } while (0)
 
 // Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n)                                             \
-  do {                                                                       \
-    sptr offset = __msan_test_shadow(x, n);                                  \
-    if (__msan::IsInSymbolizer()) break;                                     \
-    if (offset >= 0 && __msan::flags()->report_umrs) {                       \
-      GET_CALLER_PC_BP_SP;                                                   \
-      (void) sp;                                                             \
-      ReportUMRInsideAddressRange(__func__, x, n, offset);                   \
-      __msan::PrintWarningWithOrigin(pc, bp,                                 \
-                                     __msan_get_origin((char *)x + offset)); \
-      if (__msan::flags()->halt_on_error) {                                  \
-        Printf("Exiting\n");                                                 \
-        Die();                                                               \
-      }                                                                      \
-    }                                                                        \
+#define CHECK_UNPOISONED_0(x, n)                                               \
+  do {                                                                         \
+    sptr offset = __msan_test_shadow(x, n);                                    \
+    if (__msan::IsInSymbolizer())                                              \
+      break;                                                                   \
+    if (offset >= 0 && __msan::flags()->report_umrs) {                         \
+      GET_CALLER_PC_BP_SP;                                                     \
+      (void) sp;                                                               \
+      ReportUMRInsideAddressRange(__func__, x, n, offset);                     \
+      __msan::PrintWarningWithOrigin(                                          \
+          pc, bp, __msan_get_origin((const char *)x + offset));                \
+      if (__msan::flags()->halt_on_error) {                                    \
+        Printf("Exiting\n");                                                   \
+        Die();                                                                 \
+      }                                                                        \
+    }                                                                          \
   } while (0)
 
 // Check that [x, x+n) range is unpoisoned unless we are in a nested
@@ -88,9 +89,6 @@
     if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
   } while (0);
 
-static void *fast_memset(void *ptr, int c, SIZE_T n);
-static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
-
 INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
   ENSURE_MSAN_INITED();
   SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -263,6 +261,7 @@
     copy_size++;  // trailing \0
   char *res = REAL(strncpy)(dest, src, n);  // NOLINT
   CopyPoison(dest, src, copy_size, &stack);
+  __msan_unpoison(dest + copy_size, n - copy_size);
   return res;
 }
 
@@ -316,11 +315,8 @@
 INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
   ENSURE_MSAN_INITED();
   char *res = REAL(gcvt)(number, ndigit, buf);
-  // DynamoRio tool will take care of unpoisoning gcvt result for us.
-  if (!__msan_has_dynamic_component()) {
-    SIZE_T n = REAL(strlen)(buf);
-    __msan_unpoison(buf, n + 1);
-  }
+  SIZE_T n = REAL(strlen)(buf);
+  __msan_unpoison(buf, n + 1);
   return res;
 }
 
@@ -350,9 +346,7 @@
 #define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
   ENSURE_MSAN_INITED();                             \
   ret_type res = REAL(func)(__VA_ARGS__);           \
-  if (!__msan_has_dynamic_component()) {            \
-    __msan_unpoison(endptr, sizeof(*endptr));       \
-  }                                                 \
+  __msan_unpoison(endptr, sizeof(*endptr));         \
   return res;
 
 #define INTERCEPTOR_STRTO(ret_type, func)                        \
@@ -409,7 +403,7 @@
 INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
   ENSURE_MSAN_INITED();
   int res = REAL(vswprintf)(str, size, format, ap);
-  if (res >= 0 && !__msan_has_dynamic_component()) {
+  if (res >= 0) {
     __msan_unpoison(str, 4 * (res + 1));
   }
   return res;
@@ -537,7 +531,7 @@
 INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
   CHECK(MEM_IS_APP(s));
   ENSURE_MSAN_INITED();
-  wchar_t *res = (wchar_t *)fast_memset(s, c, n * sizeof(wchar_t));
+  wchar_t *res = (wchar_t *)REAL(memset)(s, c, n * sizeof(wchar_t));
   __msan_unpoison(s, n * sizeof(wchar_t));
   return res;
 }
@@ -576,20 +570,16 @@
 INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
   ENSURE_MSAN_INITED();
   char *res = REAL(fcvt)(x, a, b, c);
-  if (!__msan_has_dynamic_component()) {
-    __msan_unpoison(b, sizeof(*b));
-    __msan_unpoison(c, sizeof(*c));
-  }
+  __msan_unpoison(b, sizeof(*b));
+  __msan_unpoison(c, sizeof(*c));
+  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
   return res;
 }
 
 INTERCEPTOR(char *, getenv, char *name) {
   ENSURE_MSAN_INITED();
   char *res = REAL(getenv)(name);
-  if (!__msan_has_dynamic_component()) {
-    if (res)
-      __msan_unpoison(res, REAL(strlen)(res) + 1);
-  }
+  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
   return res;
 }
 
@@ -843,7 +833,7 @@
   if (flags()->poison_in_malloc)
     __msan_poison(data, size);
   if (__msan_get_track_origins()) {
-    u32 stack_id = StackDepotPut(stack.trace, stack.size);
+    u32 stack_id = StackDepotPut(stack);
     u32 id;
     ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
     __msan_set_origin(data, size, Origin(id, 1).raw_id());
@@ -927,17 +917,15 @@
   }
   dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
   UnpoisonParam(3);
-  return IndirectExternCall(cbdata->callback)(info, size, cbdata->data);
+  return cbdata->callback(info, size, cbdata->data);
 }
 
 INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
   ENSURE_MSAN_INITED();
-  EnterLoader();
   dl_iterate_phdr_data cbdata;
   cbdata.callback = callback;
   cbdata.data = data;
   int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
-  ExitLoader();
   return res;
 }
 
@@ -977,7 +965,7 @@
   typedef void (*signal_cb)(int x);
   signal_cb cb =
       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
-  IndirectExternCall(cb)(signo);
+  cb(signo);
 }
 
 static void SignalAction(int signo, void *si, void *uc) {
@@ -990,7 +978,7 @@
   typedef void (*sigaction_cb)(int, void *, void *);
   sigaction_cb cb =
       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
-  IndirectExternCall(cb)(signo, si, uc);
+  cb(signo, si, uc);
 }
 
 INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
@@ -1006,7 +994,7 @@
     __sanitizer_sigaction new_act;
     __sanitizer_sigaction *pnew_act = act ? &new_act : 0;
     if (act) {
-      internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
+      REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
       uptr cb = (uptr)pnew_act->sigaction;
       uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
                         ? (uptr)SignalAction
@@ -1118,7 +1106,7 @@
 void MSanAtExitWrapper(void *arg) {
   UnpoisonParam(1);
   MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
-  IndirectExternCall(r->func)(r->arg);
+  r->func(r->arg);
   InternalFree(r);
 }
 
@@ -1149,34 +1137,22 @@
   return p;
 }
 
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
-  static atomic_uint8_t printed;
-  if (atomic_exchange(&printed, 1, memory_order_relaxed))
-    return;
-  VPrintf(1,
-          "INFO: MemorySanitizer ignores mlock/mlockall/munlock/munlockall\n");
+static void BeforeFork() {
+  StackDepotLockAll();
+  ChainedOriginDepotLockAll();
 }
 
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
+static void AfterFork() {
+  ChainedOriginDepotUnlockAll();
+  StackDepotUnlockAll();
 }
 
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, mlockall, int flags) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, munlockall, void) {
-  MlockIsUnsupported();
-  return 0;
+INTERCEPTOR(int, fork, void) {
+  ENSURE_MSAN_INITED();
+  BeforeFork();
+  int pid = REAL(fork)();
+  AfterFork();
+  return pid;
 }
 
 struct MSanInterceptorContext {
@@ -1240,12 +1216,8 @@
   } while (false)  // FIXME
 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
-#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map)                       \
-  if (!__msan_has_dynamic_component() && map) {                                \
-    /* If msandr didn't clear the shadow before the initializers ran, we do */ \
-    /* it ourselves afterwards. */                                             \
-    ForEachMappedRegion((link_map *)map, __msan_unpoison);                     \
-  }
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) \
+  if (map) ForEachMappedRegion((link_map *)map, __msan_unpoison);
 
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
@@ -1259,59 +1231,25 @@
 #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
 #include "sanitizer_common/sanitizer_common_syscalls.inc"
 
-// static
-void *fast_memset(void *ptr, int c, SIZE_T n) {
-  // hack until we have a really fast internal_memset
-  if (sizeof(uptr) == 8 &&
-      (n % 8) == 0 &&
-      ((uptr)ptr % 8) == 0) {
-    uptr c8 = (unsigned)c & 0xFF;
-    c8 = (c8 << 8) | c8;
-    c8 = (c8 << 16) | c8;
-    c8 = (c8 << 32) | c8;
-    uptr *p = (uptr*)ptr;
-    for (SIZE_T i = 0; i < n / 8; i++)
-      p[i] = c8;
-    return ptr;
-  }
-  return internal_memset(ptr, c, n);
-}
-
-// static
-void *fast_memcpy(void *dst, const void *src, SIZE_T n) {
-  // Same hack as in fast_memset above.
-  if (sizeof(uptr) == 8 &&
-      (n % 8) == 0 &&
-      ((uptr)dst % 8) == 0 &&
-      ((uptr)src % 8) == 0) {
-    uptr *d = (uptr*)dst;
-    uptr *s = (uptr*)src;
-    for (SIZE_T i = 0; i < n / 8; i++)
-      d[i] = s[i];
-    return dst;
-  }
-  return internal_memcpy(dst, src, n);
-}
-
 static void PoisonShadow(uptr ptr, uptr size, u8 value) {
   uptr PageSize = GetPageSizeCached();
   uptr shadow_beg = MEM_TO_SHADOW(ptr);
   uptr shadow_end = MEM_TO_SHADOW(ptr + size);
   if (value ||
       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
-    fast_memset((void*)shadow_beg, value, shadow_end - shadow_beg);
+    REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
   } else {
     uptr page_beg = RoundUpTo(shadow_beg, PageSize);
     uptr page_end = RoundDownTo(shadow_end, PageSize);
 
     if (page_beg >= page_end) {
-      fast_memset((void *)shadow_beg, 0, shadow_end - shadow_beg);
+      REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
     } else {
       if (page_beg != shadow_beg) {
-        fast_memset((void *)shadow_beg, 0, page_beg - shadow_beg);
+        REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
       }
       if (page_end != shadow_end) {
-        fast_memset((void *)page_end, 0, shadow_end - page_end);
+        REAL(memset)((void *)page_end, 0, shadow_end - page_end);
       }
       MmapFixedNoReserve(page_beg, page_end - page_beg);
     }
@@ -1319,7 +1257,7 @@
 }
 
 // These interface functions reside here so that they can use
-// fast_memset, etc.
+// REAL(memset), etc.
 void __msan_unpoison(const void *a, uptr size) {
   if (!MEM_IS_APP(a)) return;
   PoisonShadow((uptr)a, size, 0);
@@ -1338,7 +1276,7 @@
 }
 
 void __msan_clear_and_unpoison(void *a, uptr size) {
-  fast_memset(a, 0, size);
+  REAL(memset)(a, 0, size);
   PoisonShadow((uptr)a, size, 0);
 }
 
@@ -1347,7 +1285,7 @@
   if (msan_init_is_running) return REAL(memcpy)(dest, src, n);
   ENSURE_MSAN_INITED();
   GET_STORE_STACK_TRACE;
-  void *res = fast_memcpy(dest, src, n);
+  void *res = REAL(memcpy)(dest, src, n);
   CopyPoison(dest, src, n, &stack);
   return res;
 }
@@ -1356,7 +1294,7 @@
   if (!msan_inited) return internal_memset(s, c, n);
   if (msan_init_is_running) return REAL(memset)(s, c, n);
   ENSURE_MSAN_INITED();
-  void *res = fast_memset(s, c, n);
+  void *res = REAL(memset)(s, c, n);
   __msan_unpoison(s, n);
   return res;
 }
@@ -1445,7 +1383,7 @@
         *dst = dst_o;
       }
     } else {
-      fast_memcpy((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+      REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
                   end - beg);
     }
   }
@@ -1455,15 +1393,15 @@
   if (!MEM_IS_APP(dst)) return;
   if (!MEM_IS_APP(src)) return;
   if (src == dst) return;
-  internal_memmove((void *)MEM_TO_SHADOW((uptr)dst),
-                   (void *)MEM_TO_SHADOW((uptr)src), size);
+  REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+                (void *)MEM_TO_SHADOW((uptr)src), size);
   CopyOrigin(dst, src, size, stack);
 }
 
 void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack) {
   if (!MEM_IS_APP(dst)) return;
   if (!MEM_IS_APP(src)) return;
-  fast_memcpy((void *)MEM_TO_SHADOW((uptr)dst),
+  REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
               (void *)MEM_TO_SHADOW((uptr)src), size);
   CopyOrigin(dst, src, size, stack);
 }
@@ -1597,6 +1535,7 @@
   INTERCEPT_FUNCTION(tzset);
   INTERCEPT_FUNCTION(__cxa_atexit);
   INTERCEPT_FUNCTION(shmat);
+  INTERCEPT_FUNCTION(fork);
 
   inited = 1;
 }
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index 47b47dc..8641f81 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -88,9 +88,9 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_set_origin(const void *a, uptr size, u32 origin);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc);
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
 SANITIZER_INTERFACE_ATTRIBUTE
 u32 __msan_chain_origin(u32 id);
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -122,16 +122,6 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 int  __msan_has_dynamic_component();
 
-// Returns x such that %fs:x is the first byte of __msan_retval_tls.
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_retval_tls_offset();
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_param_tls_offset();
-
-// For intercepting mmap from ld.so in msandr.
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader();
-
 // For testing.
 SANITIZER_INTERFACE_ATTRIBUTE
 u32 __msan_get_umr_origin();
@@ -161,37 +151,6 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_unaligned_store64(uu64 *p, u64 x);
 
-// ---------------------------
-// FIXME: Replace these functions with __sanitizer equivalent.
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_estimated_allocated_size(uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_ownership(const void *p);
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_allocated_size(const void *p);
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_current_allocated_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_heap_size();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_free_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_unmapped_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_malloc_hook(void *ptr, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_free_hook(void *ptr);
-// ---------------------------
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_dr_is_initialized();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__msan_wrap_indirect_call(void *target);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_indirect_call_wrapper(uptr wrapper);
-
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_set_death_callback(void (*callback)(void));
 }  // extern "C"
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index a8fbabb..2a970c0 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -35,8 +35,14 @@
 
 namespace __msan {
 
+#if defined(__mips64)
+static const uptr kMemBeg     = 0xe000000000;
+static const uptr kMemEnd     = 0xffffffffff;
+#elif defined(__x86_64__)
 static const uptr kMemBeg     = 0x600000000000;
 static const uptr kMemEnd     = 0x7fffffffffff;
+#endif
+
 static const uptr kShadowBeg  = MEM_TO_SHADOW(kMemBeg);
 static const uptr kShadowEnd  = MEM_TO_SHADOW(kMemEnd);
 static const uptr kBad1Beg    = 0;
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index 3bae49c..9a8e56e 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "msan.h"
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 
 #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
 
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index 85e61e2..f4978c7 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -46,15 +46,15 @@
   Printf(
       "  %sUninitialized value was created by an allocation of '%s%s%s'"
       " in the stack frame of function '%s%s%s'%s\n",
-      d.Origin(), d.Name(), s, d.Origin(), d.Name(),
-      Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End());
+      d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+      d.End());
   InternalFree(s);
 
   if (pc) {
     // For some reason function address in LLVM IR is 1 less then the address
     // of the first instruction.
-    pc += 1;
-    StackTrace::PrintStack(&pc, 1);
+    pc = StackTrace::GetNextInstructionPc(pc);
+    StackTrace(&pc, 1).Print();
   }
 }
 
@@ -77,20 +77,16 @@
       DescribeStackOrigin(so, pc);
       break;
     } else if (prev_o.isHeapRoot()) {
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(stack_id, &size);
       Printf("  %sUninitialized value was created by a heap allocation%s\n",
              d.Origin(), d.End());
-      StackTrace::PrintStack(trace, size);
+      StackDepotGet(stack_id).Print();
       break;
     } else {
       // chained origin
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(stack_id, &size);
       // FIXME: copied? modified? passed through? observed?
       Printf("  %sUninitialized value was stored to memory at%s\n", d.Origin(),
              d.End());
-      StackTrace::PrintStack(trace, size);
+      StackDepotGet(stack_id).Print();
       id = prev_id;
     }
   }
diff --git a/lib/msan/msan_thread.cc b/lib/msan/msan_thread.cc
index 5fe99f6..2a1e05a 100644
--- a/lib/msan/msan_thread.cc
+++ b/lib/msan/msan_thread.cc
@@ -73,7 +73,7 @@
     return 0;
   }
 
-  thread_return_t res = IndirectExternCall(start_routine_)(arg_);
+  thread_return_t res = start_routine_(arg_);
 
   return res;
 }
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index c654615..f3c11ba 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -48,7 +48,7 @@
   -lstdc++
 )
 
-append_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
 set(MSAN_LOADABLE_LINK_FLAGS
   -fsanitize=memory
   -shared
diff --git a/lib/msan/tests/msan_loadable.cc b/lib/msan/tests/msan_loadable.cc
index db3bf48..06e880f 100644
--- a/lib/msan/tests/msan_loadable.cc
+++ b/lib/msan/tests/msan_loadable.cc
@@ -20,24 +20,6 @@
 // No name mangling.
 extern "C" {
 
-__attribute__((constructor))
-void loadable_module_init(void) {
-  if (!__msan_has_dynamic_component())
-    return;
-  // The real test is that this compare should not make an uninit.
-  if (dso_global == NULL)
-    dso_global = malloc(4);
-}
-
-__attribute__((destructor))
-void loadable_module_fini(void) {
-  if (!__msan_has_dynamic_component())
-    return;
-  free(dso_global);
-  // *Don't* overwrite it with NULL!  That would unpoison it, but our test
-  // relies on reloading at the same address and keeping the poison.
-}
-
 void **get_dso_global() {
   return &dso_global;
 }
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index f7268d6..12012a0 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -251,7 +251,6 @@
 
 
 TEST(MemorySanitizer, CallAndRet) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S1>();
   ReturnPoisoned<S2>();
   ReturnPoisoned<S4>();
@@ -494,14 +493,12 @@
 static char *DynRetTestStr;
 
 TEST(MemorySanitizer, DynRet) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S8>();
   EXPECT_NOT_POISONED(clearenv());
 }
 
 
 TEST(MemorySanitizer, DynRet1) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S8>();
 }
 
@@ -570,7 +567,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   fclose(f);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, read) {
@@ -583,7 +580,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   close(fd);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, pread) {
@@ -596,7 +593,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   close(fd);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, readv) {
@@ -1452,13 +1449,8 @@
   x[2] = 0;
   memmove(x, x + 1, (size - 1) * sizeof(T));
   EXPECT_NOT_POISONED(x[1]);
-  if (!__msan_has_dynamic_component()) {
-    // FIXME: under DR we will lose this information
-    // because accesses in memmove will unpoisin the shadow.
-    // We need to use our own memove implementation instead of libc's.
-    EXPECT_POISONED(x[0]);
-    EXPECT_POISONED(x[2]);
-  }
+  EXPECT_POISONED(x[0]);
+  EXPECT_POISONED(x[2]);
   delete [] x;
 }
 
@@ -1483,14 +1475,16 @@
 
 TEST(MemorySanitizer, strncpy) {  // NOLINT
   char* x = new char[3];
-  char* y = new char[3];
+  char* y = new char[5];
   x[0] = 'a';
   x[1] = *GetPoisoned<char>(1, 1);
-  x[2] = 0;
-  strncpy(y, x, 2);  // NOLINT
+  x[2] = '\0';
+  strncpy(y, x, 4);  // NOLINT
   EXPECT_NOT_POISONED(y[0]);
   EXPECT_POISONED(y[1]);
-  EXPECT_POISONED(y[2]);
+  EXPECT_NOT_POISONED(y[2]);
+  EXPECT_NOT_POISONED(y[3]);
+  EXPECT_POISONED(y[4]);
 }
 
 TEST(MemorySanitizer, stpcpy) {  // NOLINT
@@ -2062,8 +2056,26 @@
   char *str = fcvt(12345.6789, 10, &a, &b);
   EXPECT_NOT_POISONED(a);
   EXPECT_NOT_POISONED(b);
+  ASSERT_NE(nullptr, str);
+  EXPECT_NOT_POISONED(str[0]);
+  ASSERT_NE(0U, strlen(str));
 }
 
+TEST(MemorySanitizer, fcvt_long) {
+  int a, b;
+  break_optimization(&a);
+  break_optimization(&b);
+  EXPECT_POISONED(a);
+  EXPECT_POISONED(b);
+  char *str = fcvt(111111112345.6789, 10, &a, &b);
+  EXPECT_NOT_POISONED(a);
+  EXPECT_NOT_POISONED(b);
+  ASSERT_NE(nullptr, str);
+  EXPECT_NOT_POISONED(str[0]);
+  ASSERT_NE(0U, strlen(str));
+}
+
+
 TEST(MemorySanitizer, memchr) {
   char x[10];
   break_optimization(x);
@@ -2787,7 +2799,7 @@
   EXPECT_NOT_POISONED(s[4]);
   EXPECT_NOT_POISONED(s[5]);
   EXPECT_POISONED(s[6]);
-  delete s;
+  delete[] s;
   delete d;
 }
 
@@ -3712,56 +3724,6 @@
 }
 #endif  // defined(__clang__)
 
-TEST(MemorySanitizerDr, StoreInDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  char* s = new char[10];
-  dso_memfill(s, 9);
-  EXPECT_NOT_POISONED(s[5]);
-  EXPECT_POISONED(s[9]);
-}
-
-int return_poisoned_int() {
-  return ReturnPoisoned<U8>();
-}
-
-TEST(MemorySanitizerDr, ReturnFromDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  EXPECT_NOT_POISONED(dso_callfn(return_poisoned_int));
-}
-
-NOINLINE int TrashParamTLS(long long x, long long y, long long z) {  //NOLINT
-  EXPECT_POISONED(x);
-  EXPECT_POISONED(y);
-  EXPECT_POISONED(z);
-  return 0;
-}
-
-static int CheckParamTLS(long long x, long long y, long long z) {  //NOLINT
-  EXPECT_NOT_POISONED(x);
-  EXPECT_NOT_POISONED(y);
-  EXPECT_NOT_POISONED(z);
-  return 0;
-}
-
-TEST(MemorySanitizerDr, CallFromDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  S8* x = GetPoisoned<S8>();
-  S8* y = GetPoisoned<S8>();
-  S8* z = GetPoisoned<S8>();
-  EXPECT_NOT_POISONED(TrashParamTLS(*x, *y, *z));
-  EXPECT_NOT_POISONED(dso_callfn1(CheckParamTLS));
-}
-
-static void StackStoreInDSOFn(int* x, int* y) {
-  EXPECT_NOT_POISONED(*x);
-  EXPECT_NOT_POISONED(*y);
-}
-
-TEST(MemorySanitizerDr, StackStoreInDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  dso_stack_store(StackStoreInDSOFn, 1);
-}
-
 TEST(MemorySanitizerOrigins, SetGet) {
   EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins());
   if (!TrackingOrigins()) return;
diff --git a/lib/msandr/CMakeLists.txt b/lib/msandr/CMakeLists.txt
deleted file mode 100644
index 5a96a9d..0000000
--- a/lib/msandr/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-if(DynamoRIO_DIR AND DrMemoryFramework_DIR)
-  set(CMAKE_COMPILER_IS_GNUCC 1)
-  find_package(DynamoRIO)
-  find_package(DrMemoryFramework)
-
-  set(arch "x86_64")
-  add_library(clang_rt.msandr-${arch} SHARED msandr.cc)
-  configure_DynamoRIO_client(clang_rt.msandr-${arch})
-
-  function(append_target_cflags tgt cflags)
-    get_property(old_cflags TARGET clang_rt.msandr-${arch} PROPERTY COMPILE_FLAGS)
-    set_property(TARGET clang_rt.msandr-${arch} PROPERTY COMPILE_FLAGS "${old_cflags} ${cflags}")
-  endfunction(append_target_cflags)
-
-  append_target_cflags(clang_rt.msandr-${arch} "-Wno-c++11-extensions")
-
-  use_DynamoRIO_extension(clang_rt.msandr-${arch} drutil)
-  use_DynamoRIO_extension(clang_rt.msandr-${arch} drmgr)
-  use_DynamoRIO_extension(clang_rt.msandr-${arch} drsyscall)
-
-  set_target_properties(clang_rt.msandr-${arch} PROPERTIES
-    LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
-  install(TARGETS clang_rt.msandr-${arch}
-    LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
-endif()
diff --git a/lib/msandr/README.txt b/lib/msandr/README.txt
deleted file mode 100644
index 81a87c6..0000000
--- a/lib/msandr/README.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Experimental DynamoRIO-MSAN plugin (codename "MSanDR").
-Supports Linux/x86_64 only.
-
-Building:
-  1. First, download and build DynamoRIO:
-     (svn co https://dynamorio.googlecode.com/svn/trunk dr && \
-      cd dr && mkdir build && cd build && \
-      cmake -DDR_EXT_DRMGR_STATIC=ON -DDR_EXT_DRSYMS_STATIC=ON \
-            -DDR_EXT_DRUTIL_STATIC=ON -DDR_EXT_DRWRAP_STATIC=ON \
-            -DDR_EXT_DRX_STATIC=ON .. && \
-      make -j10 && make install)
-
-  2. Download and build DrMemory (for DrSyscall extension)
-     (svn co http://drmemory.googlecode.com/svn/trunk/ drmemory && \
-      cd drmemory && mkdir build && cd build && \
-      cmake -DDynamoRIO_DIR=`pwd`/../../dr/exports/cmake .. && \
-      make -j10 && make install)
-
-  NOTE: The line above will build a shared DrSyscall library in a non-standard
-  location. This will require the use of LD_LIBRARY_PATH when running MSanDR.
-  To build a static DrSyscall library (and link it into MSanDR), add
-  -DDR_EXT_DRSYSCALL_STATIC=ON to the CMake invocation above, but
-  beware: DrSyscall is LGPL.
-
-  3. Now, build LLVM with two extra CMake flags:
-       -DDynamoRIO_DIR=<path_to_dynamorio>/exports/cmake
-       -DDrMemoryFramework_DIR=<path_to_drmemory>/exports64/drmf
-
-  This will build a lib/clang/$VERSION/lib/linux/libclang_rt.msandr-x86_64.so
-
-Running:
-  <path_to_dynamorio>/exports/bin64/drrun -c lib/clang/$VERSION/lib/linux/libclang_rt.msandr-x86_64.so -- test_binary
-
-MSan unit tests contain several tests for MSanDR (use MemorySanitizerDr.* gtest filter).
-
-Debugging:
-  Add -DCMAKE_BUILD_TYPE=Debug to the first and/or second cmake invocation(s).
-  Add -debug -v to drrun invocation line (right before -c).
-  Add -checklevel 1 to drrun (as the first argument) to make debug DR faster.
-
diff --git a/lib/msandr/msandr.cc b/lib/msandr/msandr.cc
deleted file mode 100644
index 5159ddb..0000000
--- a/lib/msandr/msandr.cc
+++ /dev/null
@@ -1,900 +0,0 @@
-//===-- msandr.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 a part of MemorySanitizer.
-//
-// DynamoRio client for MemorySanitizer.
-//
-// MemorySanitizer requires that all program code is instrumented. Any memory
-// store that can turn an uninitialized value into an initialized value must be
-// observed by the tool, otherwise we risk reporting a false UMR.
-//
-// This also includes any libraries that the program depends on.
-//
-// In the case when rebuilding all program dependencies with MemorySanitizer is
-// problematic, an experimental MSanDR tool (the code you are currently looking
-// at) can be used. It is a DynamoRio-based tool that uses dynamic
-// instrumentation to
-// * Unpoison all memory stores.
-// * Unpoison TLS slots used by MemorySanitizer to pass function arguments and
-//   return value shadow on anything that looks like a function call or a return
-//   from a function.
-//
-// This tool does not detect the use of uninitialized values in uninstrumented
-// libraries. It merely gets rid of false positives by marking all data that
-// passes through uninstrumented code as fully initialized.
-//===----------------------------------------------------------------------===//
-
-#include <dr_api.h>
-#include <drutil.h>
-#include <drmgr.h>
-#include <drsyscall.h>
-
-#include <sys/mman.h>
-#include <sys/syscall.h>  /* for SYS_mmap */
-
-#include <string.h>
-
-// XXX: it seems setting macro in CMakeLists.txt does not work,
-// so manually set it here now.
-
-// Building msandr client for running in DynamoRIO hybrid mode,
-// which allows some module running natively.
-// TODO: turn it on by default when hybrid is stable enough
-// #define MSANDR_NATIVE_EXEC
-
-#ifndef MSANDR_NATIVE_EXEC
-#include <algorithm>
-#include <set>
-#include <string>
-#include <vector>
-#endif
-
-#define TESTALL(mask, var) (((mask) & (var)) == (mask))
-#define TESTANY(mask, var) (((mask) & (var)) != 0)
-
-#define CHECK_IMPL(condition, file, line)                                      \
-  do {                                                                         \
-    if (!(condition)) {                                                        \
-      dr_printf("Check failed: `%s`\nat %s:%d\n", #condition, file, line);     \
-      dr_abort();                                                              \
-    }                                                                          \
-  } while (0) // TODO: stacktrace
-
-#define CHECK(condition) CHECK_IMPL(condition, __FILE__, __LINE__)
-
-#define VERBOSITY 0
-
-// Building msandr client for standalone test that does not need to
-// run with msan build executables. Disable by default.
-// #define MSANDR_STANDALONE_TEST
-
-#define NUM_TLS_RETVAL 1
-#define NUM_TLS_PARAM  6
-
-#ifdef MSANDR_STANDALONE_TEST
-// For testing purpose, we map app to shadow memory at [0x100000, 0x20000).
-// Normally, the app starts at 0x400000:
-// 00400000-004e0000 r-xp 00000000 fc:00 524343       /bin/bash
-// so there should be no problem.
-# define SHADOW_MEMORY_BASE ((void *)0x100000)
-# define SHADOW_MEMORY_SIZE (0x100000)
-# define SHADOW_MEMORY_MASK (SHADOW_MEMORY_SIZE - 4 /* to avoid overflow */)
-#else
-// shadow memory range [0x200000000000, 0x400000000000)
-// assuming no app memory below 0x200000000000
-# define SHADOW_MEMORY_MASK 0x3fffffffffffULL
-#endif /* MSANDR_STANDALONE_TEST */
-
-typedef void *(*WrapperFn)(void *);
-extern "C" void __msan_set_indirect_call_wrapper(WrapperFn wrapper);
-extern "C" void __msan_dr_is_initialized();
-
-namespace {
-
-int msan_retval_tls_offset;
-int msan_param_tls_offset;
-
-#ifndef MSANDR_NATIVE_EXEC
-class ModuleData {
-public:
-  ModuleData();
-  ModuleData(const module_data_t *info);
-  // Yes, we want default copy, assign, and dtor semantics.
-
-public:
-  app_pc start_;
-  app_pc end_;
-  // Full path to the module.
-  std::string path_;
-  module_handle_t handle_;
-  bool should_instrument_;
-  bool executed_;
-};
-
-// A vector of loaded modules sorted by module bounds.  We lookup the current PC
-// in here from the bb event.  This is better than an rb tree because the lookup
-// is faster and the bb event occurs far more than the module load event.
-std::vector<ModuleData> g_module_list;
-
-ModuleData::ModuleData()
-    : start_(NULL), end_(NULL), path_(""), handle_(NULL),
-      should_instrument_(false), executed_(false) {
-}
-
-ModuleData::ModuleData(const module_data_t *info)
-    : start_(info->start), end_(info->end), path_(info->full_path),
-      handle_(info->handle),
-      // We'll check the black/white lists later and adjust this.
-      should_instrument_(true), executed_(false) {
-}
-#endif /* !MSANDR_NATIVE_EXEC */
-
-int(*__msan_get_retval_tls_offset)();
-int(*__msan_get_param_tls_offset)();
-void (*__msan_unpoison)(void *base, size_t size);
-bool (*__msan_is_in_loader)();
-
-#ifdef MSANDR_STANDALONE_TEST
-uint mock_msan_retval_tls_offset;
-uint mock_msan_param_tls_offset;
-static int mock_msan_get_retval_tls_offset() {
-  return (int)mock_msan_retval_tls_offset;
-}
-
-static int mock_msan_get_param_tls_offset() {
-  return (int)mock_msan_param_tls_offset;
-}
-
-static void mock_msan_unpoison(void *base, size_t size) {
-  /* do nothing */
-}
-
-static bool mock_msan_is_in_loader() {
-  return false;
-}
-#endif /* MSANDR_STANDALONE_TEST */
-
-static generic_func_t LookupCallback(module_data_t *app, const char *name) {
-#ifdef MSANDR_STANDALONE_TEST
-  if (strcmp("__msan_get_retval_tls_offset", name) == 0) {
-    return (generic_func_t)mock_msan_get_retval_tls_offset;
-  } else if (strcmp("__msan_get_param_tls_offset", name) == 0) {
-    return (generic_func_t)mock_msan_get_param_tls_offset;
-  } else if (strcmp("__msan_unpoison", name) == 0) {
-    return (generic_func_t)mock_msan_unpoison;
-  } else if (strcmp("__msan_is_in_loader", name) == 0) {
-    return (generic_func_t)mock_msan_is_in_loader;
-  }
-  CHECK(false);
-  return NULL;
-#else /* !MSANDR_STANDALONE_TEST */
-  generic_func_t callback = dr_get_proc_address(app->handle, name);
-  if (callback == NULL) {
-    dr_printf("Couldn't find `%s` in %s\n", name, app->full_path);
-    CHECK(callback);
-  }
-  return callback;
-#endif /* !MSANDR_STANDALONE_TEST */
-}
-
-void InitializeMSanCallbacks() {
-  module_data_t *app = dr_lookup_module_by_name(dr_get_application_name());
-  if (!app) {
-    dr_printf("%s - oops, dr_lookup_module_by_name failed!\n",
-              dr_get_application_name());
-    CHECK(app);
-  }
-
-  __msan_get_retval_tls_offset = (int (*)())
-      LookupCallback(app, "__msan_get_retval_tls_offset");
-  __msan_get_param_tls_offset = (int (*)())
-      LookupCallback(app, "__msan_get_param_tls_offset");
-  __msan_unpoison = (void(*)(void *, size_t))
-      LookupCallback(app, "__msan_unpoison");
-  __msan_is_in_loader = (bool (*)())
-      LookupCallback(app, "__msan_is_in_loader");
-
-  dr_free_module_data(app);
-}
-
-// FIXME: Handle absolute addresses and PC-relative addresses.
-// FIXME: Handle TLS accesses via FS or GS.  DR assumes all other segments have
-// a zero base anyway.
-bool OperandIsInteresting(opnd_t opnd) {
-  return (opnd_is_base_disp(opnd) && opnd_get_segment(opnd) != DR_SEG_FS &&
-          opnd_get_segment(opnd) != DR_SEG_GS);
-}
-
-bool WantToInstrument(instr_t *instr) {
-  // TODO: skip push instructions?
-  switch (instr_get_opcode(instr)) {
-    // FIXME: support the instructions excluded below:
-  case OP_rep_cmps:
-    // f3 a6    rep cmps %ds:(%rsi) %es:(%rdi) %rsi %rdi %rcx -> %rsi %rdi %rcx
-    return false;
-  }
-
-  // Labels appear due to drutil_expand_rep_string()
-  if (instr_is_label(instr))
-    return false;
-
-  CHECK(instr_ok_to_mangle(instr) == true);
-
-  if (instr_writes_memory(instr)) {
-    for (int d = 0; d < instr_num_dsts(instr); d++) {
-      opnd_t op = instr_get_dst(instr, d);
-      if (OperandIsInteresting(op))
-        return true;
-    }
-  }
-
-  return false;
-}
-
-#define PRE(at, what) instrlist_meta_preinsert(bb, at, INSTR_CREATE_##what);
-#define PREF(at, what) instrlist_meta_preinsert(bb, at, what);
-
-void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
-                    bool is_write) {
-  bool need_to_restore_eflags = false;
-  uint flags = instr_get_arith_flags(instr);
-  // TODO: do something smarter with flags and spills in general?
-  // For example, spill them only once for a sequence of instrumented
-  // instructions that don't change/read flags.
-
-  if (!TESTALL(EFLAGS_WRITE_6, flags) || TESTANY(EFLAGS_READ_6, flags)) {
-    if (VERBOSITY > 1)
-      dr_printf("Spilling eflags...\n");
-    need_to_restore_eflags = true;
-    // TODO: Maybe sometimes don't need to 'seto'.
-    // TODO: Maybe sometimes don't want to spill XAX here?
-    // TODO: No need to spill XAX here if XAX is not used in the BB.
-    dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-    dr_save_arith_flags_to_xax(drcontext, bb, instr);
-    dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3);
-    dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-  }
-
-#if 0
-  dr_printf("==DRMSAN== DEBUG: %d %d %d %d %d %d\n",
-            opnd_is_memory_reference(op), opnd_is_base_disp(op),
-            opnd_is_base_disp(op) ? opnd_get_index(op) : -1,
-            opnd_is_far_memory_reference(op), opnd_is_reg_pointer_sized(op),
-            opnd_is_base_disp(op) ? opnd_get_disp(op) : -1);
-#endif
-
-  reg_id_t R1;
-  bool address_in_R1 = false;
-  if (opnd_is_base_disp(op) && opnd_get_index(op) == DR_REG_NULL &&
-      opnd_get_disp(op) == 0) {
-    // If this is a simple access with no offset or index, we can just use the
-    // base for R1.
-    address_in_R1 = true;
-    R1 = opnd_get_base(op);
-  } else {
-    // Otherwise, we need to compute the addr into R1.
-    // TODO: reuse some spare register? e.g. r15 on x64
-    // TODO: might be used as a non-mem-ref register?
-    R1 = DR_REG_XAX;
-  }
-  CHECK(reg_is_pointer_sized(R1)); // otherwise R2 may be wrong.
-
-  // Pick R2 from R8 to R15.
-  // It's OK if the instr uses R2 elsewhere, since we'll restore it before instr.
-  reg_id_t R2;
-  for (R2 = DR_REG_R8; R2 <= DR_REG_R15; R2++) {
-    if (!opnd_uses_reg(op, R2))
-      break;
-  }
-  CHECK((R2 <= DR_REG_R15) && R1 != R2);
-
-  // Save the current values of R1 and R2.
-  dr_save_reg(drcontext, bb, instr, R1, SPILL_SLOT_1);
-  // TODO: Something smarter than spilling a "fixed" register R2?
-  dr_save_reg(drcontext, bb, instr, R2, SPILL_SLOT_2);
-
-  if (!address_in_R1)
-    CHECK(drutil_insert_get_mem_addr(drcontext, bb, instr, op, R1, R2));
-  PRE(instr, mov_imm(drcontext, opnd_create_reg(R2),
-                     OPND_CREATE_INT64(SHADOW_MEMORY_MASK)));
-  PRE(instr, and(drcontext, opnd_create_reg(R1), opnd_create_reg(R2)));
-#ifdef MSANDR_STANDALONE_TEST
-  PRE(instr, add(drcontext, opnd_create_reg(R1),
-                 OPND_CREATE_INT32(SHADOW_MEMORY_BASE)));
-#endif
-  // There is no mov_st of a 64-bit immediate, so...
-  opnd_size_t op_size = opnd_get_size(op);
-  CHECK(op_size != OPSZ_NA);
-  uint access_size = opnd_size_in_bytes(op_size);
-  if (access_size <= 4 || op_size == OPSZ_PTR /* x64 support sign extension */) {
-    instr_t *label = INSTR_CREATE_label(drcontext);
-    opnd_t   immed;
-    if (op_size == OPSZ_PTR || op_size == OPSZ_4)
-        immed = OPND_CREATE_INT32(0);
-    else
-        immed = opnd_create_immed_int((ptr_int_t) 0, op_size);
-    // we check if target is 0 before write to reduce unnecessary memory stores.
-    PRE(instr, cmp(drcontext,
-                   opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
-                   immed));
-    PRE(instr, jcc(drcontext, OP_je, opnd_create_instr(label)));
-    PRE(instr, mov_st(drcontext,
-                      opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
-                      immed));
-    PREF(instr, label);
-  } else {
-    // FIXME: tail?
-    for (uint ofs = 0; ofs < access_size; ofs += 4) {
-      instr_t *label = INSTR_CREATE_label(drcontext);
-      opnd_t   immed = OPND_CREATE_INT32(0);
-      PRE(instr, cmp(drcontext, OPND_CREATE_MEM32(R1, ofs), immed));
-      PRE(instr, jcc(drcontext, OP_je, opnd_create_instr(label)));
-      PRE(instr, mov_st(drcontext, OPND_CREATE_MEM32(R1, ofs), immed));
-      PREF(instr, label)
-    }
-  }
-
-  // Restore the registers and flags.
-  dr_restore_reg(drcontext, bb, instr, R1, SPILL_SLOT_1);
-  dr_restore_reg(drcontext, bb, instr, R2, SPILL_SLOT_2);
-
-  // TODO: move aflags save/restore to per instr instead of per opnd
-  if (need_to_restore_eflags) {
-    if (VERBOSITY > 1)
-      dr_printf("Restoring eflags\n");
-    // TODO: Check if it's reverse to the dr_restore_reg above and optimize.
-    dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-    dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_3);
-    dr_restore_arith_flags_from_xax(drcontext, bb, instr);
-    dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-  }
-
-  // The original instruction is left untouched. The above instrumentation is just
-  // a prefix.
-}
-
-void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) {
-#ifdef MSANDR_STANDALONE_TEST
-  PRE(instr,
-      mov_st(drcontext,
-             opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
-                                       DR_REG_NULL, DR_REG_NULL,
-                                       0, msan_retval_tls_offset,
-                                       OPSZ_PTR),
-             OPND_CREATE_INT32(0)));
-#else  /* !MSANDR_STANDALONE_TEST */
-# ifdef MSANDR_NATIVE_EXEC
-  /* For optimized native exec, -mangle_app_seg and -private_loader are turned off,
-   * so we can reference msan_retval_tls_offset directly.
-   */
-  PRE(instr,
-      mov_st(drcontext,
-             opnd_create_far_base_disp(DR_SEG_FS, DR_REG_NULL, DR_REG_NULL, 0,
-                                       msan_retval_tls_offset, OPSZ_PTR),
-             OPND_CREATE_INT32(0)));
-# else /* !MSANDR_NATIVE_EXEC */
-  /* XXX: the code below only works if -mangle_app_seg and -private_loader, 
-   * which is turned off for optimized native exec
-   */
-  dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
-  // Clobbers nothing except xax.
-  bool res =
-      dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX);
-  CHECK(res);
-
-  // TODO: unpoison more bytes?
-  PRE(instr,
-      mov_st(drcontext, OPND_CREATE_MEM64(DR_REG_XAX, msan_retval_tls_offset),
-             OPND_CREATE_INT32(0)));
-
-  dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-# endif /* !MSANDR_NATIVE_EXEC */
-  // The original instruction is left untouched. The above instrumentation is just
-  // a prefix.
-#endif  /* !MSANDR_STANDALONE_TEST */
-}
-
-void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
-                              instr_t *instr) {
-#ifdef MSANDR_STANDALONE_TEST
-  for (int i = 0; i < NUM_TLS_PARAM; ++i) {
-      PRE(instr,
-          mov_st(drcontext,
-                 opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
-                                           DR_REG_NULL, DR_REG_NULL,
-                                           0,
-                                           msan_param_tls_offset +
-                                           i * sizeof(void *),
-                                           OPSZ_PTR),
-                 OPND_CREATE_INT32(0)));
-  }
-#else  /* !MSANDR_STANDALONE_TEST */
-# ifdef MSANDR_NATIVE_EXEC
-  for (int i = 0; i < NUM_TLS_PARAM; ++i) {
-    PRE(instr,
-        mov_st(drcontext,
-               opnd_create_far_base_disp(DR_SEG_FS, DR_REG_NULL, DR_REG_NULL, 0,
-                                         msan_param_tls_offset + i*sizeof(void*),
-                                         OPSZ_PTR),
-               OPND_CREATE_INT32(0)));
-  }
-# else /* !MSANDR_NATIVE_EXEC */
-  /* XXX: the code below only works if -mangle_app_seg and -private_loader, 
-   * which is turned off for optimized native exec
-   */
-  dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-
-  // Clobbers nothing except xax.
-  bool res =
-      dr_insert_get_seg_base(drcontext, bb, instr, DR_SEG_FS, DR_REG_XAX);
-  CHECK(res);
-
-  // TODO: unpoison more bytes?
-  for (int i = 0; i < NUM_TLS_PARAM; ++i) {
-    PRE(instr,
-        mov_st(drcontext, OPND_CREATE_MEMPTR(DR_REG_XAX, msan_param_tls_offset +
-                                                         i * sizeof(void *)),
-               OPND_CREATE_INT32(0)));
-  }
-
-  dr_restore_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
-# endif /* !MSANDR_NATIVE_EXEC */
-  // The original instruction is left untouched. The above instrumentation is just
-  // a prefix.
-#endif  /* !MSANDR_STANDALONE_TEST */
-}
-
-#ifndef MSANDR_NATIVE_EXEC
-// For use with binary search.  Modules shouldn't overlap, so we shouldn't have
-// to look at end_.  If that can happen, we won't support such an application.
-bool ModuleDataCompareStart(const ModuleData &left, const ModuleData &right) {
-  return left.start_ < right.start_;
-}
-
-// Look up the module containing PC.  Should be relatively fast, as its called
-// for each bb instrumentation.
-ModuleData *LookupModuleByPC(app_pc pc) {
-  ModuleData fake_mod_data;
-  fake_mod_data.start_ = pc;
-  std::vector<ModuleData>::iterator it =
-      lower_bound(g_module_list.begin(), g_module_list.end(), fake_mod_data,
-                  ModuleDataCompareStart);
-  // if (it == g_module_list.end())
-  //   return NULL;
-  if (it == g_module_list.end() || pc < it->start_)
-    --it;
-  CHECK(it->start_ <= pc);
-  if (pc >= it->end_) {
-    // We're past the end of this module.  We shouldn't be in the next module,
-    // or lower_bound lied to us.
-    ++it;
-    CHECK(it == g_module_list.end() || pc < it->start_);
-    return NULL;
-  }
-
-  // OK, we found the module.
-  return &*it;
-}
-
-bool ShouldInstrumentNonModuleCode() { return true; }
-
-bool ShouldInstrumentModule(ModuleData *mod_data) {
-  // TODO(rnk): Flags for blacklist would get wired in here.
-  generic_func_t p =
-      dr_get_proc_address(mod_data->handle_, "__msan_track_origins");
-  return !p;
-}
-
-bool ShouldInstrumentPc(app_pc pc, ModuleData **pmod_data) {
-  ModuleData *mod_data = LookupModuleByPC(pc);
-  if (pmod_data)
-    *pmod_data = mod_data;
-  if (mod_data != NULL) {
-    // This module is on a blacklist.
-    if (!mod_data->should_instrument_) {
-      return false;
-    }
-  } else if (!ShouldInstrumentNonModuleCode()) {
-    return false;
-  }
-  return true;
-}
-#endif /* !MSANDR_NATIVE_CLIENT */
-
-// TODO(rnk): Make sure we instrument after __msan_init.
-dr_emit_flags_t
-event_basic_block_app2app(void *drcontext, void *tag, instrlist_t *bb,
-                          bool for_trace, bool translating) {
-#ifndef MSANDR_NATIVE_EXEC
-  app_pc pc = dr_fragment_app_pc(tag);
-  if (ShouldInstrumentPc(pc, NULL))
-    CHECK(drutil_expand_rep_string(drcontext, bb));
-#else  /* MSANDR_NATIVE_EXEC */
-  CHECK(drutil_expand_rep_string(drcontext, bb));
-#endif /* MSANDR_NATIVE_EXEC */
-  return DR_EMIT_PERSISTABLE;
-}
-
-dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
-                                  bool for_trace, bool translating) {
-  app_pc pc = dr_fragment_app_pc(tag);
-#ifndef MSANDR_NATIVE_EXEC
-  ModuleData *mod_data;
-
-  if (!ShouldInstrumentPc(pc, &mod_data))
-    return DR_EMIT_PERSISTABLE;
-
-  if (VERBOSITY > 1)
-    dr_printf("============================================================\n");
-  if (VERBOSITY > 0) {
-    std::string mod_path = (mod_data ? mod_data->path_ : "<no module, JITed?>");
-    if (mod_data && !mod_data->executed_) {
-      mod_data->executed_ = true; // Nevermind this race.
-      dr_printf("Executing from new module: %s\n", mod_path.c_str());
-    }
-    dr_printf("BB to be instrumented: %p [from %s]; translating = %s\n", pc,
-        mod_path.c_str(), translating ? "true" : "false");
-    if (mod_data) {
-      // Match standard sanitizer trace format for free symbols.
-      // #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
-      dr_printf(" #0 %p (%s+%p)\n", pc, mod_data->path_.c_str(),
-          pc - mod_data->start_);
-    }
-  }
-#endif /* !MSANDR_NATIVE_EXEC */
-
-  if (VERBOSITY > 1) {
-    instrlist_disassemble(drcontext, pc, bb, STDOUT);
-    instr_t *instr;
-    for (instr = instrlist_first(bb); instr; instr = instr_get_next(instr)) {
-      dr_printf("opcode: %d\n", instr_get_opcode(instr));
-    }
-  }
-
-  for (instr_t *i = instrlist_first(bb); i != NULL; i = instr_get_next(i)) {
-    int opcode = instr_get_opcode(i);
-    if (opcode == OP_ret || opcode == OP_ret_far) {
-      InstrumentReturn(drcontext, bb, i);
-      continue;
-    }
-
-    // These instructions hopefully cover all cases where control is transferred
-    // to a function in a different module (we only care about calls into
-    // compiler-instrumented modules).
-    // * call_ind is used for normal indirect calls.
-    // * jmp_ind is used for indirect tail calls, and calls through PLT (PLT
-    //   stub includes a jump to an address from GOT).
-    if (opcode == OP_call_ind || opcode == OP_call_far_ind ||
-        opcode == OP_jmp_ind || opcode == OP_jmp_far_ind) {
-      InstrumentIndirectBranch(drcontext, bb, i);
-      continue;
-    }
-
-    if (!WantToInstrument(i))
-      continue;
-
-    if (VERBOSITY > 1) {
-      app_pc orig_pc = dr_fragment_app_pc(tag);
-      uint flags = instr_get_arith_flags(i);
-      dr_printf("+%d -> to be instrumented! [opcode=%d, flags = 0x%08X]\n",
-          instr_get_app_pc(i) - orig_pc, instr_get_opcode(i), flags);
-    }
-
-    if (instr_writes_memory(i)) {
-      // Instrument memory writes
-      // bool instrumented_anything = false;
-      for (int d = 0; d < instr_num_dsts(i); d++) {
-        opnd_t op = instr_get_dst(i, d);
-        if (!OperandIsInteresting(op))
-          continue;
-
-        // CHECK(!instrumented_anything);
-        // instrumented_anything = true;
-        InstrumentMops(drcontext, bb, i, op, true);
-        break; // only instrumenting the first dst
-      }
-    }
-  }
-
-// TODO: optimize away redundant restore-spill pairs?
-
-  if (VERBOSITY > 1) {
-    pc = dr_fragment_app_pc(tag);
-    dr_printf("\nFinished instrumenting dynamorio_basic_block(PC=" PFX ")\n", pc);
-    instrlist_disassemble(drcontext, pc, bb, STDOUT);
-  }
-  return DR_EMIT_PERSISTABLE;
-}
-
-#ifndef MSANDR_NATIVE_EXEC
-void event_module_load(void *drcontext, const module_data_t *info,
-                       bool loaded) {
-  // Insert the module into the list while maintaining the ordering.
-  ModuleData mod_data(info);
-  std::vector<ModuleData>::iterator it =
-      upper_bound(g_module_list.begin(), g_module_list.end(), mod_data,
-                  ModuleDataCompareStart);
-  it = g_module_list.insert(it, mod_data);
-  // Check if we should instrument this module.
-  it->should_instrument_ = ShouldInstrumentModule(&*it);
-  dr_module_set_should_instrument(info->handle, it->should_instrument_);
-
-  if (VERBOSITY > 0)
-    dr_printf("==DRMSAN== Loaded module: %s [%p...%p], instrumentation is %s\n",
-        info->full_path, info->start, info->end,
-        it->should_instrument_ ? "on" : "off");
-}
-
-void event_module_unload(void *drcontext, const module_data_t *info) {
-  if (VERBOSITY > 0)
-    dr_printf("==DRMSAN== Unloaded module: %s [%p...%p]\n", info->full_path,
-        info->start, info->end);
-
-  // Remove the module from the list.
-  ModuleData mod_data(info);
-  std::vector<ModuleData>::iterator it =
-      lower_bound(g_module_list.begin(), g_module_list.end(), mod_data,
-                  ModuleDataCompareStart);
-  // It's a bug if we didn't actually find the module.
-  CHECK(it != g_module_list.end() && it->start_ == mod_data.start_ &&
-        it->end_ == mod_data.end_ && it->path_ == mod_data.path_);
-  g_module_list.erase(it);
-}
-#endif /* !MSANDR_NATIVE_EXEC */
-
-void event_exit() {
-  // Clean up so DR doesn't tell us we're leaking memory.
-  drsys_exit();
-  drutil_exit();
-  drmgr_exit();
-
-#ifdef MSANDR_STANDALONE_TEST
-  /* free tls */
-  bool res;
-  res = dr_raw_tls_cfree(msan_retval_tls_offset, NUM_TLS_RETVAL);
-  CHECK(res);
-  res = dr_raw_tls_cfree(msan_param_tls_offset, NUM_TLS_PARAM);
-  CHECK(res);
-  /* we do not bother to free the shadow memory */
-#endif /* !MSANDR_STANDALONE_TEST */
-  if (VERBOSITY > 0)
-    dr_printf("==DRMSAN== DONE\n");
-}
-
-bool event_filter_syscall(void *drcontext, int sysnum) {
-  // FIXME: only intercept syscalls with memory effects.
-  return true; /* intercept everything */
-}
-
-bool drsys_iter_memarg_cb(drsys_arg_t *arg, void *user_data) {
-  CHECK(arg->valid);
-
-  if (arg->pre)
-    return true;
-  if (!TESTANY(DRSYS_PARAM_OUT, arg->mode))
-    return true;
-
-  size_t sz = arg->size;
-
-  if (sz > 0xFFFFFFFF) {
-    drmf_status_t res;
-    drsys_syscall_t *syscall = (drsys_syscall_t *)user_data;
-    const char *name;
-    res = drsys_syscall_name(syscall, &name);
-    CHECK(res == DRMF_SUCCESS);
-
-    dr_printf("SANITY: syscall '%s' arg %d writes %llu bytes memory?!"
-              " Clipping to %llu.\n",
-              name, arg->ordinal, (unsigned long long) sz,
-              (unsigned long long)(sz & 0xFFFFFFFF));
-  }
-
-  if (VERBOSITY > 0) {
-    drmf_status_t res;
-    drsys_syscall_t *syscall = (drsys_syscall_t *)user_data;
-    const char *name;
-    res = drsys_syscall_name(syscall, &name);
-    CHECK(res == DRMF_SUCCESS);
-    dr_printf("drsyscall: syscall '%s' arg %d wrote range [%p, %p)\n",
-              name, arg->ordinal, arg->start_addr,
-              (char *)arg->start_addr + sz);
-  }
-
-  // We don't switch to the app context because __msan_unpoison() doesn't need
-  // TLS segments.
-  __msan_unpoison(arg->start_addr, sz);
-
-  return true; /* keep going */
-}
-
-bool event_pre_syscall(void *drcontext, int sysnum) {
-  drsys_syscall_t *syscall;
-  drsys_sysnum_t sysnum_full;
-  bool known;
-  drsys_param_type_t ret_type;
-  drmf_status_t res;
-  const char *name;
-
-  res = drsys_cur_syscall(drcontext, &syscall);
-  CHECK(res == DRMF_SUCCESS);
-
-  res = drsys_syscall_number(syscall, &sysnum_full);
-  CHECK(res == DRMF_SUCCESS);
-  CHECK(sysnum == sysnum_full.number);
-
-  res = drsys_syscall_is_known(syscall, &known);
-  CHECK(res == DRMF_SUCCESS);
-
-  res = drsys_syscall_name(syscall, &name);
-  CHECK(res == DRMF_SUCCESS);
-
-  res = drsys_syscall_return_type(syscall, &ret_type);
-  CHECK(res == DRMF_SUCCESS);
-  CHECK(ret_type != DRSYS_TYPE_INVALID);
-  CHECK(!known || ret_type != DRSYS_TYPE_UNKNOWN);
-
-  res = drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, NULL);
-  CHECK(res == DRMF_SUCCESS);
-
-  return true;
-}
-
-static bool IsInLoader(void *drcontext) {
-  // TODO: This segment swap is inefficient.  DR should just let us query the
-  // app segment base, which it has.  Alternatively, if we disable
-  // -mangle_app_seg, then we won't need the swap.
-  bool need_swap = !dr_using_app_state(drcontext);
-  if (need_swap)
-    dr_switch_to_app_state(drcontext);
-  bool is_in_loader = __msan_is_in_loader();
-  if (need_swap)
-    dr_switch_to_dr_state(drcontext);
-  return is_in_loader;
-}
-
-void event_post_syscall(void *drcontext, int sysnum) {
-  drsys_syscall_t *syscall;
-  drsys_sysnum_t sysnum_full;
-  bool success = false;
-  drmf_status_t res;
-
-  res = drsys_cur_syscall(drcontext, &syscall);
-  CHECK(res == DRMF_SUCCESS);
-
-  res = drsys_syscall_number(syscall, &sysnum_full);
-  CHECK(res == DRMF_SUCCESS);
-  CHECK(sysnum == sysnum_full.number);
-
-  res = drsys_syscall_succeeded(syscall, dr_syscall_get_result(drcontext),
-                                &success);
-  CHECK(res == DRMF_SUCCESS);
-
-  if (success) {
-    res =
-        drsys_iterate_memargs(drcontext, drsys_iter_memarg_cb, (void *)syscall);
-    CHECK(res == DRMF_SUCCESS);
-  }
-
-  // Our normal mmap interceptor can't intercept calls from the loader itself.
-  // This means we don't clear the shadow for calls to dlopen.  For now, we
-  // solve this by intercepting mmap from ld.so here, but ideally we'd have a
-  // solution that doesn't rely on msandr.
-  //
-  // Be careful not to intercept maps done by the msan rtl.  Otherwise we end up
-  // unpoisoning vast regions of memory and OOMing.
-  // TODO: __msan_unpoison() could "flush" large regions of memory like tsan
-  // does instead of doing a large memset.  However, we need the memory to be
-  // zeroed, where as tsan does not, so plain madvise is not enough.
-  if (success && (sysnum == SYS_mmap IF_NOT_X64(|| sysnum == SYS_mmap2))) {
-    if (IsInLoader(drcontext)) {
-      app_pc base = (app_pc)dr_syscall_get_result(drcontext);
-      ptr_uint_t size;
-      drmf_status_t res = drsys_pre_syscall_arg(drcontext, 1, &size);
-      CHECK(res == DRMF_SUCCESS);
-      if (VERBOSITY > 0)
-        dr_printf("unpoisoning for dlopen: [%p-%p]\n", base, base + size);
-      // We don't switch to the app context because __msan_unpoison() doesn't
-      // need TLS segments.
-      __msan_unpoison(base, size);
-    }
-  }
-}
-
-} // namespace
-
-DR_EXPORT void dr_init(client_id_t id) {
-  drmf_status_t res;
-
-  drmgr_init();
-  drutil_init();
-
-#ifndef MSANDR_NATIVE_EXEC
-  // We should use drconfig to ignore these applications.
-  std::string app_name = dr_get_application_name();
-  // This blacklist will still run these apps through DR's code cache.  On the
-  // other hand, we are able to follow children of these apps.
-  // FIXME: Once DR has detach, we could just detach here.  Alternatively,
-  // if DR had a fork or exec hook to let us decide there, that would be nice.
-  // FIXME: make the blacklist cmd-adjustable.
-  if (app_name == "python" || app_name == "python2.7" || app_name == "bash" ||
-      app_name == "sh" || app_name == "true" || app_name == "exit" ||
-      app_name == "yes" || app_name == "echo")
-    return;
-#endif /* !MSANDR_NATIVE_EXEC */
-
-  drsys_options_t ops;
-  memset(&ops, 0, sizeof(ops));
-  ops.struct_size = sizeof(ops);
-  ops.analyze_unknown_syscalls = false;
-
-  res = drsys_init(id, &ops);
-  CHECK(res == DRMF_SUCCESS);
-
-  dr_register_filter_syscall_event(event_filter_syscall);
-  drmgr_register_pre_syscall_event(event_pre_syscall);
-  drmgr_register_post_syscall_event(event_post_syscall);
-  res = drsys_filter_all_syscalls();
-  CHECK(res == DRMF_SUCCESS);
-
-#ifdef MSANDR_STANDALONE_TEST
-  reg_id_t reg_seg;
-  /* alloc tls */
-  if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_retval_tls_offset, NUM_TLS_RETVAL, 0))
-      CHECK(false);
-  CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
-  if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_param_tls_offset, NUM_TLS_PARAM, 0))
-      CHECK(false);
-  CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
-  /* alloc shadow memory */
-  if (mmap(SHADOW_MEMORY_BASE, SHADOW_MEMORY_SIZE, PROT_READ|PROT_WRITE,
-           MAP_PRIVATE | MAP_ANON, -1, 0) != SHADOW_MEMORY_BASE) {
-      CHECK(false);
-  }
-#endif /* MSANDR_STANDALONE_TEST */
-  InitializeMSanCallbacks();
-
-  // FIXME: the shadow is initialized earlier when DR calls one of our wrapper
-  // functions. This may change one day.
-  // TODO: make this more robust.
-
-  void *drcontext = dr_get_current_drcontext();
-
-  dr_switch_to_app_state(drcontext);
-  msan_retval_tls_offset = __msan_get_retval_tls_offset();
-  msan_param_tls_offset = __msan_get_param_tls_offset();
-  dr_switch_to_dr_state(drcontext);
-  if (VERBOSITY > 0) {
-    dr_printf("__msan_retval_tls offset: %d\n", msan_retval_tls_offset);
-    dr_printf("__msan_param_tls offset: %d\n", msan_param_tls_offset);
-  }
-
-  // Standard DR events.
-  dr_register_exit_event(event_exit);
-
-  drmgr_priority_t priority = {
-    sizeof(priority), /* size of struct */
-    "msandr",         /* name of our operation */
-    NULL,             /* optional name of operation we should precede */
-    NULL,             /* optional name of operation we should follow */
-    0
-  };                  /* numeric priority */
-
-  drmgr_register_bb_app2app_event(event_basic_block_app2app, &priority);
-  drmgr_register_bb_instru2instru_event(event_basic_block, &priority);
-#ifndef MSANDR_NATIVE_EXEC
-  drmgr_register_module_load_event(event_module_load);
-  drmgr_register_module_unload_event(event_module_unload);
-#endif /* MSANDR_NATIVE_EXEC */
-  __msan_dr_is_initialized();
-  __msan_set_indirect_call_wrapper(dr_app_handle_mbr_target);
-  if (VERBOSITY > 0)
-    dr_printf("==MSANDR== Starting!\n");
-}
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index ea4712d..420d766 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -17,13 +17,9 @@
 else()
   foreach(arch ${PROFILE_SUPPORTED_ARCH})
     add_compiler_rt_runtime(clang_rt.profile-${arch} ${arch} STATIC
-      SOURCES ${PROFILE_SOURCES})
-    add_dependencies(profile clang_rt.profile-${arch})
-
-    add_compiler_rt_runtime(clang_rt.profile-pic-${arch} ${arch} STATIC
       CFLAGS -fPIC
       SOURCES ${PROFILE_SOURCES})
-    add_dependencies(profile clang_rt.profile-pic-${arch})
+    add_dependencies(profile clang_rt.profile-${arch})
   endforeach()
 endif()
 
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 5cd22c7..45fbd07 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -389,13 +389,17 @@
   if (val != (uint32_t)-1) {
     /* There are counters present in the file. Merge them. */
     if (val != 0x01a10000) {
-      fprintf(stderr, "profiling:invalid arc tag (0x%08x)\n", val);
+      fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+                      "corrupt arc tag (0x%08x)\n",
+              filename, val);
       return;
     }
 
     val = read_32bit_value();
     if (val == (uint32_t)-1 || val / 2 != num_counters) {
-      fprintf(stderr, "profiling:invalid number of counters (%d)\n", val);
+      fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: "
+                      "mismatched number of counters (%d)\n",
+              filename, val);
       return;
     }
 
@@ -437,13 +441,17 @@
   if (val != (uint32_t)-1) {
     /* There are counters present in the file. Merge them. */
     if (val != 0xa1000000) {
-      fprintf(stderr, "profiling:invalid object tag (0x%08x)\n", val);
+      fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+                      "corrupt object tag (0x%08x)\n",
+              filename, val);
       return;
     }
 
     val = read_32bit_value(); /* length */
     if (val != obj_summary_len) {
-      fprintf(stderr, "profiling:invalid object length (%d)\n", val);
+      fprintf(stderr, "profiling: %s: cannot merge previous run count: "
+                      "mismatched object length (%d)\n",
+              filename, val);
       return;
     }
 
diff --git a/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c
index aeb3681..8d010df 100644
--- a/lib/profile/InstrProfiling.c
+++ b/lib/profile/InstrProfiling.c
@@ -41,8 +41,8 @@
 
 __attribute__((visibility("hidden")))
 void __llvm_profile_reset_counters(void) {
-  uint64_t *I = __llvm_profile_counters_begin();
-  uint64_t *E = __llvm_profile_counters_end();
+  uint64_t *I = __llvm_profile_begin_counters();
+  uint64_t *E = __llvm_profile_end_counters();
 
   memset(I, 0, sizeof(uint64_t)*(E - I));
 }
diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h
index c5dd641..a086f3d 100644
--- a/lib/profile/InstrProfiling.h
+++ b/lib/profile/InstrProfiling.h
@@ -50,15 +50,15 @@
  */
 int __llvm_profile_write_buffer(char *Buffer);
 
-const __llvm_profile_data *__llvm_profile_data_begin(void);
-const __llvm_profile_data *__llvm_profile_data_end(void);
-const char *__llvm_profile_names_begin(void);
-const char *__llvm_profile_names_end(void);
-uint64_t *__llvm_profile_counters_begin(void);
-uint64_t *__llvm_profile_counters_end(void);
+const __llvm_profile_data *__llvm_profile_begin_data(void);
+const __llvm_profile_data *__llvm_profile_end_data(void);
+const char *__llvm_profile_begin_names(void);
+const char *__llvm_profile_end_names(void);
+uint64_t *__llvm_profile_begin_counters(void);
+uint64_t *__llvm_profile_end_counters(void);
 
 #define PROFILE_RANGE_SIZE(Range) \
-  (__llvm_profile_ ## Range ## _end() - __llvm_profile_ ## Range ## _begin())
+  (__llvm_profile_end_ ## Range () - __llvm_profile_begin_ ## Range ())
 
 /*!
  * \brief Write instrumentation data to the current file.
diff --git a/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c
index b53d4f7..3351b07 100644
--- a/lib/profile/InstrProfilingBuffer.c
+++ b/lib/profile/InstrProfilingBuffer.c
@@ -26,12 +26,12 @@
   /* Match logic in __llvm_profile_get_size_for_buffer().
    * Match logic in __llvm_profile_write_file().
    */
-  const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
-  const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
-  const uint64_t *CountersBegin = __llvm_profile_counters_begin();
-  const uint64_t *CountersEnd   = __llvm_profile_counters_end();
-  const char *NamesBegin = __llvm_profile_names_begin();
-  const char *NamesEnd   = __llvm_profile_names_end();
+  const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+  const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+  const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+  const uint64_t *CountersEnd   = __llvm_profile_end_counters();
+  const char *NamesBegin = __llvm_profile_begin_names();
+  const char *NamesEnd   = __llvm_profile_end_names();
 
   /* Calculate size of sections. */
   const uint64_t DataSize = DataEnd - DataBegin;
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index 5fb78e3..5aef390 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -16,12 +16,12 @@
 
 static int writeFile(FILE *File) {
   /* Match logic in __llvm_profile_write_buffer(). */
-  const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
-  const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
-  const uint64_t *CountersBegin = __llvm_profile_counters_begin();
-  const uint64_t *CountersEnd   = __llvm_profile_counters_end();
-  const char *NamesBegin = __llvm_profile_names_begin();
-  const char *NamesEnd   = __llvm_profile_names_end();
+  const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+  const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+  const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+  const uint64_t *CountersEnd   = __llvm_profile_end_counters();
+  const char *NamesBegin = __llvm_profile_begin_names();
+  const char *NamesEnd   = __llvm_profile_end_names();
 
   /* Calculate size of sections. */
   const uint64_t DataSize = DataEnd - DataBegin;
diff --git a/lib/profile/InstrProfilingPlatformDarwin.c b/lib/profile/InstrProfilingPlatformDarwin.c
index 7401977..02299cc 100644
--- a/lib/profile/InstrProfilingPlatformDarwin.c
+++ b/lib/profile/InstrProfilingPlatformDarwin.c
@@ -25,19 +25,19 @@
 extern uint64_t CountersEnd   __asm("section$end$__DATA$__llvm_prf_cnts");
 
 __attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_data_begin(void) {
+const __llvm_profile_data *__llvm_profile_begin_data(void) {
   return &DataStart;
 }
 __attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_data_end(void) {
+const __llvm_profile_data *__llvm_profile_end_data(void) {
   return &DataEnd;
 }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_names_begin(void) { return &NamesStart; }
+const char *__llvm_profile_begin_names(void) { return &NamesStart; }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_names_end(void) { return &NamesEnd; }
+const char *__llvm_profile_end_names(void) { return &NamesEnd; }
 __attribute__((visibility("hidden")))
-uint64_t *__llvm_profile_counters_begin(void) { return &CountersStart; }
+uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
 __attribute__((visibility("hidden")))
-uint64_t *__llvm_profile_counters_end(void) { return &CountersEnd; }
+uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
 #endif
diff --git a/lib/profile/InstrProfilingPlatformOther.c b/lib/profile/InstrProfilingPlatformOther.c
index 404c1a8..548d6a3 100644
--- a/lib/profile/InstrProfilingPlatformOther.c
+++ b/lib/profile/InstrProfilingPlatformOther.c
@@ -56,19 +56,19 @@
 }
 
 __attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_data_begin(void) {
+const __llvm_profile_data *__llvm_profile_begin_data(void) {
   return DataFirst;
 }
 __attribute__((visibility("hidden")))
-const __llvm_profile_data *__llvm_profile_data_end(void) {
+const __llvm_profile_data *__llvm_profile_end_data(void) {
   return DataLast;
 }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_names_begin(void) { return NamesFirst; }
+const char *__llvm_profile_begin_names(void) { return NamesFirst; }
 __attribute__((visibility("hidden")))
-const char *__llvm_profile_names_end(void) { return NamesLast; }
+const char *__llvm_profile_end_names(void) { return NamesLast; }
 __attribute__((visibility("hidden")))
-uint64_t *__llvm_profile_counters_begin(void) { return CountersFirst; }
+uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
 __attribute__((visibility("hidden")))
-uint64_t *__llvm_profile_counters_end(void) { return CountersLast; }
+uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
 #endif
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 7ad3f31..fe4418c 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -16,10 +16,13 @@
   sanitizer_platform_limits_posix.cc
   sanitizer_posix.cc
   sanitizer_printf.cc
+  sanitizer_procmaps_common.cc
+  sanitizer_procmaps_freebsd.cc
   sanitizer_procmaps_linux.cc
   sanitizer_procmaps_mac.cc
   sanitizer_stackdepot.cc
   sanitizer_stacktrace.cc
+  sanitizer_stacktrace_printer.cc
   sanitizer_suppressions.cc
   sanitizer_symbolizer.cc
   sanitizer_symbolizer_libbacktrace.cc
@@ -37,7 +40,8 @@
   sanitizer_stacktrace_libcdep.cc
   sanitizer_stoptheworld_linux_libcdep.cc
   sanitizer_symbolizer_libcdep.cc
-  sanitizer_symbolizer_posix_libcdep.cc)
+  sanitizer_symbolizer_posix_libcdep.cc
+  sanitizer_unwind_posix_libcdep.cc)
 
 # Explicitly list all sanitizer_common headers. Not all of these are
 # included in sanitizer_common source files, but we need to depend on
@@ -79,6 +83,7 @@
   sanitizer_stackdepot.h
   sanitizer_stackdepotbase.h
   sanitizer_stacktrace.h
+  sanitizer_stacktrace_printer.h
   sanitizer_stoptheworld.h
   sanitizer_suppressions.h
   sanitizer_symbolizer.h
@@ -100,8 +105,11 @@
 set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 append_no_rtti_flag(SANITIZER_CFLAGS)
 
-append_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 SANITIZER_CFLAGS)
-append_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors SANITIZER_CFLAGS)
+# Stack frames on PowerPC are much larger than anticipated.
+if(NOT ${LLVM_NATIVE_ARCH} STREQUAL "PowerPC")
+  append_list_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 SANITIZER_CFLAGS)
+endif()
+append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors SANITIZER_CFLAGS)
 
 add_custom_target(sanitizer_common)
 set(SANITIZER_RUNTIME_LIBRARIES)
@@ -115,14 +123,6 @@
       DEFS ${SANITIZER_COMMON_DEFINITIONS})
     list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os})
   endforeach()
-elseif(ANDROID)
-  add_library(RTSanitizerCommon.arm.android OBJECT
-    ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES})
-  set_target_compile_flags(RTSanitizerCommon.arm.android
-    ${SANITIZER_CFLAGS})
-  set_property(TARGET RTSanitizerCommon.arm.android APPEND PROPERTY
-    COMPILE_DEFINITIONS ${SANITIZER_COMMON_DEFINITIONS})
-  list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.arm.android)
 else()
   # Otherwise, build separate libraries for each target.
   foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index c83c672..2321801 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -461,6 +461,11 @@
     }
   }
 
+  static uptr AdditionalSize() {
+    return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+                     GetPageSizeCached());
+  }
+
   typedef SizeClassMap SizeClassMapT;
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
   static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -490,11 +495,6 @@
   };
   COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
 
-  static uptr AdditionalSize() {
-    return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
-                     GetPageSizeCached());
-  }
-
   RegionInfo *GetRegionInfo(uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
@@ -1015,12 +1015,15 @@
     if (map_size < size) return AllocatorReturnNull();  // Overflow.
     uptr map_beg = reinterpret_cast<uptr>(
         MmapOrDie(map_size, "LargeMmapAllocator"));
+    CHECK(IsAligned(map_beg, page_size_));
     MapUnmapCallback().OnMap(map_beg, map_size);
     uptr map_end = map_beg + map_size;
     uptr res = map_beg + page_size_;
     if (res & (alignment - 1))  // Align.
       res += alignment - (res & (alignment - 1));
-    CHECK_EQ(0, res & (alignment - 1));
+    CHECK(IsAligned(res, alignment));
+    CHECK(IsAligned(res, page_size_));
+    CHECK_GE(res + size, map_beg);
     CHECK_LE(res + size, map_end);
     Header *h = GetHeader(res);
     h->size = size;
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index c5f9028..4409fd6 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -25,38 +25,25 @@
 
 static const uptr kInternalAllocatorSpace = 0;
 static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
-#if SANITIZER_WORDSIZE == 32
 static const uptr kInternalAllocatorRegionSizeLog = 20;
+#if SANITIZER_WORDSIZE == 32
 static const uptr kInternalAllocatorNumRegions =
     kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
 typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
 #else
-static const uptr kInternalAllocatorRegionSizeLog = 24;
 static const uptr kInternalAllocatorNumRegions =
     kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
 typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
 #endif
 typedef SizeClassAllocator32<
-    kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
+    kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
     kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
 
 typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
     InternalAllocatorCache;
 
-// We don't want our internal allocator to do any map/unmap operations from
-// LargeMmapAllocator.
-struct CrashOnMapUnmap {
-  void OnMap(uptr p, uptr size) const {
-    RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!\n");
-  }
-  void OnUnmap(uptr p, uptr size) const {
-    RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!\n");
-  }
-};
-
 typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
-                          LargeMmapAllocator<CrashOnMapUnmap> >
-    InternalAllocator;
+                          LargeMmapAllocator<> > InternalAllocator;
 
 void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
 void InternalFree(void *p, InternalAllocatorCache *cache = 0);
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 6b76714..c77e50e 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -14,8 +14,6 @@
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -157,23 +155,12 @@
   return pos;
 }
 
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
-                         int line, int column) {
-  CHECK(file);
-  buffer->append("%s",
-                 StripPathPrefix(file, common_flags()->strip_path_prefix));
-  if (line > 0) {
-    buffer->append(":%d", line);
-    if (column > 0)
-      buffer->append(":%d", column);
-  }
-}
-
-void PrintModuleAndOffset(InternalScopedString *buffer, const char *module,
-                          uptr offset) {
-  buffer->append("(%s+0x%zx)",
-                 StripPathPrefix(module, common_flags()->strip_path_prefix),
-                 offset);
+const char *StripModuleName(const char *module) {
+  if (module == 0)
+    return 0;
+  if (const char *slash_pos = internal_strrchr(module, '/'))
+    return slash_pos + 1;
+  return module;
 }
 
 void ReportErrorSummary(const char *error_message) {
@@ -197,21 +184,6 @@
   ReportErrorSummary(buff.data());
 }
 
-void ReportErrorSummary(const char *error_type, StackTrace *stack) {
-  if (!common_flags()->print_summary)
-    return;
-  AddressInfo ai;
-#if !SANITIZER_GO
-  if (stack->size > 0 && Symbolizer::Get()->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]);
-    Symbolizer::Get()->SymbolizePC(pc, &ai, 1);
-  }
-#endif
-  ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
-}
-
 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
   full_name_ = internal_strdup(module_name);
   base_address_ = base_address;
@@ -234,17 +206,6 @@
   return false;
 }
 
-char *StripModuleName(const char *module) {
-  if (module == 0)
-    return 0;
-  const char *short_module_name = internal_strrchr(module, '/');
-  if (short_module_name)
-    short_module_name += 1;
-  else
-    short_module_name = module;
-  return internal_strdup(short_module_name);
-}
-
 static atomic_uintptr_t g_total_mmaped;
 
 void IncreaseTotalMmap(uptr size) {
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 2481cb1..c1e2101 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -167,16 +167,16 @@
 void *MapFileToMemory(const char *file_name, uptr *buff_size);
 void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
 
+bool IsAccessibleMemoryRange(uptr beg, uptr size);
+
 // Error report formatting.
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix);
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
-                         int line, int column);
-void PrintModuleAndOffset(InternalScopedString *buffer,
-                          const char *module, uptr offset);
+// Strip the directories from the module name.
+const char *StripModuleName(const char *module);
 
 // OS
-void DisableCoreDumper();
+void DisableCoreDumperIfNecessary();
 void DumpProcessMap();
 bool FileExists(const char *filename);
 const char *GetEnv(const char *name);
@@ -187,6 +187,8 @@
 void ReExec();
 bool StackSizeIsUnlimited();
 void SetStackSizeLimitInBytes(uptr limit);
+bool AddressSpaceIsUnlimited();
+void SetAddressSpaceUnlimited();
 void AdjustStackSize(void *attr);
 void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
 void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
@@ -205,9 +207,6 @@
 u64 NanoTime();
 int Atexit(void (*function)(void));
 void SortArray(uptr *array, uptr size);
-// Strip the directories from the module name, return a new string allocated
-// with internal_strdup.
-char *StripModuleName(const char *module);
 
 // Exit
 void NORETURN Abort();
@@ -246,7 +245,7 @@
 // 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
+//   error_type file:line function
 void ReportErrorSummary(const char *error_type, const char *file,
                         int line, const char *function);
 void ReportErrorSummary(const char *error_type, StackTrace *trace);
@@ -524,23 +523,6 @@
 // Callback type for iterating over a set of memory ranges.
 typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
 
-#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !defined(SANITIZER_GO)
-extern uptr indirect_call_wrapper;
-void SetIndirectCallWrapper(uptr wrapper);
-
-template <typename F>
-F IndirectExternCall(F f) {
-  typedef F (*WrapF)(F);
-  return indirect_call_wrapper ? ((WrapF)indirect_call_wrapper)(f) : f;
-}
-#else
-INLINE void SetIndirectCallWrapper(uptr wrapper) {}
-template <typename F>
-F IndirectExternCall(F f) {
-  return f;
-}
-#endif
-
 #if SANITIZER_ANDROID
 // Initialize Android logging. Any writes before this are silently lost.
 void AndroidLogInit();
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 64ddeed..274e87c 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -27,6 +27,7 @@
 //   COMMON_INTERCEPTOR_MUTEX_REPAIR
 //   COMMON_INTERCEPTOR_SET_PTHREAD_NAME
 //   COMMON_INTERCEPTOR_HANDLE_RECVMSG
+//   COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
 //===----------------------------------------------------------------------===//
 #include "interception/interception.h"
 #include "sanitizer_addrhashmap.h"
@@ -40,6 +41,10 @@
 #define va_copy(dst, src) ((dst) = (src))
 #endif // _WIN32
 
+#if SANITIZER_FREEBSD
+#define pthread_setname_np pthread_set_name_np
+#endif
+
 #ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
 #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
 #endif
@@ -89,6 +94,10 @@
   COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__)
 #endif
 
+#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
+#endif
+
 struct FileMetadata {
   // For open_memstream().
   char **addr;
@@ -174,6 +183,8 @@
 }
 
 INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
+  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+    return internal_strncmp(s1, s2, size);
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
   unsigned char c1 = 0, c2 = 0;
@@ -244,7 +255,7 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
   void *res = REAL(memchr)(s, c, n);
-  uptr len = res ? (char*)res - (char*)s + 1 : n;
+  uptr len = res ? (char *)res - (const char *)s + 1 : n;
   COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
   return res;
 }
@@ -1030,7 +1041,8 @@
 #endif
 
 #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
-    SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
+    SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \
+    SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
 static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
   if (pwd) {
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
@@ -1077,7 +1089,9 @@
   }
 }
 #endif  // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
-        // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
+        // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT ||
+        // SANITIZER_INTERCEPT_GETPWENT_R ||
+        // SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
 
 #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
 INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
@@ -1428,30 +1442,30 @@
 
 static void wrapped_gl_closedir(void *dir) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
-  IndirectExternCall(pglob_copy->gl_closedir)(dir);
+  pglob_copy->gl_closedir(dir);
 }
 
 static void *wrapped_gl_readdir(void *dir) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
-  return IndirectExternCall(pglob_copy->gl_readdir)(dir);
+  return pglob_copy->gl_readdir(dir);
 }
 
 static void *wrapped_gl_opendir(const char *s) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
-  return IndirectExternCall(pglob_copy->gl_opendir)(s);
+  return pglob_copy->gl_opendir(s);
 }
 
 static int wrapped_gl_lstat(const char *s, void *st) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
-  return IndirectExternCall(pglob_copy->gl_lstat)(s, st);
+  return pglob_copy->gl_lstat(s, st);
 }
 
 static int wrapped_gl_stat(const char *s, void *st) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
-  return IndirectExternCall(pglob_copy->gl_stat)(s, st);
+  return pglob_copy->gl_stat(s, st);
 }
 
 INTERCEPTOR(int, glob, const char *pattern, int flags,
@@ -1535,8 +1549,14 @@
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
   return res;
 }
+// On FreeBSD id_t is always 64-bit wide.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop,
+                        int options) {
+#else
 INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
                         int options) {
+#endif
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
   // FIXME: under ASan the call below may write to freed memory and corrupt
@@ -2613,7 +2633,7 @@
 static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
-  return IndirectExternCall(scandir_filter)(dir);
+  return scandir_filter(dir);
 }
 
 static int wrapped_scandir_compar(const struct __sanitizer_dirent **a,
@@ -2623,7 +2643,7 @@
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
-  return IndirectExternCall(scandir_compar)(a, b);
+  return scandir_compar(a, b);
 }
 
 INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
@@ -2665,7 +2685,7 @@
 static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) {
   COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
-  return IndirectExternCall(scandir64_filter)(dir);
+  return scandir64_filter(dir);
 }
 
 static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a,
@@ -2675,7 +2695,7 @@
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, (*a)->d_reclen);
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
   COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, (*b)->d_reclen);
-  return IndirectExternCall(scandir64_compar)(a, b);
+  return scandir64_compar(a, b);
 }
 
 INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
@@ -4628,6 +4648,91 @@
 #define INIT_DLOPEN_DLCLOSE
 #endif
 
+#if SANITIZER_INTERCEPT_GETPASS
+INTERCEPTOR(char *, getpass, const char *prompt) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt);
+  if (prompt)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, REAL(strlen)(prompt)+1);
+  char *res = REAL(getpass)(prompt);
+  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res)+1);
+  return res;
+}
+
+#define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass);
+#else
+#define INIT_GETPASS
+#endif
+
+#if SANITIZER_INTERCEPT_TIMERFD
+INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value,
+            void *old_value) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value,
+                           old_value);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz);
+  int res = REAL(timerfd_settime)(fd, flags, new_value, old_value);
+  if (res != -1 && old_value)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz);
+  return res;
+}
+
+INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value);
+  int res = REAL(timerfd_gettime)(fd, curr_value);
+  if (res != -1 && curr_value)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz);
+  return res;
+}
+#define INIT_TIMERFD                          \
+  COMMON_INTERCEPT_FUNCTION(timerfd_settime); \
+  COMMON_INTERCEPT_FUNCTION(timerfd_gettime);
+#else
+#define INIT_TIMERFD
+#endif
+
+#if SANITIZER_INTERCEPT_MLOCKX
+// Linux kernel has a bug that leads to kernel deadlock if a process
+// maps TBs of memory and then calls mlock().
+static void MlockIsUnsupported() {
+  static atomic_uint8_t printed;
+  if (atomic_exchange(&printed, 1, memory_order_relaxed))
+    return;
+  VPrintf(1, "INFO: %s ignores mlock/mlockall/munlock/munlockall\n",
+          SanitizerToolName);
+}
+
+INTERCEPTOR(int, mlock, const void *addr, uptr len) {
+  MlockIsUnsupported();
+  return 0;
+}
+
+INTERCEPTOR(int, munlock, const void *addr, uptr len) {
+  MlockIsUnsupported();
+  return 0;
+}
+
+INTERCEPTOR(int, mlockall, int flags) {
+  MlockIsUnsupported();
+  return 0;
+}
+
+INTERCEPTOR(int, munlockall, void) {
+  MlockIsUnsupported();
+  return 0;
+}
+
+#define INIT_MLOCKX                                                            \
+  COMMON_INTERCEPT_FUNCTION(mlock);                                            \
+  COMMON_INTERCEPT_FUNCTION(munlock);                                          \
+  COMMON_INTERCEPT_FUNCTION(mlockall);                                         \
+  COMMON_INTERCEPT_FUNCTION(munlockall);
+
+#else
+#define INIT_MLOCKX
+#endif  // SANITIZER_INTERCEPT_MLOCKX
+
 static void InitializeCommonInterceptors() {
   static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
   interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
@@ -4786,4 +4891,7 @@
   INIT_FFLUSH;
   INIT_FCLOSE;
   INIT_DLOPEN_DLCLOSE;
+  INIT_GETPASS;
+  INIT_TIMERFD;
+  INIT_MLOCKX;
 }
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index e4b2d76..4374f56 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -13,6 +13,8 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -47,6 +49,21 @@
   sandboxing_callback = f;
 }
 
+void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+  if (!common_flags()->print_summary)
+    return;
+  AddressInfo ai;
+#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]);
+    Symbolizer::GetOrInit()->SymbolizePC(pc, &ai, 1);
+  }
+#endif
+  ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
+}
+
 }  // namespace __sanitizer
 
 void NOINLINE
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 23da703..a52338b 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -1326,13 +1326,13 @@
     } else if (op == iocb_cmd_pread && buf && len) {
       POST_WRITE(buf, len);
     } else if (op == iocb_cmd_pwritev) {
-      __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
+      __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
       for (uptr v = 0; v < len; v++)
-        PRE_READ(iovec[i].iov_base, iovec[i].iov_len);
+        PRE_READ(iovec[v].iov_base, iovec[v].iov_len);
     } else if (op == iocb_cmd_preadv) {
-      __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
+      __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf;
       for (uptr v = 0; v < len; v++)
-        POST_WRITE(iovec[i].iov_base, iovec[i].iov_len);
+        POST_WRITE(iovec[v].iov_base, iovec[v].iov_len);
     }
     // See comment in io_getevents.
     COMMON_SYSCALL_RELEASE(data);
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index c22de97..bd98adb 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -38,9 +38,12 @@
 #include "sanitizer_mutex.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 #include "sanitizer_flags.h"
 
-atomic_uint32_t dump_once_guard;  // Ensure that CovDump runs only once.
+static atomic_uint32_t dump_once_guard;  // Ensure that CovDump runs only once.
+
+static atomic_uintptr_t coverage_counter;
 
 // pc_array is the array containing the covered PCs.
 // To make the pc_array thread- and async-signal-safe it has to be large enough.
@@ -63,6 +66,13 @@
   void AfterFork(int child_pid);
   void Extend(uptr npcs);
   void Add(uptr pc);
+  void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+                 uptr cache_size);
+  void DumpCallerCalleePairs();
+  void DumpTrace();
+
+  ALWAYS_INLINE
+  void TraceBasicaBlock(uptr *cache);
 
   uptr *data();
   uptr size();
@@ -85,6 +95,34 @@
   uptr pc_array_mapped_size;
   // Descriptor of the file mapped pc array.
   int pc_fd;
+
+  // Caller-Callee (cc) array, size and current index.
+  static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
+  uptr **cc_array;
+  atomic_uintptr_t cc_array_index;
+  atomic_uintptr_t cc_array_size;
+
+  // Tracing (tr) pc and event arrays, their size and current index.
+  // We record all events (basic block entries) in a global buffer of u32
+  // values. Each such value is an index in the table of TracedPc objects.
+  // So far the tracing is highly experimental:
+  //   - not thread-safe;
+  //   - does not support long traces;
+  //   - not tuned for performance.
+  struct TracedPc {
+    uptr pc;
+    const char *module_name;
+    uptr module_offset;
+  };
+  static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30);
+  u32 *tr_event_array;
+  uptr tr_event_array_size;
+  uptr tr_event_array_index;
+  static const uptr kTrPcArrayMaxSize    = FIRST_32_SECOND_64(1 << 22, 1 << 27);
+  TracedPc *tr_pc_array;
+  uptr tr_pc_array_size;
+  uptr tr_pc_array_index;
+
   StaticSpinMutex mu;
 
   void DirectOpen();
@@ -118,6 +156,22 @@
     atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
     atomic_store(&pc_array_index, 0, memory_order_relaxed);
   }
+
+  cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
+      sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
+  atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
+  atomic_store(&cc_array_index, 0, memory_order_relaxed);
+
+  tr_event_array = reinterpret_cast<u32 *>(
+      MmapNoReserveOrDie(sizeof(tr_event_array[0]) * kTrEventArrayMaxSize,
+                         "CovInit::tr_event_array"));
+  tr_event_array_size = kTrEventArrayMaxSize;
+  tr_event_array_index = 0;
+
+  tr_pc_array = reinterpret_cast<TracedPc *>(MmapNoReserveOrDie(
+      sizeof(tr_pc_array[0]) * kTrEventArrayMaxSize, "CovInit::tr_pc_array"));
+  tr_pc_array_size = kTrEventArrayMaxSize;
+  tr_pc_array_index = 0;
 }
 
 void CoverageData::ReInit() {
@@ -184,6 +238,41 @@
   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);
+}
+
+// Registers a pair caller=>callee.
+// When a given caller is seen for the first time, the callee_cache is added
+// to the global array cc_array, callee_cache[0] is set to caller and
+// callee_cache[1] is set to cache_size.
+// Then we are trying to add callee to callee_cache [2,cache_size) if it is
+// not there yet.
+// If the cache is full we drop the callee (may want to fix this later).
+void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+                             uptr cache_size) {
+  if (!cc_array) return;
+  atomic_uintptr_t *atomic_callee_cache =
+      reinterpret_cast<atomic_uintptr_t *>(callee_cache);
+  uptr zero = 0;
+  if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
+                                     memory_order_seq_cst)) {
+    uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
+    CHECK_LT(idx * sizeof(uptr),
+             atomic_load(&cc_array_size, memory_order_acquire));
+    callee_cache[1] = cache_size;
+    cc_array[idx] = callee_cache;
+  }
+  CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
+  for (uptr i = 2; i < cache_size; i++) {
+    uptr was = 0;
+    if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
+                                       memory_order_seq_cst)) {
+      atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
+      return;
+    }
+    if (was == callee)  // Already have this callee.
+      return;
+  }
 }
 
 uptr *CoverageData::data() {
@@ -228,7 +317,7 @@
     internal_memcpy(block_pos, module, module_name_length);
     block_pos += module_name_length;
     char *block_data_begin = block_pos;
-    char *blob_pos = (char *)blob;
+    const char *blob_pos = (const char *)blob;
     while (blob_size > 0) {
       unsigned int payload_size = Min(blob_size, max_payload_size);
       blob_size -= payload_size;
@@ -249,7 +338,6 @@
   InternalScopedBuffer<char> path(1024);
   if (!packed) {
     CHECK(name);
-    Printf("%s\n", common_flags()->coverage_dir);
     internal_snprintf((char *)path.data(), path.size(), "%s/%s.%zd.sancov",
                       common_flags()->coverage_dir, name, internal_getpid());
   } else {
@@ -269,6 +357,97 @@
   return fd;
 }
 
+// Dump trace PCs and trace events into two separate files.
+void CoverageData::DumpTrace() {
+  uptr max_idx = tr_event_array_index;
+  if (!max_idx) return;
+  auto sym = Symbolizer::GetOrInit();
+  if (!sym)
+    return;
+  InternalScopedString out(32 << 20);
+  for (uptr i = 0; i < max_idx; i++) {
+    u32 pc_idx = tr_event_array[i];
+    TracedPc *t = &tr_pc_array[pc_idx];
+    if (!t->module_name) {
+      const char *module_name = "<unknown>";
+      uptr module_address = 0;
+      sym->GetModuleNameAndOffsetForPC(t->pc, &module_name, &module_address);
+      t->module_name = internal_strdup(module_name);
+      t->module_offset = module_address;
+      out.append("%s 0x%zx\n", t->module_name, t->module_offset);
+    }
+  }
+  int fd = CovOpenFile(false, "trace-points");
+  if (fd < 0) return;
+  internal_write(fd, out.data(), out.length());
+  internal_close(fd);
+
+  fd = CovOpenFile(false, "trace-events");
+  if (fd < 0) return;
+  internal_write(fd, tr_event_array, max_idx * sizeof(tr_event_array[0]));
+  internal_close(fd);
+  VReport(1, " CovDump: Trace: %zd PCs written\n", tr_pc_array_index);
+  VReport(1, " CovDump: Trace: %zd Events written\n", tr_event_array_index);
+}
+
+// This function dumps the caller=>callee pairs into a file as a sequence of
+// lines like "module_name offset".
+void CoverageData::DumpCallerCalleePairs() {
+  uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
+  if (!max_idx) return;
+  auto sym = Symbolizer::GetOrInit();
+  if (!sym)
+    return;
+  InternalScopedString out(32 << 20);
+  uptr total = 0;
+  for (uptr i = 0; i < max_idx; i++) {
+    uptr *cc_cache = cc_array[i];
+    CHECK(cc_cache);
+    uptr caller = cc_cache[0];
+    uptr n_callees = cc_cache[1];
+    const char *caller_module_name = "<unknown>";
+    uptr caller_module_address = 0;
+    sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
+                                     &caller_module_address);
+    for (uptr j = 2; j < n_callees; j++) {
+      uptr callee = cc_cache[j];
+      if (!callee) break;
+      total++;
+      const char *callee_module_name = "<unknown>";
+      uptr callee_module_address = 0;
+      sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
+                                       &callee_module_address);
+      out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
+                 caller_module_address, callee_module_name,
+                 callee_module_address);
+    }
+  }
+  int fd = CovOpenFile(false, "caller-callee");
+  if (fd < 0) return;
+  internal_write(fd, out.data(), out.length());
+  internal_close(fd);
+  VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
+}
+
+// Record the current PC into the event buffer.
+// Every event is a u32 value (index in tr_pc_array_index) so we compute
+// it once and then cache in the provided 'cache' storage.
+void CoverageData::TraceBasicaBlock(uptr *cache) {
+  CHECK(common_flags()->coverage);
+  uptr idx = *cache;
+  if (!idx) {
+    CHECK_LT(tr_pc_array_index, kTrPcArrayMaxSize);
+    idx = tr_pc_array_index++;
+    TracedPc *t = &tr_pc_array[idx];
+    t->pc = GET_CALLER_PC();
+    *cache = idx;
+    CHECK_LT(idx, 1U << 31);
+  }
+  CHECK_LT(tr_event_array_index, tr_event_array_size);
+  tr_event_array[tr_event_array_index] = static_cast<u32>(idx);
+  tr_event_array_index++;
+}
+
 // Dump the coverage on disk.
 static void CovDump() {
   if (!common_flags()->coverage || common_flags()->coverage_direct) return;
@@ -300,7 +479,7 @@
         CHECK_LE(diff, 0xffffffffU);
         offsets.push_back(static_cast<u32>(diff));
       }
-      char *module_name = StripModuleName(module.data());
+      const char *module_name = StripModuleName(module.data());
       if (cov_sandboxed) {
         if (cov_fd >= 0) {
           CovWritePacked(internal_getpid(), module_name, offsets.data(),
@@ -320,11 +499,12 @@
                   vb - old_vb);
         }
       }
-      InternalFree(module_name);
     }
   }
   if (cov_fd >= 0)
     internal_close(cov_fd);
+  coverage_data.DumpCallerCalleePairs();
+  coverage_data.DumpTrace();
 #endif  // !SANITIZER_WINDOWS
 }
 
@@ -360,6 +540,11 @@
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() {
   coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()));
 }
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
+  coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+                          callee, callee_cache16, 16);
+}
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
   coverage_data.Init();
@@ -377,4 +562,17 @@
 sptr __sanitizer_maybe_open_cov_file(const char *name) {
   return MaybeOpenCovFile(name);
 }
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __sanitizer_get_total_unique_coverage() {
+  return atomic_load(&coverage_counter, memory_order_relaxed);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_func_enter(uptr *cache) {
+  coverage_data.TraceBasicaBlock(cache);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_cov_trace_basic_block(uptr *cache) {
+  coverage_data.TraceBasicaBlock(cache);
+}
 }  // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index e4ee875..dddf2f0 100644
--- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -80,7 +80,7 @@
 
   text.append("%d\n", sizeof(uptr) * 8);
   for (int i = 0; i < n_modules; ++i) {
-    char *module_name = StripModuleName(modules[i].full_name());
+    const char *module_name = StripModuleName(modules[i].full_name());
     for (unsigned j = 0; j < modules[i].n_ranges(); ++j) {
       if (modules[i].address_range_executable(j)) {
         uptr start = modules[i].address_range_start(j);
@@ -91,7 +91,6 @@
           cached_mapping.SetModuleRange(start, end);
       }
     }
-    InternalFree(module_name);
   }
 
   int err;
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index 0a70e16..40b6ec0 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -39,6 +39,7 @@
   f->external_symbolizer_path = 0;
   f->allow_addr2line = false;
   f->strip_path_prefix = "";
+  f->fast_unwind_on_check = false;
   f->fast_unwind_on_fatal = false;
   f->fast_unwind_on_malloc = true;
   f->handle_ioctl = false;
@@ -63,6 +64,11 @@
   f->coverage_direct = SANITIZER_ANDROID;
   f->coverage_dir = ".";
   f->full_address_space = false;
+  f->suppressions = "";
+  f->print_suppressions = true;
+  f->disable_coredump = (SANITIZER_WORDSIZE == 64);
+  f->symbolize_inline_frames = true;
+  f->stack_trace_format = "DEFAULT";
 }
 
 void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
@@ -78,6 +84,9 @@
       "unavailable.");
   ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix",
       "Strips this prefix from file paths in error reports.");
+  ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check",
+      "If available, use the fast frame-pointer-based unwinder on "
+      "internal CHECK failures.");
   ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal",
       "If available, use the fast frame-pointer-based unwinder on fatal "
       "errors.");
@@ -144,6 +153,19 @@
   ParseFlag(str, &f->full_address_space, "full_address_space",
             "Sanitize complete address space; "
             "by default kernel area on 32-bit platforms will not be sanitized");
+  ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name.");
+  ParseFlag(str, &f->print_suppressions, "print_suppressions",
+            "Print matched suppressions at exit.");
+  ParseFlag(str, &f->disable_coredump, "disable_coredump",
+      "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
+      "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
+      "default and for sanitizers that don't reserve lots of virtual memory.");
+  ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
+            "Print inlined frames in stacktraces. Defaults to true.");
+  ParseFlag(str, &f->stack_trace_format, "stack_trace_format",
+            "Format string used to render stack frames. "
+            "See sanitizer_stacktrace_printer.h for the format description. "
+            "Use DEFAULT to get default format.");
 
   // Do a sanity check for certain flags.
   if (f->malloc_context_size < 1)
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index 41dc218..4791397 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -32,6 +32,7 @@
   const char *external_symbolizer_path;
   bool allow_addr2line;
   const char *strip_path_prefix;
+  bool fast_unwind_on_check;
   bool fast_unwind_on_fatal;
   bool fast_unwind_on_malloc;
   bool handle_ioctl;
@@ -57,6 +58,11 @@
   bool coverage_direct;
   const char *coverage_dir;
   bool full_address_space;
+  const char *suppressions;
+  bool print_suppressions;
+  bool disable_coredump;
+  bool symbolize_inline_frames;
+  const char *stack_trace_format;
 };
 
 inline CommonFlags *common_flags() {
diff --git a/lib/sanitizer_common/sanitizer_freebsd.h b/lib/sanitizer_common/sanitizer_freebsd.h
index 52a2a85..c9bba80 100644
--- a/lib/sanitizer_common/sanitizer_freebsd.h
+++ b/lib/sanitizer_common/sanitizer_freebsd.h
@@ -22,10 +22,14 @@
 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
 # include <osreldate.h>
 # if __FreeBSD_version <= 902001  // v9.2
+#  include <link.h>
+#  include <sys/param.h>
 #  include <ucontext.h>
 
 namespace __sanitizer {
 
+typedef unsigned long long __xuint64_t;
+
 typedef __int32_t __xregister_t;
 
 typedef struct __xmcontext {
@@ -74,6 +78,57 @@
   int __spare__[4];
 } xucontext_t;
 
+struct xkinfo_vmentry {
+  int kve_structsize;
+  int kve_type;
+  __xuint64_t kve_start;
+  __xuint64_t kve_end;
+  __xuint64_t kve_offset;
+  __xuint64_t kve_vn_fileid;
+  __uint32_t kve_vn_fsid;
+  int kve_flags;
+  int kve_resident;
+  int kve_private_resident;
+  int kve_protection;
+  int kve_ref_count;
+  int kve_shadow_count;
+  int kve_vn_type;
+  __xuint64_t kve_vn_size;
+  __uint32_t kve_vn_rdev;
+  __uint16_t kve_vn_mode;
+  __uint16_t kve_status;
+  int _kve_ispare[12];
+  char kve_path[PATH_MAX];
+};
+
+typedef struct {
+  __uint32_t p_type;
+  __uint32_t p_offset;
+  __uint32_t p_vaddr;
+  __uint32_t p_paddr;
+  __uint32_t p_filesz;
+  __uint32_t p_memsz;
+  __uint32_t p_flags;
+  __uint32_t p_align;
+} XElf32_Phdr;
+
+struct xdl_phdr_info {
+  Elf_Addr dlpi_addr;
+  const char *dlpi_name;
+  const XElf32_Phdr *dlpi_phdr;
+  Elf_Half dlpi_phnum;
+  unsigned long long int dlpi_adds;
+  unsigned long long int dlpi_subs;
+  size_t dlpi_tls_modid;
+  void *dlpi_tls_data;
+};
+
+typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*);
+typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*);
+
+#define xdl_iterate_phdr(callback, param) \
+  (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param)))
+
 }  // namespace __sanitizer
 
 # endif  // __FreeBSD_version <= 902001
diff --git a/lib/sanitizer_common/sanitizer_interception.h b/lib/sanitizer_common/sanitizer_interception.h
deleted file mode 100644
index b63462d..0000000
--- a/lib/sanitizer_common/sanitizer_interception.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- sanitizer_interception.h --------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Common macro definitions for interceptors.
-// Always use this headers instead of interception/interception.h.
-//
-//===----------------------------------------------------------------------===//
-#ifndef SANITIZER_INTERCEPTION_H
-#define SANITIZER_INTERCEPTION_H
-
-#include "interception/interception.h"
-#include "sanitizer_common.h"
-
-#if SANITIZER_LINUX && !defined(SANITIZER_GO)
-#undef REAL
-#define REAL(x) IndirectExternCall(__interception::PTR_TO_REAL(x))
-#endif
-
-#endif  // SANITIZER_INTERCEPTION_H
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index c8985b4..d77ca8f 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -34,6 +34,15 @@
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 0
 #endif
 
+// We can use .preinit_array section on Linux to call sanitizer initialization
+// functions very early in the process startup (unless PIC macro is defined).
+// FIXME: do we have anything like this on Mac?
+#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
+#else
+# define SANITIZER_CAN_USE_PREINIT_ARRAY 0
+#endif
+
 // GCC does not understand __has_feature
 #if !defined(__has_feature)
 # define __has_feature(x) 0
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index 00596f5..8d8ad59 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -31,16 +31,16 @@
 }
 
 void *internal_memchr(const void *s, int c, uptr n) {
-  const char* t = (char*)s;
+  const char *t = (const char *)s;
   for (uptr i = 0; i < n; ++i, ++t)
     if (*t == c)
-      return (void*)t;
+      return reinterpret_cast<void *>(const_cast<char *>(t));
   return 0;
 }
 
 int internal_memcmp(const void* s1, const void* s2, uptr n) {
-  const char* t1 = (char*)s1;
-  const char* t2 = (char*)s2;
+  const char *t1 = (const char *)s1;
+  const char *t2 = (const char *)s2;
   for (uptr i = 0; i < n; ++i, ++t1, ++t2)
     if (*t1 != *t2)
       return *t1 < *t2 ? -1 : 1;
@@ -49,7 +49,7 @@
 
 void *internal_memcpy(void *dest, const void *src, uptr n) {
   char *d = (char*)dest;
-  char *s = (char*)src;
+  const char *s = (const char *)src;
   for (uptr i = 0; i < n; ++i)
     d[i] = s[i];
   return dest;
@@ -57,7 +57,7 @@
 
 void *internal_memmove(void *dest, const void *src, uptr n) {
   char *d = (char*)dest;
-  char *s = (char*)src;
+  const char *s = (const char *)src;
   sptr i, signed_n = (sptr)n;
   CHECK_GE(signed_n, 0);
   if (d < s) {
@@ -138,7 +138,7 @@
 char* internal_strchr(const char *s, int c) {
   while (true) {
     if (*s == (char)c)
-      return (char*)s;
+      return const_cast<char *>(s);
     if (*s == 0)
       return 0;
     s++;
@@ -148,7 +148,7 @@
 char *internal_strchrnul(const char *s, int c) {
   char *res = internal_strchr(s, c);
   if (!res)
-    res = (char*)s + internal_strlen(s);
+    res = const_cast<char *>(s) + internal_strlen(s);
   return res;
 }
 
@@ -157,7 +157,7 @@
   for (uptr i = 0; s[i]; i++) {
     if (s[i] == c) res = s + i;
   }
-  return (char*)res;
+  return const_cast<char *>(res);
 }
 
 uptr internal_strlen(const char *s) {
@@ -196,7 +196,7 @@
   if (len1 < len2) return 0;
   for (uptr pos = 0; pos <= len1 - len2; pos++) {
     if (internal_memcmp(haystack + pos, needle, len2) == 0)
-      return (char*)haystack + pos;
+      return const_cast<char *>(haystack) + pos;
   }
   return 0;
 }
@@ -207,7 +207,7 @@
   int sgn = 1;
   u64 res = 0;
   bool have_digits = false;
-  char *old_nptr = (char*)nptr;
+  char *old_nptr = const_cast<char *>(nptr);
   if (*nptr == '+') {
     sgn = 1;
     nptr++;
@@ -223,7 +223,7 @@
     nptr++;
   }
   if (endptr != 0) {
-    *endptr = (have_digits) ? (char*)nptr : old_nptr;
+    *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr;
   }
   if (sgn > 0) {
     return (s64)(Min((u64)INT64_MAX, res));
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index a0bb871..44e4529 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -8,7 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
 
 #include "sanitizer_libignore.h"
 #include "sanitizer_flags.h"
@@ -103,4 +103,4 @@
 
 }  // namespace __sanitizer
 
-#endif  // #if SANITIZER_LINUX
+#endif  // #if SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 98640f7..acae5bb 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -537,7 +537,7 @@
   __sanitizer_kernel_sigaction_t k_act, k_oldact;
   internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
   internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t));
-  const __sanitizer_sigaction *u_act = (__sanitizer_sigaction *)act;
+  const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act;
   __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
   if (u_act) {
     k_act.handler = u_act->handler;
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 92e6b78..2ca55b4 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -17,6 +17,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_freebsd.h"
 #include "sanitizer_linux.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
@@ -24,17 +25,17 @@
 #include "sanitizer_atomic.h"
 #include "sanitizer_symbolizer.h"
 
-#include <dlfcn.h>
+#if SANITIZER_ANDROID || SANITIZER_FREEBSD
+#include <dlfcn.h>  // for dlsym()
+#endif
+
 #include <pthread.h>
 #include <signal.h>
 #include <sys/resource.h>
-#if SANITIZER_FREEBSD
-#define _GNU_SOURCE  // to declare _Unwind_Backtrace() from <unwind.h>
-#endif
-#include <unwind.h>
 
 #if SANITIZER_FREEBSD
 #include <pthread_np.h>
+#include <osreldate.h>
 #define pthread_getattr_np pthread_attr_get_np
 #endif
 
@@ -68,7 +69,8 @@
 int internal_sigaction(int signum, const void *act, void *oldact) {
   if (real_sigaction)
     return real_sigaction(signum, act, oldact);
-  return sigaction(signum, (struct sigaction *)act, (struct sigaction *)oldact);
+  return sigaction(signum, (const struct sigaction *)act,
+                   (struct sigaction *)oldact);
 }
 
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -126,7 +128,7 @@
   setenv_ft setenv_f;
   CHECK_EQ(sizeof(setenv_f), sizeof(f));
   internal_memcpy(&setenv_f, &f, sizeof(f));
-  return IndirectExternCall(setenv_f)(name, value, 1) == 0;
+  return setenv_f(name, value, 1) == 0;
 }
 
 bool SanitizerSetThreadName(const char *name) {
@@ -150,127 +152,6 @@
 #endif
 }
 
-//------------------------- SlowUnwindStack -----------------------------------
-
-typedef struct {
-  uptr absolute_pc;
-  uptr stack_top;
-  uptr stack_size;
-} backtrace_frame_t;
-
-extern "C" {
-typedef void *(*acquire_my_map_info_list_func)();
-typedef void (*release_my_map_info_list_func)(void *map);
-typedef sptr (*unwind_backtrace_signal_arch_func)(
-    void *siginfo, void *sigcontext, void *map_info_list,
-    backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
-acquire_my_map_info_list_func acquire_my_map_info_list;
-release_my_map_info_list_func release_my_map_info_list;
-unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
-} // extern "C"
-
-#if SANITIZER_ANDROID
-void SanitizerInitializeUnwinder() {
-  void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
-  if (!p) {
-    VReport(1,
-            "Failed to open libcorkscrew.so. You may see broken stack traces "
-            "in SEGV reports.");
-    return;
-  }
-  acquire_my_map_info_list =
-      (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
-  release_my_map_info_list =
-      (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
-  unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
-      p, "unwind_backtrace_signal_arch");
-  if (!acquire_my_map_info_list || !release_my_map_info_list ||
-      !unwind_backtrace_signal_arch) {
-    VReport(1,
-            "Failed to find one of the required symbols in libcorkscrew.so. "
-            "You may see broken stack traces in SEGV reports.");
-    acquire_my_map_info_list = NULL;
-    unwind_backtrace_signal_arch = NULL;
-    release_my_map_info_list = NULL;
-  }
-}
-#endif
-
-#ifdef __arm__
-#define UNWIND_STOP _URC_END_OF_STACK
-#define UNWIND_CONTINUE _URC_NO_REASON
-#else
-#define UNWIND_STOP _URC_NORMAL_STOP
-#define UNWIND_CONTINUE _URC_NO_REASON
-#endif
-
-uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
-#ifdef __arm__
-  uptr val;
-  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
-      15 /* r15 = PC */, _UVRSD_UINT32, &val);
-  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
-  // Clear the Thumb bit.
-  return val & ~(uptr)1;
-#else
-  return _Unwind_GetIP(ctx);
-#endif
-}
-
-struct UnwindTraceArg {
-  StackTrace *stack;
-  uptr max_depth;
-};
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
-  UnwindTraceArg *arg = (UnwindTraceArg*)param;
-  CHECK_LT(arg->stack->size, arg->max_depth);
-  uptr pc = Unwind_GetIP(ctx);
-  arg->stack->trace[arg->stack->size++] = pc;
-  if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
-  return UNWIND_CONTINUE;
-}
-
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
-  CHECK_GE(max_depth, 2);
-  size = 0;
-  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
-  _Unwind_Backtrace(Unwind_Trace, &arg);
-  // We need to pop a few frames so that pc is on top.
-  uptr to_pop = LocatePcInTrace(pc);
-  // trace[0] belongs to the current function so we always pop it.
-  if (to_pop == 0)
-    to_pop = 1;
-  PopStackFrames(to_pop);
-  trace[0] = pc;
-}
-
-void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
-                                            uptr max_depth) {
-  CHECK_GE(max_depth, 2);
-  if (!unwind_backtrace_signal_arch) {
-    SlowUnwindStack(pc, max_depth);
-    return;
-  }
-
-  void *map = acquire_my_map_info_list();
-  CHECK(map);
-  InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
-  // siginfo argument appears to be unused.
-  sptr res = unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map,
-                                          frames.data(),
-                                          /* ignore_depth */ 0, max_depth);
-  release_my_map_info_list(map);
-  if (res < 0) return;
-  CHECK_LE((uptr)res, kStackTraceMax);
-
-  size = 0;
-  // +2 compensate for libcorkscrew unwinder returning addresses of call
-  // instructions instead of raw return addresses.
-  for (sptr i = 0; i < res; ++i)
-    trace[size++] = frames[i].absolute_pc + 2;
-}
-
 #if !SANITIZER_FREEBSD
 static uptr g_tls_size;
 #endif
@@ -292,7 +173,7 @@
   CHECK_NE(get_tls, 0);
   size_t tls_size = 0;
   size_t tls_align = 0;
-  IndirectExternCall(get_tls)(&tls_size, &tls_align);
+  get_tls(&tls_size, &tls_align);
   g_tls_size = tls_size;
 #endif  // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
 }
@@ -471,6 +352,10 @@
 #else  // SANITIZER_ANDROID
 # if !SANITIZER_FREEBSD
 typedef ElfW(Phdr) Elf_Phdr;
+# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001  // v9.2
+#  define Elf_Phdr XElf32_Phdr
+#  define dl_phdr_info xdl_phdr_info
+#  define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
 # endif
 
 struct DlIteratePhdrData {
@@ -523,14 +408,6 @@
 }
 #endif  // SANITIZER_ANDROID
 
-uptr indirect_call_wrapper;
-
-void SetIndirectCallWrapper(uptr wrapper) {
-  CHECK(!indirect_call_wrapper);
-  CHECK(wrapper);
-  indirect_call_wrapper = wrapper;
-}
-
 void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
   // Some kinds of sandboxes may forbid filesystem access, so we won't be able
   // to read the file mappings from /proc/self/maps. Luckily, neither the
@@ -539,8 +416,7 @@
   MemoryMappingLayout::CacheMemoryMappings();
   // Same for /proc/self/exe in the symbolizer.
 #if !SANITIZER_GO
-  if (Symbolizer *sym = Symbolizer::GetOrNull())
-    sym->PrepareForSandboxing();
+  Symbolizer::GetOrInit()->PrepareForSandboxing();
   CovPrepareForSandboxing(args);
 #endif
 }
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 5985bd2..1b77087 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -160,7 +160,7 @@
   // pthread_get_stacksize_np() returns an incorrect stack size for the main
   // thread on Mavericks. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=261
-  if ((GetMacosVersion() == MACOS_VERSION_MAVERICKS) && at_initialization &&
+  if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
       stacksize == (1 << 19))  {
     struct rlimit rl;
     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
@@ -297,6 +297,7 @@
         case '1': return MACOS_VERSION_LION;
         case '2': return MACOS_VERSION_MOUNTAIN_LION;
         case '3': return MACOS_VERSION_MAVERICKS;
+        case '4': return MACOS_VERSION_YOSEMITE;
         default: return MACOS_VERSION_UNKNOWN;
       }
     }
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
index fae784a..3ed0ed3 100644
--- a/lib/sanitizer_common/sanitizer_mac.h
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -25,7 +25,8 @@
   MACOS_VERSION_SNOW_LEOPARD,
   MACOS_VERSION_LION,
   MACOS_VERSION_MOUNTAIN_LION,
-  MACOS_VERSION_MAVERICKS
+  MACOS_VERSION_MAVERICKS,
+  MACOS_VERSION_YOSEMITE,
 };
 
 MacosVersion GetMacosVersion();
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index a369599..6f8cd30 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -81,7 +81,7 @@
 // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
 // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
 #ifndef SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__aarch64__)
+# if defined(__aarch64__) || defined(__mips64)
 #  define SANITIZER_CAN_USE_ALLOCATOR64 0
 # else
 #  define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
@@ -94,6 +94,8 @@
 // but will consume more memory for TwoLevelByteMap.
 #if defined(__aarch64__)
 # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
+#elif defined(__mips__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
 #else
 # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
 #endif
@@ -109,4 +111,10 @@
 # endif
 #endif
 
+#ifdef __mips__
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
+#else
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
+#endif
+
 #endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index e9d5c35..95c2e9d 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -29,6 +29,12 @@
 # define SI_LINUX_NOT_ANDROID 0
 #endif
 
+#if SANITIZER_FREEBSD
+# define SI_FREEBSD 1
+#else
+# define SI_FREEBSD 0
+#endif
+
 #if SANITIZER_LINUX
 # define SI_LINUX 1
 #else
@@ -145,7 +151,8 @@
 #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SIGSETOPS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SIGSETOPS \
+  SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
@@ -196,10 +203,11 @@
 // FIXME: getline seems to be available on OSX 10.7
 #define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
 
-#define SANITIZER_INTERCEPT__EXIT SI_LINUX
+#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
 
 #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
+  SI_FREEBSD || SI_LINUX_NOT_ANDROID
 
 #define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID
 
@@ -221,6 +229,11 @@
 #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
+    SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
 
 #endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index fa963e6..fc09522 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -412,7 +412,7 @@
   unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
 #endif
 
-  unsigned IOCTL_NOT_PRESENT = 0;
+  const unsigned IOCTL_NOT_PRESENT = 0;
 
   unsigned IOCTL_FIOASYNC = FIOASYNC;
   unsigned IOCTL_FIOCLEX = FIOCLEX;
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 8ec1c58..80a3ddb 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -472,7 +472,7 @@
   typedef long __sanitizer___kernel_off_t;
 #endif
 
-#if defined(__powerpc__) || defined(__aarch64__) || defined(__mips__)
+#if defined(__powerpc__) || defined(__mips__)
   typedef unsigned int __sanitizer___kernel_old_uid_t;
   typedef unsigned int __sanitizer___kernel_old_gid_t;
 #else
@@ -861,7 +861,7 @@
 
   // A special value to mark ioctls that are not present on the target platform,
   // when it can not be determined without including any system headers.
-  extern unsigned IOCTL_NOT_PRESENT;
+  extern const unsigned IOCTL_NOT_PRESENT;
 
   extern unsigned IOCTL_FIOASYNC;
   extern unsigned IOCTL_FIOCLEX;
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 8df1fa7..eb2497b 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -84,9 +84,12 @@
   // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
   // Note that with 'ulimit -s unlimited' the stack is moved away from the top
   // of the address space, so simply checking the stack address is not enough.
-  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
+  // This should (does) work for both PowerPC64 Endian modes.
+  return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
 # elif defined(__aarch64__)
   return (1ULL << 39) - 1;
+# elif defined(__mips64)
+  return (1ULL << 40) - 1;  // 0x000000ffffffffffUL;
 # else
   return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
 # endif
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index e859959..ed1e372 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -44,30 +44,49 @@
   madvise((void*)addr, size, MADV_DONTNEED);
 }
 
-void DisableCoreDumper() {
-  struct rlimit nocore;
-  nocore.rlim_cur = 0;
-  nocore.rlim_max = 0;
-  setrlimit(RLIMIT_CORE, &nocore);
+static rlim_t getlim(int res) {
+  rlimit rlim;
+  CHECK_EQ(0, getrlimit(res, &rlim));
+  return rlim.rlim_cur;
 }
 
-bool StackSizeIsUnlimited() {
-  struct rlimit rlim;
-  CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
-  return ((uptr)rlim.rlim_cur == (uptr)-1);
-}
-
-void SetStackSizeLimitInBytes(uptr limit) {
-  struct rlimit rlim;
-  rlim.rlim_cur = limit;
-  rlim.rlim_max = limit;
-  if (setrlimit(RLIMIT_STACK, &rlim)) {
+static void setlim(int res, rlim_t lim) {
+  // The following magic is to prevent clang from replacing it with memset.
+  volatile struct rlimit rlim;
+  rlim.rlim_cur = lim;
+  rlim.rlim_max = lim;
+  if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
     Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
+}
+
+void DisableCoreDumperIfNecessary() {
+  if (common_flags()->disable_coredump) {
+    setlim(RLIMIT_CORE, 0);
+  }
+}
+
+bool StackSizeIsUnlimited() {
+  rlim_t stack_size = getlim(RLIMIT_STACK);
+  return (stack_size == RLIM_INFINITY);
+}
+
+void SetStackSizeLimitInBytes(uptr limit) {
+  setlim(RLIMIT_STACK, (rlim_t)limit);
   CHECK(!StackSizeIsUnlimited());
 }
 
+bool AddressSpaceIsUnlimited() {
+  rlim_t as_size = getlim(RLIMIT_AS);
+  return (as_size == RLIM_INFINITY);
+}
+
+void SetAddressSpaceUnlimited() {
+  setlim(RLIMIT_AS, RLIM_INFINITY);
+  CHECK(AddressSpaceIsUnlimited());
+}
+
 void SleepForSeconds(int seconds) {
   sleep(seconds);
 }
@@ -129,7 +148,9 @@
   struct sigaction sigact;
   internal_memset(&sigact, 0, sizeof(sigact));
   sigact.sa_sigaction = (sa_sigaction_t)handler;
-  sigact.sa_flags = SA_SIGINFO;
+  // Do not block the signal from being received in that signal's handler.
+  // Clients are responsible for handling this correctly.
+  sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
   if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
   CHECK_EQ(0, internal_sigaction(signum, &sigact, 0));
   VReport(1, "Installed the sigaction for signal %d\n", signum);
@@ -145,6 +166,28 @@
 }
 #endif  // SANITIZER_GO
 
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+  uptr page_size = GetPageSizeCached();
+  // Checking too large memory ranges is slow.
+  CHECK_LT(size, page_size * 10);
+  int sock_pair[2];
+  if (pipe(sock_pair))
+    return false;
+  uptr bytes_written =
+      internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
+  int write_errno;
+  bool result;
+  if (internal_iserror(bytes_written, &write_errno)) {
+    CHECK_EQ(EFAULT, write_errno);
+    result = false;
+  } else {
+    result = (bytes_written == size);
+  }
+  internal_close(sock_pair[0]);
+  internal_close(sock_pair[1]);
+  return result;
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index 8018131..3be6723 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -22,7 +22,8 @@
 #include <stdio.h>
 #include <stdarg.h>
 
-#if SANITIZER_WINDOWS && !defined(va_copy)
+#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 &&               \
+      !defined(va_copy)
 # define va_copy(dst, src) ((dst) = (src))
 #endif
 
@@ -112,7 +113,7 @@
   int result = 0;
   result += AppendString(buff, buff_end, -1, "0x");
   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
-                           (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
+                           SANITIZER_POINTER_FORMAT_LENGTH, true);
   return result;
 }
 
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index c59a27c..94e3871 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -26,6 +26,9 @@
   uptr mmaped_size;
   uptr len;
 };
+
+// Reads process memory map in an OS-specific way.
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
 
 class MemoryMappingLayout {
@@ -57,7 +60,7 @@
   // platform-specific files.
 # if SANITIZER_FREEBSD || SANITIZER_LINUX
   ProcSelfMapsBuff proc_self_maps_;
-  char *current_;
+  const char *current_;
 
   // Static mappings cache.
   static ProcSelfMapsBuff cached_proc_self_maps_;
@@ -86,6 +89,11 @@
 // Returns code range for the specified module.
 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
 
+bool IsDecimal(char c);
+uptr ParseDecimal(const char **p);
+bool IsHex(char c);
+uptr ParseHex(const char **p);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_PROCMAPS_H
diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc
new file mode 100644
index 0000000..3b1a311
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc
@@ -0,0 +1,178 @@
+//===-- sanitizer_procmaps_common.cc --------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (common parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+// Linker initialized.
+ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
+StaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
+
+static int TranslateDigit(char c) {
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  return -1;
+}
+
+// Parse a number and promote 'p' up to the first non-digit character.
+static uptr ParseNumber(const char **p, int base) {
+  uptr n = 0;
+  int d;
+  CHECK(base >= 2 && base <= 16);
+  while ((d = TranslateDigit(**p)) >= 0 && d < base) {
+    n = n * base + d;
+    (*p)++;
+  }
+  return n;
+}
+
+bool IsDecimal(char c) {
+  int d = TranslateDigit(c);
+  return d >= 0 && d < 10;
+}
+
+uptr ParseDecimal(const char **p) {
+  return ParseNumber(p, 10);
+}
+
+bool IsHex(char c) {
+  int d = TranslateDigit(c);
+  return d >= 0 && d < 16;
+}
+
+uptr ParseHex(const char **p) {
+  return ParseNumber(p, 16);
+}
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+  ReadProcMaps(&proc_self_maps_);
+  if (cache_enabled) {
+    if (proc_self_maps_.mmaped_size == 0) {
+      LoadFromCache();
+      CHECK_GT(proc_self_maps_.len, 0);
+    }
+  } else {
+    CHECK_GT(proc_self_maps_.mmaped_size, 0);
+  }
+  Reset();
+  // FIXME: in the future we may want to cache the mappings on demand only.
+  if (cache_enabled)
+    CacheMemoryMappings();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+  // Only unmap the buffer if it is different from the cached one. Otherwise
+  // it will be unmapped when the cache is refreshed.
+  if (proc_self_maps_.data != cached_proc_self_maps_.data) {
+    UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
+  }
+}
+
+void MemoryMappingLayout::Reset() {
+  current_ = proc_self_maps_.data;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+  SpinMutexLock l(&cache_lock_);
+  // Don't invalidate the cache if the mappings are unavailable.
+  ProcSelfMapsBuff old_proc_self_maps;
+  old_proc_self_maps = cached_proc_self_maps_;
+  ReadProcMaps(&cached_proc_self_maps_);
+  if (cached_proc_self_maps_.mmaped_size == 0) {
+    cached_proc_self_maps_ = old_proc_self_maps;
+  } else {
+    if (old_proc_self_maps.mmaped_size) {
+      UnmapOrDie(old_proc_self_maps.data,
+                 old_proc_self_maps.mmaped_size);
+    }
+  }
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+  SpinMutexLock l(&cache_lock_);
+  if (cached_proc_self_maps_.data) {
+    proc_self_maps_ = cached_proc_self_maps_;
+  }
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+                                            uptr max_modules,
+                                            string_predicate_t filter) {
+  Reset();
+  uptr cur_beg, cur_end, cur_offset, prot;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  uptr n_modules = 0;
+  for (uptr i = 0; n_modules < max_modules &&
+                       Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
+                            module_name.size(), &prot);
+       i++) {
+    const char *cur_name = module_name.data();
+    if (cur_name[0] == '\0')
+      continue;
+    if (filter && !filter(cur_name))
+      continue;
+    void *mem = &modules[n_modules];
+    // Don't subtract 'cur_beg' from the first entry:
+    // * If a binary is compiled w/o -pie, then the first entry in
+    //   process maps is likely the binary itself (all dynamic libs
+    //   are mapped higher in address space). For such a binary,
+    //   instruction offset in binary coincides with the actual
+    //   instruction address in virtual memory (as code section
+    //   is mapped to a fixed memory range).
+    // * If a binary is compiled with -pie, all the modules are
+    //   mapped high at address space (in particular, higher than
+    //   shadow memory of the tool), so the module can't be the
+    //   first entry.
+    uptr base_address = (i ? cur_beg : 0) - cur_offset;
+    LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
+    cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+    n_modules++;
+  }
+  return n_modules;
+}
+
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
+  char *smaps = 0;
+  uptr smaps_cap = 0;
+  uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
+      &smaps, &smaps_cap, 64<<20);
+  uptr start = 0;
+  bool file = false;
+  const char *pos = smaps;
+  while (pos < smaps + smaps_len) {
+    if (IsHex(pos[0])) {
+      start = ParseHex(&pos);
+      for (; *pos != '/' && *pos > '\n'; pos++) {}
+      file = *pos == '/';
+    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
+      while (!IsDecimal(*pos)) pos++;
+      uptr rss = ParseDecimal(&pos) * 1024;
+      cb(start, rss, file, stats, stats_size);
+    }
+    while (*pos++ != '\n') {}
+  }
+  UnmapOrDie(smaps, smaps_cap);
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
new file mode 100644
index 0000000..5011b1f
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_freebsd.cc
@@ -0,0 +1,88 @@
+//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (FreeBSD-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD
+#include "sanitizer_common.h"
+#include "sanitizer_freebsd.h"
+#include "sanitizer_procmaps.h"
+
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
+#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
+# include <osreldate.h>
+# if __FreeBSD_version <= 902001  // v9.2
+#  define kinfo_vmentry xkinfo_vmentry
+# endif
+#endif
+
+namespace __sanitizer {
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+  const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
+  size_t Size = 0;
+  int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
+  CHECK_EQ(Err, 0);
+  CHECK_GT(Size, 0);
+
+  size_t MmapedSize = Size * 4 / 3;
+  void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
+  Size = MmapedSize;
+  Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
+  CHECK_EQ(Err, 0);
+
+  proc_maps->data = (char*)VmMap;
+  proc_maps->mmaped_size = MmapedSize;
+  proc_maps->len = Size;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+                               char filename[], uptr filename_size,
+                               uptr *protection) {
+  char *last = proc_self_maps_.data + proc_self_maps_.len;
+  if (current_ >= last) return false;
+  uptr dummy;
+  if (!start) start = &dummy;
+  if (!end) end = &dummy;
+  if (!offset) offset = &dummy;
+  if (!protection) protection = &dummy;
+  struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
+
+  *start = (uptr)VmEntry->kve_start;
+  *end = (uptr)VmEntry->kve_end;
+  *offset = (uptr)VmEntry->kve_offset;
+
+  *protection = 0;
+  if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
+    *protection |= kProtectionRead;
+  if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
+    *protection |= kProtectionWrite;
+  if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
+    *protection |= kProtectionExecute;
+
+  if (filename != NULL && filename_size > 0) {
+    internal_snprintf(filename,
+                      Min(filename_size, (uptr)PATH_MAX),
+                      "%s", VmEntry->kve_path);
+  }
+
+  current_ += VmEntry->kve_structsize;
+
+  return true;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FREEBSD
diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
index c647765..79ca4df 100644
--- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc
+++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -11,151 +11,20 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_LINUX
 #include "sanitizer_common.h"
-#include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
-#if SANITIZER_FREEBSD
-#include <unistd.h>
-#include <sys/sysctl.h>
-#include <sys/user.h>
-#endif
-
 namespace __sanitizer {
 
-// Linker initialized.
-ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
-StaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
-
-static void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
-#if SANITIZER_FREEBSD
-  const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
-  size_t Size = 0;
-  int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
-  CHECK_EQ(Err, 0);
-  CHECK_GT(Size, 0);
-
-  size_t MmapedSize = Size * 4 / 3;
-  void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
-  Size = MmapedSize;
-  Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
-  CHECK_EQ(Err, 0);
-
-  proc_maps->data = (char*)VmMap;
-  proc_maps->mmaped_size = MmapedSize;
-  proc_maps->len = Size;
-#else
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
   proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
                                     &proc_maps->mmaped_size, 1 << 26);
-#endif
-}
-
-MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
-  ReadProcMaps(&proc_self_maps_);
-  if (cache_enabled) {
-    if (proc_self_maps_.mmaped_size == 0) {
-      LoadFromCache();
-      CHECK_GT(proc_self_maps_.len, 0);
-    }
-  } else {
-    CHECK_GT(proc_self_maps_.mmaped_size, 0);
-  }
-  Reset();
-  // FIXME: in the future we may want to cache the mappings on demand only.
-  if (cache_enabled)
-    CacheMemoryMappings();
-}
-
-MemoryMappingLayout::~MemoryMappingLayout() {
-  // Only unmap the buffer if it is different from the cached one. Otherwise
-  // it will be unmapped when the cache is refreshed.
-  if (proc_self_maps_.data != cached_proc_self_maps_.data) {
-    UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
-  }
-}
-
-void MemoryMappingLayout::Reset() {
-  current_ = proc_self_maps_.data;
-}
-
-// static
-void MemoryMappingLayout::CacheMemoryMappings() {
-  SpinMutexLock l(&cache_lock_);
-  // Don't invalidate the cache if the mappings are unavailable.
-  ProcSelfMapsBuff old_proc_self_maps;
-  old_proc_self_maps = cached_proc_self_maps_;
-  ReadProcMaps(&cached_proc_self_maps_);
-  if (cached_proc_self_maps_.mmaped_size == 0) {
-    cached_proc_self_maps_ = old_proc_self_maps;
-  } else {
-    if (old_proc_self_maps.mmaped_size) {
-      UnmapOrDie(old_proc_self_maps.data,
-                 old_proc_self_maps.mmaped_size);
-    }
-  }
-}
-
-void MemoryMappingLayout::LoadFromCache() {
-  SpinMutexLock l(&cache_lock_);
-  if (cached_proc_self_maps_.data) {
-    proc_self_maps_ = cached_proc_self_maps_;
-  }
-}
-
-#if !SANITIZER_FREEBSD
-// Parse a hex value in str and update str.
-static uptr ParseHex(char **str) {
-  uptr x = 0;
-  char *s;
-  for (s = *str; ; s++) {
-    char c = *s;
-    uptr v = 0;
-    if (c >= '0' && c <= '9')
-      v = c - '0';
-    else if (c >= 'a' && c <= 'f')
-      v = c - 'a' + 10;
-    else if (c >= 'A' && c <= 'F')
-      v = c - 'A' + 10;
-    else
-      break;
-    x = x * 16 + v;
-  }
-  *str = s;
-  return x;
 }
 
 static bool IsOneOf(char c, char c1, char c2) {
   return c == c1 || c == c2;
 }
-#endif
-
-static bool IsDecimal(char c) {
-  return c >= '0' && c <= '9';
-}
-
-static bool IsHex(char c) {
-  return (c >= '0' && c <= '9')
-      || (c >= 'a' && c <= 'f');
-}
-
-static uptr ReadHex(const char *p) {
-  uptr v = 0;
-  for (; IsHex(p[0]); p++) {
-    if (p[0] >= '0' && p[0] <= '9')
-      v = v * 16 + p[0] - '0';
-    else
-      v = v * 16 + p[0] - 'a' + 10;
-  }
-  return v;
-}
-
-static uptr ReadDecimal(const char *p) {
-  uptr v = 0;
-  for (; IsDecimal(p[0]); p++)
-    v = v * 10 + p[0] - '0';
-  return v;
-}
 
 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
                                char filename[], uptr filename_size,
@@ -167,29 +36,6 @@
   if (!end) end = &dummy;
   if (!offset) offset = &dummy;
   if (!protection) protection = &dummy;
-#if SANITIZER_FREEBSD
-  struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
-
-  *start = (uptr)VmEntry->kve_start;
-  *end = (uptr)VmEntry->kve_end;
-  *offset = (uptr)VmEntry->kve_offset;
-
-  *protection = 0;
-  if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
-    *protection |= kProtectionRead;
-  if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
-    *protection |= kProtectionWrite;
-  if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
-    *protection |= kProtectionExecute;
-
-  if (filename != NULL && filename_size > 0) {
-    internal_snprintf(filename,
-                      Min(filename_size, (uptr)PATH_MAX),
-                      "%s", VmEntry->kve_path);
-  }
-
-  current_ += VmEntry->kve_structsize;
-#else  // !SANITIZER_FREEBSD
   char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
   if (next_line == 0)
     next_line = last;
@@ -236,69 +82,9 @@
   if (filename && i < filename_size)
     filename[i] = 0;
   current_ = next_line + 1;
-#endif  // !SANITIZER_FREEBSD
   return true;
 }
 
-uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
-                                            uptr max_modules,
-                                            string_predicate_t filter) {
-  Reset();
-  uptr cur_beg, cur_end, cur_offset, prot;
-  InternalScopedBuffer<char> module_name(kMaxPathLength);
-  uptr n_modules = 0;
-  for (uptr i = 0; n_modules < max_modules &&
-                       Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
-                            module_name.size(), &prot);
-       i++) {
-    const char *cur_name = module_name.data();
-    if (cur_name[0] == '\0')
-      continue;
-    if (filter && !filter(cur_name))
-      continue;
-    void *mem = &modules[n_modules];
-    // Don't subtract 'cur_beg' from the first entry:
-    // * If a binary is compiled w/o -pie, then the first entry in
-    //   process maps is likely the binary itself (all dynamic libs
-    //   are mapped higher in address space). For such a binary,
-    //   instruction offset in binary coincides with the actual
-    //   instruction address in virtual memory (as code section
-    //   is mapped to a fixed memory range).
-    // * If a binary is compiled with -pie, all the modules are
-    //   mapped high at address space (in particular, higher than
-    //   shadow memory of the tool), so the module can't be the
-    //   first entry.
-    uptr base_address = (i ? cur_beg : 0) - cur_offset;
-    LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
-    cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
-    n_modules++;
-  }
-  return n_modules;
-}
-
-void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
-  char *smaps = 0;
-  uptr smaps_cap = 0;
-  uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
-      &smaps, &smaps_cap, 64<<20);
-  uptr start = 0;
-  bool file = false;
-  const char *pos = smaps;
-  while (pos < smaps + smaps_len) {
-    if (IsHex(pos[0])) {
-      start = ReadHex(pos);
-      for (; *pos != '/' && *pos > '\n'; pos++) {}
-      file = *pos == '/';
-    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
-      for (; *pos < '0' || *pos > '9'; pos++) {}
-      uptr rss = ReadDecimal(pos) * 1024;
-      cb(start, rss, file, stats, stats_size);
-    }
-    while (*pos++ != '\n') {}
-  }
-  UnmapOrDie(smaps, smaps_cap);
-}
-
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif  // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc
index 5b70dfc..f10f1f9 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.cc
+++ b/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -18,31 +18,6 @@
 
 namespace __sanitizer {
 
-struct StackDepotDesc {
-  const uptr *stack;
-  uptr size;
-  u32 hash() const {
-    // murmur2
-    const u32 m = 0x5bd1e995;
-    const u32 seed = 0x9747b28c;
-    const u32 r = 24;
-    u32 h = seed ^ (size * sizeof(uptr));
-    for (uptr i = 0; i < size; i++) {
-      u32 k = stack[i];
-      k *= m;
-      k ^= k >> r;
-      k *= m;
-      h *= m;
-      h ^= k;
-    }
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-    return h;
-  }
-  bool is_valid() { return size > 0 && stack; }
-};
-
 struct StackDepotNode {
   StackDepotNode *link;
   u32 id;
@@ -58,28 +33,49 @@
   static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
   static const u32 kHashMask = ~kUseCountMask;
 
-  typedef StackDepotDesc args_type;
+  typedef StackTrace args_type;
   bool eq(u32 hash, const args_type &args) const {
     u32 hash_bits =
         atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
     if ((hash & kHashMask) != hash_bits || args.size != size) return false;
     uptr i = 0;
     for (; i < size; i++) {
-      if (stack[i] != args.stack[i]) return false;
+      if (stack[i] != args.trace[i]) return false;
     }
     return true;
   }
   static uptr storage_size(const args_type &args) {
     return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
   }
+  static u32 hash(const args_type &args) {
+    // murmur2
+    const u32 m = 0x5bd1e995;
+    const u32 seed = 0x9747b28c;
+    const u32 r = 24;
+    u32 h = seed ^ (args.size * sizeof(uptr));
+    for (uptr i = 0; i < args.size; i++) {
+      u32 k = args.trace[i];
+      k *= m;
+      k ^= k >> r;
+      k *= m;
+      h *= m;
+      h ^= k;
+    }
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+    return h;
+  }
+  static bool is_valid(const args_type &args) {
+    return args.size > 0 && args.trace;
+  }
   void store(const args_type &args, u32 hash) {
     atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
     size = args.size;
-    internal_memcpy(stack, args.stack, size * sizeof(uptr));
+    internal_memcpy(stack, args.trace, size * sizeof(uptr));
   }
   args_type load() const {
-    args_type ret = {&stack[0], size};
-    return ret;
+    return args_type(&stack[0], size);
   }
   StackDepotHandle get_handle() { return StackDepotHandle(this); }
 
@@ -99,8 +95,6 @@
       StackDepotNode::kUseCountMask;
   CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
 }
-uptr StackDepotHandle::size() { return node_->size; }
-uptr *StackDepotHandle::stack() { return &node_->stack[0]; }
 
 // FIXME(dvyukov): this single reserved bit is used in TSan.
 typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
@@ -111,21 +105,25 @@
   return theDepot.GetStats();
 }
 
-u32 StackDepotPut(const uptr *stack, uptr size) {
-  StackDepotDesc desc = {stack, size};
-  StackDepotHandle h = theDepot.Put(desc);
+u32 StackDepotPut(StackTrace stack) {
+  StackDepotHandle h = theDepot.Put(stack);
   return h.valid() ? h.id() : 0;
 }
 
-StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) {
-  StackDepotDesc desc = {stack, size};
-  return theDepot.Put(desc);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) {
+  return theDepot.Put(stack);
 }
 
-const uptr *StackDepotGet(u32 id, uptr *size) {
-  StackDepotDesc desc = theDepot.Get(id);
-  *size = desc.size;
-  return desc.stack;
+StackTrace StackDepotGet(u32 id) {
+  return theDepot.Get(id);
+}
+
+void StackDepotLockAll() {
+  theDepot.LockAll();
+}
+
+void StackDepotUnlockAll() {
+  theDepot.UnlockAll();
 }
 
 bool StackDepotReverseMap::IdDescPair::IdComparator(
@@ -148,18 +146,15 @@
   InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
 }
 
-const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
-  if (!map_.size()) return 0;
+StackTrace StackDepotReverseMap::Get(u32 id) {
+  if (!map_.size())
+    return StackTrace();
   IdDescPair pair = {id, 0};
   uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
                                   IdDescPair::IdComparator);
-  if (idx > map_.size()) {
-    *size = 0;
-    return 0;
-  }
-  StackDepotNode *desc = map_[idx].desc;
-  *size = desc->size;
-  return desc->stack;
+  if (idx > map_.size())
+    return StackTrace();
+  return map_[idx].desc->load();
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.h b/lib/sanitizer_common/sanitizer_stackdepot.h
index 58cc91f..5e3a8b7 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -15,6 +15,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_stacktrace.h"
 
 namespace __sanitizer {
 
@@ -28,17 +29,18 @@
   u32 id();
   int use_count();
   void inc_use_count_unsafe();
-  uptr size();
-  uptr *stack();
 };
 
 const int kStackDepotMaxUseCount = 1U << 20;
 
 StackDepotStats *StackDepotGetStats();
-u32 StackDepotPut(const uptr *stack, uptr size);
-StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size);
+u32 StackDepotPut(StackTrace stack);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack);
 // Retrieves a stored stack trace by the id.
-const uptr *StackDepotGet(u32 id, uptr *size);
+StackTrace StackDepotGet(u32 id);
+
+void StackDepotLockAll();
+void StackDepotUnlockAll();
 
 // Instantiating this class creates a snapshot of StackDepot which can be
 // efficiently queried with StackDepotGet(). You can use it concurrently with
@@ -47,7 +49,7 @@
 class StackDepotReverseMap {
  public:
   StackDepotReverseMap();
-  const uptr *Get(u32 id, uptr *size);
+  StackTrace Get(u32 id);
 
  private:
   struct IdDescPair {
diff --git a/lib/sanitizer_common/sanitizer_stackdepotbase.h b/lib/sanitizer_common/sanitizer_stackdepotbase.h
index b4fa875..5de2e71 100644
--- a/lib/sanitizer_common/sanitizer_stackdepotbase.h
+++ b/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -32,6 +32,9 @@
 
   StackDepotStats *GetStats() { return &stats; }
 
+  void LockAll();
+  void UnlockAll();
+
  private:
   static Node *find(Node *s, args_type args, u32 hash);
   static Node *lock(atomic_uintptr_t *p);
@@ -94,8 +97,8 @@
 StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
                                                       bool *inserted) {
   if (inserted) *inserted = false;
-  if (!args.is_valid()) return handle_type();
-  uptr h = args.hash();
+  if (!Node::is_valid(args)) return handle_type();
+  uptr h = Node::hash(args);
   atomic_uintptr_t *p = &tab[h % kTabSize];
   uptr v = atomic_load(p, memory_order_consume);
   Node *s = (Node *)(v & ~1);
@@ -153,5 +156,21 @@
   return args_type();
 }
 
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
+  for (int i = 0; i < kTabSize; ++i) {
+    lock(&tab[i]);
+  }
+}
+
+template <class Node, int kReservedBits, int kTabSizeLog>
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
+  for (int i = 0; i < kTabSize; ++i) {
+    atomic_uintptr_t *p = &tab[i];
+    uptr s = atomic_load(p, memory_order_relaxed);
+    unlock(p, (Node *)(s & ~1UL));
+  }
+}
+
 }  // namespace __sanitizer
 #endif  // SANITIZER_STACKDEPOTBASE_H
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index 3539639..cf061fb 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -25,38 +25,83 @@
 #if defined(__powerpc__) || defined(__powerpc64__)
   // PCs are always 4 byte aligned.
   return pc - 4;
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__mips__)
   return pc - 8;
 #else
   return pc - 1;
 #endif
 }
 
+uptr StackTrace::GetNextInstructionPc(uptr pc) {
+#if defined(__mips__)
+  return pc + 8;
+#else
+  return pc + 1;
+#endif
+}
+
 uptr StackTrace::GetCurrentPc() {
   return GET_CALLER_PC();
 }
 
-void StackTrace::FastUnwindStack(uptr pc, uptr bp,
-                                 uptr stack_top, uptr stack_bottom,
-                                 uptr max_depth) {
+void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+  size = cnt + !!extra_top_pc;
+  CHECK_LE(size, kStackTraceMax);
+  internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+  if (extra_top_pc)
+    trace_buffer[cnt] = extra_top_pc;
+  top_frame_bp = 0;
+}
+
+// Check if given pointer points into allocated stack area.
+static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
+  return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
+}
+
+// In GCC on ARM bp points to saved lr, not fp, so we should check the next
+// cell in stack to be a saved frame pointer. GetCanonicFrame returns the
+// pointer to saved frame pointer in any case.
+static inline uhwptr *GetCanonicFrame(uptr bp,
+                                      uptr stack_top,
+                                      uptr stack_bottom) {
+#ifdef __arm__
+  if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
+  uhwptr *bp_prev = (uhwptr *)bp;
+  if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
+  // The next frame pointer does not look right. This could be a GCC frame, step
+  // back by 1 word and try again.
+  if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom))
+    return bp_prev - 1;
+  // Nope, this does not look right either. This means the frame after next does
+  // not have a valid frame pointer, but we can still extract the caller PC.
+  // Unfortunately, there is no way to decide between GCC and LLVM frame
+  // layouts. Assume LLVM.
+  return bp_prev;
+#else
+  return (uhwptr*)bp;
+#endif
+}
+
+void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
+                                         uptr stack_bottom, uptr max_depth) {
   CHECK_GE(max_depth, 2);
-  trace[0] = pc;
+  trace_buffer[0] = pc;
   size = 1;
-  uhwptr *frame = (uhwptr *)bp;
-  uhwptr *prev_frame = frame - 1;
   if (stack_top < 4096) return;  // Sanity check for stack top.
+  uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
+  // Lowest possible address that makes sense as the next frame pointer.
+  // Goes up as we walk the stack.
+  uptr bottom = stack_bottom;
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
-  while (frame > prev_frame &&
-         frame < (uhwptr *)stack_top - 2 &&
-         frame > (uhwptr *)stack_bottom &&
+  while (IsValidFrame((uptr)frame, stack_top, bottom) &&
          IsAligned((uptr)frame, sizeof(*frame)) &&
          size < max_depth) {
     uhwptr pc1 = frame[1];
     if (pc1 != pc) {
-      trace[size++] = (uptr) pc1;
+      trace_buffer[size++] = (uptr) pc1;
     }
-    prev_frame = frame;
-    frame = (uhwptr *)frame[0];
+    bottom = (uptr)frame;
+    frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom);
   }
 }
 
@@ -64,15 +109,15 @@
   return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
 }
 
-void StackTrace::PopStackFrames(uptr count) {
+void BufferedStackTrace::PopStackFrames(uptr count) {
   CHECK_LT(count, size);
   size -= count;
   for (uptr i = 0; i < size; ++i) {
-    trace[i] = trace[i + count];
+    trace_buffer[i] = trace_buffer[i + count];
   }
 }
 
-uptr StackTrace::LocatePcInTrace(uptr pc) {
+uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
   // Use threshold to find PC in stack trace, as PC we want to unwind from may
   // slightly differ from return address in the actual unwinded stack trace.
   const int kPcThreshold = 288;
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index fcaa777..e755c05 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -29,44 +29,50 @@
 # define SANITIZER_CAN_FAST_UNWIND 1
 #endif
 
+// Fast unwind is the only option on Mac for now; we will need to
+// revisit this macro when slow unwind works on Mac, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+#if SANITIZER_MAC
+# define SANITIZER_CAN_SLOW_UNWIND 0
+#else
+# define SANITIZER_CAN_SLOW_UNWIND 1
+#endif
+
 struct StackTrace {
-  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
-                                     int out_size);
-  uptr top_frame_bp;
+  const uptr *trace;
   uptr size;
-  uptr trace[kStackTraceMax];
+
+  StackTrace() : trace(nullptr), size(0) {}
+  StackTrace(const uptr *trace, uptr size) : trace(trace), size(size) {}
 
   // Prints a symbolized stacktrace, followed by an empty line.
-  static void PrintStack(const uptr *addr, uptr size);
-  void Print() const {
-    PrintStack(trace, size);
-  }
-
-  void CopyFrom(const uptr *src, uptr src_size) {
-    top_frame_bp = 0;
-    size = src_size;
-    if (size > kStackTraceMax) size = kStackTraceMax;
-    for (uptr i = 0; i < size; i++)
-      trace[i] = src[i];
-  }
+  void Print() const;
 
   static bool WillUseFastUnwind(bool request_fast_unwind) {
-    // Check if fast unwind is available. Fast unwind is the only option on Mac.
-    // It is also the only option on FreeBSD as the slow unwinding that
-    // leverages _Unwind_Backtrace() yields the call stack of the signal's
-    // handler and not of the code that raised the signal (as it does on Linux).
     if (!SANITIZER_CAN_FAST_UNWIND)
       return false;
-    else if (SANITIZER_MAC != 0 || SANITIZER_FREEBSD != 0)
+    else if (!SANITIZER_CAN_SLOW_UNWIND)
       return true;
     return request_fast_unwind;
   }
 
-  void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
-              uptr stack_bottom, bool request_fast_unwind);
-
   static uptr GetCurrentPc();
   static uptr GetPreviousInstructionPc(uptr pc);
+  static uptr GetNextInstructionPc(uptr pc);
+  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
+                                    int out_size);
+};
+
+// StackTrace that owns the buffer used to store the addresses.
+struct BufferedStackTrace : public StackTrace {
+  uptr trace_buffer[kStackTraceMax];
+  uptr top_frame_bp;  // Optional bp of a top frame.
+
+  BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
+
+  void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+  void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
+              uptr stack_bottom, bool request_fast_unwind);
 
  private:
   void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
@@ -76,6 +82,9 @@
                                   uptr max_depth);
   void PopStackFrames(uptr count);
   uptr LocatePcInTrace(uptr pc);
+
+  BufferedStackTrace(const BufferedStackTrace &);
+  void operator=(const BufferedStackTrace &);
 };
 
 }  // namespace __sanitizer
@@ -88,6 +97,10 @@
   uptr local_stack;                           \
   uptr sp = (uptr)&local_stack
 
+#define GET_CALLER_PC_BP \
+  uptr bp = GET_CURRENT_FRAME();              \
+  uptr pc = GET_CALLER_PC();
+
 // Use this macro if you want to print stack trace with the current
 // function in the top frame.
 #define GET_CURRENT_PC_BP_SP \
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index c68149d..13fb01f 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -12,58 +12,40 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_stacktrace_printer.h"
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
-                                  uptr pc) {
-  buffer->append("    #%zu 0x%zx", frame_num, pc);
-}
-
-void StackTrace::PrintStack(const uptr *addr, uptr size) {
-  if (addr == 0 || size == 0) {
+void StackTrace::Print() const {
+  if (trace == nullptr || size == 0) {
     Printf("    <empty stack>\n\n");
     return;
   }
-  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
-  InternalScopedBuffer<AddressInfo> addr_frames(64);
+  const int kMaxAddrFrames = 64;
+  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
+  for (uptr i = 0; i < kMaxAddrFrames; i++)
+    new(&addr_frames[i]) AddressInfo();
   InternalScopedString frame_desc(GetPageSizeCached() * 2);
   uptr frame_num = 0;
-  for (uptr i = 0; i < size && addr[i]; i++) {
+  for (uptr i = 0; i < size && trace[i]; i++) {
     // PCs in stack traces are actually the return addresses, that is,
     // addresses of the next instructions after the call.
-    uptr pc = GetPreviousInstructionPc(addr[i]);
+    uptr pc = GetPreviousInstructionPc(trace[i]);
     uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
-        pc, addr_frames.data(), addr_frames.size());
+        pc, addr_frames.data(), kMaxAddrFrames);
     if (addr_frames_num == 0) {
-      frame_desc.clear();
-      PrintStackFramePrefix(&frame_desc, frame_num, pc);
-      frame_desc.append(" (<unknown module>)");
-      Printf("%s\n", frame_desc.data());
-      frame_num++;
-      continue;
+      addr_frames[0].address = pc;
+      addr_frames_num = 1;
     }
     for (uptr j = 0; j < addr_frames_num; j++) {
       AddressInfo &info = addr_frames[j];
       frame_desc.clear();
-      PrintStackFramePrefix(&frame_desc, frame_num, pc);
-      if (info.function) {
-        frame_desc.append(" in %s", info.function);
-        // Print offset in function if we don't know the source file.
-        if (!info.file && info.function_offset != AddressInfo::kUnknown)
-          frame_desc.append("+0x%zx", info.function_offset);
-      }
-      if (info.file) {
-        frame_desc.append(" ");
-        PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
-      } else if (info.module) {
-        frame_desc.append(" ");
-        PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
-      }
+      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
+                  info, common_flags()->strip_path_prefix);
       Printf("%s\n", frame_desc.data());
-      frame_num++;
       info.Clear();
     }
   }
@@ -71,9 +53,9 @@
   Printf("\n");
 }
 
-void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
-                        uptr stack_top, uptr stack_bottom,
-                        bool request_fast_unwind) {
+void BufferedStackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
+                                uptr stack_top, uptr stack_bottom,
+                                bool request_fast_unwind) {
   top_frame_bp = (max_depth > 0) ? bp : 0;
   // Avoid doing any work for small max_depth.
   if (max_depth == 0) {
@@ -82,7 +64,7 @@
   }
   if (max_depth == 1) {
     size = 1;
-    trace[0] = pc;
+    trace_buffer[0] = pc;
     return;
   }
   if (!WillUseFastUnwind(request_fast_unwind)) {
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
new file mode 100644
index 0000000..7b37dbc
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -0,0 +1,132 @@
+//===-- sanitizer_common.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 sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_stacktrace_printer.h"
+
+namespace __sanitizer {
+
+static const char *StripFunctionName(const char *function, const char *prefix) {
+  if (function == 0) return 0;
+  if (prefix == 0) return function;
+  uptr prefix_len = internal_strlen(prefix);
+  if (0 == internal_strncmp(function, prefix, prefix_len))
+    return function + prefix_len;
+  return function;
+}
+
+static const char kDefaultFormat[] = "    #%n %p %F %L";
+
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+                 const AddressInfo &info, const char *strip_path_prefix,
+                 const char *strip_func_prefix) {
+  if (0 == internal_strcmp(format, "DEFAULT"))
+    format = kDefaultFormat;
+  for (const char *p = format; *p != '\0'; p++) {
+    if (*p != '%') {
+      buffer->append("%c", *p);
+      continue;
+    }
+    p++;
+    switch (*p) {
+    case '%':
+      buffer->append("%%");
+      break;
+    // Frame number and all fields of AddressInfo structure.
+    case 'n':
+      buffer->append("%zu", frame_no);
+      break;
+    case 'p':
+      buffer->append("0x%zx", info.address);
+      break;
+    case 'm':
+      buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
+      break;
+    case 'o':
+      buffer->append("0x%zx", info.module_offset);
+      break;
+    case 'f':
+      buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
+      break;
+    case 'q':
+      buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
+                                  ? info.function_offset
+                                  : 0x0);
+      break;
+    case 's':
+      buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
+      break;
+    case 'l':
+      buffer->append("%d", info.line);
+      break;
+    case 'c':
+      buffer->append("%d", info.column);
+      break;
+    // Smarter special cases.
+    case 'F':
+      // Function name and offset, if file is unknown.
+      if (info.function) {
+        buffer->append("in %s",
+                       StripFunctionName(info.function, strip_func_prefix));
+        if (!info.file && info.function_offset != AddressInfo::kUnknown)
+          buffer->append("+0x%zx", info.function_offset);
+      }
+      break;
+    case 'S':
+      // File/line information.
+      RenderSourceLocation(buffer, info.file, info.line, info.column,
+                           strip_path_prefix);
+      break;
+    case 'L':
+      // Source location, or module location.
+      if (info.file) {
+        RenderSourceLocation(buffer, info.file, info.line, info.column,
+                             strip_path_prefix);
+      } else if (info.module) {
+        RenderModuleLocation(buffer, info.module, info.module_offset,
+                             strip_path_prefix);
+      } else {
+        buffer->append("(<unknown module>)");
+      }
+      break;
+    case 'M':
+      // Module basename and offset, or PC.
+      if (info.module)
+        buffer->append("(%s+%p)", StripModuleName(info.module),
+                       (void *)info.module_offset);
+      else
+        buffer->append("(%p)", (void *)info.address);
+      break;
+    default:
+      Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n",
+             *p, *p);
+      Die();
+    }
+  }
+}
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+                          int line, int column, const char *strip_path_prefix) {
+  buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
+  if (line > 0) {
+    buffer->append(":%d", line);
+    if (column > 0)
+      buffer->append(":%d", column);
+  }
+}
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+                          uptr offset, const char *strip_path_prefix) {
+  buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
+                 offset);
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.h b/lib/sanitizer_common/sanitizer_stacktrace_printer.h
new file mode 100644
index 0000000..9356988
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -0,0 +1,62 @@
+//===-- sanitizer_stacktrace_printer.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 sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKTRACE_PRINTER_H
+#define SANITIZER_STACKTRACE_PRINTER_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// Render the contents of "info" structure, which represents the contents of
+// stack frame "frame_no" and appends it to the "buffer". "format" is a
+// string with placeholders, which is copied to the output with
+// placeholders substituted with the contents of "info". For example,
+// format string
+//   "  frame %n: function %F at %S"
+// will be turned into
+//   "  frame 10: function foo::bar() at my/file.cc:10"
+// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
+// source files and modules, and "strip_func_prefix" to strip prefixes of
+// function names.
+// Here's the full list of available placeholders:
+//   %% - represents a '%' character;
+//   %n - frame number (copy of frame_no);
+//   %p - PC in hex format;
+//   %m - path to module (binary or shared object);
+//   %o - offset in the module in hex format;
+//   %f - function name;
+//   %q - offset in the function in hex format (*if available*);
+//   %s - path to source file;
+//   %l - line in the source file;
+//   %c - column in the source file;
+//   %F - if function is known to be <foo>, prints "in <foo>", possibly
+//        followed by the offset in this function, but only if source file
+//        is unknown;
+//   %S - prints file/line/column information;
+//   %L - prints location information: file/line/column, if it is known, or
+//        module+offset if it is known, or (<unknown module>) string.
+//   %M - prints module basename and offset, if it is known, or PC.
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+                 const AddressInfo &info, const char *strip_path_prefix = "",
+                 const char *strip_func_prefix = "");
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+                          int line, int column, const char *strip_path_prefix);
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+                          uptr offset, const char *strip_path_prefix);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_STACKTRACE_PRINTER_H
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
index 87ccf7f..7f76693 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -15,13 +15,15 @@
 
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_placement_new.h"
 
 namespace __sanitizer {
 
 static const char *const kTypeStrings[SuppressionTypeCount] = {
-    "none",   "race", "mutex",           "thread",
-    "signal", "leak", "called_from_lib", "deadlock"};
+    "none", "race",            "mutex",    "thread",    "signal",
+    "leak", "called_from_lib", "deadlock", "vptr_check"};
 
 bool TemplateMatch(char *templ, const char *str) {
   if (str == 0 || str[0] == 0)
@@ -65,6 +67,33 @@
   return true;
 }
 
+ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
+static SuppressionContext *suppression_ctx = 0;
+
+SuppressionContext *SuppressionContext::Get() {
+  CHECK(suppression_ctx);
+  return suppression_ctx;
+}
+
+void SuppressionContext::InitIfNecessary() {
+  if (suppression_ctx)
+    return;
+  suppression_ctx = new(placeholder) SuppressionContext;
+  if (common_flags()->suppressions[0] == '\0')
+    return;
+  char *suppressions_from_file;
+  uptr buffer_size;
+  uptr contents_size =
+      ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
+                       &buffer_size, 1 << 26 /* max_len */);
+  if (contents_size == 0) {
+    Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
+           common_flags()->suppressions);
+    Die();
+  }
+  suppression_ctx->Parse(suppressions_from_file);
+}
+
 bool SuppressionContext::Match(const char *str, SuppressionType type,
                                Suppression **s) {
   can_parse_ = false;
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
index 772b9aa..37fd3c4 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -27,6 +27,7 @@
   SuppressionLeak,
   SuppressionLib,
   SuppressionDeadlock,
+  SuppressionVptrCheck,
   SuppressionTypeCount
 };
 
@@ -39,14 +40,21 @@
 
 class SuppressionContext {
  public:
-  SuppressionContext() : suppressions_(1), can_parse_(true) {}
   void Parse(const char *str);
   bool Match(const char* str, SuppressionType type, Suppression **s);
   uptr SuppressionCount() const;
   const Suppression *SuppressionAt(uptr i) const;
   void GetMatched(InternalMmapVector<Suppression *> *matched);
 
+  // Create a SuppressionContext singleton if it hasn't been created earlier.
+  // Not thread safe. Must be called early during initialization (but after
+  // runtime flags are parsed).
+  static void InitIfNecessary();
+  // Returns a SuppressionContext singleton.
+  static SuppressionContext *Get();
+
  private:
+  SuppressionContext() : suppressions_(1), can_parse_(true) {}
   InternalMmapVector<Suppression> suppressions_;
   bool can_parse_;
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc
index 2290767..8aa9de0 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer.cc
@@ -22,17 +22,6 @@
 StaticSpinMutex Symbolizer::init_mu_;
 LowLevelAllocator Symbolizer::symbolizer_allocator_;
 
-Symbolizer *Symbolizer::GetOrNull() {
-  SpinMutexLock l(&init_mu_);
-  return symbolizer_;
-}
-
-Symbolizer *Symbolizer::Get() {
-  SpinMutexLock l(&init_mu_);
-  RAW_CHECK_MSG(symbolizer_ != 0, "Using uninitialized symbolizer!");
-  return symbolizer_;
-}
-
 Symbolizer *Symbolizer::Disable() {
   CHECK_EQ(0, symbolizer_);
   // Initialize a dummy symbolizer.
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 7057a89..82093e4 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -61,31 +61,30 @@
   }
 };
 
+// For now, DataInfo is used to describe global variable.
 struct DataInfo {
-  uptr address;
   char *module;
   uptr module_offset;
   char *name;
   uptr start;
   uptr size;
+
+  DataInfo() {
+    internal_memset(this, 0, sizeof(DataInfo));
+  }
+
+  void Clear() {
+    InternalFree(module);
+    InternalFree(name);
+    internal_memset(this, 0, sizeof(DataInfo));
+  }
 };
 
 class Symbolizer {
  public:
-  /// Returns platform-specific implementation of Symbolizer. The symbolizer
-  /// must be initialized (with init or disable) before calling this function.
-  static Symbolizer *Get();
-  /// Returns platform-specific implementation of Symbolizer, or null if not
-  /// initialized.
-  static Symbolizer *GetOrNull();
-  /// Returns platform-specific implementation of Symbolizer.  Will
-  /// automatically initialize symbolizer as if by calling Init(0) if needed.
+  /// Initialize and return platform-specific implementation of symbolizer
+  /// (if it wasn't already initialized).
   static Symbolizer *GetOrInit();
-  /// Initialize and return the symbolizer, given an optional path to an
-  /// external symbolizer.  The path argument is only required for legacy
-  /// reasons as this function will check $PATH for an external symbolizer.  Not
-  /// thread safe.
-  static Symbolizer *Init(const char* path_to_external = 0);
   // Fills at most "max_frames" elements of "frames" with descriptions
   // for a given address (in all inlined functions). Returns the number
   // of descriptions actually filled.
@@ -122,10 +121,7 @@
 
  private:
   /// Platform-specific function for creating a Symbolizer object.
-  static Symbolizer *PlatformInit(const char *path_to_external);
-  /// Create a symbolizer and store it to symbolizer_ without checking if one
-  /// already exists.  Not thread safe.
-  static Symbolizer *CreateAndStore(const char *path_to_external);
+  static Symbolizer *PlatformInit();
   /// Initialize the symbolizer in a disabled state.  Not thread safe.
   static Symbolizer *Disable();
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index b431e51..63c9356 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -16,24 +16,13 @@
 
 namespace __sanitizer {
 
-Symbolizer *Symbolizer::CreateAndStore(const char *path_to_external) {
-  Symbolizer *platform_symbolizer = PlatformInit(path_to_external);
-  if (!platform_symbolizer)
-    return Disable();
-  symbolizer_ = platform_symbolizer;
-  return platform_symbolizer;
-}
-
-Symbolizer *Symbolizer::Init(const char *path_to_external) {
-  CHECK_EQ(0, symbolizer_);
-  return CreateAndStore(path_to_external);
-}
-
 Symbolizer *Symbolizer::GetOrInit() {
   SpinMutexLock l(&init_mu_);
-  if (symbolizer_ == 0)
-    return CreateAndStore(0);
-  return symbolizer_;
+  if (symbolizer_)
+    return symbolizer_;
+  if ((symbolizer_ = PlatformInit()))
+    return symbolizer_;
+  return Disable();
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index ddb9e17..eb2b707 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -341,12 +341,19 @@
     const char* const kSymbolizerArch = "--default-arch=x86_64";
 #elif defined(__i386__)
     const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__)
+#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
     const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+    const char* const kSymbolizerArch = "--default-arch=powerpc64le";
 #else
     const char* const kSymbolizerArch = "--default-arch=unknown";
 #endif
-    execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0);
+
+    const char *const inline_flag = common_flags()->symbolize_inline_frames
+                                        ? "--inlining=true"
+                                        : "--inlining=false";
+    execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch,
+          (char *)0);
   }
 };
 
@@ -582,8 +589,7 @@
       return false;
     const char *module_name = module->full_name();
     uptr module_offset = addr - module->base_address();
-    internal_memset(info, 0, sizeof(*info));
-    info->address = addr;
+    info->Clear();
     info->module = internal_strdup(module_name);
     info->module_offset = module_offset;
     // First, try to use libbacktrace symbolizer (if it's available).
@@ -716,7 +722,7 @@
   LibbacktraceSymbolizer *libbacktrace_symbolizer_;   // Leaked.
 };
 
-Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+Symbolizer *Symbolizer::PlatformInit() {
   if (!common_flags()->symbolize) {
     return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
   }
@@ -729,6 +735,7 @@
     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 {
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index dc4816b..e8cf0a8 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -32,11 +32,22 @@
 
     BlockingMutexLock l(&dbghelp_mu_);
     if (!initialized_) {
-      SymSetOptions(SYMOPT_DEFERRED_LOADS |
-                    SYMOPT_UNDNAME |
-                    SYMOPT_LOAD_LINES);
-      CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
-      // FIXME: We don't call SymCleanup() on exit yet - should we?
+      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;
     }
 
@@ -92,13 +103,19 @@
   // FIXME: Implement GetModuleNameAndOffsetForPC().
 
  private:
+  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_;
 };
 
-Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+Symbolizer *Symbolizer::PlatformInit() {
   static bool called_once = false;
   CHECK(!called_once && "Shouldn't create more than one symbolizer");
   called_once = true;
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index ed2c601..2ec92ff 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -218,7 +218,7 @@
   }
 }
 
-void ThreadRegistry::DetachThread(u32 tid) {
+void ThreadRegistry::DetachThread(u32 tid, void *arg) {
   BlockingMutexLock l(&mtx_);
   CHECK_LT(tid, n_contexts_);
   ThreadContextBase *tctx = threads_[tid];
@@ -227,6 +227,7 @@
     Report("%s: Detach of non-existent thread\n", SanitizerToolName);
     return;
   }
+  tctx->OnDetached(arg);
   if (tctx->status == ThreadStatusFinished) {
     tctx->SetDead();
     QuarantinePush(tctx);
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index 8bb7ff3..5d9c3b9 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -68,6 +68,7 @@
   virtual void OnStarted(void *arg) {}
   virtual void OnCreated(void *arg) {}
   virtual void OnReset() {}
+  virtual void OnDetached(void *arg) {}
 };
 
 typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
@@ -110,7 +111,7 @@
 
   void SetThreadName(u32 tid, const char *name);
   void SetThreadNameByUserId(uptr user_id, const char *name);
-  void DetachThread(u32 tid);
+  void DetachThread(u32 tid, void *arg);
   void JoinThread(u32 tid, void *arg);
   void FinishThread(u32 tid);
   void StartThread(u32 tid, uptr os_id, void *arg);
diff --git a/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
new file mode 100644
index 0000000..a98e617
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
@@ -0,0 +1,158 @@
+//===-- sanitizer_unwind_posix.cc ----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the unwind.h-based (aka "slow") stack unwinding routines
+// available to the tools on Linux, Android, FreeBSD and OS X.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_POSIX
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace.h"
+
+#if SANITIZER_ANDROID
+#include <dlfcn.h>  // for dlopen()
+#endif
+
+#if SANITIZER_FREEBSD
+#define _GNU_SOURCE  // to declare _Unwind_Backtrace() from <unwind.h>
+#endif
+#include <unwind.h>
+
+namespace __sanitizer {
+
+//------------------------- SlowUnwindStack -----------------------------------
+
+typedef struct {
+  uptr absolute_pc;
+  uptr stack_top;
+  uptr stack_size;
+} backtrace_frame_t;
+
+extern "C" {
+typedef void *(*acquire_my_map_info_list_func)();
+typedef void (*release_my_map_info_list_func)(void *map);
+typedef sptr (*unwind_backtrace_signal_arch_func)(
+    void *siginfo, void *sigcontext, void *map_info_list,
+    backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
+acquire_my_map_info_list_func acquire_my_map_info_list;
+release_my_map_info_list_func release_my_map_info_list;
+unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
+} // extern "C"
+
+#if SANITIZER_ANDROID
+void SanitizerInitializeUnwinder() {
+  void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
+  if (!p) {
+    VReport(1,
+            "Failed to open libcorkscrew.so. You may see broken stack traces "
+            "in SEGV reports.");
+    return;
+  }
+  acquire_my_map_info_list =
+      (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
+  release_my_map_info_list =
+      (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
+  unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
+      p, "unwind_backtrace_signal_arch");
+  if (!acquire_my_map_info_list || !release_my_map_info_list ||
+      !unwind_backtrace_signal_arch) {
+    VReport(1,
+            "Failed to find one of the required symbols in libcorkscrew.so. "
+            "You may see broken stack traces in SEGV reports.");
+    acquire_my_map_info_list = 0;
+    unwind_backtrace_signal_arch = 0;
+    release_my_map_info_list = 0;
+  }
+}
+#endif
+
+#ifdef __arm__
+#define UNWIND_STOP _URC_END_OF_STACK
+#define UNWIND_CONTINUE _URC_NO_REASON
+#else
+#define UNWIND_STOP _URC_NORMAL_STOP
+#define UNWIND_CONTINUE _URC_NO_REASON
+#endif
+
+uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
+#ifdef __arm__
+  uptr val;
+  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
+      15 /* r15 = PC */, _UVRSD_UINT32, &val);
+  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
+  // Clear the Thumb bit.
+  return val & ~(uptr)1;
+#else
+  return _Unwind_GetIP(ctx);
+#endif
+}
+
+struct UnwindTraceArg {
+  BufferedStackTrace *stack;
+  uptr max_depth;
+};
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+  UnwindTraceArg *arg = (UnwindTraceArg*)param;
+  CHECK_LT(arg->stack->size, arg->max_depth);
+  uptr pc = Unwind_GetIP(ctx);
+  arg->stack->trace_buffer[arg->stack->size++] = pc;
+  if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
+  return UNWIND_CONTINUE;
+}
+
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+  CHECK_GE(max_depth, 2);
+  size = 0;
+  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+  _Unwind_Backtrace(Unwind_Trace, &arg);
+  // We need to pop a few frames so that pc is on top.
+  uptr to_pop = LocatePcInTrace(pc);
+  // trace_buffer[0] belongs to the current function so we always pop it,
+  // unless there is only 1 frame in the stack trace (1 frame is always better
+  // than 0!).
+  // 1-frame stacks don't normally happen, but this depends on the actual
+  // unwinder implementation (libgcc, libunwind, etc) which is outside of our
+  // control.
+  if (to_pop == 0 && size > 1)
+    to_pop = 1;
+  PopStackFrames(to_pop);
+  trace_buffer[0] = pc;
+}
+
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+                                                    uptr max_depth) {
+  CHECK_GE(max_depth, 2);
+  if (!unwind_backtrace_signal_arch) {
+    SlowUnwindStack(pc, max_depth);
+    return;
+  }
+
+  void *map = acquire_my_map_info_list();
+  CHECK(map);
+  InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax);
+  // siginfo argument appears to be unused.
+  sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
+                                          frames.data(),
+                                          /* ignore_depth */ 0, max_depth);
+  release_my_map_info_list(map);
+  if (res < 0) return;
+  CHECK_LE((uptr)res, kStackTraceMax);
+
+  size = 0;
+  // +2 compensate for libcorkscrew unwinder returning addresses of call
+  // instructions instead of raw return addresses.
+  for (sptr i = 0; i < res; ++i)
+    trace_buffer[size++] = frames[i].absolute_pc + 2;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index da24df6..2f9b158 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -17,9 +17,10 @@
 
 #define WIN32_LEAN_AND_MEAN
 #define NOGDI
-#include <stdlib.h>
-#include <io.h>
 #include <windows.h>
+#include <dbghelp.h>
+#include <io.h>
+#include <stdlib.h>
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
@@ -64,6 +65,7 @@
   return GetTid();
 }
 
+#if !SANITIZER_GO
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom) {
   CHECK(stack_top);
@@ -76,6 +78,7 @@
   *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
   *stack_bottom = (uptr)mbi.AllocationBase;
 }
+#endif  // #if !SANITIZER_GO
 
 void *MmapOrDie(uptr size, const char *mem_type) {
   void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
@@ -188,7 +191,7 @@
   UNIMPLEMENTED();
 }
 
-void DisableCoreDumper() {
+void DisableCoreDumperIfNecessary() {
   // Do nothing.
 }
 
@@ -209,6 +212,14 @@
   UNIMPLEMENTED();
 }
 
+bool AddressSpaceIsUnlimited() {
+  UNIMPLEMENTED();
+}
+
+void SetAddressSpaceUnlimited() {
+  UNIMPLEMENTED();
+}
+
 char *FindPathToBinary(const char *name) {
   // Nothing here for now.
   return 0;
@@ -432,7 +443,8 @@
 #endif
 }
 
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+#if !SANITIZER_GO
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
   CHECK_GE(max_depth, 2);
   // FIXME: CaptureStackBackTrace might be too slow for us.
   // FIXME: Compare with StackWalk64.
@@ -447,10 +459,34 @@
   PopStackFrames(pc_location);
 }
 
-void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
-                                            uptr max_depth) {
-  UNREACHABLE("no signal context on windows");
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+                                                    uptr max_depth) {
+  CONTEXT ctx = *(CONTEXT *)context;
+  STACKFRAME64 stack_frame;
+  memset(&stack_frame, 0, sizeof(stack_frame));
+  size = 0;
+#if defined(_WIN64)
+  int machine_type = IMAGE_FILE_MACHINE_AMD64;
+  stack_frame.AddrPC.Offset = ctx.Rip;
+  stack_frame.AddrFrame.Offset = ctx.Rbp;
+  stack_frame.AddrStack.Offset = ctx.Rsp;
+#else
+  int machine_type = IMAGE_FILE_MACHINE_I386;
+  stack_frame.AddrPC.Offset = ctx.Eip;
+  stack_frame.AddrFrame.Offset = ctx.Ebp;
+  stack_frame.AddrStack.Offset = ctx.Esp;
+#endif
+  stack_frame.AddrPC.Mode = AddrModeFlat;
+  stack_frame.AddrFrame.Mode = AddrModeFlat;
+  stack_frame.AddrStack.Mode = AddrModeFlat;
+  while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
+                     &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
+                     &SymGetModuleBase64, NULL) &&
+         size < Min(max_depth, kStackTraceMax)) {
+    trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
+  }
 }
+#endif  // #if !SANITIZER_GO
 
 void MaybeOpenReportFile() {
   // Windows doesn't have native fork, and we don't support Cygwin or other
@@ -486,6 +522,11 @@
   return false;
 }
 
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+  // FIXME: Actually implement this function.
+  return true;
+}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 33ab883..267273d 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -1,9 +1,9 @@
-#!/usr/bin/env bash
+#!/bin/sh
 
 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
 
 # Guess path to LLVM_CHECKOUT if not provided
-if [ "${LLVM_CHECKOUT}" == "" ]; then
+if [ "${LLVM_CHECKOUT}" = "" ]; then
   LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
 fi
 
@@ -29,7 +29,7 @@
 MSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
-DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references
+DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references,-readability/function
 COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf,-readability/fn_size
 SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
 MKTEMP="mktemp -q /tmp/tmp.XXXXXXXXXX"
@@ -47,7 +47,7 @@
     cat $TASK_LOG | grep -v "Done processing" | grep -v "Total errors found" \
       | grep -v "Skipping input" >> $ERROR_LOG
   fi
-  if [[ "${SILENT}" != "1" ]]; then
+  if [ "${SILENT}" != "1" ]; then
     cat $TASK_LOG
   fi
   ${LITLINT} "$@" 2>>$ERROR_LOG
@@ -56,7 +56,7 @@
 run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
   lib/Transforms/Instrumentation/*Sanitizer.cpp &
 
-if [ "${COMPILER_RT}" == "" ]; then
+if [ "${COMPILER_RT}" = "" ]; then
   COMPILER_RT=projects/compiler-rt
 fi
 LIT_TESTS=${COMPILER_RT}/test
@@ -66,38 +66,47 @@
 
 # Sanitizer_common
 COMMON_RTL=${COMPILER_RT}/lib/sanitizer_common
-run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.{cc,h} \
+run_lint ${COMMON_RTL_INC_LINT_FILTER} ${COMMON_RTL}/*.cc \
+                                       ${COMMON_RTL}/*.h \
                                        ${COMMON_RTL}/tests/*.cc &
 
 # Interception
 INTERCEPTION=${COMPILER_RT}/lib/interception
-run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.{cc,h} &
+run_lint ${ASAN_RTL_LINT_FILTER} ${INTERCEPTION}/*.cc \
+                                 ${INTERCEPTION}/*.h &
 
 # ASan
 ASAN_RTL=${COMPILER_RT}/lib/asan
-run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.{cc,h} &
-run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.{cc,h} &
+run_lint ${ASAN_RTL_LINT_FILTER} ${ASAN_RTL}/*.cc \
+                                 ${ASAN_RTL}/*.h &
+run_lint ${ASAN_TEST_LINT_FILTER} ${ASAN_RTL}/tests/*.cc \
+                                  ${ASAN_RTL}/tests/*.h &
 run_lint ${ASAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/asan/*/*.cc &
 
 # TSan
 TSAN_RTL=${COMPILER_RT}/lib/tsan
-run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.{cc,h} &
-run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.{cc,h} \
+run_lint ${TSAN_RTL_LINT_FILTER} ${TSAN_RTL}/rtl/*.cc \
+                                 ${TSAN_RTL}/rtl/*.h &
+run_lint ${TSAN_TEST_LINT_FILTER} ${TSAN_RTL}/tests/rtl/*.cc \
+                                  ${TSAN_RTL}/tests/rtl/*.h \
                                   ${TSAN_RTL}/tests/unit/*.cc &
 run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/tsan/*.cc &
 
 # MSan
 MSAN_RTL=${COMPILER_RT}/lib/msan
-run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.{cc,h} &
+run_lint ${MSAN_RTL_LINT_FILTER} ${MSAN_RTL}/*.cc \
+                                 ${MSAN_RTL}/*.h &
 
 # LSan
 LSAN_RTL=${COMPILER_RT}/lib/lsan
-run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,h}
+run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.cc \
+                                 ${LSAN_RTL}/*.h &
 run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/lsan/*/*.cc &
 
 # DFSan
 DFSAN_RTL=${COMPILER_RT}/lib/dfsan
-run_lint ${DFSAN_RTL_LINT_FILTER} ${DFSAN_RTL}/*.{cc,h} &
+run_lint ${DFSAN_RTL_LINT_FILTER} ${DFSAN_RTL}/*.cc \
+                                  ${DFSAN_RTL}/*.h &
 ${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
 
 # Misc files
@@ -116,7 +125,7 @@
   rm -f $temp
 done
 
-if [[ -s $ERROR_LOG ]]; then
+if [ -s $ERROR_LOG ]; then
   cat $ERROR_LOG
   exit 1
 fi
diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py
index fdc442a..7bab230 100755
--- a/lib/sanitizer_common/scripts/gen_dynamic_list.py
+++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py
@@ -38,9 +38,13 @@
   nm_out = nm_proc.communicate()[0].decode().split('\n')
   if nm_proc.returncode != 0:
     raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
+  func_symbols = ['T', 'W']
+  # On PowerPC, nm prints function descriptors from .data section.
+  if os.uname()[4] in ["powerpc", "ppc64"]:
+    func_symbols += ['D']
   for line in nm_out:
     cols = line.split(' ')
-    if (len(cols) == 3 and cols[1] in ('T', 'W')) :
+    if len(cols) == 3 and cols[1] in func_symbols :
       functions.append(cols[2])
   return functions
 
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index cbc0c25..bb7a399 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -1,5 +1,7 @@
 include(CompilerRTCompile)
 
+clang_compiler_add_cxx_check()
+
 set(SANITIZER_UNITTESTS
   sanitizer_allocator_test.cc
   sanitizer_atomic_test.cc
@@ -19,6 +21,7 @@
   sanitizer_printf_test.cc
   sanitizer_procmaps_test.cc
   sanitizer_stackdepot_test.cc
+  sanitizer_stacktrace_printer_test.cc
   sanitizer_stacktrace_test.cc
   sanitizer_stoptheworld_test.cc
   sanitizer_suppressions_test.cc
@@ -55,8 +58,13 @@
   list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON --driver-mode=g++)
 endif()
 
-append_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON)
-append_if(COMPILER_RT_HAS_LIBPTHREAD -pthread SANITIZER_TEST_LINK_FLAGS_COMMON)
+set(SANITIZER_TEST_LINK_LIBS)
+append_list_if(ANDROID log SANITIZER_TEST_LINK_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS)
+
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread SANITIZER_TEST_LINK_FLAGS_COMMON)
 # x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also,
 # 'libm' shall be specified explicitly to build i386 tests.
 if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
@@ -141,7 +149,7 @@
   endif()
 endmacro()
 
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
   # We use just-built clang to build sanitizer_common unittests, so we must
   # be sure that produced binaries would work.
   if(APPLE)
@@ -170,20 +178,21 @@
 endif()
 
 if(ANDROID)
-  # We assume that unit tests on Android are built in a build
-  # tree with fresh Clang as a host compiler.
-  add_executable(SanitizerTest
-    ${SANITIZER_UNITTESTS}
-    ${COMPILER_RT_GTEST_SOURCE}
-    $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
-  set_target_compile_flags(SanitizerTest
-    ${SANITIZER_COMMON_CFLAGS}
-    ${SANITIZER_TEST_CFLAGS_COMMON})
-  # Setup correct output directory and link flags.
-  set_target_properties(SanitizerTest PROPERTIES
-    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-  set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
-  target_link_libraries(SanitizerTest log)
-  # Add unit test to test suite.
-  add_dependencies(SanitizerUnitTests SanitizerTest)
+  foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
+    add_executable(SanitizerTest
+      ${SANITIZER_UNITTESTS}
+      ${COMPILER_RT_GTEST_SOURCE}
+      $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+    set_target_compile_flags(SanitizerTest
+      ${SANITIZER_COMMON_CFLAGS}
+      ${SANITIZER_TEST_CFLAGS_COMMON})
+    # Setup correct output directory and link flags.
+    set_target_properties(SanitizerTest PROPERTIES
+      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+    set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
+    target_link_libraries(SanitizerTest ${SANITIZER_TEST_LINK_LIBS})
+    # Add unit test to test suite.
+    add_dependencies(SanitizerUnitTests SanitizerTest)
+  endforeach()
 endif()
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index 4340f37..f61d58d 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -629,9 +629,9 @@
   }
 }
 
-TEST(Allocator, InternalAllocFailure) {
-  EXPECT_DEATH(Ident(InternalAlloc(10 << 20)),
-               "Unexpected mmap in InternalAllocator!");
+TEST(Allocator, LargeAlloc) {
+  void *p = InternalAlloc(10 << 20);
+  InternalFree(p);
 }
 
 TEST(Allocator, ScopedBuffer) {
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 8dcecaf..e08a38c 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -226,40 +226,4 @@
   EXPECT_STREQ("012345678", str.data());
 }
 
-TEST(SanitizerCommon, PrintSourceLocation) {
-  InternalScopedString str(128);
-  PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
-  EXPECT_STREQ("/dir/file.cc:10:5", str.data());
-
-  str.clear();
-  PrintSourceLocation(&str, "/dir/file.cc", 11, 0);
-  EXPECT_STREQ("/dir/file.cc:11", str.data());
-
-  str.clear();
-  PrintSourceLocation(&str, "/dir/file.cc", 0, 0);
-  EXPECT_STREQ("/dir/file.cc", str.data());
-
-  // Check that we strip file prefix if necessary.
-  const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
-  common_flags()->strip_path_prefix = "/dir/";
-  str.clear();
-  PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
-  EXPECT_STREQ("file.cc:10:5", str.data());
-  common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
-TEST(SanitizerCommon, PrintModuleAndOffset) {
-  InternalScopedString str(128);
-  PrintModuleAndOffset(&str, "/dir/exe", 0x123);
-  EXPECT_STREQ("(/dir/exe+0x123)", str.data());
-
-  // Check that we strip file prefix if necessary.
-  const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
-  common_flags()->strip_path_prefix = "/dir/";
-  str.clear();
-  PrintModuleAndOffset(&str, "/dir/exe", 0x123);
-  EXPECT_STREQ("(exe+0x123)", str.data());
-  common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
index 035899c..56ce416 100644
--- a/lib/sanitizer_common/tests/sanitizer_posix_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
@@ -18,6 +18,7 @@
 #include "gtest/gtest.h"
 
 #include <pthread.h>
+#include <sys/mman.h>
 
 namespace __sanitizer {
 
@@ -57,6 +58,23 @@
   EXPECT_FALSE(destructor_executed);
 }
 
+TEST(SanitizerCommon, IsAccessibleMemoryRange) {
+  const int page_size = GetPageSize();
+  uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANON, -1, 0);
+  // Protect the middle page.
+  mprotect((void *)(mem + page_size), page_size, PROT_NONE);
+  EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1));
+  EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size));
+  EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1));
+  EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1));
+  EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2));
+  EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1));
+  EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size));
+  EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size));
+  EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2));
+}
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
index 5c075d5..513432f 100644
--- a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
@@ -18,74 +18,75 @@
 namespace __sanitizer {
 
 TEST(SanitizerCommon, StackDepotBasic) {
-  uptr s1[] = {1, 2, 3, 4, 5};
-  u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
-  uptr sz1 = 0;
-  const uptr *sp1 = StackDepotGet(i1, &sz1);
-  EXPECT_NE(sp1, (uptr*)0);
-  EXPECT_EQ(sz1, ARRAY_SIZE(s1));
-  EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+  uptr array[] = {1, 2, 3, 4, 5};
+  StackTrace s1(array, ARRAY_SIZE(array));
+  u32 i1 = StackDepotPut(s1);
+  StackTrace stack = StackDepotGet(i1);
+  EXPECT_NE(stack.trace, (uptr*)0);
+  EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+  EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
 }
 
 TEST(SanitizerCommon, StackDepotAbsent) {
-  uptr sz1 = 0;
-  const uptr *sp1 = StackDepotGet((1 << 30) - 1, &sz1);
-  EXPECT_EQ(sp1, (uptr*)0);
+  StackTrace stack = StackDepotGet((1 << 30) - 1);
+  EXPECT_EQ((uptr*)0, stack.trace);
 }
 
 TEST(SanitizerCommon, StackDepotEmptyStack) {
-  u32 i1 = StackDepotPut(0, 0);
-  uptr sz1 = 0;
-  const uptr *sp1 = StackDepotGet(i1, &sz1);
-  EXPECT_EQ(sp1, (uptr*)0);
+  u32 i1 = StackDepotPut(StackTrace());
+  StackTrace stack = StackDepotGet(i1);
+  EXPECT_EQ((uptr*)0, stack.trace);
 }
 
 TEST(SanitizerCommon, StackDepotZeroId) {
-  uptr sz1 = 0;
-  const uptr *sp1 = StackDepotGet(0, &sz1);
-  EXPECT_EQ(sp1, (uptr*)0);
+  StackTrace stack = StackDepotGet(0);
+  EXPECT_EQ((uptr*)0, stack.trace);
 }
 
 TEST(SanitizerCommon, StackDepotSame) {
-  uptr s1[] = {1, 2, 3, 4, 6};
-  u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
-  u32 i2 = StackDepotPut(s1, ARRAY_SIZE(s1));
+  uptr array[] = {1, 2, 3, 4, 6};
+  StackTrace s1(array, ARRAY_SIZE(array));
+  u32 i1 = StackDepotPut(s1);
+  u32 i2 = StackDepotPut(s1);
   EXPECT_EQ(i1, i2);
-  uptr sz1 = 0;
-  const uptr *sp1 = StackDepotGet(i1, &sz1);
-  EXPECT_NE(sp1, (uptr*)0);
-  EXPECT_EQ(sz1, ARRAY_SIZE(s1));
-  EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+  StackTrace stack = StackDepotGet(i1);
+  EXPECT_NE(stack.trace, (uptr*)0);
+  EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+  EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
 }
 
 TEST(SanitizerCommon, StackDepotSeveral) {
-  uptr s1[] = {1, 2, 3, 4, 7};
-  u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
-  uptr s2[] = {1, 2, 3, 4, 8, 9};
-  u32 i2 = StackDepotPut(s2, ARRAY_SIZE(s2));
+  uptr array1[] = {1, 2, 3, 4, 7};
+  StackTrace s1(array1, ARRAY_SIZE(array1));
+  u32 i1 = StackDepotPut(s1);
+  uptr array2[] = {1, 2, 3, 4, 8, 9};
+  StackTrace s2(array2, ARRAY_SIZE(array2));
+  u32 i2 = StackDepotPut(s2);
   EXPECT_NE(i1, i2);
 }
 
 TEST(SanitizerCommon, StackDepotReverseMap) {
-  uptr s1[] = {1, 2, 3, 4, 5};
-  uptr s2[] = {7, 1, 3, 0};
-  uptr s3[] = {10, 2, 5, 3};
-  uptr s4[] = {1, 3, 2, 5};
+  uptr array1[] = {1, 2, 3, 4, 5};
+  uptr array2[] = {7, 1, 3, 0};
+  uptr array3[] = {10, 2, 5, 3};
+  uptr array4[] = {1, 3, 2, 5};
   u32 ids[4] = {0};
-  ids[0] = StackDepotPut(s1, ARRAY_SIZE(s1));
-  ids[1] = StackDepotPut(s2, ARRAY_SIZE(s2));
-  ids[2] = StackDepotPut(s3, ARRAY_SIZE(s3));
-  ids[3] = StackDepotPut(s4, ARRAY_SIZE(s4));
+  StackTrace s1(array1, ARRAY_SIZE(array1));
+  StackTrace s2(array2, ARRAY_SIZE(array2));
+  StackTrace s3(array3, ARRAY_SIZE(array3));
+  StackTrace s4(array4, ARRAY_SIZE(array4));
+  ids[0] = StackDepotPut(s1);
+  ids[1] = StackDepotPut(s2);
+  ids[2] = StackDepotPut(s3);
+  ids[3] = StackDepotPut(s4);
 
   StackDepotReverseMap map;
 
   for (uptr i = 0; i < 4; i++) {
-    uptr sz_depot, sz_map;
-    const uptr *sp_depot, *sp_map;
-    sp_depot = StackDepotGet(ids[i], &sz_depot);
-    sp_map = map.Get(ids[i], &sz_map);
-    EXPECT_EQ(sz_depot, sz_map);
-    EXPECT_EQ(sp_depot, sp_map);
+    StackTrace stack = StackDepotGet(ids[i]);
+    StackTrace from_map = map.Get(ids[i]);
+    EXPECT_EQ(stack.size, from_map.size);
+    EXPECT_EQ(stack.trace, from_map.trace);
   }
 }
 
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
new file mode 100644
index 0000000..cc9a9ed
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
@@ -0,0 +1,122 @@
+//===-- sanitizer_common_printer_test.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 a part of sanitizer_common test suite.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
+  InternalScopedString str(128);
+  RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "");
+  EXPECT_STREQ("/dir/file.cc:10:5", str.data());
+
+  str.clear();
+  RenderSourceLocation(&str, "/dir/file.cc", 11, 0, "");
+  EXPECT_STREQ("/dir/file.cc:11", str.data());
+
+  str.clear();
+  RenderSourceLocation(&str, "/dir/file.cc", 0, 0, "");
+  EXPECT_STREQ("/dir/file.cc", str.data());
+
+  str.clear();
+  RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "/dir/");
+  EXPECT_STREQ("file.cc:10:5", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
+  InternalScopedString str(128);
+  RenderModuleLocation(&str, "/dir/exe", 0x123, "");
+  EXPECT_STREQ("(/dir/exe+0x123)", str.data());
+
+  // Check that we strip file prefix if necessary.
+  str.clear();
+  RenderModuleLocation(&str, "/dir/exe", 0x123, "/dir/");
+  EXPECT_STREQ("(exe+0x123)", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderFrame) {
+  int frame_no = 42;
+  AddressInfo info;
+  info.address = 0x400000;
+  info.module = internal_strdup("/path/to/my/module");
+  info.module_offset = 0x200;
+  info.function = internal_strdup("function_foo");
+  info.function_offset = 0x100;
+  info.file = internal_strdup("/path/to/my/source");
+  info.line = 10;
+  info.column = 5;
+  InternalScopedString str(256);
+
+  // Dump all the AddressInfo fields.
+  RenderFrame(&str, "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
+                    "Function:%f FunctionOffset:%q Source:%s Line:%l "
+                    "Column:%c",
+              frame_no, info, "/path/to/", "function_");
+  EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
+               "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
+               "Column:5",
+               str.data());
+  info.Clear();
+  str.clear();
+
+  // Test special format specifiers.
+  info.address = 0x400000;
+  RenderFrame(&str, "%M", frame_no, info);
+  EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
+  str.clear();
+
+  RenderFrame(&str, "%L", frame_no, info);
+  EXPECT_STREQ("(<unknown module>)", str.data());
+  str.clear();
+
+  info.module = internal_strdup("/path/to/module");
+  info.module_offset = 0x200;
+  RenderFrame(&str, "%M", frame_no, info);
+  EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
+  EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
+  str.clear();
+
+  RenderFrame(&str, "%L", frame_no, info);
+  EXPECT_STREQ("(/path/to/module+0x200)", str.data());
+  str.clear();
+
+  info.function = internal_strdup("my_function");
+  RenderFrame(&str, "%F", frame_no, info);
+  EXPECT_STREQ("in my_function", str.data());
+  str.clear();
+
+  info.function_offset = 0x100;
+  RenderFrame(&str, "%F %S", frame_no, info);
+  EXPECT_STREQ("in my_function+0x100 <null>", str.data());
+  str.clear();
+
+  info.file = internal_strdup("my_file");
+  RenderFrame(&str, "%F %S", frame_no, info);
+  EXPECT_STREQ("in my_function my_file", str.data());
+  str.clear();
+
+  info.line = 10;
+  RenderFrame(&str, "%F %S", frame_no, info);
+  EXPECT_STREQ("in my_function my_file:10", str.data());
+  str.clear();
+
+  info.column = 5;
+  RenderFrame(&str, "%S %L", frame_no, info);
+  EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
+  str.clear();
+
+  info.Clear();
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index b71044a..ac820c2 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -20,6 +20,7 @@
 class FastUnwindTest : public ::testing::Test {
  protected:
   virtual void SetUp();
+  virtual void TearDown();
   bool TryFastUnwind(uptr max_depth) {
     if (!StackTrace::WillUseFastUnwind(true))
       return false;
@@ -28,11 +29,13 @@
     return true;
   }
 
-  uptr fake_stack[10];
+  void *mapping;
+  uptr *fake_stack;
+  const uptr fake_stack_size = 10;
   uptr start_pc;
   uptr fake_top;
   uptr fake_bottom;
-  StackTrace trace;
+  BufferedStackTrace trace;
 };
 
 static uptr PC(uptr idx) {
@@ -40,22 +43,34 @@
 }
 
 void FastUnwindTest::SetUp() {
+  size_t ps = GetPageSize();
+  mapping = MmapOrDie(2 * ps, "FastUnwindTest");
+  Mprotect((uptr)mapping, ps);
+
+  // Unwinder may peek 1 word down from the starting FP.
+  fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr));
+
   // Fill an array of pointers with fake fp+retaddr pairs.  Frame pointers have
   // even indices.
-  for (uptr i = 0; i+1 < ARRAY_SIZE(fake_stack); i += 2) {
+  for (uptr i = 0; i + 1 < fake_stack_size; i += 2) {
     fake_stack[i] = (uptr)&fake_stack[i+2];  // fp
     fake_stack[i+1] = PC(i + 1); // retaddr
   }
-  // Mark the last fp as zero to terminate the stack trace.
-  fake_stack[RoundDownTo(ARRAY_SIZE(fake_stack) - 1, 2)] = 0;
+  // Mark the last fp point back up to terminate the stack trace.
+  fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0];
 
   // Top is two slots past the end because FastUnwindStack subtracts two.
-  fake_top = (uptr)&fake_stack[ARRAY_SIZE(fake_stack) + 2];
+  fake_top = (uptr)&fake_stack[fake_stack_size + 2];
   // Bottom is one slot before the start because FastUnwindStack uses >.
-  fake_bottom = (uptr)&fake_stack[-1];
+  fake_bottom = (uptr)mapping;
   start_pc = PC(0);
 }
 
+void FastUnwindTest::TearDown() {
+  size_t ps = GetPageSize();
+  UnmapOrDie(mapping, 2 * ps);
+}
+
 TEST_F(FastUnwindTest, Basic) {
   if (!TryFastUnwind(kStackTraceMax))
     return;
@@ -109,10 +124,22 @@
   EXPECT_EQ(0U, trace.top_frame_bp);
 }
 
+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[1] = PC(1);
+  if (!TryFastUnwind(3))
+    return;
+  EXPECT_EQ(2U, trace.size);
+  EXPECT_EQ(PC(0), trace.trace[0]);
+  EXPECT_EQ(PC(1), trace.trace[1]);
+}
+
 TEST(SlowUnwindTest, ShortStackTrace) {
   if (StackTrace::WillUseFastUnwind(false))
     return;
-  StackTrace stack;
+  BufferedStackTrace stack;
   uptr pc = StackTrace::GetCurrentPc();
   uptr bp = GET_CURRENT_FRAME();
   stack.Unwind(0, pc, bp, 0, 0, 0, false);
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index 93fc8a3..2a1e356 100644
--- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -66,11 +66,13 @@
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
-      "called_from_lib"));
+                         "called_from_lib"));
   CHECK(
       !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
+  CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
+                         "vptr_check"));
   // Ensure this test is up-to-date when suppression types are added.
-  CHECK_EQ(SuppressionTypeCount, 8);
+  CHECK_EQ(9, SuppressionTypeCount);
 }
 
 class SuppressionContextTest : public ::testing::Test {
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index b6a60d5..58c627a 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -107,13 +107,13 @@
             registry->FindThread(HasUid, (void*)0x1234));
   // Detach and finish and join remaining threads.
   for (u32 i = 6; i <= 10; i++) {
-    registry->DetachThread(i);
+    registry->DetachThread(i, 0);
     registry->FinishThread(i);
   }
   for (u32 i = 0; i < new_tids.size(); i++) {
     u32 tid = new_tids[i];
     registry->StartThread(tid, 0, 0);
-    registry->DetachThread(tid);
+    registry->DetachThread(tid, 0);
     registry->FinishThread(tid);
   }
   CheckThreadQuantity(registry, exp_total, 1, 1);
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index 19efb54..6d51faa 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -5,12 +5,12 @@
 set(TSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 # SANITIZER_COMMON_CFLAGS contains -fPIC, but it's performance-critical for
 # TSan runtime to be built with -fPIE to reduce the number of register spills.
-append_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TSAN_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TSAN_CFLAGS)
 append_no_rtti_flag(TSAN_CFLAGS)
 
 set(TSAN_RTL_CFLAGS ${TSAN_CFLAGS})
-append_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 TSAN_RTL_CFLAGS)
-append_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors TSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG -Wframe-larger-than=512 TSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors TSAN_RTL_CFLAGS)
 # FIXME: Add support for --sysroot=. compile flag:
 
 if("${CMAKE_BUILD_TYPE}" EQUAL "Release")
@@ -103,7 +103,8 @@
 add_dependencies(compiler-rt tsan)
 
 # Build libcxx instrumented with TSan.
-if(COMPILER_RT_HAS_LIBCXX_SOURCES AND
+if(TSAN_SUPPORTED_ARCH AND
+   COMPILER_RT_HAS_LIBCXX_SOURCES AND
    COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang")
   set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_tsan)
   add_custom_libcxx(libcxx_tsan ${LIBCXX_PREFIX}
diff --git a/lib/tsan/check_cmake.sh b/lib/tsan/check_cmake.sh
index 7e858ef..7668c5b 100755
--- a/lib/tsan/check_cmake.sh
+++ b/lib/tsan/check_cmake.sh
@@ -3,11 +3,11 @@
 set -e
 
 ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-if [ -d "$ROOT/build" ]; then
-  cd $ROOT/build
+if [ -d "$ROOT/llvm-build" ]; then
+  cd $ROOT/llvm-build
 else
-  mkdir -p $ROOT/build
-  cd $ROOT/build
+  mkdir -p $ROOT/llvm-build
+  cd $ROOT/llvm-build
   CC=clang CXX=clang++ cmake -G Ninja -DLLVM_ENABLE_WERROR=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON $ROOT/../../../..
 fi
 ninja
diff --git a/lib/tsan/dd/CMakeLists.txt b/lib/tsan/dd/CMakeLists.txt
index 9328721..aa7d63d 100644
--- a/lib/tsan/dd/CMakeLists.txt
+++ b/lib/tsan/dd/CMakeLists.txt
@@ -22,6 +22,10 @@
   dd_rtl.h
 )
 
+set(DD_LINKLIBS)
+append_list_if(COMPILER_RT_HAS_LIBDL dl DD_LINKLIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS)
+
 add_custom_target(dd)
 # Deadlock detector is currently supported on 64-bit Linux only.
 if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID)
@@ -43,7 +47,7 @@
             $<TARGET_OBJECTS:RTInterception.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
-  target_link_libraries(clang_rt.dyndd-${arch} pthread dl)
+  target_link_libraries(clang_rt.dyndd-${arch} ${DD_LINKLIBS})
 endif()
 
 add_dependencies(compiler-rt dd)
diff --git a/lib/tsan/dd/dd_rtl.cc b/lib/tsan/dd/dd_rtl.cc
index 729e79e..44de617 100644
--- a/lib/tsan/dd/dd_rtl.cc
+++ b/lib/tsan/dd/dd_rtl.cc
@@ -19,20 +19,19 @@
 static Context *ctx;
 
 static u32 CurrentStackTrace(Thread *thr, uptr skip) {
-  StackTrace trace;
+  BufferedStackTrace stack;
   thr->ignore_interceptors = true;
-  trace.Unwind(1000, 0, 0, 0, 0, 0, false);
+  stack.Unwind(1000, 0, 0, 0, 0, 0, false);
   thr->ignore_interceptors = false;
-  if (trace.size <= skip)
+  if (stack.size <= skip)
     return 0;
-  return StackDepotPut(trace.trace + skip, trace.size - skip);
+  return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
 }
 
 static void PrintStackTrace(Thread *thr, u32 stk) {
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(stk, &size);
+  StackTrace stack = StackDepotGet(stk);
   thr->ignore_interceptors = true;
-  StackTrace::PrintStack(trace, size);
+  stack.Print();
   thr->ignore_interceptors = false;
 }
 
diff --git a/lib/tsan/go/build.bat b/lib/tsan/go/build.bat
index 4480e66..7156b7d 100644
--- a/lib/tsan/go/build.bat
+++ b/lib/tsan/go/build.bat
@@ -1,4 +1,4 @@
-type tsan_go.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc > gotsan.cc
+type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc > gotsan.cc
 
 gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 -Wno-error=attributes -Wno-attributes -Wno-format -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer
 
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index f8eb081..dbb92f3 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -4,6 +4,7 @@
 	tsan_go.cc
 	../rtl/tsan_clock.cc
 	../rtl/tsan_flags.cc
+	../rtl/tsan_interface_atomic.cc
 	../rtl/tsan_md5.cc
 	../rtl/tsan_mutex.cc
 	../rtl/tsan_report.cc
@@ -25,6 +26,7 @@
 	../../sanitizer_common/sanitizer_suppressions.cc
 	../../sanitizer_common/sanitizer_thread_registry.cc
 	../../sanitizer_common/sanitizer_stackdepot.cc
+	../../sanitizer_common/sanitizer_stacktrace.cc
 "
 
 if [ "`uname -a | grep Linux`" != "" ]; then
@@ -35,6 +37,7 @@
 		../rtl/tsan_platform_linux.cc
 		../../sanitizer_common/sanitizer_posix.cc
 		../../sanitizer_common/sanitizer_posix_libcdep.cc
+		../../sanitizer_common/sanitizer_procmaps_common.cc
 		../../sanitizer_common/sanitizer_procmaps_linux.cc
 		../../sanitizer_common/sanitizer_linux.cc
 		../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -47,7 +50,8 @@
                 ../rtl/tsan_platform_linux.cc
                 ../../sanitizer_common/sanitizer_posix.cc
                 ../../sanitizer_common/sanitizer_posix_libcdep.cc
-                ../../sanitizer_common/sanitizer_procmaps_linux.cc
+                ../../sanitizer_common/sanitizer_procmaps_common.cc
+                ../../sanitizer_common/sanitizer_procmaps_freebsd.cc
                 ../../sanitizer_common/sanitizer_linux.cc
                 ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
         "
@@ -82,7 +86,7 @@
 	cat $F >> gotsan.cc
 done
 
-FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -m64 -Wall -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"
+FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4 -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS"
 if [ "$DEBUG" == "" ]; then
 	FLAGS+=" -DTSAN_DEBUG=0 -O3 -msse3 -fomit-frame-pointer"
 else
diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc
index 5e22092..c1d401f 100644
--- a/lib/tsan/go/tsan_go.cc
+++ b/lib/tsan/go/tsan_go.cc
@@ -39,14 +39,6 @@
   return 0;
 }
 
-ReportStack *NewReportStackEntry(uptr addr) {
-  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
-                                                  sizeof(ReportStack));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->pc = addr;
-  return ent;
-}
-
 void *internal_alloc(MBlockType typ, uptr sz) {
   return InternalAlloc(sz);
 }
@@ -68,20 +60,17 @@
 static void (*symbolize_cb)(SymbolizeContext *ctx);
 
 ReportStack *SymbolizeCode(uptr addr) {
-  ReportStack *s = (ReportStack*)internal_alloc(MBlockReportStack,
-                                                sizeof(ReportStack));
-  internal_memset(s, 0, sizeof(*s));
-  s->pc = addr;
+  ReportStack *s = ReportStack::New(addr);
   SymbolizeContext ctx;
   internal_memset(&ctx, 0, sizeof(ctx));
   ctx.pc = addr;
   symbolize_cb(&ctx);
   if (ctx.res) {
-    s->offset = ctx.off;
-    s->func = internal_strdup(ctx.func ? ctx.func : "??");
-    s->file = internal_strdup(ctx.file ? ctx.file : "-");
-    s->line = ctx.line;
-    s->col = 0;
+    s->info.module_offset = ctx.off;
+    s->info.function = internal_strdup(ctx.func ? ctx.func : "??");
+    s->info.file = internal_strdup(ctx.file ? ctx.file : "-");
+    s->info.line = ctx.line;
+    s->info.column = 0;
   }
   return s;
 }
@@ -208,6 +197,14 @@
     MutexReadUnlock(thr, 0, addr);
 }
 
+void __tsan_go_ignore_sync_begin(ThreadState *thr) {
+  ThreadIgnoreSyncBegin(thr, 0);
+}
+
+void __tsan_go_ignore_sync_end(ThreadState *thr) {
+  ThreadIgnoreSyncEnd(thr, 0);
+}
+
 }  // extern "C"
 }  // namespace __tsan
 
diff --git a/lib/tsan/rtl/tsan_clock.cc b/lib/tsan/rtl/tsan_clock.cc
index e140a3c..1855f05 100644
--- a/lib/tsan/rtl/tsan_clock.cc
+++ b/lib/tsan/rtl/tsan_clock.cc
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 #include "tsan_clock.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 
 // SyncClock and ThreadClock implement vector clocks for sync variables
 // (mutexes, atomic variables, file descriptors, etc) and threads, respectively.
@@ -102,13 +103,13 @@
   clk_[tid_].reused = reused_;
 }
 
-void ThreadClock::acquire(const SyncClock *src) {
+void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
   DCHECK(nclk_ <= kMaxTid);
-  DCHECK(src->clk_.Size() <= kMaxTid);
+  DCHECK(src->size_ <= kMaxTid);
   CPP_STAT_INC(StatClockAcquire);
 
   // Check if it's empty -> no need to do anything.
-  const uptr nclk = src->clk_.Size();
+  const uptr nclk = src->size_;
   if (nclk == 0) {
     CPP_STAT_INC(StatClockAcquireEmpty);
     return;
@@ -118,12 +119,12 @@
   bool acquired = false;
   if (nclk > tid_) {
     CPP_STAT_INC(StatClockAcquireLarge);
-    if (src->clk_[tid_].reused == reused_) {
+    if (src->elem(tid_).reused == reused_) {
       CPP_STAT_INC(StatClockAcquireRepeat);
       for (unsigned i = 0; i < kDirtyTids; i++) {
         unsigned tid = src->dirty_tids_[i];
         if (tid != kInvalidTid) {
-          u64 epoch = src->clk_[tid].epoch;
+          u64 epoch = src->elem(tid).epoch;
           if (clk_[tid].epoch < epoch) {
             clk_[tid].epoch = epoch;
             acquired = true;
@@ -142,7 +143,7 @@
   CPP_STAT_INC(StatClockAcquireFull);
   nclk_ = max(nclk_, nclk);
   for (uptr i = 0; i < nclk; i++) {
-    u64 epoch = src->clk_[i].epoch;
+    u64 epoch = src->elem(i).epoch;
     if (clk_[i].epoch < epoch) {
       clk_[i].epoch = epoch;
       acquired = true;
@@ -151,7 +152,7 @@
 
   // Remember that this thread has acquired this clock.
   if (nclk > tid_)
-    src->clk_[tid_].reused = reused_;
+    src->elem(tid_).reused = reused_;
 
   if (acquired) {
     CPP_STAT_INC(StatClockAcquiredSomething);
@@ -159,28 +160,26 @@
   }
 }
 
-void ThreadClock::release(SyncClock *dst) const {
+void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
   DCHECK_LE(nclk_, kMaxTid);
-  DCHECK_LE(dst->clk_.Size(), kMaxTid);
+  DCHECK_LE(dst->size_, kMaxTid);
 
-  if (dst->clk_.Size() == 0) {
+  if (dst->size_ == 0) {
     // ReleaseStore will correctly set release_store_tid_,
     // which can be important for future operations.
-    ReleaseStore(dst);
+    ReleaseStore(c, dst);
     return;
   }
 
   CPP_STAT_INC(StatClockRelease);
   // Check if we need to resize dst.
-  if (dst->clk_.Size() < nclk_) {
-    CPP_STAT_INC(StatClockReleaseResize);
-    dst->clk_.Resize(nclk_);
-  }
+  if (dst->size_ < nclk_)
+    dst->Resize(c, nclk_);
 
   // Check if we had not acquired anything from other threads
   // since the last release on dst. If so, we need to update
-  // only dst->clk_[tid_].
-  if (dst->clk_[tid_].epoch > last_acquire_) {
+  // only dst->elem(tid_).
+  if (dst->elem(tid_).epoch > last_acquire_) {
     UpdateCurrentThread(dst);
     if (dst->release_store_tid_ != tid_ ||
         dst->release_store_reused_ != reused_)
@@ -196,14 +195,15 @@
     CPP_STAT_INC(StatClockReleaseAcquired);
   // Update dst->clk_.
   for (uptr i = 0; i < nclk_; i++) {
-    dst->clk_[i].epoch = max(dst->clk_[i].epoch, clk_[i].epoch);
-    dst->clk_[i].reused = 0;
+    ClockElem &ce = dst->elem(i);
+    ce.epoch = max(ce.epoch, clk_[i].epoch);
+    ce.reused = 0;
   }
   // Clear 'acquired' flag in the remaining elements.
-  if (nclk_ < dst->clk_.Size())
+  if (nclk_ < dst->size_)
     CPP_STAT_INC(StatClockReleaseClearTail);
-  for (uptr i = nclk_; i < dst->clk_.Size(); i++)
-    dst->clk_[i].reused = 0;
+  for (uptr i = nclk_; i < dst->size_; i++)
+    dst->elem(i).reused = 0;
   for (unsigned i = 0; i < kDirtyTids; i++)
     dst->dirty_tids_[i] = kInvalidTid;
   dst->release_store_tid_ = kInvalidTid;
@@ -211,23 +211,21 @@
   // If we've acquired dst, remember this fact,
   // so that we don't need to acquire it on next acquire.
   if (acquired)
-    dst->clk_[tid_].reused = reused_;
+    dst->elem(tid_).reused = reused_;
 }
 
-void ThreadClock::ReleaseStore(SyncClock *dst) const {
+void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
   DCHECK(nclk_ <= kMaxTid);
-  DCHECK(dst->clk_.Size() <= kMaxTid);
+  DCHECK(dst->size_ <= kMaxTid);
   CPP_STAT_INC(StatClockStore);
 
   // Check if we need to resize dst.
-  if (dst->clk_.Size() < nclk_) {
-    CPP_STAT_INC(StatClockStoreResize);
-    dst->clk_.Resize(nclk_);
-  }
+  if (dst->size_ < nclk_)
+    dst->Resize(c, nclk_);
 
   if (dst->release_store_tid_ == tid_ &&
       dst->release_store_reused_ == reused_ &&
-      dst->clk_[tid_].epoch > last_acquire_) {
+      dst->elem(tid_).epoch > last_acquire_) {
     CPP_STAT_INC(StatClockStoreFast);
     UpdateCurrentThread(dst);
     return;
@@ -236,13 +234,17 @@
   // O(N) release-store.
   CPP_STAT_INC(StatClockStoreFull);
   for (uptr i = 0; i < nclk_; i++) {
-    dst->clk_[i].epoch = clk_[i].epoch;
-    dst->clk_[i].reused = 0;
+    ClockElem &ce = dst->elem(i);
+    ce.epoch = clk_[i].epoch;
+    ce.reused = 0;
   }
   // Clear the tail of dst->clk_.
-  if (nclk_ < dst->clk_.Size()) {
-    internal_memset(&dst->clk_[nclk_], 0,
-        (dst->clk_.Size() - nclk_) * sizeof(dst->clk_[0]));
+  if (nclk_ < dst->size_) {
+    for (uptr i = nclk_; i < dst->size_; i++) {
+      ClockElem &ce = dst->elem(i);
+      ce.epoch = 0;
+      ce.reused = 0;
+    }
     CPP_STAT_INC(StatClockStoreTail);
   }
   for (unsigned i = 0; i < kDirtyTids; i++)
@@ -250,19 +252,19 @@
   dst->release_store_tid_ = tid_;
   dst->release_store_reused_ = reused_;
   // Rememeber that we don't need to acquire it in future.
-  dst->clk_[tid_].reused = reused_;
+  dst->elem(tid_).reused = reused_;
 }
 
-void ThreadClock::acq_rel(SyncClock *dst) {
+void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
   CPP_STAT_INC(StatClockAcquireRelease);
-  acquire(dst);
-  ReleaseStore(dst);
+  acquire(c, dst);
+  ReleaseStore(c, dst);
 }
 
 // Updates only single element related to the current thread in dst->clk_.
 void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
   // Update the threads time, but preserve 'acquired' flag.
-  dst->clk_[tid_].epoch = clk_[tid_].epoch;
+  dst->elem(tid_).epoch = clk_[tid_].epoch;
 
   for (unsigned i = 0; i < kDirtyTids; i++) {
     if (dst->dirty_tids_[i] == tid_) {
@@ -277,27 +279,73 @@
   }
   // Reset all 'acquired' flags, O(N).
   CPP_STAT_INC(StatClockReleaseSlow);
-  for (uptr i = 0; i < dst->clk_.Size(); i++) {
-    dst->clk_[i].reused = 0;
-  }
+  for (uptr i = 0; i < dst->size_; i++)
+    dst->elem(i).reused = 0;
   for (unsigned i = 0; i < kDirtyTids; i++)
     dst->dirty_tids_[i] = kInvalidTid;
 }
 
 // Checks whether the current threads has already acquired src.
 bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
-  if (src->clk_[tid_].reused != reused_)
+  if (src->elem(tid_).reused != reused_)
     return false;
   for (unsigned i = 0; i < kDirtyTids; i++) {
     unsigned tid = src->dirty_tids_[i];
     if (tid != kInvalidTid) {
-      if (clk_[tid].epoch < src->clk_[tid].epoch)
+      if (clk_[tid].epoch < src->elem(tid).epoch)
         return false;
     }
   }
   return true;
 }
 
+void SyncClock::Resize(ClockCache *c, uptr nclk) {
+  CPP_STAT_INC(StatClockReleaseResize);
+  if (RoundUpTo(nclk, ClockBlock::kClockCount) <=
+      RoundUpTo(size_, ClockBlock::kClockCount)) {
+    // Growing within the same block.
+    // Memory is already allocated, just increase the size.
+    size_ = nclk;
+    return;
+  }
+  if (nclk <= ClockBlock::kClockCount) {
+    // Grow from 0 to one-level table.
+    CHECK_EQ(size_, 0);
+    CHECK_EQ(tab_, 0);
+    CHECK_EQ(tab_idx_, 0);
+    size_ = nclk;
+    tab_idx_ = ctx->clock_alloc.Alloc(c);
+    tab_ = ctx->clock_alloc.Map(tab_idx_);
+    internal_memset(tab_, 0, sizeof(*tab_));
+    return;
+  }
+  // Growing two-level table.
+  if (size_ == 0) {
+    // Allocate first level table.
+    tab_idx_ = ctx->clock_alloc.Alloc(c);
+    tab_ = ctx->clock_alloc.Map(tab_idx_);
+    internal_memset(tab_, 0, sizeof(*tab_));
+  } else if (size_ <= ClockBlock::kClockCount) {
+    // Transform one-level table to two-level table.
+    u32 old = tab_idx_;
+    tab_idx_ = ctx->clock_alloc.Alloc(c);
+    tab_ = ctx->clock_alloc.Map(tab_idx_);
+    internal_memset(tab_, 0, sizeof(*tab_));
+    tab_->table[0] = old;
+  }
+  // At this point we have first level table allocated.
+  // Add second level tables as necessary.
+  for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount);
+      i < nclk; i += ClockBlock::kClockCount) {
+    u32 idx = ctx->clock_alloc.Alloc(c);
+    ClockBlock *cb = ctx->clock_alloc.Map(idx);
+    internal_memset(cb, 0, sizeof(*cb));
+    CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0);
+    tab_->table[i/ClockBlock::kClockCount] = idx;
+  }
+  size_ = nclk;
+}
+
 // Sets a single element in the vector clock.
 // This function is called only from weird places like AcquireGlobal.
 void ThreadClock::set(unsigned tid, u64 v) {
@@ -321,33 +369,59 @@
 }
 
 SyncClock::SyncClock()
-    : clk_(MBlockClock) {
+    : release_store_tid_(kInvalidTid)
+    , release_store_reused_()
+    , tab_()
+    , tab_idx_()
+    , size_() {
+  for (uptr i = 0; i < kDirtyTids; i++)
+    dirty_tids_[i] = kInvalidTid;
+}
+
+SyncClock::~SyncClock() {
+  // Reset must be called before dtor.
+  CHECK_EQ(size_, 0);
+  CHECK_EQ(tab_, 0);
+  CHECK_EQ(tab_idx_, 0);
+}
+
+void SyncClock::Reset(ClockCache *c) {
+  if (size_ == 0) {
+    // nothing
+  } else if (size_ <= ClockBlock::kClockCount) {
+    // One-level table.
+    ctx->clock_alloc.Free(c, tab_idx_);
+  } else {
+    // Two-level table.
+    for (uptr i = 0; i < size_; i += ClockBlock::kClockCount)
+      ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]);
+    ctx->clock_alloc.Free(c, tab_idx_);
+  }
+  tab_ = 0;
+  tab_idx_ = 0;
+  size_ = 0;
   release_store_tid_ = kInvalidTid;
   release_store_reused_ = 0;
   for (uptr i = 0; i < kDirtyTids; i++)
     dirty_tids_[i] = kInvalidTid;
 }
 
-void SyncClock::Reset() {
-  clk_.Reset();
-  Zero();
-}
-
-void SyncClock::Zero() {
-  clk_.Resize(0);
-  release_store_tid_ = kInvalidTid;
-  release_store_reused_ = 0;
-  for (uptr i = 0; i < kDirtyTids; i++)
-    dirty_tids_[i] = kInvalidTid;
+ClockElem &SyncClock::elem(unsigned tid) const {
+  DCHECK_LT(tid, size_);
+  if (size_ <= ClockBlock::kClockCount)
+    return tab_->clock[tid];
+  u32 idx = tab_->table[tid / ClockBlock::kClockCount];
+  ClockBlock *cb = ctx->clock_alloc.Map(idx);
+  return cb->clock[tid % ClockBlock::kClockCount];
 }
 
 void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
   printf("clock=[");
-  for (uptr i = 0; i < clk_.Size(); i++)
-    printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
+  for (uptr i = 0; i < size_; i++)
+    printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch);
   printf("] reused=[");
-  for (uptr i = 0; i < clk_.Size(); i++)
-    printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
+  for (uptr i = 0; i < size_; i++)
+    printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
   printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
       release_store_tid_, release_store_reused_,
       dirty_tids_[0], dirty_tids_[1]);
diff --git a/lib/tsan/rtl/tsan_clock.h b/lib/tsan/rtl/tsan_clock.h
index f7ab69a..4e352cb 100644
--- a/lib/tsan/rtl/tsan_clock.h
+++ b/lib/tsan/rtl/tsan_clock.h
@@ -14,7 +14,7 @@
 #define TSAN_CLOCK_H
 
 #include "tsan_defs.h"
-#include "tsan_vector.h"
+#include "tsan_dense_alloc.h"
 
 namespace __tsan {
 
@@ -23,37 +23,65 @@
   u64 reused : 64 - kClkBits;
 };
 
+struct ClockBlock {
+  static const uptr kSize = 512;
+  static const uptr kTableSize = kSize / sizeof(u32);
+  static const uptr kClockCount = kSize / sizeof(ClockElem);
+
+  union {
+    u32       table[kTableSize];
+    ClockElem clock[kClockCount];
+  };
+
+  ClockBlock() {
+  }
+};
+
+typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
+typedef DenseSlabAllocCache ClockCache;
+
 // The clock that lives in sync variables (mutexes, atomics, etc).
 class SyncClock {
  public:
   SyncClock();
+  ~SyncClock();
 
   uptr size() const {
-    return clk_.Size();
+    return size_;
   }
 
   u64 get(unsigned tid) const {
-    DCHECK_LT(tid, clk_.Size());
-    return clk_[tid].epoch;
+    return elem(tid).epoch;
   }
 
-  void Reset();
-  void Zero();
+  void Resize(ClockCache *c, uptr nclk);
+  void Reset(ClockCache *c);
 
   void DebugDump(int(*printf)(const char *s, ...));
 
  private:
+  friend struct ThreadClock;
+  static const uptr kDirtyTids = 2;
+
   unsigned release_store_tid_;
   unsigned release_store_reused_;
-  static const uptr kDirtyTids = 2;
   unsigned dirty_tids_[kDirtyTids];
-  mutable Vector<ClockElem> clk_;
-  friend struct ThreadClock;
+  // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc.
+  // If size_ <= 64, then tab_ points to an array with 64 ClockElem's.
+  // Otherwise, tab_ points to an array with 128 u32 elements,
+  // each pointing to the second-level 512b block with 64 ClockElem's.
+  ClockBlock *tab_;
+  u32 tab_idx_;
+  u32 size_;
+
+  ClockElem &elem(unsigned tid) const;
 };
 
 // The clock that lives in threads.
 struct ThreadClock {
  public:
+  typedef DenseSlabAllocCache Cache;
+
   explicit ThreadClock(unsigned tid, unsigned reused = 0);
 
   u64 get(unsigned tid) const {
@@ -76,10 +104,10 @@
     return nclk_;
   }
 
-  void acquire(const SyncClock *src);
-  void release(SyncClock *dst) const;
-  void acq_rel(SyncClock *dst);
-  void ReleaseStore(SyncClock *dst) const;
+  void acquire(ClockCache *c, const SyncClock *src);
+  void release(ClockCache *c, SyncClock *dst) const;
+  void acq_rel(ClockCache *c, SyncClock *dst);
+  void ReleaseStore(ClockCache *c, SyncClock *dst) const;
 
   void DebugReset();
   void DebugDump(int(*printf)(const char *s, ...));
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 969d09f..0a356fb 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -43,7 +43,6 @@
 const int kClkBits = 42;
 const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
 const uptr kShadowStackSize = 64 * 1024;
-const uptr kTraceStackSize = 256;
 
 #ifdef TSAN_SHADOW_COUNT
 # if TSAN_SHADOW_COUNT == 2 \
@@ -174,7 +173,6 @@
 struct ReportStack;
 class ReportDesc;
 class RegionAlloc;
-class StackTrace;
 
 // Descriptor of user's memory block.
 struct MBlock {
diff --git a/lib/tsan/rtl/tsan_dense_alloc.h b/lib/tsan/rtl/tsan_dense_alloc.h
index 2c2e75e..a1cf84b 100644
--- a/lib/tsan/rtl/tsan_dense_alloc.h
+++ b/lib/tsan/rtl/tsan_dense_alloc.h
@@ -65,6 +65,7 @@
   }
 
   void Free(Cache *c, IndexT idx) {
+    DCHECK_NE(idx, 0);
     if (c->pos == Cache::kSize)
       Drain(c);
     c->cache[c->pos++] = idx;
diff --git a/lib/tsan/rtl/tsan_fd.cc b/lib/tsan/rtl/tsan_fd.cc
index 68242e0..d18502f 100644
--- a/lib/tsan/rtl/tsan_fd.cc
+++ b/lib/tsan/rtl/tsan_fd.cc
@@ -48,7 +48,8 @@
 }
 
 static FdSync *allocsync(ThreadState *thr, uptr pc) {
-  FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync));
+  FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
+      false);
   atomic_store(&s->rc, 1, memory_order_relaxed);
   return s;
 }
@@ -65,7 +66,7 @@
       CHECK_NE(s, &fdctx.globsync);
       CHECK_NE(s, &fdctx.filesync);
       CHECK_NE(s, &fdctx.socksync);
-      user_free(thr, pc, s);
+      user_free(thr, pc, s, false);
     }
   }
 }
@@ -78,13 +79,13 @@
   if (l1 == 0) {
     uptr size = kTableSizeL2 * sizeof(FdDesc);
     // We need this to reside in user memory to properly catch races on it.
-    void *p = user_alloc(thr, pc, size);
+    void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
     internal_memset(p, 0, size);
     MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
     if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
       l1 = (uptr)p;
     else
-      user_free(thr, pc, p);
+      user_free(thr, pc, p, false);
   }
   return &((FdDesc*)l1)[fd % kTableSizeL2];  // NOLINT
 }
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 123df49..5dc331f 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -37,7 +37,6 @@
   ParseFlag(env, &f->enable_annotations, "enable_annotations", "");
   ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks", "");
   ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses", "");
-  ParseFlag(env, &f->suppress_java, "suppress_java", "");
   ParseFlag(env, &f->report_bugs, "report_bugs", "");
   ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks", "");
   ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked", "");
@@ -45,8 +44,6 @@
   ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe", "");
   ParseFlag(env, &f->report_atomic_races, "report_atomic_races", "");
   ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics", "");
-  ParseFlag(env, &f->suppressions, "suppressions", "");
-  ParseFlag(env, &f->print_suppressions, "print_suppressions", "");
   ParseFlag(env, &f->print_benign, "print_benign", "");
   ParseFlag(env, &f->exitcode, "exitcode", "");
   ParseFlag(env, &f->halt_on_error, "halt_on_error", "");
@@ -72,7 +69,6 @@
   f->enable_annotations = true;
   f->suppress_equal_stacks = true;
   f->suppress_equal_addresses = true;
-  f->suppress_java = false;
   f->report_bugs = true;
   f->report_thread_leaks = true;
   f->report_destroy_locked = true;
@@ -80,8 +76,6 @@
   f->report_signal_unsafe = true;
   f->report_atomic_races = true;
   f->force_seq_cst_atomics = false;
-  f->suppressions = "";
-  f->print_suppressions = false;
   f->print_benign = false;
   f->exitcode = 66;
   f->halt_on_error = false;
@@ -99,20 +93,20 @@
   // DDFlags
   f->second_deadlock_stack = false;
 
-  SetCommonFlagsDefaults(f);
+  CommonFlags *cf = common_flags();
+  SetCommonFlagsDefaults(cf);
   // Override some common flags defaults.
-  f->allow_addr2line = true;
-  f->detect_deadlocks = true;
+  cf->allow_addr2line = true;
+  cf->detect_deadlocks = true;
+  cf->print_suppressions = false;
+  cf->stack_trace_format = "    #%n %f %S %M";
 
   // Let a frontend override.
   ParseFlags(f, __tsan_default_options());
-  ParseCommonFlagsFromString(f, __tsan_default_options());
+  ParseCommonFlagsFromString(cf, __tsan_default_options());
   // Override from command line.
   ParseFlags(f, env);
-  ParseCommonFlagsFromString(f, env);
-
-  // Copy back to common flags.
-  *common_flags() = *f;
+  ParseCommonFlagsFromString(cf, env);
 
   // Sanity check.
   if (!f->report_bugs) {
@@ -121,7 +115,7 @@
     f->report_signal_unsafe = false;
   }
 
-  if (f->help) PrintFlagDescriptions();
+  if (cf->help) PrintFlagDescriptions();
 
   if (f->history_size < 0 || f->history_size > 7) {
     Printf("ThreadSanitizer: incorrect value for history_size"
diff --git a/lib/tsan/rtl/tsan_flags.h b/lib/tsan/rtl/tsan_flags.h
index c6b4bbf..621ca13 100644
--- a/lib/tsan/rtl/tsan_flags.h
+++ b/lib/tsan/rtl/tsan_flags.h
@@ -19,7 +19,7 @@
 
 namespace __tsan {
 
-struct Flags : CommonFlags, DDFlags {
+struct Flags : DDFlags {
   // Enable dynamic annotations, otherwise they are no-ops.
   bool enable_annotations;
   // Suppress a race report if we've already output another race report
@@ -28,9 +28,6 @@
   // Suppress a race report if we've already output another race report
   // on the same address.
   bool suppress_equal_addresses;
-  // Suppress weird race reports that can be seen if JVM is embed
-  // into the process.
-  bool suppress_java;
   // Turns off bug reporting entirely (useful for benchmarking).
   bool report_bugs;
   // Report thread leaks at exit?
@@ -47,10 +44,6 @@
   // If set, all atomics are effectively sequentially consistent (seq_cst),
   // regardless of what user actually specified.
   bool force_seq_cst_atomics;
-  // Suppressions filename.
-  const char *suppressions;
-  // Print matched suppressions at exit.
-  bool print_suppressions;
   // Print matched "benign" races at exit.
   bool print_benign;
   // Override exit status if something was reported.
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 100834e..7889942 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -29,6 +29,16 @@
 
 using namespace __tsan;  // NOLINT
 
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#define __libc_malloc __malloc
+#define __libc_realloc __realloc
+#define __libc_calloc __calloc
+#define __libc_free __free
+#define stdout __stdoutp
+#define stderr __stderrp
+#endif
+
 const int kSigCount = 65;
 
 struct my_siginfo_t {
@@ -62,7 +72,9 @@
 extern "C" void *__libc_calloc(uptr size, uptr n);
 extern "C" void *__libc_realloc(void *ptr, uptr size);
 extern "C" void __libc_free(void *ptr);
+#if !SANITIZER_FREEBSD
 extern "C" int mallopt(int param, int value);
+#endif
 extern __sanitizer_FILE *stdout, *stderr;
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
@@ -98,9 +110,14 @@
     sighandler_t sa_handler;
     void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx);
   };
+#if SANITIZER_FREEBSD
+  int sa_flags;
+  __sanitizer_sigset_t sa_mask;
+#else
   __sanitizer_sigset_t sa_mask;
   int sa_flags;
   void (*sa_restorer)();
+#endif
 };
 
 const sighandler_t SIG_DFL = (sighandler_t)0;
@@ -124,9 +141,9 @@
 };
 
 struct SignalContext {
-  int in_blocking_func;
   int int_signal_send;
-  int pending_signal_count;
+  atomic_uintptr_t in_blocking_func;
+  atomic_uintptr_t have_pending_signals;
   SignalDesc pending_signals[kSigCount];
 };
 
@@ -138,7 +155,7 @@
 }
 
 void InitializeLibIgnore() {
-  libignore()->Init(*GetSuppressionContext());
+  libignore()->Init(*SuppressionContext::Get());
   libignore()->OnLibraryLoaded(0);
 }
 
@@ -146,7 +163,7 @@
 
 static SignalContext *SigCtx(ThreadState *thr) {
   SignalContext *ctx = (SignalContext*)thr->signal_ctx;
-  if (ctx == 0 && thr->is_alive) {
+  if (ctx == 0 && !thr->is_dead) {
     ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
     MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
     thr->signal_ctx = ctx;
@@ -199,7 +216,7 @@
     ThreadState *thr = cur_thread(); \
     const uptr caller_pc = GET_CALLER_PC(); \
     ScopedInterceptor si(thr, #func, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+    const uptr pc = StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -215,28 +232,40 @@
 
 #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
 #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
-#define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#if SANITIZER_FREEBSD
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
+#else
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#endif
 
 #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
 
 struct BlockingCall {
   explicit BlockingCall(ThreadState *thr)
-      : ctx(SigCtx(thr)) {
-    ctx->in_blocking_func++;
+      : thr(thr)
+      , ctx(SigCtx(thr)) {
+    for (;;) {
+      atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed);
+      if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0)
+        break;
+      atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
+      ProcessPendingSignals(thr);
+    }
+    // When we are in a "blocking call", we process signals asynchronously
+    // (right when they arrive). In this context we do not expect to be
+    // executing any user/runtime code. The known interceptor sequence when
+    // this is not true is: pthread_join -> munmap(stack). It's fine
+    // to ignore munmap in this case -- we handle stack shadow separately.
+    thr->ignore_interceptors++;
   }
 
   ~BlockingCall() {
-    ctx->in_blocking_func--;
+    thr->ignore_interceptors--;
+    atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
   }
 
+  ThreadState *thr;
   SignalContext *ctx;
-
-  // When we are in a "blocking call", we process signals asynchronously
-  // (right when they arrive). In this context we do not expect to be
-  // executing any user/runtime code. The known interceptor sequence when
-  // this is not true is: pthread_join -> munmap(stack). It's fine
-  // to ignore munmap in this case -- we handle stack shadow separately.
-  ScopedIgnoreInterceptors ignore_interceptors;
 };
 
 TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
@@ -260,63 +289,24 @@
   return res;
 }
 
-class AtExitContext {
- public:
-  AtExitContext()
-    : mtx_(MutexTypeAtExit, StatMtxAtExit)
-    , pos_() {
-  }
-
-  typedef void(*atexit_t)();
-
-  int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
-             atexit_t f, void *arg) {
-    Lock l(&mtx_);
-    if (pos_ == kMaxAtExit)
-      return 1;
-    Release(thr, pc, (uptr)this);
-    stack_[pos_] = f;
-    args_[pos_] = arg;
-    is_on_exits_[pos_] = is_on_exit;
-    pos_++;
-    return 0;
-  }
-
-  void exit(ThreadState *thr, uptr pc) {
-    for (;;) {
-      atexit_t f = 0;
-      void *arg = 0;
-      bool is_on_exit = false;
-      {
-        Lock l(&mtx_);
-        if (pos_) {
-          pos_--;
-          f = stack_[pos_];
-          arg = args_[pos_];
-          is_on_exit = is_on_exits_[pos_];
-          Acquire(thr, pc, (uptr)this);
-        }
-      }
-      if (f == 0)
-        break;
-      DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
-      if (is_on_exit)
-        ((void(*)(int status, void *arg))f)(0, arg);
-      else
-        ((void(*)(void *arg, void *dso))f)(arg, 0);
-    }
-  }
-
- private:
-  static const int kMaxAtExit = 128;
-  Mutex mtx_;
-  atexit_t stack_[kMaxAtExit];
-  void *args_[kMaxAtExit];
-  bool is_on_exits_[kMaxAtExit];
-  int pos_;
+// The sole reason tsan wraps atexit callbacks is to establish synchronization
+// between callback setup and callback execution.
+struct AtExitCtx {
+  void (*f)();
+  void *arg;
 };
 
-static AtExitContext *atexit_ctx;
+static void at_exit_wrapper(void *arg) {
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  Acquire(thr, pc, (uptr)arg);
+  AtExitCtx *ctx = (AtExitCtx*)arg;
+  ((void(*)(void *arg))ctx->f)(ctx->arg);
+  __libc_free(ctx);
+}
+
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+      void *arg, void *dso);
 
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
   if (cur_thread()->in_symbolizer)
@@ -324,29 +314,53 @@
   // We want to setup the atexit callback even if we are in ignored lib
   // or after fork.
   SCOPED_INTERCEPTOR_RAW(atexit, f);
-  return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0);
-}
-
-TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
-  if (cur_thread()->in_symbolizer)
-    return 0;
-  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
-  return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg);
+  return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
 }
 
 TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
   if (cur_thread()->in_symbolizer)
     return 0;
   SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
-  if (dso) {
-    // Memory allocation in __cxa_atexit will race with free during exit,
-    // because we do not see synchronization around atexit callback list.
-    ThreadIgnoreBegin(thr, pc);
-    int res = REAL(__cxa_atexit)(f, arg, dso);
-    ThreadIgnoreEnd(thr, pc);
-    return res;
-  }
-  return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
+  return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso);
+}
+
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+      void *arg, void *dso) {
+  AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+  ctx->f = f;
+  ctx->arg = arg;
+  Release(thr, pc, (uptr)ctx);
+  // Memory allocation in __cxa_atexit will race with free during exit,
+  // because we do not see synchronization around atexit callback list.
+  ThreadIgnoreBegin(thr, pc);
+  int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso);
+  ThreadIgnoreEnd(thr, pc);
+  return res;
+}
+
+static void on_exit_wrapper(int status, void *arg) {
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  Acquire(thr, pc, (uptr)arg);
+  AtExitCtx *ctx = (AtExitCtx*)arg;
+  ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
+  __libc_free(ctx);
+}
+
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+  if (cur_thread()->in_symbolizer)
+    return 0;
+  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+  AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+  ctx->f = (void(*)())f;
+  ctx->arg = arg;
+  Release(thr, pc, (uptr)ctx);
+  // Memory allocation in __cxa_atexit will race with free during exit,
+  // because we do not see synchronization around atexit callback list.
+  ThreadIgnoreBegin(thr, pc);
+  int res = REAL(on_exit)(on_exit_wrapper, ctx);
+  ThreadIgnoreEnd(thr, pc);
+  return res;
 }
 
 // Cleanup old bufs.
@@ -372,10 +386,21 @@
   buf->sp = sp;
   buf->mangled_sp = mangled_sp;
   buf->shadow_stack_pos = thr->shadow_stack_pos;
+  SignalContext *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) :
+      false;
+  buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
+      memory_order_relaxed);
 }
 
 static void LongJmp(ThreadState *thr, uptr *env) {
+#if SANITIZER_FREEBSD
+  uptr mangled_sp = env[2];
+#else
   uptr mangled_sp = env[6];
+#endif  // SANITIZER_FREEBSD
   // Find the saved buf by mangled_sp.
   for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
     JmpBuf *buf = &thr->jmp_bufs[i];
@@ -384,6 +409,14 @@
       // Unwind the stack.
       while (thr->shadow_stack_pos > buf->shadow_stack_pos)
         FuncExit(thr);
+      SignalContext *sctx = SigCtx(thr);
+      if (sctx) {
+        sctx->int_signal_send = buf->int_signal_send;
+        atomic_store(&sctx->in_blocking_func, buf->in_blocking_func,
+            memory_order_relaxed);
+      }
+      atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
+          memory_order_relaxed);
       JmpBufGarbageCollect(thr, buf->sp - 1);  // do not collect buf->sp
       return;
     }
@@ -615,7 +648,8 @@
   int res = 0;
   uptr len = 0;
   for (; len < n; len++) {
-    if ((res = ((unsigned char*)s1)[len] - ((unsigned char*)s2)[len]))
+    if ((res = ((const unsigned char *)s1)[len] -
+               ((const unsigned char *)s2)[len]))
       break;
   }
   MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false);
@@ -712,6 +746,7 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
                            int flags, int fd, u64 off) {
   SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
@@ -725,6 +760,10 @@
   }
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64)
+#else
+#define TSAN_MAYBE_INTERCEPT_MMAP64
+#endif
 
 TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
   SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
@@ -733,10 +772,15 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
   return user_alloc(thr, pc, sz, align);
 }
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
+#else
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
 
 TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
@@ -748,11 +792,16 @@
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
   sz = RoundUp(sz, GetPageSizeCached());
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
+#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
+#else
+#define TSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
 
 TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
@@ -824,11 +873,13 @@
     ThreadState *thr = cur_thread();
     // Thread-local state is not initialized yet.
     ScopedIgnoreInterceptors ignore;
+    ThreadIgnoreBegin(thr, 0);
     if (pthread_setspecific(g_thread_finalize_key,
                             (void *)kPthreadDestructorIterations)) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
     }
+    ThreadIgnoreEnd(thr, 0);
     while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
       pthread_yield();
     atomic_store(&p->tid, 0, memory_order_release);
@@ -1297,73 +1348,135 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
   return REAL(__xstat)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+  return REAL(stat)(path, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
   return REAL(__xstat)(0, path, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
   return REAL(__xstat64)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
   return REAL(__xstat64)(0, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_STAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
   return REAL(__lxstat)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+  return REAL(lstat)(path, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
   return REAL(__lxstat)(0, path, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
   return REAL(__lxstat64)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
   return REAL(__lxstat64)(0, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_LSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat)(version, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(fstat)(fd, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat)(0, fd, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat64)(version, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat64)(0, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_FSTAT64
+#endif
 
 TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
@@ -1373,6 +1486,7 @@
   return fd;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
   int fd = REAL(open64)(name, flags, mode);
@@ -1380,6 +1494,10 @@
     FdFileCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64)
+#else
+#define TSAN_MAYBE_INTERCEPT_OPEN64
+#endif
 
 TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
@@ -1389,6 +1507,7 @@
   return fd;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
   int fd = REAL(creat64)(name, mode);
@@ -1396,6 +1515,10 @@
     FdFileCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_CREAT64
+#endif
 
 TSAN_INTERCEPTOR(int, dup, int oldfd) {
   SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
@@ -1421,6 +1544,7 @@
   return newfd2;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
   SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
   int fd = REAL(eventfd)(initval, flags);
@@ -1428,7 +1552,12 @@
     FdEventCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_EVENTFD
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
   SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
   if (fd >= 0)
@@ -1438,7 +1567,12 @@
     FdSignalCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, inotify_init, int fake) {
   SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
   int fd = REAL(inotify_init)(fake);
@@ -1446,7 +1580,12 @@
     FdInotifyCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
   SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
   int fd = REAL(inotify_init1)(flags);
@@ -1454,6 +1593,10 @@
     FdInotifyCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1
+#endif
 
 TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) {
   SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol);
@@ -1496,6 +1639,7 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_create, int size) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
   int fd = REAL(epoll_create)(size);
@@ -1503,7 +1647,12 @@
     FdPollCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
   int fd = REAL(epoll_create1)(flags);
@@ -1511,6 +1660,10 @@
     FdPollCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1
+#endif
 
 TSAN_INTERCEPTOR(int, close, int fd) {
   SCOPED_TSAN_INTERCEPTOR(close, fd);
@@ -1519,14 +1672,20 @@
   return REAL(close)(fd);
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __close, int fd) {
   SCOPED_TSAN_INTERCEPTOR(__close, fd);
   if (fd >= 0)
     FdClose(thr, pc, fd);
   return REAL(__close)(fd);
 }
+#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close)
+#else
+#define TSAN_MAYBE_INTERCEPT___CLOSE
+#endif
 
 // glibc guts
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
   SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
   int fds[64];
@@ -1537,6 +1696,10 @@
   }
   REAL(__res_iclose)(state, free_addr);
 }
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose)
+#else
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE
+#endif
 
 TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
@@ -1603,6 +1766,7 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
   SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
   void *res = REAL(tmpfile64)(fake);
@@ -1613,6 +1777,10 @@
   }
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64)
+#else
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64
+#endif
 
 TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
   // libc file streams can call user-supplied functions, see fopencookie.
@@ -1659,6 +1827,7 @@
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
   SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
   if (epfd >= 0)
@@ -1670,7 +1839,12 @@
   int res = REAL(epoll_ctl)(epfd, op, fd, ev);
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
   SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
   if (epfd >= 0)
@@ -1680,11 +1854,17 @@
     FdAcquire(thr, pc, epfd);
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
 
 namespace __tsan {
 
-static void CallUserSignalHandler(ThreadState *thr, bool sync, bool sigact,
-    int sig, my_siginfo_t *info, void *uctx) {
+static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
+    bool sigact, int sig, my_siginfo_t *info, void *uctx) {
+  if (acquire)
+    Acquire(thr, 0, (uptr)&sigactions[sig]);
   // Ensure that the handler does not spoil errno.
   const int saved_errno = errno;
   errno = 99;
@@ -1705,12 +1885,12 @@
   // from rtl_generic_sighandler) we have not yet received the reraised
   // signal; and it looks too fragile to intercept all ways to reraise a signal.
   if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
-    __tsan::StackTrace stack;
-    stack.ObtainCurrent(thr, pc);
+    VarSizeStackTrace stack;
+    ObtainCurrentStack(thr, pc, &stack);
     ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeErrnoInSignal);
     if (!IsFiredSuppression(ctx, rep, stack)) {
-      rep.AddStack(&stack, true);
+      rep.AddStack(stack, true);
       OutputReport(thr, rep);
     }
   }
@@ -1719,10 +1899,11 @@
 
 void ProcessPendingSignals(ThreadState *thr) {
   SignalContext *sctx = SigCtx(thr);
-  if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
+  if (sctx == 0 ||
+      atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0)
     return;
-  thr->in_signal_handler = true;
-  sctx->pending_signal_count = 0;
+  atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed);
+  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);
@@ -1733,14 +1914,13 @@
       signal->armed = false;
       if (sigactions[sig].sa_handler != SIG_DFL
           && sigactions[sig].sa_handler != SIG_IGN) {
-        CallUserSignalHandler(thr, false, signal->sigaction,
+        CallUserSignalHandler(thr, false, true, signal->sigaction,
             sig, &signal->siginfo, &signal->ctx);
       }
     }
   }
   pthread_sigmask(SIG_SETMASK, &oldset, 0);
-  CHECK_EQ(thr->in_signal_handler, true);
-  thr->in_signal_handler = false;
+  atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
 }
 
 }  // namespace __tsan
@@ -1766,21 +1946,27 @@
       // If we are in blocking function, we can safely process it now
       // (but check if we are in a recursive interceptor,
       // i.e. pthread_join()->munmap()).
-      (sctx && sctx->in_blocking_func == 1)) {
-    CHECK_EQ(thr->in_signal_handler, false);
-    thr->in_signal_handler = true;
-    if (sctx && sctx->in_blocking_func == 1) {
+      (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) {
+    atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
+    if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) {
       // We ignore interceptors in blocking functions,
       // temporary enbled them again while we are calling user function.
       int const i = thr->ignore_interceptors;
       thr->ignore_interceptors = 0;
-      CallUserSignalHandler(thr, sync, sigact, sig, info, ctx);
+      atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed);
+      CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx);
       thr->ignore_interceptors = i;
+      atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed);
     } else {
-      CallUserSignalHandler(thr, sync, sigact, sig, info, ctx);
+      // Be very conservative with when we do acquire in this case.
+      // It's unsafe to do acquire in async handlers, because ThreadState
+      // can be in inconsistent state.
+      // SIGSYS looks relatively safe -- it's synchronous and can actually
+      // need some global state.
+      bool acq = (sig == SIGSYS);
+      CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx);
     }
-    CHECK_EQ(thr->in_signal_handler, true);
-    thr->in_signal_handler = false;
+    atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
     return;
   }
 
@@ -1794,7 +1980,7 @@
       internal_memcpy(&signal->siginfo, info, sizeof(*info));
     if (ctx)
       internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx));
-    sctx->pending_signal_count++;
+    atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed);
   }
 }
 
@@ -1822,6 +2008,7 @@
     else
       newact.sa_handler = rtl_sighandler;
   }
+  ReleaseStore(thr, pc, (uptr)&sigactions[sig]);
   int res = REAL(sigaction)(sig, &newact, 0);
   return res;
 }
@@ -1905,35 +2092,6 @@
   return res;
 }
 
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
-  static atomic_uint8_t printed;
-  if (atomic_exchange(&printed, 1, memory_order_relaxed))
-    return;
-  VPrintf(1, "INFO: ThreadSanitizer ignores mlock/munlock[all]\n");
-}
-
-TSAN_INTERCEPTOR(int, mlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-TSAN_INTERCEPTOR(int, munlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-TSAN_INTERCEPTOR(int, mlockall, int flags) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-TSAN_INTERCEPTOR(int, munlockall, void) {
-  MlockIsUnsupported();
-  return 0;
-}
-
 TSAN_INTERCEPTOR(int, fork, int fake) {
   if (cur_thread()->in_symbolizer)
     return REAL(fork)(fake);
@@ -1994,6 +2152,18 @@
 #include "sanitizer_common/sanitizer_platform_interceptors.h"
 // Causes interceptor recursion (getaddrinfo() and fopen())
 #undef SANITIZER_INTERCEPT_GETADDRINFO
+// There interceptors do not seem to be strictly necessary for tsan.
+// But we see cases where the interceptors consume 70% of execution time.
+// Memory blocks passed to fgetgrent_r are "written to" by tsan several times.
+// First, there is some recursion (getgrnam_r calls fgetgrent_r), and each
+// function "writes to" the buffer. Then, the same memory is "written to"
+// twice, first as buf and then as pwbufp (both of them refer to the same
+// addresses).
+#undef SANITIZER_INTERCEPT_GETPWENT
+#undef SANITIZER_INTERCEPT_GETPWENT_R
+#undef SANITIZER_INTERCEPT_FGETPWENT
+#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
+#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
 
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
 
@@ -2195,8 +2365,6 @@
 
 static void finalize(void *arg) {
   ThreadState *thr = cur_thread();
-  uptr pc = 0;
-  atexit_ctx->exit(thr, pc);
   int status = Finalize(thr);
   // Make sure the output is not lost.
   // Flushing all the streams here may freeze the process if a child thread is
@@ -2219,8 +2387,10 @@
   REAL(memcmp) = internal_memcmp;
 
   // Instruct libc malloc to consume less memory.
+#if !SANITIZER_FREEBSD
   mallopt(1, 0);  // M_MXFAST
   mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
+#endif
 
   InitializeCommonInterceptors();
 
@@ -2242,11 +2412,11 @@
   TSAN_INTERCEPT(free);
   TSAN_INTERCEPT(cfree);
   TSAN_INTERCEPT(mmap);
-  TSAN_INTERCEPT(mmap64);
+  TSAN_MAYBE_INTERCEPT_MMAP64;
   TSAN_INTERCEPT(munmap);
-  TSAN_INTERCEPT(memalign);
+  TSAN_MAYBE_INTERCEPT_MEMALIGN;
   TSAN_INTERCEPT(valloc);
-  TSAN_INTERCEPT(pvalloc);
+  TSAN_MAYBE_INTERCEPT_PVALLOC;
   TSAN_INTERCEPT(posix_memalign);
 
   TSAN_INTERCEPT(strlen);
@@ -2309,38 +2479,38 @@
   TSAN_INTERCEPT(sem_getvalue);
 
   TSAN_INTERCEPT(stat);
-  TSAN_INTERCEPT(__xstat);
-  TSAN_INTERCEPT(stat64);
-  TSAN_INTERCEPT(__xstat64);
+  TSAN_MAYBE_INTERCEPT___XSTAT;
+  TSAN_MAYBE_INTERCEPT_STAT64;
+  TSAN_MAYBE_INTERCEPT___XSTAT64;
   TSAN_INTERCEPT(lstat);
-  TSAN_INTERCEPT(__lxstat);
-  TSAN_INTERCEPT(lstat64);
-  TSAN_INTERCEPT(__lxstat64);
+  TSAN_MAYBE_INTERCEPT___LXSTAT;
+  TSAN_MAYBE_INTERCEPT_LSTAT64;
+  TSAN_MAYBE_INTERCEPT___LXSTAT64;
   TSAN_INTERCEPT(fstat);
-  TSAN_INTERCEPT(__fxstat);
-  TSAN_INTERCEPT(fstat64);
-  TSAN_INTERCEPT(__fxstat64);
+  TSAN_MAYBE_INTERCEPT___FXSTAT;
+  TSAN_MAYBE_INTERCEPT_FSTAT64;
+  TSAN_MAYBE_INTERCEPT___FXSTAT64;
   TSAN_INTERCEPT(open);
-  TSAN_INTERCEPT(open64);
+  TSAN_MAYBE_INTERCEPT_OPEN64;
   TSAN_INTERCEPT(creat);
-  TSAN_INTERCEPT(creat64);
+  TSAN_MAYBE_INTERCEPT_CREAT64;
   TSAN_INTERCEPT(dup);
   TSAN_INTERCEPT(dup2);
   TSAN_INTERCEPT(dup3);
-  TSAN_INTERCEPT(eventfd);
-  TSAN_INTERCEPT(signalfd);
-  TSAN_INTERCEPT(inotify_init);
-  TSAN_INTERCEPT(inotify_init1);
+  TSAN_MAYBE_INTERCEPT_EVENTFD;
+  TSAN_MAYBE_INTERCEPT_SIGNALFD;
+  TSAN_MAYBE_INTERCEPT_INOTIFY_INIT;
+  TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1;
   TSAN_INTERCEPT(socket);
   TSAN_INTERCEPT(socketpair);
   TSAN_INTERCEPT(connect);
   TSAN_INTERCEPT(bind);
   TSAN_INTERCEPT(listen);
-  TSAN_INTERCEPT(epoll_create);
-  TSAN_INTERCEPT(epoll_create1);
+  TSAN_MAYBE_INTERCEPT_EPOLL_CREATE;
+  TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1;
   TSAN_INTERCEPT(close);
-  TSAN_INTERCEPT(__close);
-  TSAN_INTERCEPT(__res_iclose);
+  TSAN_MAYBE_INTERCEPT___CLOSE;
+  TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
@@ -2350,7 +2520,7 @@
 
   TSAN_INTERCEPT(unlink);
   TSAN_INTERCEPT(tmpfile);
-  TSAN_INTERCEPT(tmpfile64);
+  TSAN_MAYBE_INTERCEPT_TMPFILE64;
   TSAN_INTERCEPT(fread);
   TSAN_INTERCEPT(fwrite);
   TSAN_INTERCEPT(abort);
@@ -2358,8 +2528,8 @@
   TSAN_INTERCEPT(rmdir);
   TSAN_INTERCEPT(opendir);
 
-  TSAN_INTERCEPT(epoll_ctl);
-  TSAN_INTERCEPT(epoll_wait);
+  TSAN_MAYBE_INTERCEPT_EPOLL_CTL;
+  TSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
 
   TSAN_INTERCEPT(sigaction);
   TSAN_INTERCEPT(signal);
@@ -2373,11 +2543,6 @@
   TSAN_INTERCEPT(gettimeofday);
   TSAN_INTERCEPT(getaddrinfo);
 
-  TSAN_INTERCEPT(mlock);
-  TSAN_INTERCEPT(munlock);
-  TSAN_INTERCEPT(mlockall);
-  TSAN_INTERCEPT(munlockall);
-
   TSAN_INTERCEPT(fork);
   TSAN_INTERCEPT(vfork);
   TSAN_INTERCEPT(on_exit);
@@ -2387,9 +2552,6 @@
   // Need to setup it, because interceptors check that the function is resolved.
   // But atexit is emitted directly into the module, so can't be resolved.
   REAL(atexit) = (int(*)(void(*)()))unreachable;
-  atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
-      AtExitContext();
-
   if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
     Printf("ThreadSanitizer: failed to setup atexit callback\n");
     Die();
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc
index a1725cb..fd3c846 100644
--- a/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/lib/tsan/rtl/tsan_interface_ann.cc
@@ -54,7 +54,7 @@
     StatInc(thr, StatAnnotation); \
     StatInc(thr, Stat##typ); \
     ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+    const uptr pc = StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -126,8 +126,6 @@
 
 static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
   ExpectRace *race = FindRace(list, addr, size);
-  if (race == 0 && AlternativeAddress(addr))
-    race = FindRace(list, AlternativeAddress(addr), size);
   if (race == 0)
     return false;
   DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
@@ -456,4 +454,6 @@
 
 void INTERFACE_ATTRIBUTE
 AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
 }  // extern "C"
diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc
index 7fbc9c6..ceb32bd 100644
--- a/lib/tsan/rtl/tsan_interface_atomic.cc
+++ b/lib/tsan/rtl/tsan_interface_atomic.cc
@@ -27,33 +27,23 @@
 
 using namespace __tsan;  // NOLINT
 
-#define SCOPED_ATOMIC(func, ...) \
-    const uptr callpc = (uptr)__builtin_return_address(0); \
-    uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
-    mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
-    ThreadState *const thr = cur_thread(); \
-    if (thr->ignore_interceptors) \
-      return NoTsanAtomic##func(__VA_ARGS__); \
-    AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
-    ScopedAtomic sa(thr, callpc, a, mo, __func__); \
-    return Atomic##func(thr, pc, __VA_ARGS__); \
-/**/
-
 // These should match declarations from public tsan_interface_atomic.h header.
 typedef unsigned char      a8;
 typedef unsigned short     a16;  // NOLINT
 typedef unsigned int       a32;
 typedef unsigned long long a64;  // NOLINT
-#if defined(__SIZEOF_INT128__) \
-    || (__clang_major__ * 100 + __clang_minor__ >= 302)
+#if !defined(TSAN_GO) && (defined(__SIZEOF_INT128__) \
+    || (__clang_major__ * 100 + __clang_minor__ >= 302))
 __extension__ typedef __int128 a128;
 # define __TSAN_HAS_INT128 1
 #else
 # define __TSAN_HAS_INT128 0
 #endif
 
+#ifndef TSAN_GO
 // Protects emulation of 128-bit atomic operations.
 static StaticSpinMutex mutex128;
+#endif
 
 // Part of ABI, do not change.
 // http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
@@ -66,38 +56,6 @@
   mo_seq_cst
 } morder;
 
-class ScopedAtomic {
- public:
-  ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
-               morder mo, const char *func)
-      : thr_(thr) {
-    FuncEntry(thr_, pc);
-    DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
-  }
-  ~ScopedAtomic() {
-    ProcessPendingSignals(thr_);
-    FuncExit(thr_);
-  }
- private:
-  ThreadState *thr_;
-};
-
-static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
-  StatInc(thr, StatAtomic);
-  StatInc(thr, t);
-  StatInc(thr, size == 1 ? StatAtomic1
-             : size == 2 ? StatAtomic2
-             : size == 4 ? StatAtomic4
-             : size == 8 ? StatAtomic8
-             :             StatAtomic16);
-  StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
-             : mo == mo_consume ? StatAtomicConsume
-             : mo == mo_acquire ? StatAtomicAcquire
-             : mo == mo_release ? StatAtomicRelease
-             : mo == mo_acq_rel ? StatAtomicAcq_Rel
-             :                    StatAtomicSeq_Cst);
-}
-
 static bool IsLoadOrder(morder mo) {
   return mo == mo_relaxed || mo == mo_consume
       || mo == mo_acquire || mo == mo_seq_cst;
@@ -167,7 +125,7 @@
 // Atomic ops are executed under tsan internal mutex,
 // here we assume that the atomic variables are not accessed
 // from non-instrumented code.
-#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(TSAN_GO)
 a128 func_xchg(volatile a128 *v, a128 op) {
   SpinMutexLock lock(&mutex128);
   a128 cmp = *v;
@@ -240,20 +198,22 @@
   // this leads to false negatives only in very obscure cases.
 }
 
+#ifndef TSAN_GO
 static atomic_uint8_t *to_atomic(const volatile a8 *a) {
-  return (atomic_uint8_t*)a;
+  return reinterpret_cast<atomic_uint8_t *>(const_cast<a8 *>(a));
 }
 
 static atomic_uint16_t *to_atomic(const volatile a16 *a) {
-  return (atomic_uint16_t*)a;
+  return reinterpret_cast<atomic_uint16_t *>(const_cast<a16 *>(a));
 }
+#endif
 
 static atomic_uint32_t *to_atomic(const volatile a32 *a) {
-  return (atomic_uint32_t*)a;
+  return reinterpret_cast<atomic_uint32_t *>(const_cast<a32 *>(a));
 }
 
 static atomic_uint64_t *to_atomic(const volatile a64 *a) {
-  return (atomic_uint64_t*)a;
+  return reinterpret_cast<atomic_uint64_t *>(const_cast<a64 *>(a));
 }
 
 static memory_order to_mo(morder mo) {
@@ -274,7 +234,7 @@
   return atomic_load(to_atomic(a), to_mo(mo));
 }
 
-#if __TSAN_HAS_INT128
+#if __TSAN_HAS_INT128 && !defined(TSAN_GO)
 static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
   SpinMutexLock lock(&mutex128);
   return *a;
@@ -304,7 +264,7 @@
   atomic_store(to_atomic(a), v, to_mo(mo));
 }
 
-#if __TSAN_HAS_INT128
+#if __TSAN_HAS_INT128 && !defined(TSAN_GO)
 static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) {
   SpinMutexLock lock(&mutex128);
   *a = v;
@@ -451,8 +411,9 @@
 #endif
 
 template<typename T>
-static bool NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
-  return NoTsanAtomicCAS(a, &c, v, mo, fmo);
+static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) {
+  NoTsanAtomicCAS(a, &c, v, mo, fmo);
+  return c;
 }
 
 template<typename T>
@@ -495,6 +456,7 @@
   return c;
 }
 
+#ifndef TSAN_GO
 static void NoTsanAtomicFence(morder mo) {
   __sync_synchronize();
 }
@@ -503,6 +465,56 @@
   // FIXME(dvyukov): not implemented.
   __sync_synchronize();
 }
+#endif
+
+// Interface functions follow.
+#ifndef TSAN_GO
+
+// C/C++
+
+#define SCOPED_ATOMIC(func, ...) \
+    const uptr callpc = (uptr)__builtin_return_address(0); \
+    uptr pc = StackTrace::GetCurrentPc(); \
+    mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
+    ThreadState *const thr = cur_thread(); \
+    if (thr->ignore_interceptors) \
+      return NoTsanAtomic##func(__VA_ARGS__); \
+    AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
+    ScopedAtomic sa(thr, callpc, a, mo, __func__); \
+    return Atomic##func(thr, pc, __VA_ARGS__); \
+/**/
+
+class ScopedAtomic {
+ public:
+  ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
+               morder mo, const char *func)
+      : thr_(thr) {
+    FuncEntry(thr_, pc);
+    DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
+  }
+  ~ScopedAtomic() {
+    ProcessPendingSignals(thr_);
+    FuncExit(thr_);
+  }
+ private:
+  ThreadState *thr_;
+};
+
+static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
+  StatInc(thr, StatAtomic);
+  StatInc(thr, t);
+  StatInc(thr, size == 1 ? StatAtomic1
+             : size == 2 ? StatAtomic2
+             : size == 4 ? StatAtomic4
+             : size == 8 ? StatAtomic8
+             :             StatAtomic16);
+  StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed
+             : mo == mo_consume ? StatAtomicConsume
+             : mo == mo_acquire ? StatAtomicAcquire
+             : mo == mo_release ? StatAtomicRelease
+             : mo == mo_acq_rel ? StatAtomicAcq_Rel
+             :                    StatAtomicSeq_Cst);
+}
 
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -854,3 +866,88 @@
 void __tsan_atomic_signal_fence(morder mo) {
 }
 }  // extern "C"
+
+#else  // #ifndef TSAN_GO
+
+// Go
+
+#define ATOMIC(func, ...) \
+    if (thr->ignore_sync) { \
+      NoTsanAtomic##func(__VA_ARGS__); \
+    } else { \
+      FuncEntry(thr, cpc); \
+      Atomic##func(thr, pc, __VA_ARGS__); \
+      FuncExit(thr); \
+    } \
+/**/
+
+#define ATOMIC_RET(func, ret, ...) \
+    if (thr->ignore_sync) { \
+      (ret) = NoTsanAtomic##func(__VA_ARGS__); \
+    } else { \
+      FuncEntry(thr, cpc); \
+      (ret) = Atomic##func(thr, pc, __VA_ARGS__); \
+      FuncExit(thr); \
+    } \
+/**/
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(Load, *(a32*)(a+8), *(a32**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(Load, *(a64*)(a+8), *(a64**)a, mo_acquire);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC(Store, *(a32**)a, *(a32*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC(Store, *(a64**)a, *(a64*)(a+8), mo_release);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(FetchAdd, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(FetchAdd, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  ATOMIC_RET(Exchange, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_compare_exchange(
+    ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  a32 cur = 0;
+  a32 cmp = *(a32*)(a+8);
+  ATOMIC_RET(CAS, cur, *(a32**)a, cmp, *(a32*)(a+12), mo_acq_rel, mo_acquire);
+  *(bool*)(a+16) = (cur == cmp);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_compare_exchange(
+    ThreadState *thr, uptr cpc, uptr pc, u8 *a) {
+  a64 cur = 0;
+  a64 cmp = *(a64*)(a+8);
+  ATOMIC_RET(CAS, cur, *(a64**)a, cmp, *(a64*)(a+16), mo_acq_rel, mo_acquire);
+  *(bool*)(a+24) = (cur == cmp);
+}
+}  // extern "C"
+#endif  // #ifndef TSAN_GO
diff --git a/lib/tsan/rtl/tsan_interface_java.cc b/lib/tsan/rtl/tsan_interface_java.cc
index 5dfb476..8615349 100644
--- a/lib/tsan/rtl/tsan_interface_java.cc
+++ b/lib/tsan/rtl/tsan_interface_java.cc
@@ -61,7 +61,7 @@
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
   const uptr caller_pc = GET_CALLER_PC(); \
-  const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+  const uptr pc = StackTrace::GetCurrentPc(); \
   (void)pc; \
   ScopedJavaFunc scoped(thr, caller_pc); \
 /**/
diff --git a/lib/tsan/rtl/tsan_md5.cc b/lib/tsan/rtl/tsan_md5.cc
index 66e8240..51279c1 100644
--- a/lib/tsan/rtl/tsan_md5.cc
+++ b/lib/tsan/rtl/tsan_md5.cc
@@ -25,7 +25,7 @@
   (a) += (b);
 
 #define SET(n) \
-  (*(MD5_u32plus *)&ptr[(n) * 4])
+  (*(const MD5_u32plus *)&ptr[(n) * 4])
 #define GET(n) \
   SET(n)
 
@@ -39,13 +39,11 @@
   MD5_u32plus block[16];
 } MD5_CTX;
 
-static void *body(MD5_CTX *ctx, void *data, ulong_t size) {
-  unsigned char *ptr;
+static const void *body(MD5_CTX *ctx, const void *data, ulong_t size) {
+  const unsigned char *ptr = (const unsigned char *)data;
   MD5_u32plus a, b, c, d;
   MD5_u32plus saved_a, saved_b, saved_c, saved_d;
 
-  ptr = (unsigned char*)data;
-
   a = ctx->a;
   b = ctx->b;
   c = ctx->c;
@@ -151,7 +149,7 @@
   ctx->hi = 0;
 }
 
-void MD5_Update(MD5_CTX *ctx, void *data, ulong_t size) {
+void MD5_Update(MD5_CTX *ctx, const void *data, ulong_t size) {
   MD5_u32plus saved_lo;
   ulong_t used, free;
 
@@ -171,7 +169,7 @@
     }
 
     internal_memcpy(&ctx->buffer[used], data, free);
-    data = (unsigned char *)data + free;
+    data = (const unsigned char *)data + free;
     size -= free;
     body(ctx, ctx->buffer, 64);
   }
@@ -238,7 +236,7 @@
   MD5Hash res;
   MD5_CTX ctx;
   MD5_Init(&ctx);
-  MD5_Update(&ctx, (void*)data, size);
+  MD5_Update(&ctx, data, size);
   MD5_Final((unsigned char*)&res.hash[0], &ctx);
   return res;
 }
diff --git a/lib/tsan/rtl/tsan_mman.cc b/lib/tsan/rtl/tsan_mman.cc
index 8542a8f..285bdb3 100644
--- a/lib/tsan/rtl/tsan_mman.cc
+++ b/lib/tsan/rtl/tsan_mman.cc
@@ -19,18 +19,11 @@
 #include "tsan_flags.h"
 
 // May be overriden by front-end.
-extern "C" void WEAK __tsan_malloc_hook(void *ptr, uptr size) {
-  (void)ptr;
-  (void)size;
-}
 extern "C" void WEAK __sanitizer_malloc_hook(void *ptr, uptr size) {
   (void)ptr;
   (void)size;
 }
 
-extern "C" void WEAK __tsan_free_hook(void *ptr) {
-  (void)ptr;
-}
 extern "C" void WEAK __sanitizer_free_hook(void *ptr) {
   (void)ptr;
 }
@@ -70,19 +63,20 @@
 }
 
 static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
-  if (!thr->in_signal_handler || !flags()->report_signal_unsafe)
+  if (atomic_load(&thr->in_signal_handler, memory_order_relaxed) == 0 ||
+      !flags()->report_signal_unsafe)
     return;
-  StackTrace stack;
-  stack.ObtainCurrent(thr, pc);
+  VarSizeStackTrace stack;
+  ObtainCurrentStack(thr, pc, &stack);
   ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(ReportTypeSignalUnsafe);
   if (!IsFiredSuppression(ctx, rep, stack)) {
-    rep.AddStack(&stack, true);
+    rep.AddStack(stack, true);
     OutputReport(thr, rep);
   }
 }
 
-void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
   if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
     return AllocatorReturnNull();
   void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
@@ -90,15 +84,17 @@
     return 0;
   if (ctx && ctx->initialized)
     OnUserAlloc(thr, pc, (uptr)p, sz, true);
-  SignalUnsafeCall(thr, pc);
+  if (signal)
+    SignalUnsafeCall(thr, pc);
   return p;
 }
 
-void user_free(ThreadState *thr, uptr pc, void *p) {
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
   if (ctx && ctx->initialized)
     OnUserFree(thr, pc, (uptr)p, true);
   allocator()->Deallocate(&thr->alloc_cache, p);
-  SignalUnsafeCall(thr, pc);
+  if (signal)
+    SignalUnsafeCall(thr, pc);
 }
 
 void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
@@ -147,7 +143,6 @@
   ThreadState *thr = cur_thread();
   if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
     return;
-  __tsan_malloc_hook(ptr, size);
   __sanitizer_malloc_hook(ptr, size);
 }
 
@@ -155,13 +150,11 @@
   ThreadState *thr = cur_thread();
   if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
     return;
-  __tsan_free_hook(ptr);
   __sanitizer_free_hook(ptr);
 }
 
 void *internal_alloc(MBlockType typ, uptr sz) {
   ThreadState *thr = cur_thread();
-  CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
   if (thr->nomalloc) {
     thr->nomalloc = 0;  // CHECK calls internal_malloc().
     CHECK(0);
@@ -188,53 +181,32 @@
   allocator()->GetStats(stats);
   return stats[AllocatorStatAllocated];
 }
-uptr __tsan_get_current_allocated_bytes() {
-  return __sanitizer_get_current_allocated_bytes();
-}
 
 uptr __sanitizer_get_heap_size() {
   uptr stats[AllocatorStatCount];
   allocator()->GetStats(stats);
   return stats[AllocatorStatMapped];
 }
-uptr __tsan_get_heap_size() {
-  return __sanitizer_get_heap_size();
-}
 
 uptr __sanitizer_get_free_bytes() {
   return 1;
 }
-uptr __tsan_get_free_bytes() {
-  return __sanitizer_get_free_bytes();
-}
 
 uptr __sanitizer_get_unmapped_bytes() {
   return 1;
 }
-uptr __tsan_get_unmapped_bytes() {
-  return __sanitizer_get_unmapped_bytes();
-}
 
 uptr __sanitizer_get_estimated_allocated_size(uptr size) {
   return size;
 }
-uptr __tsan_get_estimated_allocated_size(uptr size) {
-  return __sanitizer_get_estimated_allocated_size(size);
-}
 
 int __sanitizer_get_ownership(const void *p) {
   return allocator()->GetBlockBegin(p) != 0;
 }
-int __tsan_get_ownership(const void *p) {
-  return __sanitizer_get_ownership(p);
-}
 
 uptr __sanitizer_get_allocated_size(const void *p) {
   return user_alloc_usable_size(p);
 }
-uptr __tsan_get_allocated_size(const void *p) {
-  return __sanitizer_get_allocated_size(p);
-}
 
 void __tsan_on_thread_idle() {
   ThreadState *thr = cur_thread();
diff --git a/lib/tsan/rtl/tsan_mman.h b/lib/tsan/rtl/tsan_mman.h
index 4f87ad6..7d41fa8 100644
--- a/lib/tsan/rtl/tsan_mman.h
+++ b/lib/tsan/rtl/tsan_mman.h
@@ -26,9 +26,9 @@
 
 // For user allocations.
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
-                 uptr align = kDefaultAlignment);
+                 uptr align = kDefaultAlignment, bool signal = true);
 // Does not accept NULL.
-void user_free(ThreadState *thr, uptr pc, void *p);
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
 void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
 void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
 uptr user_alloc_usable_size(const void *p);
diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h
index 7d8d977..45f8631 100644
--- a/lib/tsan/rtl/tsan_platform.h
+++ b/lib/tsan/rtl/tsan_platform.h
@@ -12,162 +12,223 @@
 // Platform-specific code.
 //===----------------------------------------------------------------------===//
 
-/*
-C++ linux memory layout:
-0000 0000 0000 - 03c0 0000 0000: protected
-03c0 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 3000 0000 0000: protected
-3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 6000 0000 0000: protected
-6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7d00 0000 0000: -
-7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7fff ffff ffff: modules and main thread stack
-
-C++ COMPAT linux memory layout:
-0000 0000 0000 - 0400 0000 0000: protected
-0400 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 2900 0000 0000: protected
-2900 0000 0000 - 2c00 0000 0000: modules
-2c00 0000 0000 - 3000 0000 0000: -
-3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 6000 0000 0000: -
-6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7d00 0000 0000: -
-7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7f00 0000 0000: -
-7f00 0000 0000 - 7fff ffff ffff: main thread stack
-
-Go linux and darwin memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
-00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 1000 0000 0000: -
-1000 0000 0000 - 1380 0000 0000: shadow
-1460 0000 0000 - 2000 0000 0000: -
-3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 6000 0000 0000: -
-6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7fff ffff ffff: -
-
-Go windows memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
-00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 0100 0000 0000: -
-0100 0000 0000 - 0560 0000 0000: shadow
-0560 0000 0000 - 0760 0000 0000: traces
-0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
-07d0 0000 0000 - 07ff ffff ffff: -
-*/
-
 #ifndef TSAN_PLATFORM_H
 #define TSAN_PLATFORM_H
 
+#if !defined(__LP64__) && !defined(_WIN64)
+# error "Only 64-bit is supported"
+#endif
+
 #include "tsan_defs.h"
 #include "tsan_trace.h"
 
-#if defined(__LP64__) || defined(_WIN64)
 namespace __tsan {
 
-#if defined(TSAN_GO)
-static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x04dfffffffffULL;
-# if SANITIZER_WINDOWS
-static const uptr kLinuxShadowMsk = 0x010000000000ULL;
-static const uptr kMetaShadow     = 0x076000000000ULL;
-static const uptr kMetaSize       = 0x007000000000ULL;
-# else  // if SANITIZER_WINDOWS
-static const uptr kLinuxShadowMsk = 0x200000000000ULL;
-static const uptr kMetaShadow     = 0x300000000000ULL;
-static const uptr kMetaSize       = 0x100000000000ULL;
-# endif  // if SANITIZER_WINDOWS
-#else  // defined(TSAN_GO)
-static const uptr kMetaShadow     = 0x300000000000ULL;
-static const uptr kMetaSize       = 0x100000000000ULL;
-// TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
-// when memory addresses are of the 0x2axxxxxxxxxx form.
-// The option is enabled with 'setarch x86_64 -L'.
-# if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-static const uptr kLinuxAppMemBeg = 0x290000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-static const uptr kAppMemGapBeg   = 0x2c0000000000ULL;
-static const uptr kAppMemGapEnd   = 0x7d0000000000ULL;
-# else
-static const uptr kLinuxAppMemBeg = 0x7cf000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-# endif
-#endif
+#if !defined(TSAN_GO)
 
-static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
+/*
+C/C++ on linux and freebsd
+0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
+0100 0000 0000 - 0200 0000 0000: -
+0200 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
+6000 0000 0000 - 6200 0000 0000: traces
+6200 0000 0000 - 7d00 0000 0000: -
+7d00 0000 0000 - 7e00 0000 0000: heap
+7e00 0000 0000 - 7e80 0000 0000: -
+7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
+*/
 
-#if SANITIZER_WINDOWS
-const uptr kTraceMemBegin = 0x056000000000ULL;
-#else
-const uptr kTraceMemBegin = 0x600000000000ULL;
-#endif
-const uptr kTraceMemSize = 0x020000000000ULL;
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg   = 0x600000000000ull;
+const uptr kTraceMemEnd   = 0x620000000000ull;
+const uptr kShadowBeg     = 0x020000000000ull;
+const uptr kShadowEnd     = 0x100000000000ull;
+const uptr kHeapMemBeg    = 0x7d0000000000ull;
+const uptr kHeapMemEnd    = 0x7e0000000000ull;
+const uptr kLoAppMemBeg   = 0x000000001000ull;
+const uptr kLoAppMemEnd   = 0x010000000000ull;
+const uptr kHiAppMemBeg   = 0x7e8000000000ull;
+const uptr kHiAppMemEnd   = 0x800000000000ull;
+const uptr kAppMemMsk     = 0x7c0000000000ull;
+const uptr kAppMemXor     = 0x020000000000ull;
 
-// This has to be a macro to allow constant initialization of constants below.
-#ifndef TSAN_GO
-#define MemToShadow(addr) \
-    ((((uptr)addr) & ~(kLinuxAppMemMsk | (kShadowCell - 1))) * kShadowCnt)
-#define MemToMeta(addr) \
-    (u32*)(((((uptr)addr) & ~(kLinuxAppMemMsk | (kMetaShadowCell - 1))) \
-    / kMetaShadowCell * kMetaShadowSize) | kMetaShadow)
-#else
-#define MemToShadow(addr) \
-    (((((uptr)addr) & ~(kShadowCell - 1)) * kShadowCnt) | kLinuxShadowMsk)
-#define MemToMeta(addr) \
-    (u32*)(((((uptr)addr) & ~(kMetaShadowCell - 1)) \
-    / kMetaShadowCell * kMetaShadowSize) | kMetaShadow)
-#endif
-
-static const uptr kLinuxShadowBeg = MemToShadow(kLinuxAppMemBeg);
-static const uptr kLinuxShadowEnd =
-    MemToShadow(kLinuxAppMemEnd) | 0xff;
-
-static inline bool IsAppMem(uptr mem) {
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-  return (mem >= kLinuxAppMemBeg && mem < kAppMemGapBeg) ||
-         (mem >= kAppMemGapEnd   && mem <= kLinuxAppMemEnd);
-#elif defined(TSAN_GO)
-  return mem <= kLinuxAppMemEnd;
-#else
-  return mem >= kLinuxAppMemBeg && mem <= kLinuxAppMemEnd;
-#endif
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
+         (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
+         (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
 }
 
-static inline bool IsShadowMem(uptr mem) {
-  return mem >= kLinuxShadowBeg && mem <= kLinuxShadowEnd;
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
 }
 
-static inline uptr ShadowToMem(uptr shadow) {
-  CHECK(IsShadowMem(shadow));
-#ifdef TSAN_GO
-  return (shadow & ~kLinuxShadowMsk) / kShadowCnt;
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
+      ^ kAppMemXor) * kShadowCnt;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
+      ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
+    return (s / kShadowCnt) ^ kAppMemXor;
+  else
+    return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
+}
+
+static USED uptr UserRegions[] = {
+  kLoAppMemBeg, kLoAppMemEnd,
+  kHiAppMemBeg, kHiAppMemEnd,
+  kHeapMemBeg,  kHeapMemEnd,
+};
+
+#elif defined(TSAN_GO) && !SANITIZER_WINDOWS
+
+/* Go on linux, darwin and freebsd
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00c0 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2380 0000 0000: shadow
+2380 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
+4000 0000 0000 - 6000 0000 0000: -
+6000 0000 0000 - 6200 0000 0000: traces
+6200 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg   = 0x600000000000ull;
+const uptr kTraceMemEnd   = 0x620000000000ull;
+const uptr kShadowBeg     = 0x200000000000ull;
+const uptr kShadowEnd     = 0x238000000000ull;
+const uptr kAppMemBeg     = 0x000000001000ull;
+const uptr kAppMemEnd     = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+      kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  return (s & ~kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+  kAppMemBeg, kAppMemEnd,
+};
+
+#elif defined(TSAN_GO) && SANITIZER_WINDOWS
+
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00f8 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 0380 0000 0000: shadow
+0380 0000 0000 - 0560 0000 0000: -
+0560 0000 0000 - 0760 0000 0000: traces
+0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
+07d0 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x076000000000ull;
+const uptr kMetaShadowEnd = 0x07d000000000ull;
+const uptr kTraceMemBeg   = 0x056000000000ull;
+const uptr kTraceMemEnd   = 0x076000000000ull;
+const uptr kShadowBeg     = 0x010000000000ull;
+const uptr kShadowEnd     = 0x038000000000ull;
+const uptr kAppMemBeg     = 0x000000001000ull;
+const uptr kAppMemEnd     = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+      kMetaShadowCell * kMetaShadowSize) | kMetaShadowEnd);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
+  return (x & ~kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+  kAppMemBeg, kAppMemEnd,
+};
+
 #else
-  return (shadow / kShadowCnt) | kLinuxAppMemMsk;
+# error "Unknown platform"
 #endif
-}
-
-// For COMPAT mapping returns an alternative address
-// that mapped to the same shadow address.
-// COMPAT mapping is not quite one-to-one.
-static inline uptr AlternativeAddress(uptr addr) {
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-  return (addr & ~kLinuxAppMemMsk) | 0x280000000000ULL;
-#else
-  return 0;
-#endif
-}
-
-void FlushShadowMemory();
-void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
-uptr GetRSS();
-
-const char *InitializePlatform();
-void FinalizePlatform();
 
 // The additional page is to catch shadow stack overflow as paging fault.
 // Windows wants 64K alignment for mmaps.
@@ -175,18 +236,23 @@
     + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
 
 uptr ALWAYS_INLINE GetThreadTrace(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
-  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+  DCHECK_LT(p, kTraceMemEnd);
   return p;
 }
 
 uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
       + kTraceSize * sizeof(Event);
-  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  DCHECK_LT(p, kTraceMemEnd);
   return p;
 }
 
+void InitializePlatform();
+void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
+uptr GetRSS();
+
 void *internal_start_thread(void(*func)(void*), void *arg);
 void internal_join_thread(void *th);
 
@@ -202,8 +268,4 @@
 
 }  // namespace __tsan
 
-#else  // defined(__LP64__) || defined(_WIN64)
-# error "Only 64-bit is supported"
-#endif
-
 #endif  // TSAN_PLATFORM_H
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 53ecfc6..46b648c 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -9,7 +9,7 @@
 //
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
-// Linux-specific code.
+// Linux- and FreeBSD-specific code.
 //===----------------------------------------------------------------------===//
 
 
@@ -20,6 +20,7 @@
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 #include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
@@ -62,6 +63,9 @@
 
 namespace __tsan {
 
+static uptr g_data_start;
+static uptr g_data_end;
+
 const uptr kPageSize = 4096;
 
 enum {
@@ -76,22 +80,26 @@
   MemCount  = 8,
 };
 
-void FillProfileCallback(uptr start, uptr rss, bool file,
+void FillProfileCallback(uptr p, uptr rss, bool file,
                          uptr *mem, uptr stats_size) {
   mem[MemTotal] += rss;
-  start >>= 40;
-  if (start < 0x10)
+  if (p >= kShadowBeg && p < kShadowEnd)
     mem[MemShadow] += rss;
-  else if (start >= 0x20 && start < 0x30)
-    mem[file ? MemFile : MemMmap] += rss;
-  else if (start >= 0x30 && start < 0x40)
+  else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
     mem[MemMeta] += rss;
-  else if (start >= 0x7e)
-    mem[file ? MemFile : MemMmap] += rss;
-  else if (start >= 0x60 && start < 0x62)
-    mem[MemTrace] += rss;
-  else if (start >= 0x7d && start < 0x7e)
+#ifndef TSAN_GO
+  else if (p >= kHeapMemBeg && p < kHeapMemEnd)
     mem[MemHeap] += rss;
+  else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
+    mem[file ? MemFile : MemMmap] += rss;
+  else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+    mem[file ? MemFile : MemMmap] += rss;
+#else
+  else if (p >= kAppMemBeg && p < kAppMemEnd)
+    mem[file ? MemFile : MemMmap] += rss;
+#endif
+  else if (p >= kTraceMemBeg && p < kTraceMemEnd)
+    mem[MemTrace] += rss;
   else
     mem[MemOther] += rss;
 }
@@ -99,26 +107,49 @@
 void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
   uptr mem[MemCount] = {};
   __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+  StackDepotStats *stacks = StackDepotGetStats();
   internal_snprintf(buf, buf_size,
       "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
-      " trace:%zd heap:%zd other:%zd nthr=%zd/%zd\n",
+      " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n",
       mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,
       mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20,
       mem[MemHeap] >> 20, mem[MemOther] >> 20,
+      stacks->allocated >> 20, stacks->n_uniq_ids,
       nlive, nthread);
 }
 
 uptr GetRSS() {
-  uptr mem[7] = {};
-  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
-  return mem[6];
+  uptr fd = OpenFile("/proc/self/statm", false);
+  if ((sptr)fd < 0)
+    return 0;
+  char buf[64];
+  uptr len = internal_read(fd, buf, sizeof(buf) - 1);
+  internal_close(fd);
+  if ((sptr)len <= 0)
+    return 0;
+  buf[len] = 0;
+  // The format of the file is:
+  // 1084 89 69 11 0 79 0
+  // We need the second number which is RSS in 4K units.
+  char *pos = buf;
+  // Skip the first number.
+  while (*pos >= '0' && *pos <= '9')
+    pos++;
+  // Skip whitespaces.
+  while (!(*pos >= '0' && *pos <= '9') && *pos != 0)
+    pos++;
+  // Read the number.
+  uptr rss = 0;
+  while (*pos >= '0' && *pos <= '9')
+    rss = rss * 10 + *pos++ - '0';
+  return rss * 4096;
 }
 
 #if SANITIZER_LINUX
 void FlushShadowMemoryCallback(
     const SuspendedThreadsList &suspended_threads_list,
     void *argument) {
-  FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
+  FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
 }
 #endif
 
@@ -199,87 +230,59 @@
 
 void InitializeShadowMemory() {
   // Map memory shadow.
-  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
-    kLinuxShadowEnd - kLinuxShadowBeg);
-  if (shadow != kLinuxShadowBeg) {
+  uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+    kShadowEnd - kShadowBeg);
+  if (shadow != kShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
-               "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
+               "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
     Die();
   }
+  // This memory range is used for thread stacks and large user mmaps.
+  // Frequently a thread uses only a small part of stack and similarly
+  // a program uses a small part of large mmap. On some programs
+  // we see 20% memory usage reduction without huge pages for this range.
+#ifdef MADV_NOHUGEPAGE
+  madvise((void*)MemToShadow(0x7f0000000000ULL),
+      0x10000000000ULL * kShadowMultiplier, MADV_NOHUGEPAGE);
+#endif
   DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
-      kLinuxShadowBeg, kLinuxShadowEnd,
-      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
+      kShadowBeg, kShadowEnd,
+      (kShadowEnd - kShadowBeg) >> 30);
 
   // Map meta shadow.
-  if (MemToMeta(kLinuxAppMemBeg) < (u32*)kMetaShadow) {
-    Printf("ThreadSanitizer: bad meta shadow (%p -> %p < %p)\n",
-        kLinuxAppMemBeg, MemToMeta(kLinuxAppMemBeg), kMetaShadow);
-    Die();
-  }
-  if (MemToMeta(kLinuxAppMemEnd) >= (u32*)(kMetaShadow + kMetaSize)) {
-    Printf("ThreadSanitizer: bad meta shadow (%p -> %p >= %p)\n",
-        kLinuxAppMemEnd, MemToMeta(kLinuxAppMemEnd), kMetaShadow + kMetaSize);
-    Die();
-  }
-  uptr meta = (uptr)MmapFixedNoReserve(kMetaShadow, kMetaSize);
-  if (meta != kMetaShadow) {
+  uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
+  uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size);
+  if (meta != kMetaShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
-               "to link with -pie (%p, %p).\n", meta, kMetaShadow);
+               "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
     Die();
   }
   DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
-      kMetaShadow, kMetaShadow + kMetaSize, kMetaSize >> 30);
-
-  // Protect gaps.
-  const uptr kClosedLowBeg  = 0x200000;
-  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
-  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
-  const uptr kClosedMidEnd = min(min(kLinuxAppMemBeg, kTraceMemBegin),
-      kMetaShadow);
-
-  ProtectRange(kClosedLowBeg, kClosedLowEnd);
-  ProtectRange(kClosedMidBeg, kClosedMidEnd);
-  VPrintf(2, "kClosedLow   %zx-%zx (%zuGB)\n",
-      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
-  VPrintf(2, "kClosedMid   %zx-%zx (%zuGB)\n",
-      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
-  VPrintf(2, "app mem: %zx-%zx (%zuGB)\n",
-      kLinuxAppMemBeg, kLinuxAppMemEnd,
-      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
-  VPrintf(2, "stack: %zx\n", (uptr)&shadow);
+      meta, meta + meta_size, meta_size >> 30);
 
   MapRodata();
 }
-#endif
-
-static uptr g_data_start;
-static uptr g_data_end;
-
-#ifndef TSAN_GO
-static void CheckPIE() {
-  // Ensure that the binary is indeed compiled with -pie.
-  MemoryMappingLayout proc_maps(true);
-  uptr start, end;
-  if (proc_maps.Next(&start, &end,
-                     /*offset*/0, /*filename*/0, /*filename_size*/0,
-                     /*protection*/0)) {
-    if ((u64)start < kLinuxAppMemBeg) {
-      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
-             "something is mapped at 0x%zx < 0x%zx)\n",
-             start, kLinuxAppMemBeg);
-      Printf("FATAL: Make sure to compile with -fPIE"
-             " and to link with -pie.\n");
-      Die();
-    }
-  }
-}
 
 static void InitDataSeg() {
   MemoryMappingLayout proc_maps(true);
   uptr start, end, offset;
   char name[128];
+#if SANITIZER_FREEBSD
+  // On FreeBSD BSS is usually the last block allocated within the
+  // low range and heap is the last block allocated within the range
+  // 0x800000000-0x8ffffffff.
+  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+                        /*protection*/ 0)) {
+    DPrintf("%p-%p %p %s\n", start, end, offset, name);
+    if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
+        name[0] == '\0') {
+      g_data_start = start;
+      g_data_end = end;
+    }
+  }
+#else
   bool prev_is_data = false;
   while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
                         /*protection*/ 0)) {
@@ -295,34 +298,39 @@
       g_data_end = end;
     prev_is_data = is_data;
   }
+#endif
   DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
   CHECK_LT(g_data_start, g_data_end);
   CHECK_GE((uptr)&g_data_start, g_data_start);
   CHECK_LT((uptr)&g_data_start, g_data_end);
 }
 
+static void CheckAndProtect() {
+  // Ensure that the binary is indeed compiled with -pie.
+  MemoryMappingLayout proc_maps(true);
+  uptr p, end;
+  while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
+    if (IsAppMem(p))
+      continue;
+    if (p >= kHeapMemEnd &&
+        p < kHeapMemEnd + PrimaryAllocator::AdditionalSize())
+      continue;
+    if (p >= 0xf000000000000000ull)  // vdso
+      break;
+    Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+    Die();
+  }
+
+  ProtectRange(kLoAppMemEnd, kShadowBeg);
+  ProtectRange(kShadowEnd, kMetaShadowBeg);
+  ProtectRange(kMetaShadowEnd, kTraceMemBeg);
+  ProtectRange(kTraceMemEnd, kHeapMemBeg);
+  ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg);
+}
 #endif  // #ifndef TSAN_GO
 
-static rlim_t getlim(int res) {
-  rlimit rlim;
-  CHECK_EQ(0, getrlimit(res, &rlim));
-  return rlim.rlim_cur;
-}
-
-static void setlim(int res, rlim_t lim) {
-  // The following magic is to prevent clang from replacing it with memset.
-  volatile rlimit rlim;
-  rlim.rlim_cur = lim;
-  rlim.rlim_max = lim;
-  setrlimit(res, (rlimit*)&rlim);
-}
-
-const char *InitializePlatform() {
-  void *p = 0;
-  if (sizeof(p) == 8) {
-    // Disable core dumps, dumping of 16TB usually takes a bit long.
-    setlim(RLIMIT_CORE, 0);
-  }
+void InitializePlatform() {
+  DisableCoreDumperIfNecessary();
 
   // Go maps shadow memory lazily and works fine with limited address space.
   // Unlimited stack is not a problem as well, because the executable
@@ -332,7 +340,7 @@
     // TSan doesn't play well with unlimited stack size (as stack
     // overlaps with shadow memory). If we detect unlimited stack size,
     // we re-exec the program with limited stack size as a best effort.
-    if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
+    if (StackSizeIsUnlimited()) {
       const uptr kMaxStackSize = 32 * 1024 * 1024;
       VReport(1, "Program is run with unlimited stack size, which wouldn't "
                  "work with ThreadSanitizer.\n"
@@ -342,11 +350,11 @@
       reexec = true;
     }
 
-    if (getlim(RLIMIT_AS) != (rlim_t)-1) {
+    if (!AddressSpaceIsUnlimited()) {
       Report("WARNING: Program is run with limited virtual address space,"
              " which wouldn't work with ThreadSanitizer.\n");
       Report("Re-execing with unlimited virtual address space.\n");
-      setlim(RLIMIT_AS, -1);
+      SetAddressSpaceUnlimited();
       reexec = true;
     }
     if (reexec)
@@ -354,11 +362,10 @@
   }
 
 #ifndef TSAN_GO
-  CheckPIE();
+  CheckAndProtect();
   InitTlsSize();
   InitDataSeg();
 #endif
-  return GetEnv(kTsanOptionsEnv);
 }
 
 bool IsGlobalVar(uptr addr) {
@@ -418,4 +425,4 @@
 
 }  // namespace __tsan
 
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index 15d0688..fd71eb3 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -56,39 +56,25 @@
 
 #ifndef TSAN_GO
 void InitializeShadowMemory() {
-  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
-    kLinuxShadowEnd - kLinuxShadowBeg);
-  if (shadow != kLinuxShadowBeg) {
+  uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+    kShadowEnd - kShadowBeg);
+  if (shadow != kShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
            "to link with -pie.\n");
     Die();
   }
-  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
-      kLinuxShadowBeg, kLinuxShadowEnd,
-      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
-  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
-      kLinuxAppMemBeg, kLinuxAppMemEnd,
-      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
+  DPrintf("kShadow %zx-%zx (%zuGB)\n",
+      kShadowBeg, kShadowEnd,
+      (kShadowEnd - kShadowBeg) >> 30);
+  DPrintf("kAppMem %zx-%zx (%zuGB)\n",
+      kAppMemBeg, kAppMemEnd,
+      (kAppMemEnd - kAppMemBeg) >> 30);
 }
 #endif
 
-const char *InitializePlatform() {
-  void *p = 0;
-  if (sizeof(p) == 8) {
-    // Disable core dumps, dumping of 16TB usually takes a bit long.
-    // The following magic is to prevent clang from replacing it with memset.
-    volatile rlimit lim;
-    lim.rlim_cur = 0;
-    lim.rlim_max = 0;
-    setrlimit(RLIMIT_CORE, (rlimit*)&lim);
-  }
-
-  return GetEnv(kTsanOptionsEnv);
-}
-
-void FinalizePlatform() {
-  fflush(0);
+void InitializePlatform() {
+  DisableCoreDumperIfNecessary();
 }
 
 #ifndef TSAN_GO
diff --git a/lib/tsan/rtl/tsan_platform_windows.cc b/lib/tsan/rtl/tsan_platform_windows.cc
index 8b9d20e..ae9f050 100644
--- a/lib/tsan/rtl/tsan_platform_windows.cc
+++ b/lib/tsan/rtl/tsan_platform_windows.cc
@@ -35,12 +35,7 @@
   return 0;
 }
 
-const char *InitializePlatform() {
-  return GetEnv(kTsanOptionsEnv);
-}
-
-void FinalizePlatform() {
-  fflush(0);
+void InitializePlatform() {
 }
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index e14d0b9..f4a1ddb 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -13,10 +13,30 @@
 #include "tsan_report.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
 
 namespace __tsan {
 
+ReportStack::ReportStack() : next(nullptr), info(), suppressable(false) {}
+
+ReportStack *ReportStack::New(uptr addr) {
+  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
+  ReportStack *res = new(mem) ReportStack();
+  res->info.address = addr;
+  return res;
+}
+
+ReportLocation::ReportLocation(ReportLocationType type)
+    : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0),
+      fd(0), suppressable(false), stack(nullptr) {}
+
+ReportLocation *ReportLocation::New(ReportLocationType type) {
+  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation));
+  return new(mem) ReportLocation(type);
+}
+
 class Decorator: public __sanitizer::SanitizerCommonDecorator {
  public:
   Decorator() : SanitizerCommonDecorator() { }
@@ -70,6 +90,8 @@
     return "data race on vptr (ctor/dtor vs virtual call)";
   if (typ == ReportTypeUseAfterFree)
     return "heap-use-after-free";
+  if (typ == ReportTypeVptrUseAfterFree)
+    return "heap-use-after-free (virtual call vs free)";
   if (typ == ReportTypeThreadLeak)
     return "thread leak";
   if (typ == ReportTypeMutexDestroyLocked)
@@ -96,14 +118,11 @@
     Printf("    [failed to restore the stack]\n\n");
     return;
   }
-  for (int i = 0; ent; ent = ent->next, i++) {
-    Printf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
-    if (ent->col)
-      Printf(":%d", ent->col);
-    if (ent->module && ent->offset)
-      Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
-    else
-      Printf(" (%p)\n", (void*)ent->pc);
+  for (int i = 0; ent && ent->info.address; ent = ent->next, i++) {
+    InternalScopedString res(2 * GetPageSizeCached());
+    RenderFrame(&res, common_flags()->stack_trace_format, i, ent->info,
+                common_flags()->strip_path_prefix, "__interceptor_");
+    Printf("%s\n", res.data());
   }
   Printf("\n");
 }
@@ -145,12 +164,15 @@
   bool print_stack = false;
   Printf("%s", d.Location());
   if (loc->type == ReportLocationGlobal) {
+    const DataInfo &global = loc->global;
     Printf("  Location is global '%s' of size %zu at %p (%s+%p)\n\n",
-               loc->name, loc->size, loc->addr, loc->module, loc->offset);
+           global.name, global.size, global.start,
+           StripModuleName(global.module), global.module_offset);
   } else if (loc->type == ReportLocationHeap) {
     char thrbuf[kThreadBufSize];
     Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
-        loc->size, loc->addr, thread_name(thrbuf, loc->tid));
+           loc->heap_chunk_size, loc->heap_chunk_start,
+           thread_name(thrbuf, loc->tid));
     print_stack = true;
   } else if (loc->type == ReportLocationStack) {
     Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
@@ -303,8 +325,10 @@
   if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
     Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
 
-  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
-    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep))) {
+    const AddressInfo &info = ent->info;
+    ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
+  }
 
   Printf("==================\n");
 }
@@ -319,8 +343,9 @@
     return;
   }
   for (int i = 0; ent; ent = ent->next, i++) {
-    Printf("  %s()\n      %s:%d +0x%zx\n",
-        ent->func, ent->file, ent->line, (void*)ent->offset);
+    const AddressInfo &info = ent->info;
+    Printf("  %s()\n      %s:%d +0x%zx\n", info.function, info.file, info.line,
+           (void *)info.module_offset);
   }
 }
 
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index 8ea9774..e6d8535 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -13,6 +13,7 @@
 #ifndef TSAN_REPORT_H
 #define TSAN_REPORT_H
 
+#include "sanitizer_common/sanitizer_symbolizer.h"
 #include "tsan_defs.h"
 #include "tsan_vector.h"
 
@@ -22,6 +23,7 @@
   ReportTypeRace,
   ReportTypeVptrRace,
   ReportTypeUseAfterFree,
+  ReportTypeVptrUseAfterFree,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
   ReportTypeMutexDoubleLock,
@@ -35,14 +37,12 @@
 
 struct ReportStack {
   ReportStack *next;
-  char *module;
-  uptr offset;
-  uptr pc;
-  char *func;
-  char *file;
-  int line;
-  int col;
+  AddressInfo info;
   bool suppressable;
+  static ReportStack *New(uptr addr);
+
+ private:
+  ReportStack();
 };
 
 struct ReportMopMutex {
@@ -72,17 +72,17 @@
 
 struct ReportLocation {
   ReportLocationType type;
-  uptr addr;
-  uptr size;
-  char *module;
-  uptr offset;
+  DataInfo global;
+  uptr heap_chunk_start;
+  uptr heap_chunk_size;
   int tid;
   int fd;
-  char *name;
-  char *file;
-  int line;
   bool suppressable;
   ReportStack *stack;
+
+  static ReportLocation *New(ReportLocationType type);
+ private:
+  explicit ReportLocation(ReportLocationType type);
 };
 
 struct ReportThread {
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 3e3e339..79320cb 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -157,7 +157,6 @@
   }
 
   u64 last_flush = NanoTime();
-  u64 last_rss_check = NanoTime();
   uptr last_rss = 0;
   for (int i = 0;
       atomic_load(&ctx->stop_background_thread, memory_order_relaxed) == 0;
@@ -168,29 +167,23 @@
     // Flush memory if requested.
     if (flags()->flush_memory_ms > 0) {
       if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
-        if (flags()->verbosity > 0)
-          Printf("ThreadSanitizer: periodic memory flush\n");
+        VPrintf(1, "ThreadSanitizer: periodic memory flush\n");
         FlushShadowMemory();
         last_flush = NanoTime();
       }
     }
     // GetRSS can be expensive on huge programs, so don't do it every 100ms.
-    if (flags()->memory_limit_mb > 0 && last_rss_check + 1000 * kMs2Ns < now) {
-      last_rss_check = now;
+    if (flags()->memory_limit_mb > 0) {
       uptr rss = GetRSS();
       uptr limit = uptr(flags()->memory_limit_mb) << 20;
-      if (flags()->verbosity > 0) {
-        Printf("ThreadSanitizer: memory flush check"
-               " RSS=%llu LAST=%llu LIMIT=%llu\n",
-               (u64)rss>>20, (u64)last_rss>>20, (u64)limit>>20);
-      }
+      VPrintf(1, "ThreadSanitizer: memory flush check"
+                 " RSS=%llu LAST=%llu LIMIT=%llu\n",
+              (u64)rss >> 20, (u64)last_rss >> 20, (u64)limit >> 20);
       if (2 * rss > limit + last_rss) {
-        if (flags()->verbosity > 0)
-          Printf("ThreadSanitizer: flushing memory due to RSS\n");
+        VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n");
         FlushShadowMemory();
         rss = GetRSS();
-        if (flags()->verbosity > 0)
-          Printf("ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
+        VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
       }
       last_rss = rss;
     }
@@ -268,8 +261,8 @@
 
 void MapThreadTrace(uptr addr, uptr size) {
   DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
-  CHECK_GE(addr, kTraceMemBegin);
-  CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
+  CHECK_GE(addr, kTraceMemBeg);
+  CHECK_LE(addr + size, kTraceMemEnd);
   CHECK_EQ(addr, addr & ~((64 << 10) - 1));  // windows wants 64K alignment
   uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
   if (addr1 != addr) {
@@ -279,6 +272,28 @@
   }
 }
 
+static void CheckShadowMapping() {
+  for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
+    const uptr beg = UserRegions[i];
+    const uptr end = UserRegions[i + 1];
+    VPrintf(3, "checking shadow region %p-%p\n", beg, end);
+    for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
+      for (int x = -1; x <= 1; x++) {
+        const uptr p = p0 + x;
+        if (p < beg || p >= end)
+          continue;
+        const uptr s = MemToShadow(p);
+        VPrintf(3, "  checking pointer %p -> %p\n", p, s);
+        CHECK(IsAppMem(p));
+        CHECK(IsShadowMem(s));
+        CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s));
+        const uptr m = (uptr)MemToMeta(p);
+        CHECK(IsMetaMem(m));
+      }
+    }
+  }
+}
+
 void Initialize(ThreadState *thr) {
   // Thread safe because done before all threads exist.
   static bool is_initialized = false;
@@ -291,36 +306,36 @@
   // Install tool-specific callbacks in sanitizer_common.
   SetCheckFailedCallback(TsanCheckFailed);
 
+  ctx = new(ctx_placeholder) Context;
+  const char *options = GetEnv(kTsanOptionsEnv);
+  InitializeFlags(&ctx->flags, options);
 #ifndef TSAN_GO
   InitializeAllocator();
 #endif
   InitializeInterceptors();
-  const char *env = InitializePlatform();
+  CheckShadowMapping();
+  InitializePlatform();
   InitializeMutex();
   InitializeDynamicAnnotations();
-  ctx = new(ctx_placeholder) Context;
 #ifndef TSAN_GO
   InitializeShadowMemory();
 #endif
-  InitializeFlags(&ctx->flags, env);
   // Setup correct file descriptor for error reports.
-  __sanitizer_set_report_path(flags()->log_path);
+  __sanitizer_set_report_path(common_flags()->log_path);
   InitializeSuppressions();
 #ifndef TSAN_GO
   InitializeLibIgnore();
-  Symbolizer::Init(common_flags()->external_symbolizer_path);
-  Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+  Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
 #endif
   StartBackgroundThread();
 #ifndef TSAN_GO
   SetSandboxingCallback(StopBackgroundThread);
 #endif
-  if (flags()->detect_deadlocks)
+  if (common_flags()->detect_deadlocks)
     ctx->dd = DDetector::Create(flags());
 
-  if (ctx->flags.verbosity)
-    Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
-           (int)internal_getpid());
+  VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n",
+          (int)internal_getpid());
 
   // Initialize thread 0.
   int tid = ThreadCreate(thr, 0, 0, true);
@@ -339,7 +354,6 @@
 }
 
 int Finalize(ThreadState *thr) {
-  Context *ctx = __tsan::ctx;
   bool failed = false;
 
   if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
@@ -352,7 +366,7 @@
   ctx->report_mtx.Unlock();
 
 #ifndef TSAN_GO
-  if (ctx->flags.verbosity)
+  if (common_flags()->verbosity)
     AllocatorPrintStats();
 #endif
 
@@ -373,7 +387,7 @@
         ctx->nmissed_expected);
   }
 
-  if (flags()->print_suppressions)
+  if (common_flags()->print_suppressions)
     PrintMatchedSuppressions();
 #ifndef TSAN_GO
   if (flags()->print_benign)
@@ -448,8 +462,8 @@
     thr->shadow_stack_pos[0] = pc;
     thr->shadow_stack_pos++;
   }
-  u32 id = StackDepotPut(thr->shadow_stack,
-                         thr->shadow_stack_pos - thr->shadow_stack);
+  u32 id = StackDepotPut(
+      StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack));
   if (pc != 0)
     thr->shadow_stack_pos--;
   return id;
@@ -462,7 +476,7 @@
   unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
   TraceHeader *hdr = &thr_trace->headers[trace];
   hdr->epoch0 = thr->fast_state.epoch();
-  hdr->stack0.ObtainCurrent(thr, 0);
+  ObtainCurrentStack(thr, 0, &hdr->stack0);
   hdr->mset0 = thr->mset;
   thr->nomalloc--;
 }
@@ -608,13 +622,13 @@
   while (size) {
     int size1 = 1;
     int kAccessSizeLog = kSizeLog1;
-    if (size >= 8 && (addr & ~7) == ((addr + 8) & ~7)) {
+    if (size >= 8 && (addr & ~7) == ((addr + 7) & ~7)) {
       size1 = 8;
       kAccessSizeLog = kSizeLog8;
-    } else if (size >= 4 && (addr & ~7) == ((addr + 4) & ~7)) {
+    } else if (size >= 4 && (addr & ~7) == ((addr + 3) & ~7)) {
       size1 = 4;
       kAccessSizeLog = kSizeLog4;
-    } else if (size >= 2 && (addr & ~7) == ((addr + 2) & ~7)) {
+    } else if (size >= 2 && (addr & ~7) == ((addr + 1) & ~7)) {
       size1 = 2;
       kAccessSizeLog = kSizeLog2;
     }
@@ -701,6 +715,8 @@
 bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
 #if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4
   bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write);
+  // NOTE: this check can fail if the shadow is concurrently mutated
+  // by other threads.
   DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write));
   return res;
 #else
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 1b590b8..591d10d 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -53,15 +53,8 @@
 namespace __tsan {
 
 #ifndef TSAN_GO
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-const uptr kAllocatorSpace = 0x7d0000000000ULL;
-#else
-const uptr kAllocatorSpace = 0x7d0000000000ULL;
-#endif
-const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
-
 struct MapUnmapCallback;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
+typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
     DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
 typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
@@ -312,6 +305,9 @@
 struct JmpBuf {
   uptr sp;
   uptr mangled_sp;
+  int int_signal_send;
+  bool in_blocking_func;
+  uptr in_signal_handler;
   uptr *shadow_stack_pos;
 };
 
@@ -360,7 +356,7 @@
   const int unique_id;
   bool in_symbolizer;
   bool in_ignored_lib;
-  bool is_alive;
+  bool is_dead;
   bool is_freeing;
   bool is_vptr_access;
   const uptr stk_addr;
@@ -373,11 +369,12 @@
   DDPhysicalThread *dd_pt;
   DDLogicalThread *dd_lt;
 
-  bool in_signal_handler;
+  atomic_uintptr_t in_signal_handler;
   SignalContext *signal_ctx;
 
   DenseSlabAllocCache block_cache;
   DenseSlabAllocCache sync_cache;
+  DenseSlabAllocCache clock_cache;
 
 #ifndef TSAN_GO
   u32 last_sleep_stack_id;
@@ -422,6 +419,7 @@
   void OnStarted(void *arg);
   void OnCreated(void *arg);
   void OnReset();
+  void OnDetached(void *arg);
 };
 
 struct RacyStacks {
@@ -470,6 +468,8 @@
   InternalMmapVector<FiredSuppression> fired_suppressions;
   DDetector *dd;
 
+  ClockAlloc clock_alloc;
+
   Flags flags;
 
   u64 stat[StatCnt];
@@ -498,9 +498,9 @@
   explicit ScopedReport(ReportType typ);
   ~ScopedReport();
 
-  void AddMemoryAccess(uptr addr, Shadow s, const StackTrace *stack,
+  void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
                        const MutexSet *mset);
-  void AddStack(const StackTrace *stack, bool suppressable = false);
+  void AddStack(StackTrace stack, bool suppressable = false);
   void AddThread(const ThreadContext *tctx, bool suppressable = false);
   void AddThread(int unique_tid, bool suppressable = false);
   void AddUniqueTid(int unique_tid);
@@ -524,7 +524,20 @@
   void operator = (const ScopedReport&);
 };
 
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset);
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+                  MutexSet *mset);
+
+template<typename StackTraceTy>
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+  uptr size = thr->shadow_stack_pos - thr->shadow_stack;
+  uptr start = 0;
+  if (size + !!toppc > kStackTraceMax) {
+    start = size + !!toppc - kStackTraceMax;
+    size = kStackTraceMax - !!toppc;
+  }
+  stack->Init(&thr->shadow_stack[start], size, toppc);
+}
+
 
 void StatAggregate(u64 *dst, u64 *src);
 void StatOutput(u64 *stat);
@@ -551,9 +564,8 @@
 
 void ReportRace(ThreadState *thr);
 bool OutputReport(ThreadState *thr, const ScopedReport &srep);
-bool IsFiredSuppression(Context *ctx,
-                        const ScopedReport &srep,
-                        const StackTrace &trace);
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+                        StackTrace trace);
 bool IsExpectedReport(uptr addr, uptr size);
 void PrintMatchedBenignRaces();
 bool FrameIsInternal(const ReportStack *frame);
@@ -574,7 +586,7 @@
 u32 CurrentStackId(ThreadState *thr, uptr pc);
 ReportStack *SymbolizeStackId(u32 stack_id);
 void PrintCurrentStack(ThreadState *thr, uptr pc);
-void PrintCurrentStackSlow();  // uses libunwind
+void PrintCurrentStackSlow(uptr pc);  // uses libunwind
 
 void Initialize(ThreadState *thr);
 int Finalize(ThreadState *thr);
@@ -654,6 +666,12 @@
 void MutexRepair(ThreadState *thr, uptr pc, uptr addr);  // call on EOWNERDEAD
 
 void Acquire(ThreadState *thr, uptr pc, uptr addr);
+// AcquireGlobal synchronizes the current thread with all other threads.
+// In terms of happens-before relation, it draws a HB edge from all threads
+// (where they happen to execute right now) to the current thread. We use it to
+// handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal
+// right before executing finalizers. This provides a coarse, but simple
+// approximation of the actual required synchronization.
 void AcquireGlobal(ThreadState *thr, uptr pc);
 void Release(ThreadState *thr, uptr pc, uptr addr);
 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
diff --git a/lib/tsan/rtl/tsan_rtl_amd64.S b/lib/tsan/rtl/tsan_rtl_amd64.S
index 11c19a7..8db62f9 100644
--- a/lib/tsan/rtl/tsan_rtl_amd64.S
+++ b/lib/tsan/rtl/tsan_rtl_amd64.S
@@ -172,10 +172,15 @@
   CFI_ADJUST_CFA_OFFSET(8)
   CFI_REL_OFFSET(%rdi, 0)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 8(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 16(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // restore env parameter
@@ -199,10 +204,15 @@
   CFI_ADJUST_CFA_OFFSET(8)
   CFI_REL_OFFSET(%rdi, 0)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 8(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 16(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // restore env parameter
@@ -233,10 +243,15 @@
   sub $8, %rsp
   CFI_ADJUST_CFA_OFFSET(8)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 24(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 32(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // unalign stack frame
@@ -274,10 +289,15 @@
   sub $8, %rsp
   CFI_ADJUST_CFA_OFFSET(8)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 24(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 32(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // unalign stack frame
@@ -298,7 +318,7 @@
   CFI_ENDPROC
 .size __sigsetjmp, .-__sigsetjmp
 
-#ifdef __linux__
+#if defined(__FreeBSD__) || defined(__linux__)
 /* We do not need executable stack.  */
 .section        .note.GNU-stack,"",@progbits
 #endif
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index 4cf47ec..0807869 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -59,9 +59,9 @@
   ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(typ);
   rep.AddMutex(mid);
-  StackTrace trace;
-  trace.ObtainCurrent(thr, pc);
-  rep.AddStack(&trace, true);
+  VarSizeStackTrace trace;
+  ObtainCurrentStack(thr, pc, &trace);
+  rep.AddStack(trace, true);
   rep.AddLocation(addr, 1);
   OutputReport(thr, rep);
 }
@@ -103,7 +103,7 @@
   SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
   if (s == 0)
     return;
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     Callback cb(thr, pc);
     ctx->dd->MutexDestroy(&cb, &s->dd);
     ctx->dd->MutexInit(&cb, &s->dd);
@@ -118,25 +118,25 @@
   u64 mid = s->GetId();
   u32 last_lock = s->last_lock;
   if (!unlock_locked)
-    s->Reset();  // must not reset it before the report is printed
+    s->Reset(thr);  // must not reset it before the report is printed
   s->mtx.Unlock();
   if (unlock_locked) {
     ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeMutexDestroyLocked);
     rep.AddMutex(mid);
-    StackTrace trace;
-    trace.ObtainCurrent(thr, pc);
-    rep.AddStack(&trace);
+    VarSizeStackTrace trace;
+    ObtainCurrentStack(thr, pc, &trace);
+    rep.AddStack(trace);
     FastState last(last_lock);
     RestoreStack(last.tid(), last.epoch(), &trace, 0);
-    rep.AddStack(&trace, true);
+    rep.AddStack(trace, true);
     rep.AddLocation(addr, 1);
     OutputReport(thr, rep);
   }
   if (unlock_locked) {
     SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
     if (s != 0) {
-      s->Reset();
+      s->Reset(thr);
       s->mtx.Unlock();
     }
   }
@@ -172,7 +172,7 @@
   }
   s->recursion += rec;
   thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
-  if (flags()->detect_deadlocks && (s->recursion - rec) == 0) {
+  if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
     Callback cb(thr, pc);
     if (!try_lock)
       ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
@@ -183,7 +183,7 @@
   // Can't touch s after this point.
   if (report_double_lock)
     ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     Callback cb(thr, pc);
     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
   }
@@ -215,7 +215,8 @@
     }
   }
   thr->mset.Del(s->GetId(), true);
-  if (flags()->detect_deadlocks && s->recursion == 0 && !report_bad_unlock) {
+  if (common_flags()->detect_deadlocks && s->recursion == 0 &&
+      !report_bad_unlock) {
     Callback cb(thr, pc);
     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
   }
@@ -224,7 +225,7 @@
   // Can't touch s after this point.
   if (report_bad_unlock)
     ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
-  if (flags()->detect_deadlocks && !report_bad_unlock) {
+  if (common_flags()->detect_deadlocks && !report_bad_unlock) {
     Callback cb(thr, pc);
     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
   }
@@ -249,7 +250,7 @@
   AcquireImpl(thr, pc, &s->clock);
   s->last_lock = thr->fast_state.raw();
   thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
-  if (flags()->detect_deadlocks && s->recursion == 0) {
+  if (common_flags()->detect_deadlocks && s->recursion == 0) {
     Callback cb(thr, pc);
     if (!trylock)
       ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
@@ -260,7 +261,7 @@
   // Can't touch s after this point.
   if (report_bad_lock)
     ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     Callback cb(thr, pc);
     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
   }
@@ -282,7 +283,7 @@
     }
   }
   ReleaseImpl(thr, pc, &s->read_clock);
-  if (flags()->detect_deadlocks && s->recursion == 0) {
+  if (common_flags()->detect_deadlocks && s->recursion == 0) {
     Callback cb(thr, pc);
     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
   }
@@ -292,7 +293,7 @@
   thr->mset.Del(mid, false);
   if (report_bad_unlock)
     ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     Callback cb(thr, pc);
     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
   }
@@ -330,7 +331,7 @@
     report_bad_unlock = true;
   }
   thr->mset.Del(s->GetId(), write);
-  if (flags()->detect_deadlocks && s->recursion == 0) {
+  if (common_flags()->detect_deadlocks && s->recursion == 0) {
     Callback cb(thr, pc);
     ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
   }
@@ -339,7 +340,7 @@
   // Can't touch s after this point.
   if (report_bad_unlock)
     ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     Callback cb(thr, pc);
     ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
   }
@@ -429,7 +430,7 @@
   if (thr->ignore_sync)
     return;
   thr->clock.set(thr->fast_state.epoch());
-  thr->clock.acquire(c);
+  thr->clock.acquire(&thr->clock_cache, c);
   StatInc(thr, StatSyncAcquire);
 }
 
@@ -438,7 +439,7 @@
     return;
   thr->clock.set(thr->fast_state.epoch());
   thr->fast_synch_epoch = thr->fast_state.epoch();
-  thr->clock.release(c);
+  thr->clock.release(&thr->clock_cache, c);
   StatInc(thr, StatSyncRelease);
 }
 
@@ -447,7 +448,7 @@
     return;
   thr->clock.set(thr->fast_state.epoch());
   thr->fast_synch_epoch = thr->fast_state.epoch();
-  thr->clock.ReleaseStore(c);
+  thr->clock.ReleaseStore(&thr->clock_cache, c);
   StatInc(thr, StatSyncRelease);
 }
 
@@ -456,7 +457,7 @@
     return;
   thr->clock.set(thr->fast_state.epoch());
   thr->fast_synch_epoch = thr->fast_state.epoch();
-  thr->clock.acq_rel(c);
+  thr->clock.acq_rel(&thr->clock_cache, c);
   StatInc(thr, StatSyncAcquire);
   StatInc(thr, StatSyncRelease);
 }
@@ -471,21 +472,17 @@
     rep.AddUniqueTid((int)r->loop[i].thr_ctx);
     rep.AddThread((int)r->loop[i].thr_ctx);
   }
-  InternalScopedBuffer<StackTrace> stacks(2 * DDReport::kMaxLoopSize);
   uptr dummy_pc = 0x42;
   for (int i = 0; i < r->n; i++) {
-    uptr size;
     for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
       u32 stk = r->loop[i].stk[j];
       if (stk) {
-        const uptr *trace = StackDepotGet(stk, &size);
-        stacks[i].Init(const_cast<uptr *>(trace), size);
+        rep.AddStack(StackDepotGet(stk), true);
       } else {
         // Sometimes we fail to extract the stack trace (FIXME: investigate),
         // but we should still produce some stack trace in the report.
-        stacks[i].Init(&dummy_pc, 1);
+        rep.AddStack(StackTrace(&dummy_pc, 1), true);
       }
-      rep.AddStack(&stacks[i], true);
     }
   }
   OutputReport(thr, rep);
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index b75c319..c7a00c9 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -30,7 +30,7 @@
 
 using namespace __sanitizer;  // NOLINT
 
-static ReportStack *SymbolizeStack(const StackTrace& trace);
+static ReportStack *SymbolizeStack(StackTrace trace);
 
 void TsanCheckFailed(const char *file, int line, const char *cond,
                      u64 v1, u64 v2) {
@@ -41,7 +41,7 @@
   Printf("FATAL: ThreadSanitizer CHECK failed: "
          "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
          file, line, cond, (uptr)v1, (uptr)v2);
-  PrintCurrentStackSlow();
+  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
   Die();
 }
 
@@ -59,27 +59,16 @@
 static void StackStripMain(ReportStack *stack) {
   ReportStack *last_frame = 0;
   ReportStack *last_frame2 = 0;
-  const char *prefix = "__interceptor_";
-  uptr prefix_len = internal_strlen(prefix);
-  const char *path_prefix = flags()->strip_path_prefix;
-  uptr path_prefix_len = internal_strlen(path_prefix);
-  char *pos;
   for (ReportStack *ent = stack; ent; ent = ent->next) {
-    if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len))
-      ent->func += prefix_len;
-    if (ent->file && (pos = internal_strstr(ent->file, path_prefix)))
-      ent->file = pos + path_prefix_len;
-    if (ent->file && ent->file[0] == '.' && ent->file[1] == '/')
-      ent->file += 2;
     last_frame2 = last_frame;
     last_frame = ent;
   }
 
   if (last_frame2 == 0)
     return;
-  const char *last = last_frame->func;
+  const char *last = last_frame->info.function;
 #ifndef TSAN_GO
-  const char *last2 = last_frame2->func;
+  const char *last2 = last_frame2->info.function;
   // Strip frame above 'main'
   if (last2 && 0 == internal_strcmp(last2, "main")) {
     last_frame2->next = 0;
@@ -107,39 +96,36 @@
 ReportStack *SymbolizeStackId(u32 stack_id) {
   if (stack_id == 0)
     return 0;
-  uptr ssz = 0;
-  const uptr *stack = StackDepotGet(stack_id, &ssz);
-  if (stack == 0)
-    return 0;
-  StackTrace trace;
-  trace.Init(stack, ssz);
-  return SymbolizeStack(trace);
+  StackTrace stack = StackDepotGet(stack_id);
+  if (stack.trace == nullptr)
+    return nullptr;
+  return SymbolizeStack(stack);
 }
 
-static ReportStack *SymbolizeStack(const StackTrace& trace) {
-  if (trace.IsEmpty())
+static ReportStack *SymbolizeStack(StackTrace trace) {
+  if (trace.size == 0)
     return 0;
   ReportStack *stack = 0;
-  for (uptr si = 0; si < trace.Size(); si++) {
-    const uptr pc = trace.Get(si);
+  for (uptr si = 0; si < trace.size; si++) {
+    const uptr pc = trace.trace[si];
 #ifndef TSAN_GO
     // We obtain the return address, that is, address of the next instruction,
     // so offset it by 1 byte.
-    const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+    const uptr pc1 = StackTrace::GetPreviousInstructionPc(pc);
 #else
     // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
     uptr pc1 = pc;
-    if (si != trace.Size() - 1)
+    if (si != trace.size - 1)
       pc1 -= 1;
 #endif
     ReportStack *ent = SymbolizeCode(pc1);
     CHECK_NE(ent, 0);
     ReportStack *last = ent;
     while (last->next) {
-      last->pc = pc;  // restore original pc for report
+      last->info.address = pc;  // restore original pc for report
       last = last->next;
     }
-    last->pc = pc;  // restore original pc for report
+    last->info.address = pc;  // restore original pc for report
     last->next = stack;
     stack = ent;
   }
@@ -162,14 +148,14 @@
   DestroyAndFree(rep_);
 }
 
-void ScopedReport::AddStack(const StackTrace *stack, bool suppressable) {
+void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
   ReportStack **rs = rep_->stacks.PushBack();
-  *rs = SymbolizeStack(*stack);
+  *rs = SymbolizeStack(stack);
   (*rs)->suppressable = suppressable;
 }
 
-void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
-    const StackTrace *stack, const MutexSet *mset) {
+void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+                                   const MutexSet *mset) {
   void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
   ReportMop *mop = new(mem) ReportMop;
   rep_->mops.PushBack(mop);
@@ -178,7 +164,7 @@
   mop->size = s.size();
   mop->write = s.IsWrite();
   mop->atomic = s.IsAtomic();
-  mop->stack = SymbolizeStack(*stack);
+  mop->stack = SymbolizeStack(stack);
   if (mop->stack)
     mop->stack->suppressable = true;
   for (uptr i = 0; i < mset->Size(); i++) {
@@ -316,15 +302,12 @@
   int fd = -1;
   int creat_tid = -1;
   u32 creat_stack = 0;
-  if (FdLocation(addr, &fd, &creat_tid, &creat_stack)
-      || FdLocation(AlternativeAddress(addr), &fd, &creat_tid, &creat_stack)) {
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = ReportLocationFD;
+  if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
+    ReportLocation *loc = ReportLocation::New(ReportLocationFD);
     loc->fd = fd;
     loc->tid = creat_tid;
     loc->stack = SymbolizeStackId(creat_stack);
+    rep_->locs.PushBack(loc);
     ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
     if (tctx)
       AddThread(tctx);
@@ -339,33 +322,25 @@
   }
   if (b != 0) {
     ThreadContext *tctx = FindThreadByTidLocked(b->tid);
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = ReportLocationHeap;
-    loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
-    loc->size = b->siz;
+    ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
+    loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
+    loc->heap_chunk_size = b->siz;
     loc->tid = tctx ? tctx->tid : b->tid;
-    loc->name = 0;
-    loc->file = 0;
-    loc->line = 0;
-    loc->stack = 0;
     loc->stack = SymbolizeStackId(b->stk);
+    rep_->locs.PushBack(loc);
     if (tctx)
       AddThread(tctx);
     return;
   }
   bool is_stack = false;
   if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
+    ReportLocation *loc =
+        ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS);
     loc->tid = tctx->tid;
+    rep_->locs.PushBack(loc);
     AddThread(tctx);
   }
-  ReportLocation *loc = SymbolizeData(addr);
-  if (loc) {
+  if (ReportLocation *loc = SymbolizeData(addr)) {
     loc->suppressable = true;
     rep_->locs.PushBack(loc);
     return;
@@ -387,7 +362,8 @@
   return rep_;
 }
 
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+                  MutexSet *mset) {
   // This function restores stack trace and mutex set for the thread/epoch.
   // It does so by getting stack trace and mutex set at the beginning of
   // trace part, and then replaying the trace till the given epoch.
@@ -412,13 +388,13 @@
   DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
           tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
   InternalScopedBuffer<uptr> stack(kShadowStackSize);
-  for (uptr i = 0; i < hdr->stack0.Size(); i++) {
-    stack[i] = hdr->stack0.Get(i);
+  for (uptr i = 0; i < hdr->stack0.size; i++) {
+    stack[i] = hdr->stack0.trace[i];
     DPrintf2("  #%02lu: pc=%zx\n", i, stack[i]);
   }
   if (mset)
     *mset = hdr->mset0;
-  uptr pos = hdr->stack0.Size();
+  uptr pos = hdr->stack0.size;
   Event *events = (Event*)GetThreadTrace(tid);
   for (uptr i = ebegin; i <= eend; i++) {
     Event ev = events[i];
@@ -453,13 +429,13 @@
   stk->Init(stack.data(), pos);
 }
 
-static bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
-    uptr addr_min, uptr addr_max) {
+static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+                             uptr addr_min, uptr addr_max) {
   bool equal_stack = false;
   RacyStacks hash;
   if (flags()->suppress_equal_stacks) {
-    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
-    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
     for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
       if (hash == ctx->racy_stacks[i]) {
         DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
@@ -492,12 +468,12 @@
   return false;
 }
 
-static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
-    uptr addr_min, uptr addr_max) {
+static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+                          uptr addr_min, uptr addr_max) {
   if (flags()->suppress_equal_stacks) {
     RacyStacks hash;
-    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
-    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
     ctx->racy_stacks.PushBack(hash);
   }
   if (flags()->suppress_equal_addresses) {
@@ -538,15 +514,14 @@
   return true;
 }
 
-bool IsFiredSuppression(Context *ctx,
-                        const ScopedReport &srep,
-                        const StackTrace &trace) {
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+                        StackTrace trace) {
   for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
     if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
       continue;
-    for (uptr j = 0; j < trace.Size(); j++) {
+    for (uptr j = 0; j < trace.size; j++) {
       FiredSuppression *s = &ctx->fired_suppressions[k];
-      if (trace.Get(j) == s->pc) {
+      if (trace.trace[j] == s->pc) {
         if (s->supp)
           s->supp->hit_count++;
         return true;
@@ -573,45 +548,13 @@
 }
 
 bool FrameIsInternal(const ReportStack *frame) {
-  return frame != 0 && frame->file != 0
-      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
-          internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
-          internal_strstr(frame->file, "tsan_interface_"));
-}
-
-// On programs that use Java we see weird reports like:
-// WARNING: ThreadSanitizer: data race (pid=22512)
-//   Read of size 8 at 0x7d2b00084318 by thread 100:
-//     #0 memcpy tsan_interceptors.cc:406 (foo+0x00000d8dfae3)
-//     #1 <null> <null>:0 (0x7f7ad9b40193)
-//   Previous write of size 8 at 0x7d2b00084318 by thread 105:
-//     #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
-//     #1 <null> <null>:0 (0x7f7ad9b42707)
-static bool IsJavaNonsense(const ReportDesc *rep) {
-#ifndef TSAN_GO
-  for (uptr i = 0; i < rep->mops.Size(); i++) {
-    ReportMop *mop = rep->mops[i];
-    ReportStack *frame = mop->stack;
-    if (frame == 0
-        || (frame->func == 0 && frame->file == 0 && frame->line == 0
-          && frame->module == 0)) {
-      return true;
-    }
-    if (FrameIsInternal(frame)) {
-      frame = frame->next;
-      if (frame == 0
-          || (frame->func == 0 && frame->file == 0 && frame->line == 0
-          && frame->module == 0)) {
-        if (frame) {
-          FiredSuppression supp = {rep->typ, frame->pc, 0};
-          ctx->fired_suppressions.push_back(supp);
-        }
-        return true;
-      }
-    }
-  }
-#endif
-  return false;
+  if (frame == 0)
+    return false;
+  const char *file = frame->info.file;
+  return file != 0 &&
+         (internal_strstr(file, "tsan_interceptors.cc") ||
+          internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+          internal_strstr(file, "tsan_interface_"));
 }
 
 static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
@@ -663,7 +606,9 @@
   ThreadRegistryLock l0(ctx->thread_registry);
 
   ReportType typ = ReportTypeRace;
-  if (thr->is_vptr_access)
+  if (thr->is_vptr_access && freed)
+    typ = ReportTypeVptrUseAfterFree;
+  else if (thr->is_vptr_access)
     typ = ReportTypeVptrRace;
   else if (freed)
     typ = ReportTypeUseAfterFree;
@@ -671,9 +616,9 @@
   if (IsFiredSuppression(ctx, rep, addr))
     return;
   const uptr kMop = 2;
-  StackTrace traces[kMop];
+  VarSizeStackTrace traces[kMop];
   const uptr toppc = TraceTopPC(thr);
-  traces[0].ObtainCurrent(thr, toppc);
+  ObtainCurrentStack(thr, toppc, &traces[0]);
   if (IsFiredSuppression(ctx, rep, traces[0]))
     return;
   InternalScopedBuffer<MutexSet> mset2(1);
@@ -688,13 +633,10 @@
 
   for (uptr i = 0; i < kMop; i++) {
     Shadow s(thr->racy_state[i]);
-    rep.AddMemoryAccess(addr, s, &traces[i],
+    rep.AddMemoryAccess(addr, s, traces[i],
                         i == 0 ? &thr->mset : mset2.data());
   }
 
-  if (flags()->suppress_java && IsJavaNonsense(rep.GetReport()))
-    return;
-
   for (uptr i = 0; i < kMop; i++) {
     FastState s(thr->racy_state[i]);
     ThreadContext *tctx = static_cast<ThreadContext*>(
@@ -721,26 +663,33 @@
 }
 
 void PrintCurrentStack(ThreadState *thr, uptr pc) {
-  StackTrace trace;
-  trace.ObtainCurrent(thr, pc);
+  VarSizeStackTrace trace;
+  ObtainCurrentStack(thr, pc, &trace);
   PrintStack(SymbolizeStack(trace));
 }
 
-void PrintCurrentStackSlow() {
+void PrintCurrentStackSlow(uptr pc) {
 #ifndef TSAN_GO
-  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
-      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
-  ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(), 0, 0,
-                 0, 0, false);
+  BufferedStackTrace *ptrace =
+      new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
+          BufferedStackTrace();
+  ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false);
   for (uptr i = 0; i < ptrace->size / 2; i++) {
-    uptr tmp = ptrace->trace[i];
-    ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
-    ptrace->trace[ptrace->size - i - 1] = tmp;
+    uptr tmp = ptrace->trace_buffer[i];
+    ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
+    ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
   }
-  StackTrace trace;
-  trace.Init(ptrace->trace, ptrace->size);
-  PrintStack(SymbolizeStack(trace));
+  PrintStack(SymbolizeStack(*ptrace));
 #endif
 }
 
 }  // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+}
+}  // extern "C"
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 94bf754..256a95c 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -36,13 +36,13 @@
 #endif
 
 void ThreadContext::OnDead() {
-  sync.Reset();
+  CHECK_EQ(sync.size(), 0);
 }
 
 void ThreadContext::OnJoined(void *arg) {
   ThreadState *caller_thr = static_cast<ThreadState *>(arg);
   AcquireImpl(caller_thr, 0, &sync);
-  sync.Reset();
+  sync.Reset(&caller_thr->clock_cache);
 }
 
 struct OnCreatedArgs {
@@ -65,11 +65,16 @@
 }
 
 void ThreadContext::OnReset() {
-  sync.Reset();
+  CHECK_EQ(sync.size(), 0);
   FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
   //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
 }
 
+void ThreadContext::OnDetached(void *arg) {
+  ThreadState *thr1 = static_cast<ThreadState*>(arg);
+  sync.Reset(&thr1->clock_cache);
+}
+
 struct OnStartedArgs {
   ThreadState *thr;
   uptr stk_addr;
@@ -102,7 +107,7 @@
 #ifndef TSAN_GO
   AllocatorThreadStart(thr);
 #endif
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     thr->dd_pt = ctx->dd->CreatePhysicalThread();
     thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
   }
@@ -113,12 +118,11 @@
   Trace *thr_trace = ThreadTrace(thr->tid);
   thr_trace->headers[trace].epoch0 = epoch0;
   StatInc(thr, StatSyncAcquire);
-  sync.Reset();
+  sync.Reset(&thr->clock_cache);
   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,
           args->tls_addr, args->tls_size);
-  thr->is_alive = true;
 }
 
 void ThreadContext::OnFinished() {
@@ -130,10 +134,11 @@
   }
   epoch1 = thr->fast_state.epoch();
 
-  if (flags()->detect_deadlocks) {
+  if (common_flags()->detect_deadlocks) {
     ctx->dd->DestroyPhysicalThread(thr->dd_pt);
     ctx->dd->DestroyLogicalThread(thr->dd_lt);
   }
+  ctx->clock_alloc.FlushCache(&thr->clock_cache);
   ctx->metamap.OnThreadIdle(thr);
 #ifndef TSAN_GO
   AllocatorThreadFinish(thr);
@@ -278,7 +283,7 @@
     DontNeedShadowFor(thr->stk_addr, thr->stk_size);
   if (thr->tls_addr && thr->tls_size)
     DontNeedShadowFor(thr->tls_addr, thr->tls_size);
-  thr->is_alive = false;
+  thr->is_dead = true;
   ctx->thread_registry->FinishThread(thr->tid);
 }
 
@@ -307,7 +312,7 @@
 void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
   CHECK_GT(tid, 0);
   CHECK_LT(tid, kMaxTid);
-  ctx->thread_registry->DetachThread(tid);
+  ctx->thread_registry->DetachThread(tid, thr);
 }
 
 void ThreadSetName(ThreadState *thr, const char *name) {
diff --git a/lib/tsan/rtl/tsan_stack_trace.cc b/lib/tsan/rtl/tsan_stack_trace.cc
index a8374f4..ceca3f8 100644
--- a/lib/tsan/rtl/tsan_stack_trace.cc
+++ b/lib/tsan/rtl/tsan_stack_trace.cc
@@ -10,103 +10,37 @@
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
 //===----------------------------------------------------------------------===//
-//#include "sanitizer_common/sanitizer_placement_new.h"
 #include "tsan_stack_trace.h"
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
 
 namespace __tsan {
 
-StackTrace::StackTrace()
-    : n_()
-    , s_()
-    , c_() {
+VarSizeStackTrace::VarSizeStackTrace()
+    : StackTrace(nullptr, 0), trace_buffer(nullptr) {}
+
+VarSizeStackTrace::~VarSizeStackTrace() {
+  ResizeBuffer(0);
 }
 
-StackTrace::StackTrace(uptr *buf, uptr cnt)
-    : n_()
-    , s_(buf)
-    , c_(cnt) {
-  CHECK_NE(buf, 0);
-  CHECK_NE(cnt, 0);
-}
-
-StackTrace::~StackTrace() {
-  Reset();
-}
-
-void StackTrace::Reset() {
-  if (s_ && !c_) {
-    CHECK_NE(n_, 0);
-    internal_free(s_);
-    s_ = 0;
+void VarSizeStackTrace::ResizeBuffer(uptr new_size) {
+  if (trace_buffer) {
+    internal_free(trace_buffer);
   }
-  n_ = 0;
+  trace_buffer =
+      (new_size > 0)
+          ? (uptr *)internal_alloc(MBlockStackTrace,
+                                   new_size * sizeof(trace_buffer[0]))
+          : nullptr;
+  trace = trace_buffer;
+  size = new_size;
 }
 
-void StackTrace::Init(const uptr *pcs, uptr cnt) {
-  Reset();
-  if (cnt == 0)
-    return;
-  if (c_) {
-    CHECK_NE(s_, 0);
-    CHECK_LE(cnt, c_);
-  } else {
-    s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
-  }
-  n_ = cnt;
-  internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
-}
-
-void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
-  Reset();
-  n_ = thr->shadow_stack_pos - thr->shadow_stack;
-  if (n_ + !!toppc == 0)
-    return;
-  uptr start = 0;
-  if (c_) {
-    CHECK_NE(s_, 0);
-    if (n_ + !!toppc > c_) {
-      start = n_ - c_ + !!toppc;
-      n_ = c_ - !!toppc;
-    }
-  } else {
-    // Cap potentially huge stacks.
-    if (n_ + !!toppc > kTraceStackSize) {
-      start = n_ - kTraceStackSize + !!toppc;
-      n_ = kTraceStackSize - !!toppc;
-    }
-    s_ = (uptr*)internal_alloc(MBlockStackTrace,
-                               (n_ + !!toppc) * sizeof(s_[0]));
-  }
-  for (uptr i = 0; i < n_; i++)
-    s_[i] = thr->shadow_stack[start + i];
-  if (toppc) {
-    s_[n_] = toppc;
-    n_++;
-  }
-}
-
-void StackTrace::CopyFrom(const StackTrace& other) {
-  Reset();
-  Init(other.Begin(), other.Size());
-}
-
-bool StackTrace::IsEmpty() const {
-  return n_ == 0;
-}
-
-uptr StackTrace::Size() const {
-  return n_;
-}
-
-uptr StackTrace::Get(uptr i) const {
-  CHECK_LT(i, n_);
-  return s_[i];
-}
-
-const uptr *StackTrace::Begin() const {
-  return s_;
+void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+  ResizeBuffer(cnt + !!extra_top_pc);
+  internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+  if (extra_top_pc)
+    trace_buffer[cnt] = extra_top_pc;
 }
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_stack_trace.h b/lib/tsan/rtl/tsan_stack_trace.h
index fe82f6e..5bf89bb 100644
--- a/lib/tsan/rtl/tsan_stack_trace.h
+++ b/lib/tsan/rtl/tsan_stack_trace.h
@@ -13,40 +13,25 @@
 #ifndef TSAN_STACK_TRACE_H
 #define TSAN_STACK_TRACE_H
 
-//#include "sanitizer_common/sanitizer_atomic.h"
-//#include "sanitizer_common/sanitizer_common.h"
-//#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_defs.h"
-//#include "tsan_clock.h"
-//#include "tsan_mutex.h"
-//#include "tsan_dense_alloc.h"
 
 namespace __tsan {
 
-class StackTrace {
- public:
-  StackTrace();
-  // Initialized the object in "static mode",
-  // in this mode it never calls malloc/free but uses the provided buffer.
-  StackTrace(uptr *buf, uptr cnt);
-  ~StackTrace();
-  void Reset();
+// StackTrace which calls malloc/free to allocate the buffer for
+// addresses in stack traces.
+struct VarSizeStackTrace : public StackTrace {
+  uptr *trace_buffer;  // Owned.
 
-  void Init(const uptr *pcs, uptr cnt);
-  void ObtainCurrent(ThreadState *thr, uptr toppc);
-  bool IsEmpty() const;
-  uptr Size() const;
-  uptr Get(uptr i) const;
-  const uptr *Begin() const;
-  void CopyFrom(const StackTrace& other);
+  VarSizeStackTrace();
+  ~VarSizeStackTrace();
+  void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
 
  private:
-  uptr n_;
-  uptr *s_;
-  const uptr c_;
+  void ResizeBuffer(uptr new_size);
 
-  StackTrace(const StackTrace&);
-  void operator = (const StackTrace&);
+  VarSizeStackTrace(const VarSizeStackTrace &);
+  void operator=(const VarSizeStackTrace &);
 };
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index 0670396..1c5bea0 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -41,55 +41,16 @@
 
 namespace __tsan {
 
-static SuppressionContext* g_ctx;
-
-static char *ReadFile(const char *filename) {
-  if (filename == 0 || filename[0] == 0)
-    return 0;
-  InternalScopedBuffer<char> tmp(4*1024);
-  if (filename[0] == '/' || GetPwd() == 0)
-    internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
-  else
-    internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
-  uptr openrv = OpenFile(tmp.data(), false);
-  if (internal_iserror(openrv)) {
-    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
-               tmp.data());
-    Die();
-  }
-  fd_t fd = openrv;
-  const uptr fsize = internal_filesize(fd);
-  if (fsize == (uptr)-1) {
-    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
-               tmp.data());
-    Die();
-  }
-  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
-  if (fsize != internal_read(fd, buf, fsize)) {
-    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
-               tmp.data());
-    Die();
-  }
-  internal_close(fd);
-  buf[fsize] = 0;
-  return buf;
-}
+static bool suppressions_inited = false;
 
 void InitializeSuppressions() {
-  ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)];
-  g_ctx = new(placeholder_) SuppressionContext;
-  const char *supp = ReadFile(flags()->suppressions);
-  g_ctx->Parse(supp);
+  CHECK(!suppressions_inited);
+  SuppressionContext::InitIfNecessary();
 #ifndef TSAN_GO
-  supp = __tsan_default_suppressions();
-  g_ctx->Parse(supp);
-  g_ctx->Parse(std_suppressions);
+  SuppressionContext::Get()->Parse(__tsan_default_suppressions());
+  SuppressionContext::Get()->Parse(std_suppressions);
 #endif
-}
-
-SuppressionContext *GetSuppressionContext() {
-  CHECK_NE(g_ctx, 0);
-  return g_ctx;
+  suppressions_inited = true;
 }
 
 SuppressionType conv(ReportType typ) {
@@ -99,6 +60,8 @@
     return SuppressionRace;
   else if (typ == ReportTypeUseAfterFree)
     return SuppressionRace;
+  else if (typ == ReportTypeVptrUseAfterFree)
+    return SuppressionRace;
   else if (typ == ReportTypeThreadLeak)
     return SuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
@@ -122,50 +85,49 @@
 }
 
 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
-  CHECK(g_ctx);
-  if (!g_ctx->SuppressionCount() || stack == 0 || !stack->suppressable)
+  if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 ||
+      !stack->suppressable)
     return 0;
   SuppressionType stype = conv(typ);
   if (stype == SuppressionNone)
     return 0;
   Suppression *s;
   for (const ReportStack *frame = stack; frame; frame = frame->next) {
-    if (g_ctx->Match(frame->func, stype, &s) ||
-        g_ctx->Match(frame->file, stype, &s) ||
-        g_ctx->Match(frame->module, stype, &s)) {
+    const AddressInfo &info = frame->info;
+    if (SuppressionContext::Get()->Match(info.function, stype, &s) ||
+        SuppressionContext::Get()->Match(info.file, stype, &s) ||
+        SuppressionContext::Get()->Match(info.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
-      return frame->pc;
+      return info.address;
     }
   }
   return 0;
 }
 
 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
-  CHECK(g_ctx);
-  if (!g_ctx->SuppressionCount() || loc == 0 ||
+  if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 ||
       loc->type != ReportLocationGlobal || !loc->suppressable)
     return 0;
   SuppressionType stype = conv(typ);
   if (stype == SuppressionNone)
     return 0;
   Suppression *s;
-  if (g_ctx->Match(loc->name, stype, &s) ||
-      g_ctx->Match(loc->file, stype, &s) ||
-      g_ctx->Match(loc->module, stype, &s)) {
+  const DataInfo &global = loc->global;
+  if (SuppressionContext::Get()->Match(global.name, stype, &s) ||
+      SuppressionContext::Get()->Match(global.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
-      return loc->addr;
+      return global.start;
   }
   return 0;
 }
 
 void PrintMatchedSuppressions() {
-  CHECK(g_ctx);
   InternalMmapVector<Suppression *> matched(1);
-  g_ctx->GetMatched(&matched);
+  SuppressionContext::Get()->GetMatched(&matched);
   if (!matched.size())
     return;
   int hit_count = 0;
diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h
index fe7db58..c618b3d 100644
--- a/lib/tsan/rtl/tsan_suppressions.h
+++ b/lib/tsan/rtl/tsan_suppressions.h
@@ -22,7 +22,6 @@
 void PrintMatchedSuppressions();
 uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
 uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
-SuppressionContext *GetSuppressionContext();
 
 }  // namespace __tsan
 
diff --git a/lib/tsan/rtl/tsan_symbolize.cc b/lib/tsan/rtl/tsan_symbolize.cc
index 943aeb0..c08de6a 100644
--- a/lib/tsan/rtl/tsan_symbolize.cc
+++ b/lib/tsan/rtl/tsan_symbolize.cc
@@ -36,38 +36,6 @@
   thr->ignore_interceptors--;
 }
 
-ReportStack *NewReportStackEntry(uptr addr) {
-  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
-                                                  sizeof(ReportStack));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->pc = addr;
-  return ent;
-}
-
-static ReportStack *NewReportStackEntry(const AddressInfo &info) {
-  ReportStack *ent = NewReportStackEntry(info.address);
-  ent->module = StripModuleName(info.module);
-  ent->offset = info.module_offset;
-  if (info.function)
-    ent->func = internal_strdup(info.function);
-  if (info.file)
-    ent->file = internal_strdup(info.file);
-  ent->line = info.line;
-  ent->col = info.column;
-  return ent;
-}
-
-
-  ReportStack *next;
-  char *module;
-  uptr offset;
-  uptr pc;
-  char *func;
-  char *file;
-  int line;
-  int col;
-
-
 // Denotes fake PC values that come from JIT/JAVA/etc.
 // For such PC values __tsan_symbolize_external() will be called.
 const uptr kExternalPCBit = 1ULL << 60;
@@ -95,32 +63,29 @@
     static char func_buf[1024];
     static char file_buf[1024];
     int line, col;
+    ReportStack *ent = ReportStack::New(addr);
     if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
                                   file_buf, sizeof(file_buf), &line, &col))
-      return NewReportStackEntry(addr);
-    ReportStack *ent = NewReportStackEntry(addr);
-    ent->module = 0;
-    ent->offset = 0;
-    ent->func = internal_strdup(func_buf);
-    ent->file = internal_strdup(file_buf);
-    ent->line = line;
-    ent->col = col;
+      return ent;
+    ent->info.function = internal_strdup(func_buf);
+    ent->info.file = internal_strdup(file_buf);
+    ent->info.line = line;
+    ent->info.column = col;
     return ent;
   }
   static const uptr kMaxAddrFrames = 16;
   InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
   for (uptr i = 0; i < kMaxAddrFrames; i++)
     new(&addr_frames[i]) AddressInfo();
-  uptr addr_frames_num = Symbolizer::Get()->SymbolizePC(
+  uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
       addr, addr_frames.data(), kMaxAddrFrames);
   if (addr_frames_num == 0)
-    return NewReportStackEntry(addr);
+    return ReportStack::New(addr);
   ReportStack *top = 0;
   ReportStack *bottom = 0;
   for (uptr i = 0; i < addr_frames_num; i++) {
-    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
-    CHECK(cur_entry);
-    addr_frames[i].Clear();
+    ReportStack *cur_entry = ReportStack::New(addr);
+    cur_entry->info = addr_frames[i];
     if (i == 0)
       top = cur_entry;
     else
@@ -132,23 +97,15 @@
 
 ReportLocation *SymbolizeData(uptr addr) {
   DataInfo info;
-  if (!Symbolizer::Get()->SymbolizeData(addr, &info))
+  if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
     return 0;
-  ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
-                                                        sizeof(ReportLocation));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->type = ReportLocationGlobal;
-  ent->module = StripModuleName(info.module);
-  ent->offset = info.module_offset;
-  if (info.name)
-    ent->name = internal_strdup(info.name);
-  ent->addr = info.start;
-  ent->size = info.size;
+  ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
+  ent->global = info;
   return ent;
 }
 
 void SymbolizeFlush() {
-  Symbolizer::Get()->Flush();
+  Symbolizer::GetOrInit()->Flush();
 }
 
 }  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 10f52b4..1041073 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -21,7 +21,7 @@
 
 SyncVar::SyncVar()
     : mtx(MutexTypeSyncVar, StatMtxSyncVar) {
-  Reset();
+  Reset(0);
 }
 
 void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
@@ -32,11 +32,11 @@
   creation_stack_id = 0;
   if (kCppMode)  // Go does not use them
     creation_stack_id = CurrentStackId(thr, pc);
-  if (flags()->detect_deadlocks)
+  if (common_flags()->detect_deadlocks)
     DDMutexInit(thr, pc, this);
 }
 
-void SyncVar::Reset() {
+void SyncVar::Reset(ThreadState *thr) {
   uid = 0;
   creation_stack_id = 0;
   owner_tid = kInvalidTid;
@@ -47,8 +47,13 @@
   is_broken = 0;
   is_linker_init = 0;
 
-  clock.Zero();
-  read_clock.Reset();
+  if (thr == 0) {
+    CHECK_EQ(clock.size(), 0);
+    CHECK_EQ(read_clock.size(), 0);
+  } else {
+    clock.Reset(&thr->clock_cache);
+    read_clock.Reset(&thr->clock_cache);
+  }
 }
 
 MetaMap::MetaMap() {
@@ -93,7 +98,7 @@
         DCHECK(idx & kFlagSync);
         SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
         u32 next = s->next;
-        s->Reset();
+        s->Reset(thr);
         sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
         idx = next;
       } else {
@@ -143,7 +148,7 @@
       SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
       if (s->addr == addr) {
         if (myidx != 0) {
-          mys->Reset();
+          mys->Reset(thr);
           sync_alloc_.Free(&thr->sync_cache, myidx);
         }
         if (write_lock)
diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h
index 7c8682f..574810d 100644
--- a/lib/tsan/rtl/tsan_sync.h
+++ b/lib/tsan/rtl/tsan_sync.h
@@ -47,7 +47,7 @@
   SyncClock clock;
 
   void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid);
-  void Reset();
+  void Reset(ThreadState *thr);
 
   u64 GetId() const {
     // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h
index 686160c..7fb5ae3 100644
--- a/lib/tsan/rtl/tsan_trace.h
+++ b/lib/tsan/rtl/tsan_trace.h
@@ -42,21 +42,15 @@
 typedef u64 Event;
 
 struct TraceHeader {
-  StackTrace stack0;  // Start stack for the trace.
+#ifndef TSAN_GO
+  BufferedStackTrace stack0;  // Start stack for the trace.
+#else
+  VarSizeStackTrace stack0;
+#endif
   u64        epoch0;  // Start epoch for the trace.
   MutexSet   mset0;
-#ifndef TSAN_GO
-  uptr       stack0buf[kTraceStackSize];
-#endif
 
-  TraceHeader()
-#ifndef TSAN_GO
-      : stack0(stack0buf, kTraceStackSize)
-#else
-      : stack0()
-#endif
-      , epoch0() {
-  }
+  TraceHeader() : stack0(), epoch0() {}
 };
 
 struct Trace {
diff --git a/lib/tsan/tests/rtl/tsan_test_util_linux.cc b/lib/tsan/tests/rtl/tsan_test_util_linux.cc
index a260148..9298bf0 100644
--- a/lib/tsan/tests/rtl/tsan_test_util_linux.cc
+++ b/lib/tsan/tests/rtl/tsan_test_util_linux.cc
@@ -10,7 +10,7 @@
 //
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
-// Test utils, linux implementation.
+// Test utils, Linux and FreeBSD implementation.
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common/sanitizer_atomic.h"
@@ -263,9 +263,14 @@
       }
     }
     CHECK_NE(tsan_mop, 0);
-    errno = ECHRNG;
+#if defined(__FreeBSD__)
+    const int ErrCode = ESOCKTNOSUPPORT;
+#else
+    const int ErrCode = ECHRNG;
+#endif
+    errno = ErrCode;
     tsan_mop(ev->ptr);
-    CHECK_EQ(errno, ECHRNG);  // In no case must errno be changed.
+    CHECK_EQ(ErrCode, errno);  // In no case must errno be changed.
     break;
   }
   case Event::VPTR_UPDATE:
diff --git a/lib/tsan/tests/unit/tsan_clock_test.cc b/lib/tsan/tests/unit/tsan_clock_test.cc
index 49e7f3f..a1fd2b7 100644
--- a/lib/tsan/tests/unit/tsan_clock_test.cc
+++ b/lib/tsan/tests/unit/tsan_clock_test.cc
@@ -17,6 +17,8 @@
 
 namespace __tsan {
 
+ClockCache cache;
+
 TEST(Clock, VectorBasic) {
   ThreadClock clk(0);
   ASSERT_EQ(clk.size(), 1U);
@@ -38,30 +40,32 @@
   SyncClock chunked;
   ASSERT_EQ(vector.size(), 1U);
   ASSERT_EQ(chunked.size(), 0U);
-  vector.acquire(&chunked);
+  vector.acquire(&cache, &chunked);
   ASSERT_EQ(vector.size(), 1U);
   ASSERT_EQ(chunked.size(), 0U);
-  vector.release(&chunked);
+  vector.release(&cache, &chunked);
   ASSERT_EQ(vector.size(), 1U);
   ASSERT_EQ(chunked.size(), 1U);
-  vector.acq_rel(&chunked);
+  vector.acq_rel(&cache, &chunked);
   ASSERT_EQ(vector.size(), 1U);
   ASSERT_EQ(chunked.size(), 1U);
+  chunked.Reset(&cache);
 }
 
 TEST(Clock, AcquireRelease) {
   ThreadClock vector1(100);
   vector1.tick();
   SyncClock chunked;
-  vector1.release(&chunked);
+  vector1.release(&cache, &chunked);
   ASSERT_EQ(chunked.size(), 101U);
   ThreadClock vector2(0);
-  vector2.acquire(&chunked);
+  vector2.acquire(&cache, &chunked);
   ASSERT_EQ(vector2.size(), 101U);
   ASSERT_EQ(vector2.get(0), 0U);
   ASSERT_EQ(vector2.get(1), 0U);
   ASSERT_EQ(vector2.get(99), 0U);
   ASSERT_EQ(vector2.get(100), 1U);
+  chunked.Reset(&cache);
 }
 
 TEST(Clock, RepeatedAcquire) {
@@ -71,10 +75,12 @@
   thr2.tick();
 
   SyncClock sync;
-  thr1.ReleaseStore(&sync);
+  thr1.ReleaseStore(&cache, &sync);
 
-  thr2.acquire(&sync);
-  thr2.acquire(&sync);
+  thr2.acquire(&cache, &sync);
+  thr2.acquire(&cache, &sync);
+
+  sync.Reset(&cache);
 }
 
 TEST(Clock, ManyThreads) {
@@ -83,9 +89,9 @@
     ThreadClock vector(0);
     vector.tick();
     vector.set(i, 1);
-    vector.release(&chunked);
+    vector.release(&cache, &chunked);
     ASSERT_EQ(i + 1, chunked.size());
-    vector.acquire(&chunked);
+    vector.acquire(&cache, &chunked);
     ASSERT_EQ(i + 1, vector.size());
   }
 
@@ -93,10 +99,12 @@
     ASSERT_EQ(1U, chunked.get(i));
 
   ThreadClock vector(1);
-  vector.acquire(&chunked);
+  vector.acquire(&cache, &chunked);
   ASSERT_EQ(100U, vector.size());
   for (unsigned i = 0; i < 100; i++)
     ASSERT_EQ(1U, vector.get(i));
+
+  chunked.Reset(&cache);
 }
 
 TEST(Clock, DifferentSizes) {
@@ -107,33 +115,102 @@
     vector2.tick();
     {
       SyncClock chunked;
-      vector1.release(&chunked);
+      vector1.release(&cache, &chunked);
       ASSERT_EQ(chunked.size(), 11U);
-      vector2.release(&chunked);
+      vector2.release(&cache, &chunked);
       ASSERT_EQ(chunked.size(), 21U);
+      chunked.Reset(&cache);
     }
     {
       SyncClock chunked;
-      vector2.release(&chunked);
+      vector2.release(&cache, &chunked);
       ASSERT_EQ(chunked.size(), 21U);
-      vector1.release(&chunked);
+      vector1.release(&cache, &chunked);
       ASSERT_EQ(chunked.size(), 21U);
+      chunked.Reset(&cache);
     }
     {
       SyncClock chunked;
-      vector1.release(&chunked);
-      vector2.acquire(&chunked);
+      vector1.release(&cache, &chunked);
+      vector2.acquire(&cache, &chunked);
       ASSERT_EQ(vector2.size(), 21U);
+      chunked.Reset(&cache);
     }
     {
       SyncClock chunked;
-      vector2.release(&chunked);
-      vector1.acquire(&chunked);
+      vector2.release(&cache, &chunked);
+      vector1.acquire(&cache, &chunked);
       ASSERT_EQ(vector1.size(), 21U);
+      chunked.Reset(&cache);
     }
   }
 }
 
+TEST(Clock, Growth) {
+  {
+    ThreadClock vector(10);
+    vector.tick();
+    vector.set(5, 42);
+    SyncClock sync;
+    vector.release(&cache, &sync);
+    ASSERT_EQ(sync.size(), 11U);
+    ASSERT_EQ(sync.get(0), 0ULL);
+    ASSERT_EQ(sync.get(1), 0ULL);
+    ASSERT_EQ(sync.get(5), 42ULL);
+    ASSERT_EQ(sync.get(9), 0ULL);
+    ASSERT_EQ(sync.get(10), 1ULL);
+    sync.Reset(&cache);
+  }
+  {
+    ThreadClock vector1(10);
+    vector1.tick();
+    ThreadClock vector2(20);
+    vector2.tick();
+    SyncClock sync;
+    vector1.release(&cache, &sync);
+    vector2.release(&cache, &sync);
+    ASSERT_EQ(sync.size(), 21U);
+    ASSERT_EQ(sync.get(0), 0ULL);
+    ASSERT_EQ(sync.get(10), 1ULL);
+    ASSERT_EQ(sync.get(19), 0ULL);
+    ASSERT_EQ(sync.get(20), 1ULL);
+    sync.Reset(&cache);
+  }
+  {
+    ThreadClock vector(100);
+    vector.tick();
+    vector.set(5, 42);
+    vector.set(90, 84);
+    SyncClock sync;
+    vector.release(&cache, &sync);
+    ASSERT_EQ(sync.size(), 101U);
+    ASSERT_EQ(sync.get(0), 0ULL);
+    ASSERT_EQ(sync.get(1), 0ULL);
+    ASSERT_EQ(sync.get(5), 42ULL);
+    ASSERT_EQ(sync.get(60), 0ULL);
+    ASSERT_EQ(sync.get(70), 0ULL);
+    ASSERT_EQ(sync.get(90), 84ULL);
+    ASSERT_EQ(sync.get(99), 0ULL);
+    ASSERT_EQ(sync.get(100), 1ULL);
+    sync.Reset(&cache);
+  }
+  {
+    ThreadClock vector1(10);
+    vector1.tick();
+    ThreadClock vector2(100);
+    vector2.tick();
+    SyncClock sync;
+    vector1.release(&cache, &sync);
+    vector2.release(&cache, &sync);
+    ASSERT_EQ(sync.size(), 101U);
+    ASSERT_EQ(sync.get(0), 0ULL);
+    ASSERT_EQ(sync.get(10), 1ULL);
+    ASSERT_EQ(sync.get(99), 0ULL);
+    ASSERT_EQ(sync.get(100), 1ULL);
+    sync.Reset(&cache);
+  }
+}
+
 const int kThreads = 4;
 const int kClocks = 4;
 
@@ -257,31 +334,31 @@
       if (printing)
         printf("acquire thr%d <- clk%d\n", tid, cid);
       thr0[tid]->acquire(sync0[cid]);
-      thr1[tid]->acquire(sync1[cid]);
+      thr1[tid]->acquire(&cache, sync1[cid]);
       break;
     case 1:
       if (printing)
         printf("release thr%d -> clk%d\n", tid, cid);
       thr0[tid]->release(sync0[cid]);
-      thr1[tid]->release(sync1[cid]);
+      thr1[tid]->release(&cache, sync1[cid]);
       break;
     case 2:
       if (printing)
         printf("acq_rel thr%d <> clk%d\n", tid, cid);
       thr0[tid]->acq_rel(sync0[cid]);
-      thr1[tid]->acq_rel(sync1[cid]);
+      thr1[tid]->acq_rel(&cache, sync1[cid]);
       break;
     case 3:
       if (printing)
         printf("rel_str thr%d >> clk%d\n", tid, cid);
       thr0[tid]->ReleaseStore(sync0[cid]);
-      thr1[tid]->ReleaseStore(sync1[cid]);
+      thr1[tid]->ReleaseStore(&cache, sync1[cid]);
       break;
     case 4:
       if (printing)
         printf("reset clk%d\n", cid);
       sync0[cid]->Reset();
-      sync1[cid]->Reset();
+      sync1[cid]->Reset(&cache);
       break;
     case 5:
       if (printing)
@@ -331,6 +408,10 @@
       return false;
     }
   }
+
+  for (unsigned i = 0; i < kClocks; i++) {
+    sync1[i]->Reset(&cache);
+  }
   return true;
 }
 
diff --git a/lib/tsan/tests/unit/tsan_dense_alloc_test.cc b/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
index fc9e4cb..e848e48 100644
--- a/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
+++ b/lib/tsan/tests/unit/tsan_dense_alloc_test.cc
@@ -36,7 +36,7 @@
     for (int i = 0; i < N; i++) {
       IndexT idx = alloc.Alloc(&cache);
       blocks[i] = idx;
-      EXPECT_NE(idx, 0);
+      EXPECT_NE(idx, 0U);
       int *v = alloc.Map(idx);
       *v = i;
     }
diff --git a/lib/tsan/tests/unit/tsan_flags_test.cc b/lib/tsan/tests/unit/tsan_flags_test.cc
index 3227d27..22610c0 100644
--- a/lib/tsan/tests/unit/tsan_flags_test.cc
+++ b/lib/tsan/tests/unit/tsan_flags_test.cc
@@ -38,7 +38,6 @@
   " enable_annotations=0"
   " suppress_equal_stacks=0"
   " suppress_equal_addresses=0"
-  " suppress_java=0"
   " report_bugs=0"
   " report_thread_leaks=0"
   " report_destroy_locked=0"
@@ -46,8 +45,6 @@
   " report_signal_unsafe=0"
   " report_atomic_races=0"
   " force_seq_cst_atomics=0"
-  " suppressions=qwerty"
-  " print_suppressions=0"
   " print_benign=0"
   " exitcode=111"
   " halt_on_error=0"
@@ -61,29 +58,12 @@
   " history_size=5"
   " io_sync=1"
   " die_after_fork=true"
-
-  " symbolize=0"
-  " external_symbolizer_path=asdfgh"
-  " allow_addr2line=true"
-  " strip_path_prefix=zxcvb"
-  " fast_unwind_on_fatal=0"
-  " fast_unwind_on_malloc=0"
-  " handle_ioctl=0"
-  " malloc_context_size=777"
-  " log_path=aaa"
-  " verbosity=2"
-  " detect_leaks=0"
-  " leak_check_at_exit=0"
-  " allocator_may_return_null=0"
-  " print_summary=0"
-  " legacy_pthread_cond=0"
   "";
 
 static const char *options2 =
   " enable_annotations=true"
   " suppress_equal_stacks=true"
   " suppress_equal_addresses=true"
-  " suppress_java=true"
   " report_bugs=true"
   " report_thread_leaks=true"
   " report_destroy_locked=true"
@@ -91,8 +71,6 @@
   " report_signal_unsafe=true"
   " report_atomic_races=true"
   " force_seq_cst_atomics=true"
-  " suppressions=aaaaa"
-  " print_suppressions=true"
   " print_benign=true"
   " exitcode=222"
   " halt_on_error=true"
@@ -106,29 +84,12 @@
   " history_size=6"
   " io_sync=2"
   " die_after_fork=false"
-
-  " symbolize=true"
-  " external_symbolizer_path=cccccc"
-  " allow_addr2line=false"
-  " strip_path_prefix=ddddddd"
-  " fast_unwind_on_fatal=true"
-  " fast_unwind_on_malloc=true"
-  " handle_ioctl=true"
-  " malloc_context_size=567"
-  " log_path=eeeeeee"
-  " verbosity=0"
-  " detect_leaks=true"
-  " leak_check_at_exit=true"
-  " allocator_may_return_null=true"
-  " print_summary=true"
-  " legacy_pthread_cond=true"
   "";
 
 void VerifyOptions1(Flags *f) {
   EXPECT_EQ(f->enable_annotations, 0);
   EXPECT_EQ(f->suppress_equal_stacks, 0);
   EXPECT_EQ(f->suppress_equal_addresses, 0);
-  EXPECT_EQ(f->suppress_java, 0);
   EXPECT_EQ(f->report_bugs, 0);
   EXPECT_EQ(f->report_thread_leaks, 0);
   EXPECT_EQ(f->report_destroy_locked, 0);
@@ -136,8 +97,6 @@
   EXPECT_EQ(f->report_signal_unsafe, 0);
   EXPECT_EQ(f->report_atomic_races, 0);
   EXPECT_EQ(f->force_seq_cst_atomics, 0);
-  EXPECT_EQ(f->suppressions, std::string("qwerty"));
-  EXPECT_EQ(f->print_suppressions, 0);
   EXPECT_EQ(f->print_benign, 0);
   EXPECT_EQ(f->exitcode, 111);
   EXPECT_EQ(f->halt_on_error, 0);
@@ -151,29 +110,12 @@
   EXPECT_EQ(f->history_size, 5);
   EXPECT_EQ(f->io_sync, 1);
   EXPECT_EQ(f->die_after_fork, true);
-
-  EXPECT_EQ(f->symbolize, 0);
-  EXPECT_EQ(f->external_symbolizer_path, std::string("asdfgh"));
-  EXPECT_EQ(f->allow_addr2line, true);
-  EXPECT_EQ(f->strip_path_prefix, std::string("zxcvb"));
-  EXPECT_EQ(f->fast_unwind_on_fatal, 0);
-  EXPECT_EQ(f->fast_unwind_on_malloc, 0);
-  EXPECT_EQ(f->handle_ioctl, 0);
-  EXPECT_EQ(f->malloc_context_size, 777);
-  EXPECT_EQ(f->log_path, std::string("aaa"));
-  EXPECT_EQ(f->verbosity, 2);
-  EXPECT_EQ(f->detect_leaks, 0);
-  EXPECT_EQ(f->leak_check_at_exit, 0);
-  EXPECT_EQ(f->allocator_may_return_null, 0);
-  EXPECT_EQ(f->print_summary, 0);
-  EXPECT_EQ(f->legacy_pthread_cond, false);
 }
 
 void VerifyOptions2(Flags *f) {
   EXPECT_EQ(f->enable_annotations, true);
   EXPECT_EQ(f->suppress_equal_stacks, true);
   EXPECT_EQ(f->suppress_equal_addresses, true);
-  EXPECT_EQ(f->suppress_java, true);
   EXPECT_EQ(f->report_bugs, true);
   EXPECT_EQ(f->report_thread_leaks, true);
   EXPECT_EQ(f->report_destroy_locked, true);
@@ -181,8 +123,6 @@
   EXPECT_EQ(f->report_signal_unsafe, true);
   EXPECT_EQ(f->report_atomic_races, true);
   EXPECT_EQ(f->force_seq_cst_atomics, true);
-  EXPECT_EQ(f->suppressions, std::string("aaaaa"));
-  EXPECT_EQ(f->print_suppressions, true);
   EXPECT_EQ(f->print_benign, true);
   EXPECT_EQ(f->exitcode, 222);
   EXPECT_EQ(f->halt_on_error, true);
@@ -196,22 +136,6 @@
   EXPECT_EQ(f->history_size, 6);
   EXPECT_EQ(f->io_sync, 2);
   EXPECT_EQ(f->die_after_fork, false);
-
-  EXPECT_EQ(f->symbolize, true);
-  EXPECT_EQ(f->external_symbolizer_path, std::string("cccccc"));
-  EXPECT_EQ(f->allow_addr2line, false);
-  EXPECT_EQ(f->strip_path_prefix, std::string("ddddddd"));
-  EXPECT_EQ(f->fast_unwind_on_fatal, true);
-  EXPECT_EQ(f->fast_unwind_on_malloc, true);
-  EXPECT_EQ(f->handle_ioctl, true);
-  EXPECT_EQ(f->malloc_context_size, 567);
-  EXPECT_EQ(f->log_path, std::string("eeeeeee"));
-  EXPECT_EQ(f->verbosity, 0);
-  EXPECT_EQ(f->detect_leaks, true);
-  EXPECT_EQ(f->leak_check_at_exit, true);
-  EXPECT_EQ(f->allocator_may_return_null, true);
-  EXPECT_EQ(f->print_summary, true);
-  EXPECT_EQ(f->legacy_pthread_cond, true);
 }
 
 static const char *test_default_options;
diff --git a/lib/tsan/tests/unit/tsan_mman_test.cc b/lib/tsan/tests/unit/tsan_mman_test.cc
index 0c4a8ff..d969989 100644
--- a/lib/tsan/tests/unit/tsan_mman_test.cc
+++ b/lib/tsan/tests/unit/tsan_mman_test.cc
@@ -103,7 +103,7 @@
   EXPECT_EQ(20U, user_alloc_usable_size(p2));
   user_free(thr, pc, p);
   user_free(thr, pc, p2);
-  EXPECT_EQ(0U, user_alloc_usable_size((void*)0x123));
+  EXPECT_EQ(0U, user_alloc_usable_size((void*)0x4123));
 }
 
 TEST(Mman, Stats) {
diff --git a/lib/tsan/tests/unit/tsan_stack_test.cc b/lib/tsan/tests/unit/tsan_stack_test.cc
index fc4d6c3..92e035d 100644
--- a/lib/tsan/tests/unit/tsan_stack_test.cc
+++ b/lib/tsan/tests/unit/tsan_stack_test.cc
@@ -17,70 +17,79 @@
 
 namespace __tsan {
 
-static void TestStackTrace(StackTrace *trace) {
+template <typename StackTraceTy>
+static void TestStackTrace(StackTraceTy *trace) {
   ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
   uptr stack[128];
   thr.shadow_stack = &stack[0];
   thr.shadow_stack_pos = &stack[0];
   thr.shadow_stack_end = &stack[128];
 
-  trace->ObtainCurrent(&thr, 0);
-  EXPECT_EQ(trace->Size(), (uptr)0);
+  ObtainCurrentStack(&thr, 0, trace);
+  EXPECT_EQ(0U, trace->size);
 
-  trace->ObtainCurrent(&thr, 42);
-  EXPECT_EQ(trace->Size(), (uptr)1);
-  EXPECT_EQ(trace->Get(0), (uptr)42);
+  ObtainCurrentStack(&thr, 42, trace);
+  EXPECT_EQ(1U, trace->size);
+  EXPECT_EQ(42U, trace->trace[0]);
 
   *thr.shadow_stack_pos++ = 100;
   *thr.shadow_stack_pos++ = 101;
-  trace->ObtainCurrent(&thr, 0);
-  EXPECT_EQ(trace->Size(), (uptr)2);
-  EXPECT_EQ(trace->Get(0), (uptr)100);
-  EXPECT_EQ(trace->Get(1), (uptr)101);
+  ObtainCurrentStack(&thr, 0, trace);
+  EXPECT_EQ(2U, trace->size);
+  EXPECT_EQ(100U, trace->trace[0]);
+  EXPECT_EQ(101U, trace->trace[1]);
 
-  trace->ObtainCurrent(&thr, 42);
-  EXPECT_EQ(trace->Size(), (uptr)3);
-  EXPECT_EQ(trace->Get(0), (uptr)100);
-  EXPECT_EQ(trace->Get(1), (uptr)101);
-  EXPECT_EQ(trace->Get(2), (uptr)42);
+  ObtainCurrentStack(&thr, 42, trace);
+  EXPECT_EQ(3U, trace->size);
+  EXPECT_EQ(100U, trace->trace[0]);
+  EXPECT_EQ(101U, trace->trace[1]);
+  EXPECT_EQ(42U, trace->trace[2]);
 }
 
-TEST(StackTrace, Basic) {
-  StackTrace trace;
+template<typename StackTraceTy>
+static void TestTrim(StackTraceTy *trace) {
+  ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
+  const uptr kShadowStackSize = 2 * kStackTraceMax;
+  uptr stack[kShadowStackSize];
+  thr.shadow_stack = &stack[0];
+  thr.shadow_stack_pos = &stack[0];
+  thr.shadow_stack_end = &stack[kShadowStackSize];
+
+  for (uptr i = 0; i < kShadowStackSize; ++i)
+    *thr.shadow_stack_pos++ = 100 + i;
+
+  ObtainCurrentStack(&thr, 0, trace);
+  EXPECT_EQ(kStackTraceMax, trace->size);
+  for (uptr i = 0; i < kStackTraceMax; i++) {
+    EXPECT_EQ(100 + kStackTraceMax + i, trace->trace[i]);
+  }
+
+  ObtainCurrentStack(&thr, 42, trace);
+  EXPECT_EQ(kStackTraceMax, trace->size);
+  for (uptr i = 0; i < kStackTraceMax - 1; i++) {
+    EXPECT_EQ(101 + kStackTraceMax + i, trace->trace[i]);
+  }
+  EXPECT_EQ(42U, trace->trace[kStackTraceMax - 1]);
+}
+
+TEST(StackTrace, BasicVarSize) {
+  VarSizeStackTrace trace;
   TestStackTrace(&trace);
 }
 
-TEST(StackTrace, StaticBasic) {
-  uptr buf[10];
-  StackTrace trace1(buf, 10);
-  TestStackTrace(&trace1);
-  StackTrace trace2(buf, 3);
-  TestStackTrace(&trace2);
+TEST(StackTrace, BasicBuffered) {
+  BufferedStackTrace trace;
+  TestStackTrace(&trace);
 }
 
-TEST(StackTrace, StaticTrim) {
-  uptr buf[2];
-  StackTrace trace(buf, 2);
-
-  ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
-  uptr stack[128];
-  thr.shadow_stack = &stack[0];
-  thr.shadow_stack_pos = &stack[0];
-  thr.shadow_stack_end = &stack[128];
-
-  *thr.shadow_stack_pos++ = 100;
-  *thr.shadow_stack_pos++ = 101;
-  *thr.shadow_stack_pos++ = 102;
-  trace.ObtainCurrent(&thr, 0);
-  EXPECT_EQ(trace.Size(), (uptr)2);
-  EXPECT_EQ(trace.Get(0), (uptr)101);
-  EXPECT_EQ(trace.Get(1), (uptr)102);
-
-  trace.ObtainCurrent(&thr, 42);
-  EXPECT_EQ(trace.Size(), (uptr)2);
-  EXPECT_EQ(trace.Get(0), (uptr)102);
-  EXPECT_EQ(trace.Get(1), (uptr)42);
+TEST(StackTrace, TrimVarSize) {
+  VarSizeStackTrace trace;
+  TestTrim(&trace);
 }
 
+TEST(StackTrace, TrimBuffered) {
+  BufferedStackTrace trace;
+  TestTrim(&trace);
+}
 
 }  // namespace __tsan
diff --git a/lib/tsan/tests/unit/tsan_sync_test.cc b/lib/tsan/tests/unit/tsan_sync_test.cc
index 6f36c64..d3616a1 100644
--- a/lib/tsan/tests/unit/tsan_sync_test.cc
+++ b/lib/tsan/tests/unit/tsan_sync_test.cc
@@ -114,7 +114,7 @@
   u64 block[1] = {};  // fake malloc block
   m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64));
   SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true);
-  s->Reset();
+  s->Reset(thr);
   s->mtx.Unlock();
   uptr sz = m->FreeBlock(thr, 0, (uptr)&block[0]);
   EXPECT_EQ(sz, 1 * sizeof(u64));
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index 78c0d70..09c7a85 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -2,6 +2,8 @@
 
 set(UBSAN_SOURCES
   ubsan_diag.cc
+  ubsan_init.cc
+  ubsan_flags.cc
   ubsan_handlers.cc
   ubsan_value.cc
   )
@@ -14,6 +16,8 @@
 include_directories(..)
 
 set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(UBSAN_CFLAGS)
+set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS})
 
 add_custom_target(ubsan)
 
@@ -23,7 +27,7 @@
     ARCH ${UBSAN_SUPPORTED_ARCH}
     SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
             $<TARGET_OBJECTS:RTSanitizerCommon.osx>
-    CFLAGS ${UBSAN_CFLAGS})
+    CFLAGS ${UBSAN_CXXFLAGS})
   add_dependencies(ubsan clang_rt.ubsan_osx)
 else()
   # Build separate libraries for each target.
@@ -35,12 +39,12 @@
     # 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}
-      CFLAGS ${UBSAN_CFLAGS})
+      CFLAGS ${UBSAN_CXXFLAGS})
     add_dependencies(ubsan
       clang_rt.san-${arch}
       clang_rt.ubsan-${arch}
       clang_rt.ubsan_cxx-${arch})
-    if (UNIX AND NOT ${arch} STREQUAL "i386")
+    if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "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_dependencies(ubsan
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index fb5cd4b..f562508 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -12,30 +12,47 @@
 //===----------------------------------------------------------------------===//
 
 #include "ubsan_diag.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_libc.h"
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include <stdio.h>
 
 using namespace __ubsan;
 
-static void InitializeSanitizerCommon() {
-  static StaticSpinMutex init_mu;
-  SpinMutexLock l(&init_mu);
-  static bool initialized;
-  if (initialized)
-   return;
-  if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
-    // UBSan is run in a standalone mode. Initialize it now.
-    SanitizerToolName = "UndefinedBehaviorSanitizer";
-    CommonFlags *cf = common_flags();
-    SetCommonFlagsDefaults(cf);
-    cf->print_summary = false;
+static void MaybePrintStackTrace(uptr pc, uptr bp) {
+  // We assume that flags are already parsed: InitIfNecessary
+  // will definitely be called when we print the first diagnostics message.
+  if (!flags()->print_stacktrace)
+    return;
+  // We can only use slow unwind, as we don't have any information about stack
+  // top/bottom.
+  // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
+  // fetch stack top/bottom information if we have it (e.g. if we're running
+  // under ASan).
+  if (StackTrace::WillUseFastUnwind(false))
+    return;
+  BufferedStackTrace stack;
+  stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+  stack.Print();
+}
+
+static void MaybeReportErrorSummary(Location Loc) {
+  if (!common_flags()->print_summary)
+    return;
+  // Don't try to unwind the stack trace in UBSan summaries: just use the
+  // provided location.
+  if (Loc.isSourceLocation()) {
+    SourceLocation SLoc = Loc.getSourceLocation();
+    if (!SLoc.isInvalid()) {
+      ReportErrorSummary("undefined-behavior", SLoc.getFilename(),
+                         SLoc.getLine(), "");
+      return;
+    }
   }
-  initialized = true;
+  ReportErrorSummary("undefined-behavior");
 }
 
 namespace {
@@ -60,11 +77,11 @@
 Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
   if (!Loc)
     return Location();
-  InitializeSanitizerCommon();
+  InitIfNecessary();
 
   AddressInfo Info;
-  if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) ||
-      !Info.module || !*Info.module)
+  if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) || !Info.module ||
+      !*Info.module)
     return Location(Loc);
 
   if (FName && Info.function)
@@ -113,14 +130,16 @@
     if (SLoc.isInvalid())
       LocBuffer.append("<unknown>");
     else
-      PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
-                          SLoc.getColumn());
+      RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+                           SLoc.getColumn(), common_flags()->strip_path_prefix);
     break;
   }
-  case Location::LK_Module:
-    PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
-                         Loc.getModuleLocation().getOffset());
+  case Location::LK_Module: {
+    ModuleLocation MLoc = Loc.getModuleLocation();
+    RenderModuleLocation(&LocBuffer, MLoc.getModuleName(), MLoc.getOffset(),
+                         common_flags()->strip_path_prefix);
     break;
+  }
   case Location::LK_Memory:
     LocBuffer.append("%p", Loc.getMemoryLocation());
     break;
@@ -193,28 +212,42 @@
   return Best;
 }
 
+static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) {
+  return (LHS < RHS) ? 0 : LHS - RHS;
+}
+
+static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
+  const uptr Limit = (uptr)-1;
+  return (LHS > Limit - RHS) ? Limit : LHS + RHS;
+}
+
 /// Render a snippet of the address space near a location.
 static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
                                 Range *Ranges, unsigned NumRanges,
                                 const Diag::Arg *Args) {
-  const unsigned BytesToShow = 32;
-  const unsigned MinBytesNearLoc = 4;
-
   // Show at least the 8 bytes surrounding Loc.
-  MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
+  const unsigned MinBytesNearLoc = 4;
+  MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
+  MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc);
+  MemoryLocation OrigMin = Min;
   for (unsigned I = 0; I < NumRanges; ++I) {
     Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
     Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
   }
 
   // If we have too many interesting bytes, prefer to show bytes after Loc.
+  const unsigned BytesToShow = 32;
   if (Max - Min > BytesToShow)
-    Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
-  Max = Min + BytesToShow;
+    Min = __sanitizer::Min(Max - BytesToShow, OrigMin);
+  Max = addNoOverflow(Min, BytesToShow);
+
+  if (!IsAccessibleMemoryRange(Min, Max - Min)) {
+    Printf("<memory cannot be printed>\n");
+    return;
+  }
 
   // Emit data.
   for (uptr P = Min; P != Max; ++P) {
-    // FIXME: Check that the address is readable before printing it.
     unsigned char C = *reinterpret_cast<const unsigned char*>(P);
     Printf("%s%02x", (P % 8 == 0) ? "  " : " ", C);
   }
@@ -274,9 +307,9 @@
 }
 
 Diag::~Diag() {
-  InitializeSanitizerCommon();
+  // All diagnostics should be printed under report mutex.
+  CommonSanitizerReportMutex.CheckLocked();
   Decorator Decor;
-  SpinMutexLock l(&CommonSanitizerReportMutex);
   Printf(Decor.Bold());
 
   renderLocation(Loc);
@@ -300,3 +333,26 @@
     renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
                         NumRanges, Args);
 }
+
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
+    : Opts(Opts), SummaryLoc(SummaryLoc) {
+  InitIfNecessary();
+  CommonSanitizerReportMutex.Lock();
+}
+
+ScopedReport::~ScopedReport() {
+  MaybePrintStackTrace(Opts.pc, Opts.bp);
+  MaybeReportErrorSummary(SummaryLoc);
+  CommonSanitizerReportMutex.Unlock();
+  if (Opts.DieAfterReport || flags()->halt_on_error)
+    Die();
+}
+
+bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) {
+  Suppression *s;
+  // If .preinit_array is not used, it is possible that the UBSan runtime is not
+  // initialized.
+  if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
+    InitIfNecessary();
+  return SuppressionContext::Get()->Match(Str, Type, &s);
+}
diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h
index 54d15a0..296ec0d 100644
--- a/lib/ubsan/ubsan_diag.h
+++ b/lib/ubsan/ubsan_diag.h
@@ -14,6 +14,8 @@
 #define UBSAN_DIAG_H
 
 #include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
 
 namespace __ubsan {
 
@@ -203,6 +205,33 @@
   Diag &operator<<(const Range &R) { return AddRange(R); }
 };
 
+struct ReportOptions {
+  /// If DieAfterReport is specified, UBSan will terminate the program after the
+  /// report is printed.
+  bool DieAfterReport;
+  /// pc/bp are used to unwind the stack trace.
+  uptr pc;
+  uptr bp;
+};
+
+#define GET_REPORT_OPTIONS(die_after_report) \
+    GET_CALLER_PC_BP; \
+    ReportOptions Opts = {die_after_report, pc, bp}
+
+/// \brief Instantiate this class before printing diagnostics in the error
+/// report. This class ensures that reports from different threads and from
+/// different sanitizers won't be mixed.
+class ScopedReport {
+  ReportOptions Opts;
+  Location SummaryLoc;
+
+public:
+  ScopedReport(ReportOptions Opts, Location SummaryLoc);
+  ~ScopedReport();
+};
+
+bool MatchSuppression(const char *Str, SuppressionType Type);
+
 } // namespace __ubsan
 
 #endif // UBSAN_DIAG_H
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
new file mode 100644
index 0000000..eda11f1
--- /dev/null
+++ b/lib/ubsan/ubsan_flags.cc
@@ -0,0 +1,63 @@
+//===-- ubsan_flags.cc ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __ubsan {
+
+static const char *MaybeCallUbsanDefaultOptions() {
+  return (&__ubsan_default_options) ? __ubsan_default_options() : "";
+}
+
+void InitializeCommonFlags() {
+  CommonFlags *cf = common_flags();
+  SetCommonFlagsDefaults(cf);
+  cf->print_summary = false;
+  // Override from user-specified string.
+  ParseCommonFlagsFromString(cf, MaybeCallUbsanDefaultOptions());
+  // Override from environment variable.
+  ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS"));
+}
+
+Flags ubsan_flags;
+
+static void ParseFlagsFromString(Flags *f, const char *str) {
+  if (!str)
+    return;
+  ParseFlag(str, &f->halt_on_error, "halt_on_error",
+            "Crash the program after printing the first error report");
+  ParseFlag(str, &f->print_stacktrace, "print_stacktrace",
+            "Include full stacktrace into an error report");
+}
+
+void InitializeFlags() {
+  Flags *f = flags();
+  // Default values.
+  f->halt_on_error = false;
+  f->print_stacktrace = false;
+  // Override from user-specified string.
+  ParseFlagsFromString(f, MaybeCallUbsanDefaultOptions());
+  // Override from environment variable.
+  ParseFlagsFromString(f, GetEnv("UBSAN_OPTIONS"));
+}
+
+}  // namespace __ubsan
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options() { return ""; }
+}  // extern "C"
+#endif
diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h
new file mode 100644
index 0000000..c496469
--- /dev/null
+++ b/lib/ubsan/ubsan_flags.h
@@ -0,0 +1,40 @@
+//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_FLAGS_H
+#define UBSAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __ubsan {
+
+struct Flags {
+  bool halt_on_error;
+  bool print_stacktrace;
+};
+
+extern Flags ubsan_flags;
+inline Flags *flags() { return &ubsan_flags; }
+
+void InitializeCommonFlags();
+void InitializeFlags();
+
+}  // namespace __ubsan
+
+extern "C" {
+// Users may provide their own implementation of __ubsan_default_options to
+// override the default flag values.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__ubsan_default_options();
+}  // extern "C"
+
+#endif  // UBSAN_FLAGS_H
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index d556431..a0ecff9 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -19,23 +19,35 @@
 using namespace __sanitizer;
 using namespace __ubsan;
 
+static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
+  // If source location is already acquired, we don't need to print an error
+  // report for the second time. However, if we're in an unrecoverable handler,
+  // it's possible that location was required by concurrently running thread.
+  // In this case, we should continue the execution to ensure that any of
+  // threads will grab the report mutex and print the report before
+  // crashing the program.
+  return SLoc.isDisabled() && !Opts.DieAfterReport;
+}
+
 namespace __ubsan {
-  const char *TypeCheckKinds[] = {
+const char *TypeCheckKinds[] = {
     "load of", "store to", "reference binding to", "member access within",
-    "member call on", "constructor call on", "downcast of", "downcast of"
-  };
+    "member call on", "constructor call on", "downcast of", "downcast of",
+    "upcast of", "cast to virtual base of"};
 }
 
 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
-                                   Location FallbackLoc) {
+                                   Location FallbackLoc, ReportOptions Opts) {
   Location Loc = Data->Loc.acquire();
-
   // Use the SourceLocation from Data to track deduplication, even if 'invalid'
-  if (Loc.getSourceLocation().isDisabled())
+  if (ignoreReport(Loc.getSourceLocation(), Opts))
     return;
+
   if (Data->Loc.isInvalid())
     Loc = FallbackLoc;
 
+  ScopedReport R(Opts, Loc);
+
   if (!Pointer)
     Diag(Loc, DL_Error, "%0 null pointer of type %1")
       << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
@@ -51,70 +63,59 @@
   if (Pointer)
     Diag(Pointer, DL_Note, "pointer points here");
 }
+
 void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
                                            ValueHandle Pointer) {
-  handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
+  GET_REPORT_OPTIONS(false);
+  handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
 }
 void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
                                                  ValueHandle Pointer) {
-  handleTypeMismatchImpl(Data, Pointer, getCallerLocation());
+  GET_REPORT_OPTIONS(true);
+  handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
   Die();
 }
 
 /// \brief Common diagnostic emission for various forms of integer overflow.
-template<typename T> static void HandleIntegerOverflow(OverflowData *Data,
-                                                       ValueHandle LHS,
-                                                       const char *Operator,
-                                                       T RHS) {
+template <typename T>
+static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
+                                      const char *Operator, T RHS,
+                                      ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Diag(Loc, DL_Error, "%0 integer overflow: "
                       "%1 %2 %3 cannot be represented in type %4")
     << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned")
     << Value(Data->Type, LHS) << Operator << RHS << Data->Type;
 }
 
-void __ubsan::__ubsan_handle_add_overflow(OverflowData *Data,
-                                          ValueHandle LHS, ValueHandle RHS) {
-  HandleIntegerOverflow(Data, LHS, "+", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_add_overflow_abort(OverflowData *Data,
-                                                 ValueHandle LHS,
-                                                 ValueHandle RHS) {
-  __ubsan_handle_add_overflow(Data, LHS, RHS);
-  Die();
-}
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort)                        \
+  void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS,              \
+                             ValueHandle RHS) {                                \
+    GET_REPORT_OPTIONS(abort);                                                 \
+    handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts);    \
+    if (abort) Die();                                                          \
+  }
 
-void __ubsan::__ubsan_handle_sub_overflow(OverflowData *Data,
-                                          ValueHandle LHS, ValueHandle RHS) {
-  HandleIntegerOverflow(Data, LHS, "-", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_sub_overflow_abort(OverflowData *Data,
-                                                 ValueHandle LHS,
-                                                 ValueHandle RHS) {
-  __ubsan_handle_sub_overflow(Data, LHS, RHS);
-  Die();
-}
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
 
-void __ubsan::__ubsan_handle_mul_overflow(OverflowData *Data,
-                                          ValueHandle LHS, ValueHandle RHS) {
-  HandleIntegerOverflow(Data, LHS, "*", Value(Data->Type, RHS));
-}
-void __ubsan::__ubsan_handle_mul_overflow_abort(OverflowData *Data,
-                                                 ValueHandle LHS,
-                                                 ValueHandle RHS) {
-  __ubsan_handle_mul_overflow(Data, LHS, RHS);
-  Die();
-}
-
-void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
-                                             ValueHandle OldVal) {
+static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
+                                     ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   if (Data->Type.isSignedIntegerTy())
     Diag(Loc, DL_Error,
          "negation of %0 cannot be represented in type %1; "
@@ -125,18 +126,27 @@
          "negation of %0 cannot be represented in type %1")
       << Value(Data->Type, OldVal) << Data->Type;
 }
+
+void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
+                                             ValueHandle OldVal) {
+  GET_REPORT_OPTIONS(false);
+  handleNegateOverflowImpl(Data, OldVal, Opts);
+}
 void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
                                                     ValueHandle OldVal) {
-  __ubsan_handle_negate_overflow(Data, OldVal);
+  GET_REPORT_OPTIONS(true);
+  handleNegateOverflowImpl(Data, OldVal, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
-                                             ValueHandle LHS, ValueHandle RHS) {
+static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
+                                     ValueHandle RHS, ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Value LHSVal(Data->Type, LHS);
   Value RHSVal(Data->Type, RHS);
   if (RHSVal.isMinusOne())
@@ -146,20 +156,29 @@
   else
     Diag(Loc, DL_Error, "division by zero");
 }
+
+void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
+                                             ValueHandle LHS, ValueHandle RHS) {
+  GET_REPORT_OPTIONS(false);
+  handleDivremOverflowImpl(Data, LHS, RHS, Opts);
+}
 void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
                                                     ValueHandle LHS,
                                                     ValueHandle RHS) {
-  __ubsan_handle_divrem_overflow(Data, LHS, RHS);
+  GET_REPORT_OPTIONS(true);
+  handleDivremOverflowImpl(Data, LHS, RHS, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
-                                                 ValueHandle LHS,
-                                                 ValueHandle RHS) {
+static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
+                                       ValueHandle LHS, ValueHandle RHS,
+                                       ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Value LHSVal(Data->LHSType, LHS);
   Value RHSVal(Data->RHSType, RHS);
   if (RHSVal.isNegative())
@@ -175,107 +194,219 @@
          "left shift of %0 by %1 places cannot be represented in type %2")
       << LHSVal << RHSVal << Data->LHSType;
 }
+
+void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
+                                                 ValueHandle LHS,
+                                                 ValueHandle RHS) {
+  GET_REPORT_OPTIONS(false);
+  handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
+}
 void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
                                                      ShiftOutOfBoundsData *Data,
                                                      ValueHandle LHS,
                                                      ValueHandle RHS) {
-  __ubsan_handle_shift_out_of_bounds(Data, LHS, RHS);
+  GET_REPORT_OPTIONS(true);
+  handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
-                                           ValueHandle Index) {
+static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
+                                  ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Value IndexVal(Data->IndexType, Index);
   Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
     << IndexVal << Data->ArrayType;
 }
+
+void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
+                                           ValueHandle Index) {
+  GET_REPORT_OPTIONS(false);
+  handleOutOfBoundsImpl(Data, Index, Opts);
+}
 void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
                                                  ValueHandle Index) {
-  __ubsan_handle_out_of_bounds(Data, Index);
+  GET_REPORT_OPTIONS(true);
+  handleOutOfBoundsImpl(Data, Index, Opts);
   Die();
 }
 
+static void handleBuiltinUnreachableImpl(UnreachableData *Data,
+                                         ReportOptions Opts) {
+  ScopedReport R(Opts, Data->Loc);
+  Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
+}
+
 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
-  Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
+  GET_REPORT_OPTIONS(true);
+  handleBuiltinUnreachableImpl(Data, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
+static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
+  ScopedReport R(Opts, Data->Loc);
   Diag(Data->Loc, DL_Error,
        "execution reached the end of a value-returning function "
        "without returning a value");
+}
+
+void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleMissingReturnImpl(Data, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
-                                                    ValueHandle Bound) {
+static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
+                                      ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Diag(Loc, DL_Error, "variable length array bound evaluates to "
                       "non-positive value %0")
     << Value(Data->Type, Bound);
 }
+
+void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
+                                                    ValueHandle Bound) {
+  GET_REPORT_OPTIONS(false);
+  handleVLABoundNotPositive(Data, Bound, Opts);
+}
 void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
-                                                           ValueHandle Bound) {
-  __ubsan_handle_vla_bound_not_positive(Data, Bound);
+                                                          ValueHandle Bound) {
+  GET_REPORT_OPTIONS(true);
+  handleVLABoundNotPositive(Data, Bound, Opts);
   Die();
 }
 
+static void handleFloatCastOverflow(FloatCastOverflowData *Data,
+                                    ValueHandle From, ReportOptions Opts) {
+  // TODO: Add deduplication once a SourceLocation is generated for this check.
+  Location Loc = getCallerLocation();
+  ScopedReport R(Opts, Loc);
+
+  Diag(Loc, DL_Error,
+       "value %0 is outside the range of representable values of type %2")
+      << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+}
 
 void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
                                                  ValueHandle From) {
-  // TODO: Add deduplication once a SourceLocation is generated for this check.
-  Diag(getCallerLocation(), DL_Error,
-       "value %0 is outside the range of representable values of type %2")
-    << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+  GET_REPORT_OPTIONS(false);
+  handleFloatCastOverflow(Data, From, Opts);
 }
-void __ubsan::__ubsan_handle_float_cast_overflow_abort(
-                                                    FloatCastOverflowData *Data,
-                                                    ValueHandle From) {
-  Diag(getCallerLocation(), DL_Error,
-       "value %0 is outside the range of representable values of type %2")
-    << Value(Data->FromType, From) << Data->FromType << Data->ToType;
+void
+__ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
+                                                  ValueHandle From) {
+  GET_REPORT_OPTIONS(true);
+  handleFloatCastOverflow(Data, From, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
-                                                ValueHandle Val) {
+static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
+                                   ReportOptions Opts) {
   SourceLocation Loc = Data->Loc.acquire();
-  if (Loc.isDisabled())
+  if (ignoreReport(Loc, Opts))
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Diag(Loc, DL_Error,
        "load of value %0, which is not a valid value for type %1")
     << Value(Data->Type, Val) << Data->Type;
 }
+
+void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
+                                                ValueHandle Val) {
+  GET_REPORT_OPTIONS(false);
+  handleLoadInvalidValue(Data, Val, Opts);
+}
 void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
                                                       ValueHandle Val) {
-  __ubsan_handle_load_invalid_value(Data, Val);
+  GET_REPORT_OPTIONS(true);
+  handleLoadInvalidValue(Data, Val, Opts);
   Die();
 }
 
-void __ubsan::__ubsan_handle_function_type_mismatch(
-    FunctionTypeMismatchData *Data,
-    ValueHandle Function) {
+static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
+                                       ValueHandle Function,
+                                       ReportOptions Opts) {
   const char *FName = "(unknown)";
 
   Location Loc = getFunctionLocation(Function, &FName);
 
+  ScopedReport R(Opts, Loc);
+
   Diag(Data->Loc, DL_Error,
        "call to function %0 through pointer to incorrect function type %1")
     << FName << Data->Type;
   Diag(Loc, DL_Note, "%0 defined here") << FName;
 }
 
+void
+__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
+                                               ValueHandle Function) {
+  GET_REPORT_OPTIONS(false);
+  handleFunctionTypeMismatch(Data, Function, Opts);
+}
+
 void __ubsan::__ubsan_handle_function_type_mismatch_abort(
-    FunctionTypeMismatchData *Data,
-    ValueHandle Function) {
-  __ubsan_handle_function_type_mismatch(Data, Function);
+    FunctionTypeMismatchData *Data, ValueHandle Function) {
+  GET_REPORT_OPTIONS(true);
+  handleFunctionTypeMismatch(Data, Function, Opts);
+  Die();
+}
+
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+  SourceLocation Loc = Data->Loc.acquire();
+  if (ignoreReport(Loc, Opts))
+    return;
+
+  ScopedReport R(Opts, Loc);
+
+  Diag(Loc, DL_Error, "null pointer returned from function declared to never "
+                      "return null");
+  if (!Data->AttrLoc.isInvalid())
+    Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
+  GET_REPORT_OPTIONS(false);
+  handleNonNullReturn(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleNonNullReturn(Data, Opts);
+  Die();
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+  SourceLocation Loc = Data->Loc.acquire();
+  if (ignoreReport(Loc, Opts))
+    return;
+
+  ScopedReport R(Opts, Loc);
+
+  Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
+       "never be null") << Data->ArgIndex;
+  if (!Data->AttrLoc.isInvalid())
+    Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(false);
+  handleNonNullArg(Data, Opts);
+}
+
+void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleNonNullArg(Data, Opts);
   Die();
 }
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 14e6f04..87149f2 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -24,10 +24,14 @@
   unsigned char TypeCheckKind;
 };
 
+#define UNRECOVERABLE(checkname, ...) \
+  extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
+    void __ubsan_handle_ ## checkname( __VA_ARGS__ );
+
 #define RECOVERABLE(checkname, ...) \
   extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
     void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
-  extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
+  extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
     void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
 
 /// \brief Handle a runtime type check failure, caused by either a misaligned
@@ -81,11 +85,9 @@
 };
 
 /// \brief Handle a __builtin_unreachable which is reached.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __ubsan_handle_builtin_unreachable(UnreachableData *Data);
+UNRECOVERABLE(builtin_unreachable, UnreachableData *Data)
 /// \brief Handle reaching the end of a value-returning function.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-void __ubsan_handle_missing_return(UnreachableData *Data);
+UNRECOVERABLE(missing_return, UnreachableData *Data)
 
 struct VLABoundData {
   SourceLocation Loc;
@@ -121,6 +123,23 @@
             FunctionTypeMismatchData *Data,
             ValueHandle Val)
 
+struct NonNullReturnData {
+  SourceLocation Loc;
+  SourceLocation AttrLoc;
+};
+
+/// \brief Handle returning null from function with returns_nonnull attribute.
+RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+
+struct NonNullArgData {
+  SourceLocation Loc;
+  SourceLocation AttrLoc;
+  int ArgIndex;
+};
+
+/// \brief Handle passing null pointer to function with nonnull attribute.
+RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+
 }
 
 #endif // UBSAN_HANDLERS_H
diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc
index b6cddef..5704c1e 100644
--- a/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/lib/ubsan/ubsan_handlers_cxx.cc
@@ -18,6 +18,7 @@
 #include "ubsan_type_hash.h"
 
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
 
 using namespace __sanitizer;
 using namespace __ubsan;
@@ -28,47 +29,54 @@
 
 static void HandleDynamicTypeCacheMiss(
     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
-    bool Abort) {
+    ReportOptions Opts) {
   if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
     // Just a cache miss. The type matches after all.
     return;
 
+  // Check if error report should be suppressed.
+  DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
+  if (DTI.isValid() &&
+      MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck))
+    return;
+
   SourceLocation Loc = Data->Loc.acquire();
   if (Loc.isDisabled())
     return;
 
+  ScopedReport R(Opts, Loc);
+
   Diag(Loc, DL_Error,
        "%0 address %1 which does not point to an object of type %2")
     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
 
   // If possible, say what type it actually points to.
-  DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer);
   if (!DTI.isValid())
     Diag(Pointer, DL_Note, "object has invalid vptr")
-      << MangledName(DTI.getMostDerivedTypeName())
-      << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+        << MangledName(DTI.getMostDerivedTypeName())
+        << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
   else if (!DTI.getOffset())
     Diag(Pointer, DL_Note, "object is of type %0")
-      << MangledName(DTI.getMostDerivedTypeName())
-      << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
+        << MangledName(DTI.getMostDerivedTypeName())
+        << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
   else
     // FIXME: Find the type at the specified offset, and include that
     //        in the note.
     Diag(Pointer - DTI.getOffset(), DL_Note,
          "object is base class subobject at offset %0 within object of type %1")
-      << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
-      << MangledName(DTI.getSubobjectTypeName())
-      << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");
-
-  if (Abort)
-    Die();
+        << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName())
+        << MangledName(DTI.getSubobjectTypeName())
+        << Range(Pointer, Pointer + sizeof(uptr),
+                 "vptr for %2 base class of %1");
 }
 
 void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
-  HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false);
+  GET_REPORT_OPTIONS(false);
+  HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
 }
 void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
-  HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true);
+  GET_REPORT_OPTIONS(true);
+  HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
 }
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
new file mode 100644
index 0000000..6080e30
--- /dev/null
+++ b/lib/ubsan/ubsan_init.cc
@@ -0,0 +1,61 @@
+//===-- ubsan_init.cc -----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization of UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_suppressions.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+using namespace __ubsan;
+
+static bool ubsan_inited;
+
+void __ubsan::InitIfNecessary() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+  // No need to lock mutex if we're initializing from preinit array.
+  static StaticSpinMutex init_mu;
+  SpinMutexLock l(&init_mu);
+#endif
+  if (LIKELY(ubsan_inited))
+   return;
+  if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
+    // WARNING: If this condition holds, then either UBSan runs in a standalone
+    // mode, or initializer for another sanitizer hasn't run yet. In a latter
+    // case, another sanitizer will overwrite "SanitizerToolName" and reparse
+    // common flags. It means, that we are not allowed to *use* common flags
+    // in this function.
+    SanitizerToolName = "UndefinedBehaviorSanitizer";
+    InitializeCommonFlags();
+  }
+  // Initialize UBSan-specific flags.
+  InitializeFlags();
+  SuppressionContext::InitIfNecessary();
+  ubsan_inited = true;
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
+#else
+// Use a dynamic initializer.
+class UbsanInitializer {
+ public:
+  UbsanInitializer() {
+    InitIfNecessary();
+  }
+};
+static UbsanInitializer ubsan_initializer;
+#endif  // SANITIZER_CAN_USE_PREINIT_ARRAY
diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h
new file mode 100644
index 0000000..18356cf
--- /dev/null
+++ b/lib/ubsan/ubsan_init.h
@@ -0,0 +1,24 @@
+//===-- ubsan_init.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization function for UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_INIT_H
+#define UBSAN_INIT_H
+
+namespace __ubsan {
+
+// NOTE: This function might take a lock (if .preinit_array initialization is
+// not used). It's generally a bad idea to call it on a fast path.
+void InitIfNecessary();
+
+}  // namespace __ubsan
+
+#endif  // UBSAN_INIT_H
diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc
index a388bcc..808a433 100644
--- a/lib/ubsan/ubsan_type_hash.cc
+++ b/lib/ubsan/ubsan_type_hash.cc
@@ -115,7 +115,8 @@
 
 /// \brief Determine whether \p Derived has a \p Base base class subobject at
 /// offset \p Offset.
-static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
+static bool isDerivedFromAtOffset(sptr Object,
+                                  const abi::__class_type_info *Derived,
                                   const abi::__class_type_info *Base,
                                   sptr Offset) {
   if (Derived->__type_name == Base->__type_name)
@@ -123,7 +124,7 @@
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
+    return isDerivedFromAtOffset(Object, SI->__base_type, Base, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -138,13 +139,13 @@
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // For now, just punt on virtual bases and say 'yes'.
-      // FIXME: OffsetHere is the offset in the vtable of the virtual base
-      //        offset. Read the vbase offset out of the vtable and use it.
-      return true;
-    if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
-                              Base, Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (isDerivedFromAtOffset(Object + OffsetHere,
+                              VTI->base_info[base].__base_type, Base,
+                              Offset - OffsetHere))
       return true;
   }
 
@@ -153,14 +154,15 @@
 
 /// \brief Find the derived-most dynamic base class of \p Derived at offset
 /// \p Offset.
-static const abi::__class_type_info *findBaseAtOffset(
-    const abi::__class_type_info *Derived, sptr Offset) {
+static const abi::__class_type_info *
+findBaseAtOffset(sptr Object, const abi::__class_type_info *Derived,
+                 sptr Offset) {
   if (!Offset)
     return Derived;
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return findBaseAtOffset(SI->__base_type, Offset);
+    return findBaseAtOffset(Object, SI->__base_type, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -172,12 +174,13 @@
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // FIXME: Can't handle virtual bases yet.
-      continue;
-    if (const abi::__class_type_info *Base =
-          findBaseAtOffset(VTI->base_info[base].__base_type,
-                           Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (const abi::__class_type_info *Base = findBaseAtOffset(
+            Object + OffsetHere, VTI->base_info[base].__base_type,
+            Offset - OffsetHere))
       return Base;
   }
 
@@ -229,7 +232,8 @@
     return false;
 
   abi::__class_type_info *Base = (abi::__class_type_info*)Type;
-  if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
+  if (!isDerivedFromAtOffset(reinterpret_cast<sptr>(Object), Derived, Base,
+                             -Vtable->Offset))
     return false;
 
   // Success. Cache this result.
@@ -243,8 +247,9 @@
   if (!Vtable)
     return DynamicTypeInfo(0, 0, 0);
   const abi::__class_type_info *ObjectType = findBaseAtOffset(
-    static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
-    -Vtable->Offset);
+      reinterpret_cast<sptr>(Object),
+      static_cast<const abi::__class_type_info *>(Vtable->TypeInfo),
+      -Vtable->Offset);
   return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
                          ObjectType ? ObjectType->__type_name : "<unknown>");
 }
diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk
index d920fa8..6ed3230 100644
--- a/make/platform/clang_darwin.mk
+++ b/make/platform/clang_darwin.mk
@@ -6,31 +6,37 @@
 
 Description := Static runtime libraries for clang/Darwin.
 
-# A function that ensures we don't try to build for architectures that we
-# don't have working toolchains for.
+# A function that ensures we don't try to build for architectures and SDKs
+# that we don't have working toolchains for. Arguments:
+# (1): List of architectures
+# (2): Library name
+# (3): SDK path
+# The result is a possibly empty subset of the architectures from argument 1.
 CheckArches = \
   $(shell \
     result=""; \
-    for arch in $(1); do \
-      if $(CC) -arch $$arch -c \
-          -integrated-as \
-          $(ProjSrcRoot)/make/platform/clang_darwin_test_input.c \
-          -isysroot $(ProjSrcRoot)/SDKs/darwin \
-          -o /dev/null > /dev/null 2> /dev/null; then \
-        if $(LD) -v 2>&1 | grep "configured to support" \
-           | tr ' ' '\n' | grep "^$$arch$$" >/dev/null 2>/dev/null; then \
-          result="$$result$$arch "; \
+    if [ "X$(3)" != X ]; then \
+      for arch in $(1); do \
+        if $(CC) -arch $$arch -c \
+            -integrated-as \
+            $(ProjSrcRoot)/make/platform/clang_darwin_test_input.c \
+            -isysroot $(3) \
+            -o /dev/null > /dev/null 2> /dev/null; then \
+          if $(LD) -v 2>&1 | grep "configured to support" \
+             | tr ' ' '\n' | grep "^$$arch$$" >/dev/null 2>/dev/null; then \
+            result="$$result$$arch "; \
+          else \
+            printf 1>&2 \
+            "warning: clang_darwin.mk: dropping arch '$$arch' from lib '$(2)'";\
+            printf 1>&2 " (ld does not support it)\n"; \
+          fi; \
         else \
           printf 1>&2 \
-            "warning: clang_darwin.mk: dropping arch '$$arch' from lib '$(2)'"; \
-          printf 1>&2 " (ld does not support it)\n"; \
+           "warning: clang_darwin.mk: dropping arch '$$arch' from lib '$(2)'"; \
+          printf 1>&2 " (clang does not support it)\n"; \
         fi; \
-      else \
-        printf 1>&2 \
-          "warning: clang_darwin.mk: dropping arch '$$arch' from lib '$(2)'"; \
-        printf 1>&2 " (clang does not support it)\n"; \
-      fi; \
-    done; \
+      done; \
+    fi; \
     echo $$result)
 
 XCRun = \
@@ -53,6 +59,10 @@
 LIPO     := $(call XCRun,lipo)
 DSYMUTIL := $(call XCRun,dsymutil)
 
+OSX_SDK := $(call XCRunSdkPath,macosx)
+IOS_SDK := $(call XCRunSdkPath,iphoneos)
+IOSSIM_SDK := $(call XCRunSdkPath,iphonesimulator)
+
 Configs :=
 UniversalArchs :=
 
@@ -60,51 +70,53 @@
 # still be referenced from Darwin system headers. This symbol is only ever
 # needed on i386.
 Configs += eprintf
-UniversalArchs.eprintf := $(call CheckArches,i386,eprintf)
+UniversalArchs.eprintf := $(call CheckArches,i386,eprintf,$(OSX_SDK))
 
 # Configuration for targeting 10.4. We need a few functions missing from
 # libgcc_s.10.4.dylib. We only build x86 slices since clang doesn't really
 # support targeting PowerPC.
 Configs += 10.4
-UniversalArchs.10.4 := $(call CheckArches,i386 x86_64,10.4)
+UniversalArchs.10.4 := $(call CheckArches,i386 x86_64,10.4,$(OSX_SDK))
 
 # Configuration for targeting iOS for a couple of functions that didn't
 # make it into libSystem.
 Configs += ios
-UniversalArchs.ios := $(call CheckArches,i386 x86_64 x86_64h armv7,ios)
+UniversalArchs.ios := $(call CheckArches,i386 x86_64,ios,$(IOSSIM_SDK))
+UniversalArchs.ios += $(call CheckArches,armv7 arm64,ios,$(IOS_SDK))
 
 # Configuration for targeting OSX. These functions may not be in libSystem
 # so we should provide our own.
 Configs += osx
-UniversalArchs.osx := $(call CheckArches,i386 x86_64 x86_64h,osx)
+UniversalArchs.osx := $(call CheckArches,i386 x86_64 x86_64h,osx,$(OSX_SDK))
 
 # Configuration for use with kernel/kexts.
 Configs += cc_kext
-UniversalArchs.cc_kext := $(call CheckArches,armv7 i386 x86_64 x86_64h,cc_kext)
+UniversalArchs.cc_kext := $(call CheckArches,i386 x86_64 x86_64h,cc_kext,$(OSX_SDK))
+UniversalArchs.cc_kext += $(call CheckArches,armv7 arm64,cc_kext,$(IOS_SDK))
 
 # Configuration for use with kernel/kexts for iOS 5.0 and earlier (which used 
-# a different code generation strategy).
+# a different code generation strategy). Note: the x86_64 slice is unused but
+# it avoids build problems (see pr14013).
 Configs += cc_kext_ios5
-UniversalArchs.cc_kext_ios5 := $(call CheckArches,x86_64 x86_64h armv7,cc_kext_ios5)
+UniversalArchs.cc_kext_ios5 := $(call CheckArches,x86_64,cc_kext_ios5,$(IOSSIM_SDK))
+UniversalArchs.cc_kext_ios5 += $(call CheckArches,armv7,cc_kext_ios5,$(IOS_SDK))
 
 # Configurations which define the profiling support functions.
 Configs += profile_osx
-UniversalArchs.profile_osx := $(call CheckArches,i386 x86_64 x86_64h,profile_osx)
+UniversalArchs.profile_osx := $(call CheckArches,i386 x86_64 x86_64h,profile_osx,$(OSX_SDK))
 Configs += profile_ios
-UniversalArchs.profile_ios := $(call CheckArches,i386 x86_64 x86_64h armv7,profile_ios)
+UniversalArchs.profile_ios := $(call CheckArches,i386 x86_64,profile_ios,$(IOSSIM_SDK))
+UniversalArchs.profile_ios += $(call CheckArches,armv7 arm64,profile_ios,$(IOS_SDK))
 
 # Configurations which define the ASAN support functions.
 Configs += asan_osx_dynamic
-UniversalArchs.asan_osx_dynamic := $(call CheckArches,i386 x86_64 x86_64h,asan_osx_dynamic)
+UniversalArchs.asan_osx_dynamic := $(call CheckArches,i386 x86_64 x86_64h,asan_osx_dynamic,$(OSX_SDK))
 
-IOSSIM_SDK_PATH := $(call XCRunSdkPath,iphonesimulator)
-ifneq ($(IOSSIM_SDK_PATH),)
 Configs += asan_iossim_dynamic
-UniversalArchs.asan_iossim_dynamic := $(call CheckArches,i386 x86_64 x86_64h,asan_iossim_dynamic)
-endif
+UniversalArchs.asan_iossim_dynamic := $(call CheckArches,i386 x86_64,asan_iossim_dynamic,$(IOSSIM_SDK))
 
 Configs += ubsan_osx
-UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx)
+UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx,$(OSX_SDK))
 
 # Darwin 10.6 has a bug in cctools that makes it unable to use ranlib on our ARM
 # object files. If we are on that platform, strip out all ARM archs. We still
@@ -117,26 +129,20 @@
 UniversalArchs.profile_ios := $(filter-out armv7, $(UniversalArchs.profile_ios))
 endif
 
-### ARM64 Support ###
-# Explicitly add these, to workaround CheckArches function not including the
-# CFLAGS, and not wanting to require an ARM64 assembler be installed.
-UniversalArchs.ios += arm64
-UniversalArchs.cc_kext += arm64
-UniversalArchs.profile_ios += arm64
-
 # If RC_SUPPORTED_ARCHS is defined, treat it as a list of the architectures we
 # are intended to support and limit what we try to build to that.
-#
-# We make sure to remove empty configs if we end up dropping all the requested
-# archs for a particular config.
 ifneq ($(RC_SUPPORTED_ARCHS),)
 $(foreach config,$(Configs),\
   $(call Set,UniversalArchs.$(config),\
-	$(filter $(RC_SUPPORTED_ARCHS),$(UniversalArchs.$(config))))\
-  $(if $(UniversalArchs.$(config)),,\
-	$(call Set,Configs,$(filter-out $(config),$(Configs)))))
+	$(filter $(RC_SUPPORTED_ARCHS),$(UniversalArchs.$(config)))))
 endif
 
+# Remove empty configs if we end up dropping all the requested
+# archs for a particular config.
+$(foreach config,$(Configs),\
+  $(if $(strip $(UniversalArchs.$(config))),,\
+	$(call Set,Configs,$(filter-out $(config),$(Configs)))))
+
 ###
 
 # Forcibly strip off any -arch, as that totally breaks our universal support.
@@ -154,32 +160,34 @@
 IOS6_DEPLOYMENT_ARGS := -mios-version-min=6.0
 IOSSIM_DEPLOYMENT_ARGS := -mios-simulator-version-min=1.0
 
-# Use our stub SDK as the sysroot to support more portable building.
-OSX_DEPLOYMENT_ARGS += -isysroot $(ProjSrcRoot)/SDKs/darwin
-IOS_DEPLOYMENT_ARGS += -isysroot $(ProjSrcRoot)/SDKs/darwin
-IOS6_DEPLOYMENT_ARGS += -isysroot $(ProjSrcRoot)/SDKs/darwin
-IOSSIM_DEPLOYMENT_ARGS += -isysroot $(ProjSrcRoot)/SDKs/darwin
+OSX_DEPLOYMENT_ARGS += -isysroot $(OSX_SDK)
+IOS_DEPLOYMENT_ARGS += -isysroot $(IOS_SDK)
+IOS6_DEPLOYMENT_ARGS += -isysroot $(IOS_SDK)
+IOSSIM_DEPLOYMENT_ARGS += -isysroot $(IOSSIM_SDK)
 
 CFLAGS.eprintf		:= $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
 CFLAGS.10.4		:= $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
-# FIXME: We can't build ASAN with our stub SDK yet.
+
 CFLAGS.asan_osx_dynamic := \
-	$(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin \
+	$(CFLAGS) -mmacosx-version-min=10.7 \
+	-isysroot $(OSX_SDK) \
+	-fno-builtin \
 	-gline-tables-only \
 	-DMAC_INTERPOSE_FUNCTIONS=1
 
 CFLAGS.asan_iossim_dynamic := \
 	$(CFLAGS) -mios-simulator-version-min=7.0 \
-        -isysroot $(IOSSIM_SDK_PATH) \
+        -isysroot $(IOSSIM_SDK) \
         -fno-builtin \
 	-gline-tables-only \
 	-DMAC_INTERPOSE_FUNCTIONS=1
 
-CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin
+CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 \
+	-isysroot $(OSX_SDK) \
+	-fno-builtin
 
 CFLAGS.ios.i386		:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.ios.x86_64	:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
-CFLAGS.ios.x86_64h	:= $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.ios.armv7	:= $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
 CFLAGS.ios.armv7k	:= $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
 CFLAGS.ios.armv7s	:= $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
@@ -202,7 +210,6 @@
 CFLAGS.profile_osx.x86_64h := $(CFLAGS) $(OSX_DEPLOYMENT_ARGS)
 CFLAGS.profile_ios.i386    := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.profile_ios.x86_64  := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
-CFLAGS.profile_ios.x86_64h := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
 CFLAGS.profile_ios.armv7  := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
 CFLAGS.profile_ios.armv7k := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
 CFLAGS.profile_ios.armv7s := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS)
@@ -210,15 +217,15 @@
 
 # Configure the asan_osx_dynamic library to be built shared.
 SHARED_LIBRARY.asan_osx_dynamic := 1
-LDFLAGS.asan_osx_dynamic := -lstdc++ -undefined dynamic_lookup
+LDFLAGS.asan_osx_dynamic := -lstdc++ -undefined dynamic_lookup -install_name @rpath/libclang_rt.asan_osx_dynamic.dylib
 
 # Configure the asan_iossim_dynamic library to be built shared.
 SHARED_LIBRARY.asan_iossim_dynamic := 1
 # configure+make uses Clang, so we're using isysroot instead of --sysroot
 # or -Wl,-syslibroot.
-LDFLAGS.asan_iossim_dynamic := -undefined dynamic_lookup \
+LDFLAGS.asan_iossim_dynamic := -undefined dynamic_lookup -install_name @rpath/libclang_rt.asan_iossim_dynamic.dylib \
   -Wl,-ios_simulator_version_min,7.0.0 \
-  -mios-simulator-version-min=7.0 -isysroot $(IOSSIM_SDK_PATH)
+  -mios-simulator-version-min=7.0 -isysroot $(IOSSIM_SDK)
 
 FUNCTIONS.eprintf := eprintf
 FUNCTIONS.10.4 := eprintf floatundidf floatundisf floatundixf
@@ -228,8 +235,7 @@
 FUNCTIONS.ios.i386    := $(FUNCTIONS.ios) \
                          divsi3 udivsi3
 FUNCTIONS.ios.x86_64  := $(FUNCTIONS.ios.i386)
-FUNCTIONS.ios.x86_64h := $(FUNCTIONS.ios.x86_64)
-FUNCTIONS.ios.arm64   := dummy
+FUNCTIONS.ios.arm64   := mulsc3 muldc3 divsc3 divdc3
 
 FUNCTIONS.osx	:= mulosi4 mulodi4 muloti4
 
@@ -399,7 +405,7 @@
 FUNCTIONS.cc_kext.armv7 := $(CCKEXT_ARMVFP_FUNCTIONS)
 FUNCTIONS.cc_kext.armv7k := $(CCKEXT_ARMVFP_FUNCTIONS)
 FUNCTIONS.cc_kext.armv7s := $(CCKEXT_ARMVFP_FUNCTIONS)
-FUNCTIONS.cc_kext.arm64 := dummy
+FUNCTIONS.cc_kext.arm64 := mulsc3 muldc3 divsc3 divdc3
 FUNCTIONS.cc_kext_ios5.armv7 := $(CCKEXT_ARMVFP_FUNCTIONS)
 FUNCTIONS.cc_kext_ios5.armv7k := $(CCKEXT_ARMVFP_FUNCTIONS)
 FUNCTIONS.cc_kext_ios5.armv7s := $(CCKEXT_ARMVFP_FUNCTIONS)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8477216..007ac3f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -14,7 +14,7 @@
     # Use LLVM utils and Clang from the same build tree.
     list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS
       clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
-      compiler-rt-headers)
+      compiler-rt-headers profile)
   endif()
   if(UNIX)
     list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS SanitizerLintCheck)
@@ -24,28 +24,28 @@
 # Run sanitizer tests only if we're sure that clang would produce
 # working binaries.
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
-  if(ASAN_SUPPORTED_ARCH OR ANDROID)
+  if(COMPILER_RT_HAS_ASAN)
     add_subdirectory(asan)
   endif()
-  if(DFSAN_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_DFSAN)
     add_subdirectory(dfsan)
   endif()
-  if(LSAN_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_LSAN)
     add_subdirectory(lsan)
   endif()
-  if(MSAN_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_MSAN)
     add_subdirectory(msan)
   endif()
-  if(PROFILE_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_PROFILE)
     add_subdirectory(profile)
   endif()
-  if(SANITIZER_COMMON_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_SANITIZER_COMMON)
     add_subdirectory(sanitizer_common)
   endif()
-  if(TSAN_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_TSAN)
     add_subdirectory(tsan)
   endif()
-  if(UBSAN_SUPPORTED_ARCH)
+  if(COMPILER_RT_HAS_UBSAN)
     add_subdirectory(ubsan)
   endif()
 endif()
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt
index cca7ccb..14f7f50 100644
--- a/test/asan/CMakeLists.txt
+++ b/test/asan/CMakeLists.txt
@@ -2,113 +2,133 @@
 
 set(ASAN_TESTSUITES)
 
-if(CAN_TARGET_arm_android)
-  # This is only true if we are cross-compiling.
-  # Build all tests with host compiler and use host tools.
-  set(ASAN_TEST_TARGET_CC ${CMAKE_C_COMPILER})
-  set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
-  get_filename_component(ASAN_TEST_LLVM_TOOLS_DIR ${CMAKE_C_COMPILER} PATH)
-  set(ASAN_TEST_CONFIG_SUFFIX "-arm-android")
-  set(ASAN_TEST_BITS "32")
-  set(ASAN_TEST_DYNAMIC True)
-  set(ASAN_TEST_TARGET_ARCH "arm-android")
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/ARMAndroidConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/ARMAndroidConfig)
-endif()
+macro(get_bits_for_arch arch bits)
+  if (${arch} STREQUAL "arm" OR
+      ${arch} STREQUAL "i386" OR
+      ${arch} STREQUAL "i686" OR
+      ${arch} STREQUAL "mips")
+    set(bits 32)
+  elseif (${arch} STREQUAL "aarch64" OR
+      ${arch} STREQUAL "x86_64" OR
+      ${arch} STREQUAL "mips64")
+    set(bits 64)
+  else()
+    message(FATAL_ERROR "Unknown target architecture: ${arch}")
+  endif()
+endmacro()
 
-if(CAN_TARGET_arm)
-  # This is only true if we are cross-compiling.
-  # Build all tests with host compiler and use host tools.
-  set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
-  set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
-  set(ASAN_TEST_CONFIG_SUFFIX "-arm-linux")
-  set(ASAN_TEST_BITS "32")
-  set(ASAN_TEST_DYNAMIC False)
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig)
-endif()
-
-if(CAN_TARGET_aarch64)
-  # This is only true if we are cross-compiling.
-  # Build all tests with host compiler and use host tools.
-  set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
-  set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
-  set(ASAN_TEST_CONFIG_SUFFIX "-aarch64-linux")
-  set(ASAN_TEST_BITS "64")
-  set(ASAN_TEST_DYNAMIC False)
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig)
-endif()
-
-if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
-  set(ASAN_TEST_CONFIG_SUFFIX "64")
-  set(ASAN_TEST_BITS "64")
-  set(ASAN_TEST_TARGET_CFLAGS ${TARGET_64_BIT_CFLAGS})
-  set(ASAN_TEST_DYNAMIC False)
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
-  if(COMPILER_RT_BUILD_SHARED_ASAN)
-    set(ASAN_TEST_CONFIG_SUFFIX "64-Dynamic")
+# TODO: merge with non-ANDROID case
+if(ANDROID)
+  foreach(arch ${ASAN_SUPPORTED_ARCH})
+    set(ASAN_TEST_TARGET_CC ${CMAKE_CXX_COMPILER})
+    set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+    set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-android")
+    get_bits_for_arch(${arch} ASAN_TEST_BITS)
     set(ASAN_TEST_DYNAMIC True)
+    set(ASAN_TEST_TARGET_ARCH "${arch}-android")
+    string(TOUPPER ${arch} ARCH_UPPER_CASE)
+    set(CONFIG ${ARCH_UPPER_CASE}AndroidConfig)
     configure_lit_site_cfg(
       ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-      ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic/lit.site.cfg)
-    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic)
-  endif()
-endif()
+      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES
+      ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG})
+  endforeach()
 
-if(CAN_TARGET_i386)
-  set(ASAN_TEST_CONFIG_SUFFIX "32")
-  set(ASAN_TEST_BITS "32")
-  set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
-  set(ASAN_TEST_DYNAMIC False)
-  set(ASAN_TEST_TARGET_ARCH "i386")
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
-  if(COMPILER_RT_BUILD_SHARED_ASAN)
-    set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
-    set(ASAN_TEST_DYNAMIC True)
+else()  # Not Android
+
+  if(CAN_TARGET_arm)
+    # This is only true if we are cross-compiling.
+    # Build all tests with host compiler and use host tools.
+    set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+    set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+    set(ASAN_TEST_CONFIG_SUFFIX "-arm-linux")
+    set(ASAN_TEST_BITS "32")
+    set(ASAN_TEST_DYNAMIC False)
     configure_lit_site_cfg(
       ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-      ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
-    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+      ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig)
   endif()
-endif()
 
-if(CAN_TARGET_mips)
-  set(ASAN_TEST_CONFIG_SUFFIX "32")
-  set(ASAN_TEST_BITS "32")
-  set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
-  set(ASAN_TEST_DYNAMIC False)
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
-    )
-  list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
-  if(COMPILER_RT_BUILD_SHARED_ASAN)
-    set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
-    set(ASAN_TEST_DYNAMIC True)
+  if(CAN_TARGET_aarch64)
+    # This is only true if we are cross-compiling.
+    # Build all tests with host compiler and use host tools.
+    set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+    set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+    set(ASAN_TEST_CONFIG_SUFFIX "-aarch64-linux")
+    set(ASAN_TEST_BITS "64")
+    set(ASAN_TEST_DYNAMIC False)
     configure_lit_site_cfg(
       ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-      ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
-    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+      ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig)
   endif()
-endif()
+
+  if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64 OR CAN_TARGET_mips64 OR CAN_TARGET_mips64el)
+    set(ASAN_TEST_CONFIG_SUFFIX "64")
+    set(ASAN_TEST_BITS "64")
+    set(ASAN_TEST_TARGET_CFLAGS ${TARGET_64_BIT_CFLAGS})
+    set(ASAN_TEST_DYNAMIC False)
+    configure_lit_site_cfg(
+      ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+      ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
+    if(COMPILER_RT_BUILD_SHARED_ASAN)
+      set(ASAN_TEST_CONFIG_SUFFIX "64-Dynamic")
+      set(ASAN_TEST_DYNAMIC True)
+      configure_lit_site_cfg(
+        ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+        ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic/lit.site.cfg)
+      list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic)
+    endif()
+  endif()
+
+  if(CAN_TARGET_i386)
+    set(ASAN_TEST_CONFIG_SUFFIX "32")
+    set(ASAN_TEST_BITS "32")
+    set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
+    set(ASAN_TEST_DYNAMIC False)
+    set(ASAN_TEST_TARGET_ARCH "i386")
+    configure_lit_site_cfg(
+      ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+      ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+    if(COMPILER_RT_BUILD_SHARED_ASAN)
+      set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
+      set(ASAN_TEST_DYNAMIC True)
+      configure_lit_site_cfg(
+        ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+        ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
+      list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+    endif()
+  endif()
+
+  if(CAN_TARGET_mips OR CAN_TARGET_mipsel)
+    set(ASAN_TEST_CONFIG_SUFFIX "32")
+    set(ASAN_TEST_BITS "32")
+    set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
+    set(ASAN_TEST_DYNAMIC False)
+    configure_lit_site_cfg(
+      ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+      ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
+      )
+    list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+    if(COMPILER_RT_BUILD_SHARED_ASAN)
+      set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
+      set(ASAN_TEST_DYNAMIC True)
+      configure_lit_site_cfg(
+        ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+        ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
+      list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+    endif()
+  endif()
+endif()  # Not Android
 
 if(COMPILER_RT_INCLUDE_TESTS)
   configure_lit_site_cfg(
@@ -118,13 +138,15 @@
 
 set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
 if(COMPILER_RT_STANDALONE_BUILD)
-  list(APPEND ASAN_TEST_DEPS ${LLVM_TOOLS_BINARY_DIR}/FileCheck)
+  add_executable(FileCheck IMPORTED GLOBAL)
+  set_property(TARGET FileCheck PROPERTY IMPORTED_LOCATION ${LLVM_TOOLS_BINARY_DIR}/FileCheck)
+  list(APPEND ASAN_TEST_DEPS FileCheck)
 else()
   list(APPEND ASAN_TEST_DEPS asan)
 endif()
 
 # FIXME: support unit test in the android test runner
-if(COMPILER_RT_INCLUDE_TESTS AND NOT CAN_TARGET_arm_android)
+if(COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID)
   list(APPEND ASAN_TEST_DEPS AsanUnitTests)
   list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
 endif()
diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc
new file mode 100644
index 0000000..b1bb456
--- /dev/null
+++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc
@@ -0,0 +1,33 @@
+// When DYLD-inserting the ASan dylib from a different location than the
+// original, make sure we don't try to reexec.
+
+// RUN: mkdir -p %T/dyld_insert_libraries_reexec
+// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \
+// RUN:   | grep "libclang_rt.asan_osx_dynamic.dylib" \
+// RUN:   | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \
+// RUN:   %T/dyld_insert_libraries_reexec/libclang_rt.asan_osx_dynamic.dylib
+// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_reexec/a.out
+// RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib \
+// RUN:   ASAN_OPTIONS=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \
+// RUN:   | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-NOINSERT %s
+
+#include <stdio.h>
+
+int main() {
+  printf("Passed\n");
+  return 0;
+}
+
+// CHECK-NOINSERT: Parsed ASAN_OPTIONS: verbosity=1
+// CHECK-NOINSERT: exec()-ing the program with
+// CHECK-NOINSERT: DYLD_INSERT_LIBRARIES
+// CHECK-NOINSERT: to enable ASan wrappers.
+// CHECK-NOINSERT: Passed
+
+// CHECK: Parsed ASAN_OPTIONS: verbosity=1
+// CHECK-NOT: exec()-ing the program with
+// CHECK-NOT: DYLD_INSERT_LIBRARIES
+// CHECK-NOT: to enable ASan wrappers.
+// CHECK: Passed
diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c
index e513954..8680d67 100644
--- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c
+++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c
@@ -5,18 +5,14 @@
 // RUN: %clang_asan -dead_strip -O2 %s -o %t.exe
 // RUN: rm -f %t.symbols %t.interface
 
-// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
-// RUN:                       tr -d '\011' | \
-// RUN:                       sed "s/.dylib.*/.dylib/"` \
+// RUN: nm -g `%clang_asan %s -fsanitize=address -### 2>&1 | grep "libclang_rt.asan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \
 // RUN:   | grep " T " | sed "s/.* T //" \
 // RUN:   | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN:   | grep -v "__asan_malloc_hook" \
-// RUN:   | grep -v "__asan_free_hook" \
+// RUN:   | sed -E "s/__asan_init_v[0-9]+/__asan_init/" \
 // RUN:   | grep -v "__asan_default_options" \
 // RUN:   | grep -v "__asan_on_error" > %t.symbols
 
 // RUN: cat %p/../../../../lib/asan/asan_interface_internal.h \
-// RUN:     %p/../../../../lib/asan/asan_init_version.h \
 // RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
 // RUN:    | grep -v "OPTIONAL" \
 // RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
diff --git a/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
new file mode 100644
index 0000000..5332c99
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
@@ -0,0 +1,33 @@
+// Check that a stack unwinding algorithm works corretly even with the assembly
+// instrumentation.
+
+// REQUIRES: x86_64-supported-target
+// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -g0 -O1 %s -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-nounwind
+
+#include <cstddef>
+
+// CHECK: READ of size 4
+// CHECK-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}}
+// CHECK-NEXT: {{#1 0x[0-9a-fA-F]+ in main}}
+
+// CHECK-nounwind: READ of size 4
+// CHECK-nounwind-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}}
+
+__attribute__((noinline)) int foo(size_t n, int *buffer) {
+  int r;
+  __asm__("movl (%[buffer], %[n], 4), %[r]  \n\t"
+          : [r] "=r"(r)
+          : [buffer] "r"(buffer), [n] "r"(n)
+          : "memory");
+  return r;
+}
+
+int main() {
+  const size_t n = 16;
+  int *buffer = new int[n];
+  foo(n, buffer);
+  delete[] buffer;
+  return 0;
+}
diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc
new file mode 100644
index 0000000..e833881
--- /dev/null
+++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: arm-supported-target
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+
+int boom() {
+  volatile int three = 3;
+  char *s = (char *)malloc(three);
+// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
+  return s[three]; //BOOM
+}
+
+__attribute__((naked, noinline)) void gcc_abi() {
+// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
+  asm volatile("str fp, [sp, #-8]!\n\t"
+               "str lr, [sp, #4]\n\t"
+               "add fp, sp, #4\n\t"
+               "bl  boom\n\t"
+               "sub sp, fp, #4\n\t"
+               "ldr fp, [sp]\n\t"
+               "add sp, sp, #4\n\t"
+               "ldr pc, [sp], #4\n\t"
+              );
+}
+
+__attribute__((naked, noinline)) void clang_abi() {
+// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
+  asm volatile("push {r11, lr}\n\t"
+               "mov r11, sp\n\t"
+               "bl  gcc_abi\n\t"
+               "add r0, r0, #1\n\t"
+               "pop {r11, pc}\n\t"
+              );
+}
+
+int main() {
+  clang_abi();
+// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
+}
diff --git a/test/asan/TestCases/Linux/coverage-and-lsan.cc b/test/asan/TestCases/Linux/coverage-and-lsan.cc
new file mode 100644
index 0000000..f0d371f
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-and-lsan.cc
@@ -0,0 +1,20 @@
+// Make sure coverage is dumped even if there are reported leaks.
+//
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+//
+// RUN: rm -rf %T/coverage-and-lsan
+//
+// RUN: mkdir -p %T/coverage-and-lsan/normal
+// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-and-lsan:verbosity=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %sancov print %T/coverage-and-lsan/*.sancov 2>&1
+//
+// REQUIRES: asan-64-bits
+
+int *g = new int;
+int main(int argc, char **argv) {
+  g = 0;
+  return 0;
+}
+
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: CovDump:
diff --git a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc
new file mode 100644
index 0000000..0201425
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc
@@ -0,0 +1,41 @@
+// Test __sanitizer_get_total_unique_coverage for caller-callee coverage
+
+// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1 %run %t
+// RUN: rm -f caller-callee*.sancov
+//
+// REQUIRES: asan-64-bits
+
+#include <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+#include <assert.h>
+int P = 0;
+struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
+struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+
+Foo *foo[3] = {new Foo, new Foo1, new Foo2};
+
+uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) {
+  uintptr_t new_total = __sanitizer_get_total_unique_coverage();
+  assert(new_total > old_total);
+  return new_total;
+}
+
+int main(int argc, char **argv) {
+  uintptr_t total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(0);
+  foo[0]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+  foo[1]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+  foo[2]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+  // Ok, called every function once.
+  // Now call them again from another call site. Should get new coverage.
+  foo[0]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+  foo[1]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+  foo[2]->f();
+  total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+}
diff --git a/test/asan/TestCases/Linux/coverage-caller-callee.cc b/test/asan/TestCases/Linux/coverage-caller-callee.cc
new file mode 100644
index 0000000..cd31896
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-caller-callee.cc
@@ -0,0 +1,74 @@
+// Test caller-callee coverage with large number of threads
+// and various numbers of callers and callees.
+
+// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-10-1
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 9  2 2>&1 | FileCheck %s --check-prefix=CHECK-9-2
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 7  3 2>&1 | FileCheck %s --check-prefix=CHECK-7-3
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 17 1 2>&1 | FileCheck %s --check-prefix=CHECK-17-1
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 15 2 2>&1 | FileCheck %s --check-prefix=CHECK-15-2
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 18 3 2>&1 | FileCheck %s --check-prefix=CHECK-18-3
+// RUN: rm -f caller-callee*.sancov
+//
+// REQUIRES: asan-64-bits
+//
+// CHECK-10-1: CovDump: 10 caller-callee pairs written
+// CHECK-9-2: CovDump: 18 caller-callee pairs written
+// CHECK-7-3: CovDump: 21 caller-callee pairs written
+// CHECK-17-1: CovDump: 14 caller-callee pairs written
+// CHECK-15-2: CovDump: 28 caller-callee pairs written
+// CHECK-18-3: CovDump: 42 caller-callee pairs written
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+int P = 0;
+struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
+struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo3 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo4 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo5 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo6 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo7 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo8 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo9 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo10 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo11 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo12 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo13 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo14 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo15 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo16 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo17 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo18 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo19 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+
+Foo *foo[20] = {
+    new Foo,   new Foo1,  new Foo2,  new Foo3,  new Foo4,  new Foo5,  new Foo6,
+    new Foo7,  new Foo8,  new Foo9,  new Foo10, new Foo11, new Foo12, new Foo13,
+    new Foo14, new Foo15, new Foo16, new Foo17, new Foo18, new Foo19,
+};
+
+int n_functions = 10;
+int n_callers = 2;
+
+void *Thread(void *arg) {
+  if (n_callers >= 1) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+  if (n_callers >= 2) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+  if (n_callers >= 3) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+  return arg;
+}
+
+int main(int argc, char **argv) {
+  if (argc >= 2)
+    n_functions = atoi(argv[1]);
+  if (argc >= 3)
+    n_callers = atoi(argv[2]);
+  const int kNumThreads = 16;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++)
+    pthread_create(&t[i], 0, Thread, 0);
+  for (int i = 0; i < kNumThreads; i++)
+    pthread_join(t[i], 0);
+}
diff --git a/test/asan/TestCases/Linux/coverage-direct-large.cc b/test/asan/TestCases/Linux/coverage-direct-large.cc
index b340da5..78aa686 100644
--- a/test/asan/TestCases/Linux/coverage-direct-large.cc
+++ b/test/asan/TestCases/Linux/coverage-direct-large.cc
@@ -1,7 +1,7 @@
 // Test for direct coverage writing with lots of data.
 // Current implementation maps output file in chunks of 64K. This test overflows
 // 1 chunk.
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -O0 %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 %s -o %t
 
 // RUN: rm -rf %T/coverage-direct-large
 
diff --git a/test/asan/TestCases/Linux/coverage-direct.cc b/test/asan/TestCases/Linux/coverage-direct.cc
index 7fe2514..2cc1aed 100644
--- a/test/asan/TestCases/Linux/coverage-direct.cc
+++ b/test/asan/TestCases/Linux/coverage-direct.cc
@@ -1,6 +1,6 @@
 // Test for direct coverage writing with dlopen.
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%T\" %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t
 
 // RUN: rm -rf %T/coverage-direct
 
diff --git a/test/asan/TestCases/Linux/coverage-disabled.cc b/test/asan/TestCases/Linux/coverage-disabled.cc
index 315c312..a75b26d 100644
--- a/test/asan/TestCases/Linux/coverage-disabled.cc
+++ b/test/asan/TestCases/Linux/coverage-disabled.cc
@@ -1,6 +1,6 @@
 // Test that no data is collected without a runtime flag.
 //
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
 //
 // RUN: rm -rf %T/coverage-disabled
 //
diff --git a/test/asan/TestCases/Linux/coverage-fork-direct.cc b/test/asan/TestCases/Linux/coverage-fork-direct.cc
index 7489b72..51cbbd8 100644
--- a/test/asan/TestCases/Linux/coverage-fork-direct.cc
+++ b/test/asan/TestCases/Linux/coverage-fork-direct.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
 // RUN: rm -rf %T/coverage-fork-direct
 // RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
 // RUN: (ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t; \
diff --git a/test/asan/TestCases/Linux/coverage-fork.cc b/test/asan/TestCases/Linux/coverage-fork.cc
index 28b2a49..38c2009 100644
--- a/test/asan/TestCases/Linux/coverage-fork.cc
+++ b/test/asan/TestCases/Linux/coverage-fork.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
 // RUN: export ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1
 // RUN: rm -rf %T/coverage-fork
 // RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork
diff --git a/test/asan/TestCases/Linux/coverage-levels.cc b/test/asan/TestCases/Linux/coverage-levels.cc
new file mode 100644
index 0000000..748ef1f
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-levels.cc
@@ -0,0 +1,20 @@
+// Test various levels of coverage
+//
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=1  %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=2  %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=3  %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
+//
+// REQUIRES: asan-64-bits
+
+volatile int sink;
+int main(int argc, char **argv) {
+  if (argc == 0)
+    sink = 0;
+}
+
+// CHECK1:  1 PCs written
+// CHECK2:  2 PCs written
+// CHECK3:  3 PCs written
diff --git a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc
index 1cd2253..4664cef 100644
--- a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc
+++ b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc
@@ -1,7 +1,7 @@
 // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
 // XFAIL: android
 //
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
 // RUN: rm -rf %T/coverage-maybe-open-file
 // RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file
 // RUN: ASAN_OPTIONS=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success
diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Linux/coverage-module-unloaded.cc
index 4b64a03..449841e 100644
--- a/test/asan/TestCases/Linux/coverage-module-unloaded.cc
+++ b/test/asan/TestCases/Linux/coverage-module-unloaded.cc
@@ -1,8 +1,8 @@
 // Check that unloading a module doesn't break coverage dumping for remaining
 // modules.
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%T\" %s -o %t
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t
 // RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
 // RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded
 // RUN: %run %t 2>&1         | FileCheck %s
diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Linux/coverage-sandboxing.cc
index 6af9865..56f9c40 100644
--- a/test/asan/TestCases/Linux/coverage-sandboxing.cc
+++ b/test/asan/TestCases/Linux/coverage-sandboxing.cc
@@ -1,5 +1,5 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=2 -DSHARED %s -shared -o %T/libcoverage_sandboxing_test.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s   -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_sandboxing_test
+// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_sandboxing_test.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s   -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_sandboxing_test
 // RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
 // RUN: rm -rf %T/coverage_sandboxing_test
 // RUN: mkdir %T/coverage_sandboxing_test && cd %T/coverage_sandboxing_test
diff --git a/test/asan/TestCases/Linux/coverage-tracing.cc b/test/asan/TestCases/Linux/coverage-tracing.cc
new file mode 100644
index 0000000..89ab0d2
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-tracing.cc
@@ -0,0 +1,22 @@
+// Test -mllvm -sanitizer-coverage-experimental-tracing
+//
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=1 -mllvm -sanitizer-coverage-experimental-tracing %s -o %t
+// RUN: rm -rf   %T/coverage-tracing
+// RUN: mkdir -p %T/coverage-tracing
+// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-tracing:verbosity=1 %run %t 1 2 3 4 2>&1 | FileCheck %s
+// RUN: rm -rf   %T/coverage-tracing
+//
+// REQUIRES: asan-64-bits
+
+volatile int sink;
+int main(int argc, char **argv) {
+  volatile int i = 0;
+  do {
+    sink = 0;
+    i++;
+  } while (i < argc);
+  return 0;
+}
+
+// CHECK: CovDump: Trace: {{[3-9]}} PCs written
+// CHECK: CovDump: Trace: {{[6-9]}} Events written
diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Linux/coverage.cc
index 5af4d69..f6eb0ae 100644
--- a/test/asan/TestCases/Linux/coverage.cc
+++ b/test/asan/TestCases/Linux/coverage.cc
@@ -1,5 +1,5 @@
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC
-// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s   -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s   -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test
 // RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
 // RUN: mkdir -p %T/coverage && cd %T/coverage
 // RUN: %run %t 2>&1         | FileCheck %s --check-prefix=CHECK-main
@@ -13,6 +13,8 @@
 // https://code.google.com/p/address-sanitizer/issues/detail?id=263
 // XFAIL: android
 
+#include "sanitizer/common_interface_defs.h"
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -29,8 +31,12 @@
 int main(int argc, char **argv) {
   fprintf(stderr, "PID: %d\n", getpid());
   for (int i = 1; i < argc; i++) {
-    if (!strcmp(argv[i], "foo"))
+    if (!strcmp(argv[i], "foo")) {
+      uintptr_t old_coverage = __sanitizer_get_total_unique_coverage();
       foo();
+      uintptr_t new_coverage = __sanitizer_get_total_unique_coverage();
+      assert(new_coverage > old_coverage);
+    }
     if (!strcmp(argv[i], "bar"))
       bar();
   }
diff --git a/test/asan/TestCases/Linux/heap-overflow-large.cc b/test/asan/TestCases/Linux/heap-overflow-large.cc
deleted file mode 100644
index 26c7015..0000000
--- a/test/asan/TestCases/Linux/heap-overflow-large.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Regression test for
-// https://code.google.com/p/address-sanitizer/issues/detail?id=183
-
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %run %t 12 2>&1 | FileCheck %s
-// RUN: not %run %t 100 2>&1 | FileCheck %s
-// RUN: not %run %t 10000 2>&1 | FileCheck %s
-
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char *argv[]) {
-  int *x = new int[5];
-  memset(x, 0, sizeof(x[0]) * 5);
-  int index = atoi(argv[1]);
-  int res = x[index];
-  // CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
-  // CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]]
-  // CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}}
-  // CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
-  delete[] x;
-  return res;
-}
diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c
index 72416f1..a616732 100644
--- a/test/asan/TestCases/Linux/interface_symbols_linux.c
+++ b/test/asan/TestCases/Linux/interface_symbols_linux.c
@@ -3,13 +3,11 @@
 // RUN: %clang_asan -O2 %s -o %t.exe
 // RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
 // RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" \
-// RUN:    | grep -v "__asan_malloc_hook" \
-// RUN:    | grep -v "__asan_free_hook" \
+// RUN:    | sed -E "s/__asan_init_v[0-9]+/__asan_init/" \
 // RUN:    | grep -v "__asan_default_options" \
 // RUN:    | grep -v "__asan_stack_" \
 // RUN:    | grep -v "__asan_on_error" > %t.symbols
 // RUN: cat %p/../../../../lib/asan/asan_interface_internal.h \
-// RUN:     %p/../../../../lib/asan/asan_init_version.h \
 // RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
 // RUN:    | grep -v "OPTIONAL" \
 // RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
diff --git a/test/asan/TestCases/Linux/malloc_delete_mismatch.cc b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc
index 085eb15..18d65ce 100644
--- a/test/asan/TestCases/Linux/malloc_delete_mismatch.cc
+++ b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc
@@ -13,6 +13,7 @@
 // RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
 // RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 #include <stdlib.h>
 
 static volatile char *x;
diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc
index 48e0907..ddc68a2 100644
--- a/test/asan/TestCases/Linux/odr-violation.cc
+++ b/test/asan/TestCases/Linux/odr-violation.cc
@@ -23,19 +23,20 @@
 #endif
 
 #if BUILD_SO
-char G[SZ];
+namespace foo { char G[SZ]; }
 #else
 #include <stdio.h>
-char G[100];
+namespace foo { char G[100]; }
+// CHECK: ERROR: AddressSanitizer: odr-violation
+// CHECK: size=100 'foo::G' {{.*}}odr-violation.cc:[[@LINE-2]]:22
+// CHECK: size={{4|100}} 'foo::G'
 int main(int argc, char **argv) {
-  printf("PASS: %p\n", &G);
+  printf("PASS: %p\n", &foo::G);
 }
 #endif
 
-// CHECK: ERROR: AddressSanitizer: odr-violation
-// CHECK: size=100 G
-// CHECK: size={{4|100}} G
 // CHECK: These globals were registered at these points:
 // CHECK: ODR-EXE
 // CHECK: ODR-SO
+// CHECK: SUMMARY: AddressSanitizer: odr-violation: global 'foo::G' at {{.*}}odr-violation.cc
 // DISABLED: PASS
diff --git a/test/asan/TestCases/Linux/ptrace.cc b/test/asan/TestCases/Linux/ptrace.cc
index 45febd3..7e5acb6 100644
--- a/test/asan/TestCases/Linux/ptrace.cc
+++ b/test/asan/TestCases/Linux/ptrace.cc
@@ -3,7 +3,7 @@
 //
 // RUN: %clangxx_asan -O0 %s -o %t && %run %t
 // RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
-// XFAIL: arm-linux-gnueabi
+// REQUIRES: x86_64-supported-target,i386-supported-target
 
 #include <assert.h>
 #include <stdio.h>
diff --git a/test/asan/TestCases/Linux/sized_delete_test.cc b/test/asan/TestCases/Linux/sized_delete_test.cc
new file mode 100644
index 0000000..823e3c0
--- /dev/null
+++ b/test/asan/TestCases/Linux/sized_delete_test.cc
@@ -0,0 +1,93 @@
+// RUN: %clangxx_asan -Xclang -fsized-deallocation -O0 %s -o %t
+// RUN:                                         not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
+// RUN:                                         not %run %t array  2>&1 | FileCheck %s -check-prefix=ARRAY
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t array  2>&1 | FileCheck %s -check-prefix=ARRAY
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0     %run %t scalar
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0     %run %t array
+
+// Sized-delete is implemented with a weak delete() definition.
+// Weak symbols are kind of broken on Android.
+// XFAIL: android
+
+#include <new>
+#include <stdio.h>
+#include <string>
+
+inline void break_optimization(void *arg) {
+  __asm__ __volatile__("" : : "r" (arg) : "memory");
+}
+
+struct S12 {
+  int a, b, c;
+};
+
+struct S20 {
+  int a, b, c, d, e;
+};
+
+struct D1 {
+  int a, b, c;
+  ~D1() { fprintf(stderr, "D1::~D1\n"); }
+};
+
+struct D2 {
+  int a, b, c, d, e;
+  ~D2() { fprintf(stderr, "D2::~D2\n"); }
+};
+
+void Del12(S12 *x) {
+  break_optimization(x);
+  delete x;
+}
+void Del12NoThrow(S12 *x) {
+  break_optimization(x);
+  operator delete(x, std::nothrow);
+}
+void Del12Ar(S12 *x) {
+  break_optimization(x);
+  delete [] x;
+}
+void Del12ArNoThrow(S12 *x) {
+  break_optimization(x);
+  operator delete[](x, std::nothrow);
+}
+
+int main(int argc, char **argv) {
+  if (argc != 2) return 1;
+  std::string flag = argv[1];
+  // These are correct.
+  Del12(new S12);
+  Del12NoThrow(new S12);
+  Del12Ar(new S12[100]);
+  Del12ArNoThrow(new S12[100]);
+
+  // Here we pass wrong type of pointer to delete,
+  // but [] and nothrow variants of delete are not sized.
+  Del12Ar(reinterpret_cast<S12*>(new S20[100]));
+  Del12NoThrow(reinterpret_cast<S12*>(new S20));
+  Del12ArNoThrow(reinterpret_cast<S12*>(new S20[100]));
+  fprintf(stderr, "OK SO FAR\n");
+  // SCALAR: OK SO FAR
+  // ARRAY: OK SO FAR
+  if (flag == "scalar") {
+    // Here asan should bark as we are passing a wrong type of pointer
+    // to sized delete.
+    Del12(reinterpret_cast<S12*>(new S20));
+    // SCALAR: AddressSanitizer: new-delete-type-mismatch
+    // SCALAR:  object passed to delete has wrong type:
+    // SCALAR:  size of the allocated type:   20 bytes;
+    // SCALAR:  size of the deallocated type: 12 bytes.
+    // SCALAR: is located 0 bytes inside of 20-byte region
+    // SCALAR: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+  } else if (flag == "array") {
+    D1 *d1 = reinterpret_cast<D1*>(new D2[10]);
+    break_optimization(d1);
+    delete [] d1;
+    // ARRAY-NOT: D2::~D2
+    // ARRAY: D1::~D1
+    // ARRAY: AddressSanitizer: new-delete-type-mismatch
+    // ARRAY:  size of the allocated type:   20{{4|8}} bytes;
+    // ARRAY:  size of the deallocated type: 12{{4|8}} bytes.
+  }
+}
diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc
index 44c8a03..e494e56 100644
--- a/test/asan/TestCases/Linux/stack-trace-dlclose.cc
+++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc
@@ -5,6 +5,7 @@
 // RUN: %clangxx_asan -DSO_DIR=\"%T\" %s -o %t
 // RUN: ASAN_OPTIONS=exitcode=0 %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <assert.h>
 #include <dlfcn.h>
diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc
index 1768643..b6443fa 100644
--- a/test/asan/TestCases/Posix/allow_user_segv.cc
+++ b/test/asan/TestCases/Posix/allow_user_segv.cc
@@ -6,12 +6,22 @@
 
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 
-struct sigaction user_sigaction;
-struct sigaction original_sigaction;
+struct sigaction original_sigaction_sigbus;
+struct sigaction original_sigaction_sigsegv;
 
 void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
   fprintf(stderr, "User sigaction called\n");
+  struct sigaction original_sigaction;
+  if (signum == SIGBUS)
+    original_sigaction = original_sigaction_sigbus;
+  else if (signum == SIGSEGV)
+    original_sigaction = original_sigaction_sigsegv;
+  else {
+    printf("Invalid signum");
+    exit(1);
+  }
   if (original_sigaction.sa_flags | SA_SIGINFO)
     original_sigaction.sa_sigaction(signum, siginfo, context);
   else
@@ -23,21 +33,22 @@
   return *x;
 }
 
-int main() {
+int InstallHandler(int signum, struct sigaction *original_sigaction) {
+  struct sigaction user_sigaction;
   user_sigaction.sa_sigaction = User_OnSIGSEGV;
   user_sigaction.sa_flags = SA_SIGINFO;
-#if defined(__APPLE__) && !defined(__LP64__)
-  // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered.
-  int signum = SIGBUS;
-#else
-  // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered.
-  // On Linux SIGSEGV is delivered as well.
-  int signum = SIGSEGV;
-#endif
-  if (sigaction(signum, &user_sigaction, &original_sigaction)) {
+  if (sigaction(signum, &user_sigaction, original_sigaction)) {
     perror("sigaction");
     return 1;
   }
+  return 0;
+}
+
+int main() {
+  // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite
+  // 32-bit Darwin triggers SIGBUS instead.
+  if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv)) return 1;
+  if (InstallHandler(SIGBUS, &original_sigaction_sigbus)) return 1;
   fprintf(stderr, "User sigaction installed\n");
   return DoSEGV();
 }
diff --git a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc
index 84dc1c2..6ed02f4 100644
--- a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc
+++ b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc
@@ -5,9 +5,10 @@
 // shared object files.
 
 // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -ldl -o %t
+// RUN: %clangxx_asan -O0 %s -o %t
 // RUN: env ASAN_OPTIONS=symbolize=0 not %run %t 2>&1 | %asan_symbolize | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #if !defined(SHARED_LIB)
 #include <dlfcn.h>
diff --git a/test/asan/TestCases/Posix/asprintf.cc b/test/asan/TestCases/Posix/asprintf.cc
new file mode 100644
index 0000000..6946e50
--- /dev/null
+++ b/test/asan/TestCases/Posix/asprintf.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+  char *p;
+  int res = asprintf(&p, "%d", argc);
+  fprintf(stderr, "x%d %sx\n", res, p);
+  // CHECK: x1 1x
+  free(p);
+  fprintf(stderr, "DONE\n");
+  // CHECK: DONE
+  return 0;
+}
diff --git a/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc b/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc
index 15096e5..ad547ce 100644
--- a/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc
+++ b/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc
@@ -1,8 +1,9 @@
 // Make sure we don't report a leak nor hang.
 // RUN: %clangxx_asan -O3 %s -o %t && %run %t
 #include <stdlib.h>
-#ifndef __APPLE__
+#include <unistd.h>
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
 # include <malloc.h>
-#endif  // __APPLE__
+#endif  // !__APPLE__ && !__FreeBSD__
 int *p = (int*)valloc(1 << 20);
 int main() { }
diff --git a/test/asan/TestCases/Linux/glob.cc b/test/asan/TestCases/Posix/glob.cc
similarity index 100%
rename from test/asan/TestCases/Linux/glob.cc
rename to test/asan/TestCases/Posix/glob.cc
diff --git a/test/asan/TestCases/Linux/glob_test_root/aa b/test/asan/TestCases/Posix/glob_test_root/aa
similarity index 100%
rename from test/asan/TestCases/Linux/glob_test_root/aa
rename to test/asan/TestCases/Posix/glob_test_root/aa
diff --git a/test/asan/TestCases/Linux/glob_test_root/ab b/test/asan/TestCases/Posix/glob_test_root/ab
similarity index 100%
rename from test/asan/TestCases/Linux/glob_test_root/ab
rename to test/asan/TestCases/Posix/glob_test_root/ab
diff --git a/test/asan/TestCases/Linux/glob_test_root/ba b/test/asan/TestCases/Posix/glob_test_root/ba
similarity index 100%
rename from test/asan/TestCases/Linux/glob_test_root/ba
rename to test/asan/TestCases/Posix/glob_test_root/ba
diff --git a/test/asan/TestCases/Posix/init-order-dlopen.cc b/test/asan/TestCases/Posix/init-order-dlopen.cc
index 2b86ace..6f20477 100644
--- a/test/asan/TestCases/Posix/init-order-dlopen.cc
+++ b/test/asan/TestCases/Posix/init-order-dlopen.cc
@@ -10,8 +10,8 @@
 // If the linker doesn't support --export-dynamic (which is ELF-specific),
 // try to link without that option.
 // FIXME: find a better solution.
-// RUN: %clangxx_asan -O0 %s -pthread -ldl -o %t -Wl,--export-dynamic || \
-// RUN:     %clangxx_asan -O0 %s -pthread -ldl -o %t
+// RUN: %clangxx_asan -O0 %s -pthread -o %t -Wl,--export-dynamic || \
+// RUN:     %clangxx_asan -O0 %s -pthread -o %t
 // RUN: ASAN_OPTIONS=strict_init_order=true %run %t 2>&1 | FileCheck %s
 #if !defined(SHARED_LIB)
 #include <dlfcn.h>
diff --git a/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc
index e467f76..0a49980 100644
--- a/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc
+++ b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #ifdef __ANDROID__
 #include <malloc.h>
@@ -23,11 +24,12 @@
 #endif
 
 int main() {
-  const int kPageSize = 4096;
+  const long kPageSize = sysconf(_SC_PAGESIZE);
   void *p = my_memalign(kPageSize, 1024 * 1024);
   free(p);
 
-  char *q = (char *)mmap(p, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
+  char *q = (char *)mmap(p, kPageSize, PROT_READ | PROT_WRITE,
+                         MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
   assert(q == p);
 
   memset(q, 42, kPageSize);
diff --git a/test/asan/TestCases/Posix/new_array_cookie_test.cc b/test/asan/TestCases/Posix/new_array_cookie_test.cc
new file mode 100644
index 0000000..85d51f3
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_test.cc
@@ -0,0 +1,24 @@
+// REQUIRES: asan-64-bits
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN:                                    not %run %t 2>&1  | FileCheck %s
+// RUN: ASAN_OPTIONS=poison_array_cookie=1 not %run %t 2>&1  | FileCheck %s
+// RUN: ASAN_OPTIONS=poison_array_cookie=0 not %run %t 2>&1  | FileCheck %s --check-prefix=NO_COOKIE
+#include <stdio.h>
+#include <stdlib.h>
+struct C {
+  int x;
+  ~C() {
+    fprintf(stderr, "ZZZZZZZZ\n");
+    exit(1);
+  }
+};
+
+int main(int argc, char **argv) {
+  C *buffer = new C[argc];
+  buffer[-2].x = 10;
+// CHECK: AddressSanitizer: heap-buffer-overflow
+// CHECK: in main {{.*}}new_array_cookie_test.cc:[[@LINE-2]]
+// CHECK: is located 0 bytes inside of 12-byte region
+// NO_COOKIE: ZZZZZZZZ
+  delete [] buffer;
+}
diff --git a/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc
new file mode 100644
index 0000000..c35cceb
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc
@@ -0,0 +1,38 @@
+// REQUIRES: asan-64-bits
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: ASAN_OPTIONS=poison_array_cookie=1 not %run %t 2>&1  | FileCheck %s --check-prefix=COOKIE
+// RUN: ASAN_OPTIONS=poison_array_cookie=0 not %run %t 2>&1  | FileCheck %s --check-prefix=NO_COOKIE
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+int dtor_counter;
+struct C {
+  int x;
+  ~C() {
+    dtor_counter++;
+    fprintf(stderr, "DTOR %d\n", dtor_counter);
+  }
+};
+
+__attribute__((noinline)) void Delete(C *c) { delete[] c; }
+__attribute__((no_sanitize_address)) void Write42ToCookie(C *c) {
+  long *p = reinterpret_cast<long*>(c);
+  p[-1] = 42;
+}
+
+int main(int argc, char **argv) {
+  C *buffer = new C[argc];
+  delete [] buffer;
+  Write42ToCookie(buffer);
+  delete [] buffer;
+// COOKIE: DTOR 1
+// COOKIE-NOT: DTOR 2
+// COOKIE: AddressSanitizer: loaded array cookie from free-d memory
+// COOKIE: AddressSanitizer: attempting double-free
+// NO_COOKIE: DTOR 1
+// NO_COOKIE: DTOR 43
+// NO_COOKIE-NOT: DTOR 44
+// NO_COOKIE-NOT: AddressSanitizer: loaded array cookie from free-d memory
+// NO_COOKIE: AddressSanitizer: attempting double-free
+
+}
diff --git a/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc
new file mode 100644
index 0000000..1cea6f6
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc
@@ -0,0 +1,38 @@
+// Test that we do not poison the array cookie if the operator new is defined
+// inside the class.
+// RUN: %clangxx_asan  %s -o %t && %run %t
+//
+// XFAIL: android
+// XFAIL: armv7l-unknown-linux-gnueabihf
+#include <new>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+struct Foo {
+  void *operator new(size_t s) { return Allocate(s); }
+  void *operator new[] (size_t s) { return Allocate(s); }
+  ~Foo();
+  static void *allocated;
+  static void *Allocate(size_t s) {
+    assert(!allocated);
+    return allocated = ::new char[s];
+  }
+};
+
+Foo::~Foo() {}
+void *Foo::allocated;
+
+Foo *getFoo(size_t n) {
+  return new Foo[n];
+}
+
+int main() {
+  Foo *foo = getFoo(10);
+  fprintf(stderr, "foo  : %p\n", foo);
+  fprintf(stderr, "alloc: %p\n", Foo::allocated);
+  assert(reinterpret_cast<uintptr_t>(foo) ==
+         reinterpret_cast<uintptr_t>(Foo::allocated) + sizeof(void*));
+  *reinterpret_cast<uintptr_t*>(Foo::allocated) = 42;
+  return 0;
+}
diff --git a/test/asan/TestCases/Posix/shared-lib-test.cc b/test/asan/TestCases/Posix/shared-lib-test.cc
index 21f26b3..a0827b5 100644
--- a/test/asan/TestCases/Posix/shared-lib-test.cc
+++ b/test/asan/TestCases/Posix/shared-lib-test.cc
@@ -1,11 +1,11 @@
 // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -ldl -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -ldl -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -ldl -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -ldl -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
 
 #if !defined(SHARED_LIB)
@@ -38,7 +38,7 @@
   // CHECK: {{    #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]]
   return 0;
 }
-#else  // SHARED_LIBS
+#else  // SHARED_LIB
 #include <stdio.h>
 #include <string.h>
 
@@ -54,4 +54,4 @@
 void inc2(int *a, int index) {
   a[index]++;
 }
-#endif  // SHARED_LIBS
+#endif  // SHARED_LIB
diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc
index 43023fb..d60677a 100644
--- a/test/asan/TestCases/Posix/start-deactivated.cc
+++ b/test/asan/TestCases/Posix/start-deactivated.cc
@@ -4,9 +4,10 @@
 
 // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
 // RUN: %clangxx -O0 %s -c -o %t.o
-// RUN: %clangxx_asan -O0 %t.o -ldl -o %t
+// RUN: %clangxx_asan -O0 %t.o -o %t
 // RUN: ASAN_OPTIONS=start_deactivated=1 not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #if !defined(SHARED_LIB)
 #include <dlfcn.h>
diff --git a/test/asan/TestCases/Linux/tsd_dtor_leak.cc b/test/asan/TestCases/Posix/tsd_dtor_leak.cc
similarity index 100%
rename from test/asan/TestCases/Linux/tsd_dtor_leak.cc
rename to test/asan/TestCases/Posix/tsd_dtor_leak.cc
diff --git a/test/asan/TestCases/Posix/wait.cc b/test/asan/TestCases/Posix/wait.cc
index 56a03bd..99d0212 100644
--- a/test/asan/TestCases/Posix/wait.cc
+++ b/test/asan/TestCases/Posix/wait.cc
@@ -7,14 +7,9 @@
 // RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
 
-// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
-
 // RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
 
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
 
 #include <assert.h>
 #include <sys/wait.h>
@@ -32,16 +27,10 @@
     res = waitpid(pid, status, WNOHANG);
 #elif defined(WAIT3)
     res = wait3(status, WNOHANG, NULL);
-#elif defined(WAIT4)
-    res = wait4(pid, status, WNOHANG, NULL);
-#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE)
+#elif defined(WAIT3_RUSAGE)
     struct rusage *ru = (struct rusage*)(x + argc * 3);
     int good_status;
-# if defined(WAIT3_RUSAGE)
     res = wait3(&good_status, WNOHANG, ru);
-# elif defined(WAIT4_RUSAGE)
-    res = wait4(pid, &good_status, WNOHANG, ru);
-# endif
 #endif
     // CHECK: stack-buffer-overflow
     // CHECK: {{WRITE of size .* at 0x.* thread T0}}
diff --git a/test/asan/TestCases/Posix/wait4.cc b/test/asan/TestCases/Posix/wait4.cc
new file mode 100644
index 0000000..b95246e
--- /dev/null
+++ b/test/asan/TestCases/Posix/wait4.cc
@@ -0,0 +1,43 @@
+// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// XFAIL: android
+
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  // This test passes on some versions of Android NDK and fails on other.
+  // https://code.google.com/p/memory-sanitizer/issues/detail?id=64
+  // Make it fail unconditionally on Android.
+#ifdef __ANDROID__
+  return 0;
+#endif
+
+  pid_t pid = fork();
+  if (pid) { // parent
+    int x[3];
+    int *status = x + argc * 3;
+    int res;
+#if defined(WAIT4)
+    res = wait4(pid, status, WNOHANG, NULL);
+#elif defined(WAIT4_RUSAGE)
+    struct rusage *ru = (struct rusage*)(x + argc * 3);
+    int good_status;
+    res = wait4(pid, &good_status, WNOHANG, ru);
+#endif
+    // CHECK: stack-buffer-overflow
+    // CHECK: {{WRITE of size .* at 0x.* thread T0}}
+    // CHECK: {{in .*wait}}
+    // CHECK: {{in main .*wait4.cc:}}
+    // CHECK: is located in stack of thread T0 at offset
+    // CHECK: {{in main}}
+    return res == -1 ? 1 : 0;
+  }
+  // child
+  return 0;
+}
diff --git a/test/asan/TestCases/Posix/waitid.cc b/test/asan/TestCases/Posix/waitid.cc
index edfe3ed..8b516dc 100644
--- a/test/asan/TestCases/Posix/waitid.cc
+++ b/test/asan/TestCases/Posix/waitid.cc
@@ -4,6 +4,7 @@
 #include <assert.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <signal.h>
 
 int main(int argc, char **argv) {
   pid_t pid = fork();
diff --git a/test/asan/TestCases/Windows/demangled_names.cc b/test/asan/TestCases/Windows/demangled_names.cc
new file mode 100644
index 0000000..a528555
--- /dev/null
+++ b/test/asan/TestCases/Windows/demangled_names.cc
@@ -0,0 +1,50 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+// This test makes sure ASan symbolizes stack traces the way they are typically
+// symbolized on Windows.
+#include <malloc.h>
+
+namespace foo {
+// A template function in a namespace.
+template<int x>
+void bar(char *p) {
+  *p = x;
+}
+
+// A regular function in a namespace.
+void spam(char *p) {
+  bar<42>(p);
+}
+}
+
+// A multi-argument template with a bool template parameter.
+template<typename T, bool U>
+void baz(T t) {
+  if (U)
+    foo::spam(t);
+}
+
+template<typename T>
+struct A {
+  A(T v) { v_ = v; }
+  ~A();
+  char *v_;
+};
+
+// A destructor of a template class.
+template<>
+A<char*>::~A() {
+  baz<char*, true>(v_);
+}
+
+int main() {
+  char *buffer = (char*)malloc(42);
+  free(buffer);
+  A<char*> a(buffer);
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: foo::bar<42> {{.*}}demangled_names.cc
+// CHECK: foo::spam {{.*}}demangled_names.cc
+// CHECK: baz<char *,1> {{.*}}demangled_names.cc
+// CHECK: A<char *>::~A<char *> {{.*}}demangled_names.cc
+}
diff --git a/test/asan/TestCases/Windows/dll_and_lib.cc b/test/asan/TestCases/Windows/dll_and_lib.cc
new file mode 100644
index 0000000..bddaa32
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_and_lib.cc
@@ -0,0 +1,19 @@
+// Just make sure we can link an implib into another DLL
+// This used to fail between r212699 and r212814.
+// RUN: %clang_cl_asan -DCONFIG=1 %s -c -Fo%t.1.obj
+// RUN: link /nologo /DLL /OUT:%t.1.dll %t.1.obj %asan_dll_thunk
+// RUN: %clang_cl_asan -DCONFIG=2 %s -c -Fo%t.2.obj
+// RUN: link /nologo /DLL /OUT:%t.2.dll %t.2.obj %t.1.lib %asan_dll_thunk
+// REQUIRES: asan-static-runtime
+
+#if CONFIG==1
+extern "C" __declspec(dllexport) int f1() {
+  int x = 0;
+  return 1;
+}
+#else
+extern "C" __declspec(dllexport) int f2() {
+  int x = 0;
+  return 2;
+}
+#endif
diff --git a/test/asan/TestCases/Windows/dll_host.cc b/test/asan/TestCases/Windows/dll_host.cc
index 5eb710e..d3b4c14 100644
--- a/test/asan/TestCases/Windows/dll_host.cc
+++ b/test/asan/TestCases/Windows/dll_host.cc
@@ -8,12 +8,13 @@
 // RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | grep -v @ | sort | uniq > %t.exported_wrappers
 //
 // Get the list of ASan wrappers imported by the DLL RTL:
-// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_dll_thunk.cc | grep -v define | sed "s/.*(\(.*\)).*/__asan_wrap_\1/" | sort | uniq > %t.dll_imports
+// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed "s/.*(\(.*\)).*/__asan_wrap_\1/" | sort | uniq > %t.dll_imports
 //
 // Now make sure the DLL thunk imports everything:
 // RUN: echo
-// RUN: echo "=== NOTE === If you see a mismatch below, please update asan_dll_thunk.cc"
+// RUN: echo "=== NOTE === If you see a mismatch below, please update asan_win_dll_thunk.cc"
 // RUN: diff %t.dll_imports %t.exported_wrappers
+// REQUIRES: asan-static-runtime
 
 #include <stdio.h>
 #include <windows.h>
diff --git a/test/asan/TestCases/Windows/dll_large_function.cc b/test/asan/TestCases/Windows/dll_large_function.cc
new file mode 100644
index 0000000..039d01f
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_large_function.cc
@@ -0,0 +1,12 @@
+// Make sure we can link a DLL with large functions which would mean
+// functions such as __asan_loadN and __asan_storeN will be called
+// from the DLL.  We simulate the large function with
+// -mllvm -asan-instrumentation-with-call-threshold=0.
+// RUN: %clang_cl_asan %s -c -Fo%t.obj -mllvm -asan-instrumentation-with-call-threshold=0
+// RUN: link /nologo /DLL /OUT:%t.dll %t.obj %asan_dll_thunk
+// REQUIRES: asan-static-runtime
+
+void f(long* foo, long* bar) {
+  // One load and one store
+  *foo = *bar;
+}
diff --git a/test/asan/TestCases/Windows/dll_null_deref.cc b/test/asan/TestCases/Windows/dll_null_deref.cc
new file mode 100644
index 0000000..0fb18de
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_null_deref.cc
@@ -0,0 +1,18 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK:   {{0x0*000.. .*pc 0x.*}}
+  ptr[10]++;  // BOOM
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in test_function .*\dll_null_deref.cc:}}[[@LINE-1]]
+  // CHECK: AddressSanitizer can not provide additional info.
+  return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc
index e52345e..736ce80 100644
--- a/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc
+++ b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc
@@ -13,10 +13,10 @@
 //
 // CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
 // CHECK-LABEL: allocated by thread T0 here:
-// FIXME: should get rid of the malloc/free frames called from the inside of
-// operator new/delete in DLLs.  Also, the operator new frame should have [].
-// CHECK-NEXT:   malloc
-// CHECK-NEXT:   operator new
+// FIXME: Should get rid of the malloc/free frames called from the inside of
+// operator new/delete in DLLs when using -MT CRT.
+// FIXME: The 'operator new' frame should have [].
+// CHECK:        operator new
 // CHECK-NEXT:   test_function {{.*}}dll_operator_array_new_left_oob.cc:[[@LINE-13]]
 // CHECK-NEXT:   main {{.*}}dll_host.cc
 // CHECK-LABEL: SUMMARY
diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc
index c61d4eb..8306a73 100644
--- a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc
+++ b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc
@@ -20,11 +20,11 @@
 //        should be "8 bytes ... left of 168-byte region", see
 //        https://code.google.com/p/address-sanitizer/issues/detail?id=314
 // CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region
-// FIXME: should get rid of the malloc/free frames called from the inside of
-// operator new/delete in DLLs.  Also, the operator new frame should have [].
+// FIXME: Should get rid of the malloc/free frames called from the inside of
+// operator new/delete in DLLs when using -MT CRT.
+// FIXME: The operator new frame should have [].
 // CHECK-LABEL: allocated by thread T0 here:
-// CHECK-NEXT:   malloc
-// CHECK-NEXT:   operator new
+// CHECK:        operator new
 // CHECK-NEXT:   test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-16]]
 // CHECK-NEXT:   main {{.*}}dll_host.cc
 // CHECK-LABEL: SUMMARY
diff --git a/test/asan/TestCases/Windows/dll_seh.cc b/test/asan/TestCases/Windows/dll_seh.cc
new file mode 100644
index 0000000..6e4c724
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_seh.cc
@@ -0,0 +1,60 @@
+// Clang doesn't support SEH on Windows yet, so for the time being we
+// build this program in two parts: the code with SEH is built with CL,
+// the rest is built with Clang.  This represents the typical scenario when we
+// build a large project using "clang-cl -fallback -fsanitize=address".
+//
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+//
+// Check both -GS and -GS- builds:
+// RUN: cl -LD -c %s -Fo%t.obj
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj
+// RUN: %run %t %t.dll
+//
+// RUN: cl -LD -GS- -c %s -Fo%t.obj
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll %t.obj
+// RUN: %run %t %t.dll
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+
+// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are
+// supported and we don't need to use CL.
+extern "C" bool __asan_address_is_poisoned(void *p);
+
+void ThrowAndCatch();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+  int local, zero = 0;
+  fprintf(stderr, "Throw:  %p\n", &local);
+  local = 5 / zero;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+  int local;
+  __try {
+    Throw();
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    fprintf(stderr, "__except:  %p\n", &local);
+  }
+}
+#else
+
+extern "C" __declspec(dllexport)
+int test_function() {
+  char x[32];
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  ThrowAndCatch();
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+  return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Windows/double_operator_delete.cc b/test/asan/TestCases/Windows/double_operator_delete.cc
index 55a6d09..eae4a64 100644
--- a/test/asan/TestCases/Windows/double_operator_delete.cc
+++ b/test/asan/TestCases/Windows/double_operator_delete.cc
@@ -8,15 +8,18 @@
   delete [] x;
   delete [] x;
 // CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
-// CHECK-NEXT: {{#0 .* operator delete}}[]
-// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-3]]
+// FIXME: The 'operator delete' frame should have [].
+// CHECK-NEXT: {{#0 .* operator delete}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-4]]
 // CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
 // CHECK-LABEL: freed by thread T0 here:
-// CHECK-NEXT: {{#0 .* operator delete}}[]
-// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-8]]
+// FIXME: The 'operator delete' frame should have [].
+// CHECK-NEXT: {{#0 .* operator delete}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-10]]
 // CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* operator new}}[]
-// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-12]]
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-15]]
   return 0;
 }
 
diff --git a/test/asan/TestCases/Windows/intercept_strdup.cc b/test/asan/TestCases/Windows/intercept_strdup.cc
index 0a40d86..edb1f2f 100644
--- a/test/asan/TestCases/Windows/intercept_strdup.cc
+++ b/test/asan/TestCases/Windows/intercept_strdup.cc
@@ -21,7 +21,7 @@
 // CHECK: [[ADDR]] is located 1 bytes to the left of 6-byte region
 // CHECK: allocated by thread T0 here:
 // CHECK:   {{#0 .* malloc }}
-// CHECK:   {{#1 .* _strdup }}
+// CHECK:   {{#1 .*strdup}}
 // CHECK:   {{#2 .* main .*}}intercept_strdup.cc:[[@LINE-16]]
   free(ptr);
 }
diff --git a/test/asan/TestCases/Windows/longjmp.cc b/test/asan/TestCases/Windows/longjmp.cc
new file mode 100644
index 0000000..443933e
--- /dev/null
+++ b/test/asan/TestCases/Windows/longjmp.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+
+// FIXME: merge this with the common longjmp test when we can run common
+// tests on Windows.
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sanitizer/asan_interface.h>
+
+static jmp_buf buf;
+
+int main() {
+  char x[32];
+  fprintf(stderr, "\nTestLongJmp\n");
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  if (0 == setjmp(buf))
+    longjmp(buf, 1);
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
diff --git a/test/asan/TestCases/Windows/null_deref.cc b/test/asan/TestCases/Windows/null_deref.cc
new file mode 100644
index 0000000..202000f
--- /dev/null
+++ b/test/asan/TestCases/Windows/null_deref.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// FIXME: merge this with the common null_deref test when we can run common
+// tests on Windows.
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK:   {{0x0*000.. .*pc 0x.*}}
+  ptr[10]++;  // BOOM
+}
+int main() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
+  // CHECK: AddressSanitizer can not provide additional info.
+}
diff --git a/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
new file mode 100644
index 0000000..62fe544
--- /dev/null
+++ b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
@@ -0,0 +1,40 @@
+// Make sure everything works even if the main module doesn't have any stack
+// variables, thus doesn't explicitly reference any symbol exported by the
+// runtime thunk.
+//
+// RUN: %clang_cl_asan -LD -O0 -DDLL1 %s -Fe%t1.dll
+// RUN: %clang_cl_asan -LD -O0 -DDLL2 %s -Fe%t2.dll
+// RUN: %clang_cl_asan -O0 -DEXE %s %t1.lib %t2.lib -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+#include <string.h>
+
+extern "C" {
+#if defined(EXE)
+__declspec(dllimport) void foo1();
+__declspec(dllimport) void foo2();
+
+int main() {
+  foo1();
+  foo2();
+}
+#elif defined(DLL1)
+__declspec(dllexport) void foo1() {}
+#elif defined(DLL2)
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK:   {{0x0*000.. .*pc 0x.*}}
+  ptr[10]++;  // BOOM
+}
+
+__declspec(dllexport) void foo2() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in foo2.*null_deref_multiple_dlls.cc:}}[[@LINE-1]]
+  // CHECK: AddressSanitizer can not provide additional info.
+}
+#else
+# error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc
index 81b709f..20a0f19 100644
--- a/test/asan/TestCases/Windows/operator_array_new_left_oob.cc
+++ b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc
@@ -10,7 +10,8 @@
 //
 // CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
 // CHECK-LABEL: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* operator new}}[]
-// CHECK-NEXT: {{#1 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-9]]
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-10]]
   delete [] buffer;
 }
diff --git a/test/asan/TestCases/Windows/operator_array_new_right_oob.cc b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc
index 079c78e..23775ef 100644
--- a/test/asan/TestCases/Windows/operator_array_new_right_oob.cc
+++ b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc
@@ -11,7 +11,8 @@
 // CHECK:   {{#0 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-3]]
 // CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region
 // CHECK: allocated by thread T0 here:
-// CHECK:   {{#0 .* operator new}}[]
-// CHECK:   {{#1 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-8]]
+// FIXME: The 'operator new' frame should have [].
+// CHECK:   {{#0 .* operator new}}
+// CHECK:   {{#1 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-9]]
   delete [] buffer;
 }
diff --git a/test/asan/TestCases/Windows/operator_array_new_uaf.cc b/test/asan/TestCases/Windows/operator_array_new_uaf.cc
index 1817996..b638ef1 100644
--- a/test/asan/TestCases/Windows/operator_array_new_uaf.cc
+++ b/test/asan/TestCases/Windows/operator_array_new_uaf.cc
@@ -12,11 +12,13 @@
 // CHECK:   {{#0 .* main .*operator_array_new_uaf.cc}}:[[@LINE-3]]
 // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
 // CHECK-LABEL: freed by thread T0 here:
-// CHECK:   {{#0 .* operator delete}}[]
-// CHECK:   {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-8]]
+// FIXME: The 'operator delete' frame should have [].
+// CHECK:   {{#0 .* operator delete}}
+// CHECK:   {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-9]]
 // CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK:   {{#0 .* operator new}}[]
-// CHECK:   {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-12]]
+// FIXME: The 'operator new' frame should have [].
+// CHECK:   {{#0 .* operator new}}
+// CHECK:   {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-14]]
   return 0;
 }
 
diff --git a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc
index c5bdba5..63f2929 100644
--- a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc
+++ b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc
@@ -18,7 +18,8 @@
 //        https://code.google.com/p/address-sanitizer/issues/detail?id=314
 // CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region
 // CHECK-LABEL: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* operator new}}[]
-// CHECK-NEXT: {{#1 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-12]]
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-13]]
   delete [] buffer;
 }
diff --git a/test/asan/TestCases/Windows/report_after_syminitialize.cc b/test/asan/TestCases/Windows/report_after_syminitialize.cc
new file mode 100644
index 0000000..faf5e35
--- /dev/null
+++ b/test/asan/TestCases/Windows/report_after_syminitialize.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+#include <dbghelp.h>
+
+int main() {
+  // Make sure the RTL recovers from "no options enabled" dbghelp setup.
+  SymSetOptions(0);
+
+  // Make sure the RTL recovers from "fInvadeProcess=FALSE".
+  if (!SymInitialize(GetCurrentProcess(), 0, FALSE))
+    return 42;
+
+  *(volatile int*)0 = 42;
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK-NEXT: {{WARNING: .*DbgHelp}}
+  // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-3]]
+  // CHECK: AddressSanitizer can not provide additional info.
+}
diff --git a/test/asan/TestCases/Windows/seh.cc b/test/asan/TestCases/Windows/seh.cc
new file mode 100644
index 0000000..50cf6dd
--- /dev/null
+++ b/test/asan/TestCases/Windows/seh.cc
@@ -0,0 +1,56 @@
+// Clang doesn't support SEH on Windows yet, so for the time being we
+// build this program in two parts: the code with SEH is built with CL,
+// the rest is built with Clang.  This represents the typical scenario when we
+// build a large project using "clang-cl -fallback -fsanitize=address".
+//
+// Check both -GS and -GS- builds:
+// RUN: cl -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+//
+// RUN: cl -GS- -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+
+// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are
+// supported and we don't need to use CL.
+extern "C" bool __asan_address_is_poisoned(void *p);
+
+void ThrowAndCatch();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+  int local, zero = 0;
+  fprintf(stderr, "Throw:  %p\n", &local);
+  local = 5 / zero;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+  int local;
+  __try {
+    Throw();
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    fprintf(stderr, "__except:  %p\n", &local);
+  }
+}
+#else
+
+int main() {
+  char x[32];
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  ThrowAndCatch();
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
+#endif
diff --git a/test/asan/TestCases/Windows/throw_catch.cc b/test/asan/TestCases/Windows/throw_catch.cc
new file mode 100644
index 0000000..5313d25
--- /dev/null
+++ b/test/asan/TestCases/Windows/throw_catch.cc
@@ -0,0 +1,73 @@
+// Clang doesn't support exceptions on Windows yet, so for the time being we
+// build this program in two parts: the code with exceptions is built with CL,
+// the rest is built with Clang.  This represents the typical scenario when we
+// build a large project using "clang-cl -fallback -fsanitize=address".
+//
+// RUN: cl -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+
+#include <assert.h>
+#include <stdio.h>
+
+// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are
+// supported and we don't need to use CL.
+extern "C" bool __asan_address_is_poisoned(void *p);
+
+void ThrowAndCatch();
+void TestThrowInline();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+  int local;
+  fprintf(stderr, "Throw:  %p\n", &local);
+  throw 1;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+  int local;
+  try {
+    Throw();
+  } catch(...) {
+    fprintf(stderr, "Catch:  %p\n", &local);
+  }
+}
+
+void TestThrowInline() {
+  char x[32];
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  try {
+    Throw();
+  } catch(...) {
+    fprintf(stderr, "Catch\n");
+  }
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
+
+#else
+
+void TestThrow() {
+  char x[32];
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  ThrowAndCatch();
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
+
+int main(int argc, char **argv) {
+  TestThrowInline();
+  TestThrow();
+}
+#endif
diff --git a/test/asan/TestCases/Windows/use_after_return_linkage.cc b/test/asan/TestCases/Windows/use_after_return_linkage.cc
new file mode 100644
index 0000000..48c5065
--- /dev/null
+++ b/test/asan/TestCases/Windows/use_after_return_linkage.cc
@@ -0,0 +1,12 @@
+// Make sure LIBCMT doesn't accidentally get added to the list of DEFAULTLIB
+// directives.  REQUIRES: asan-dynamic-runtime
+// RUN: %clang_cl_asan -LD %s | FileCheck %s
+// CHECK: Creating library
+// CHECK-NOT: LIBCMT
+
+void foo(int *p) { *p = 42; }
+
+__declspec(dllexport) void bar() {
+  int x;
+  foo(&x);
+}
diff --git a/test/asan/TestCases/asan_and_llvm_coverage_test.cc b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
new file mode 100644
index 0000000..35bdfcb
--- /dev/null
+++ b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
@@ -0,0 +1,10 @@
+// RUN: %clangxx_asan -coverage -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=1 %run %t 2>&1 | FileCheck %s
+// XFAIL: android
+#include <stdio.h>
+int foo() { return 1; }
+int XXX = foo();
+int main() {
+  printf("PASS\n");
+// CHECK: PASS
+}
diff --git a/test/asan/TestCases/atexit_stats.cc b/test/asan/TestCases/atexit_stats.cc
index b5a5fad..be65344 100644
--- a/test/asan/TestCases/atexit_stats.cc
+++ b/test/asan/TestCases/atexit_stats.cc
@@ -7,7 +7,7 @@
 // XFAIL: android
 
 #include <stdlib.h>
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
 #include <malloc.h>
 #endif
 int *p1 = (int*)malloc(900);
diff --git a/test/asan/TestCases/debug_locate.cc b/test/asan/TestCases/debug_locate.cc
new file mode 100644
index 0000000..5971a77
--- /dev/null
+++ b/test/asan/TestCases/debug_locate.cc
@@ -0,0 +1,80 @@
+// Checks the ASan memory address type debugging API, makes sure it returns
+// the correct memory type for heap, stack, global and shadow addresses and
+// that it correctly finds out which region (and name and size) the address
+// belongs to.
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int global_var;
+
+int main() {
+  int local_var;
+  char *heap_ptr = (char *)malloc(10);
+
+  char name[100];
+  void *region_address;
+  size_t region_size;
+  const char *type;
+
+  type = __asan_locate_address(&global_var, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(name, "global_var"));
+  assert(0 == strcmp(type, "global"));
+  assert(region_address == &global_var);
+  assert(region_size == sizeof(global_var));
+
+  type = __asan_locate_address((char *)(&global_var)+1, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(name, "global_var"));
+  assert(0 == strcmp(type, "global"));
+  assert(region_address == &global_var);
+  assert(region_size == sizeof(global_var));
+
+  type = __asan_locate_address(&local_var, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(name, "local_var"));
+  assert(0 == strcmp(type, "stack"));
+  assert(region_address == &local_var);
+  assert(region_size == sizeof(local_var));
+
+  type = __asan_locate_address((char *)(&local_var)+1, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(name, "local_var"));
+  assert(0 == strcmp(type, "stack"));
+  assert(region_address == &local_var);
+  assert(region_size == sizeof(local_var));
+
+  type = __asan_locate_address(heap_ptr, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(type, "heap"));
+  assert(region_address == heap_ptr);
+  assert(10 == region_size);
+
+  type = __asan_locate_address(heap_ptr+1, name, 100,
+                               &region_address, &region_size);
+  assert(0 == strcmp(type, "heap"));
+  assert(region_address == heap_ptr);
+  assert(10 == region_size);
+
+  size_t shadow_scale;
+  size_t shadow_offset;
+  __asan_get_shadow_mapping(&shadow_scale, &shadow_offset);
+
+  uintptr_t shadow_ptr = (((uintptr_t)heap_ptr) >> shadow_scale)
+                         + shadow_offset;
+  type = __asan_locate_address((void *)shadow_ptr, NULL, 0, NULL, NULL);
+  assert((0 == strcmp(type, "high shadow")) || 0 == strcmp(type, "low shadow"));
+
+  uintptr_t shadow_gap = (shadow_ptr >> shadow_scale) + shadow_offset;
+  type = __asan_locate_address((void *)shadow_gap, NULL, 0, NULL, NULL);
+  assert(0 == strcmp(type, "shadow gap"));
+
+  free(heap_ptr);
+
+  return 0;
+}
diff --git a/test/asan/TestCases/debug_mapping.cc b/test/asan/TestCases/debug_mapping.cc
new file mode 100644
index 0000000..f96abf6
--- /dev/null
+++ b/test/asan/TestCases/debug_mapping.cc
@@ -0,0 +1,24 @@
+// Checks that the debugging API returns correct shadow scale and offset.
+// RUN: %clangxx_asan -O %s -o %t
+// RUN: env ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// printed because of verbosity=1
+// CHECK: SHADOW_SCALE: [[SCALE:[0-9]+]]
+// CHECK: SHADOW_OFFSET: [[OFFSET:[0-9]+]]
+
+int main() {
+  size_t scale, offset;
+  __asan_get_shadow_mapping(&scale, &offset);
+
+  fprintf(stderr, "scale: %lx\n", scale);
+  fprintf(stderr, "offset: %lx\n", offset);
+
+  // CHECK: scale: [[SCALE]]
+  // CHECK: offset: [[OFFSET]]
+
+  return 0;
+}
diff --git a/test/asan/TestCases/debug_ppc64_mapping.cc b/test/asan/TestCases/debug_ppc64_mapping.cc
new file mode 100644
index 0000000..3ddd3e1
--- /dev/null
+++ b/test/asan/TestCases/debug_ppc64_mapping.cc
@@ -0,0 +1,37 @@
+// RUN: %clang_asan -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=verbosity=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64-V0
+// RUN: env ASAN_OPTIONS=verbosity=2 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64
+// REQUIRES: powerpc64-supported-target
+
+#include <stdio.h>
+
+int main() {
+// CHECK-PPC64: || `[{{0x0a0|0x040}}000000000, {{0x3ff|0x0ff}}fffffffff]` || HighMem    ||
+// CHECK-PPC64: || `[{{0x034|0x028}}000000000, {{0x09f|0x03f}}fffffffff]` || HighShadow ||
+// CHECK-PPC64: || `[{{0x024|0x024}}000000000, {{0x033|0x027}}fffffffff]` || ShadowGap  ||
+// CHECK-PPC64: || `[0x020000000000, 0x023fffffffff]`       || LowShadow  ||
+// CHECK-PPC64: || `[0x000000000000, 0x01ffffffffff]`       || LowMem     ||
+//
+  printf("ppc64 eyecatcher \n");
+// CHECK-PPC64-V0: ppc64 eyecatcher
+
+  return 0;
+}
+
+/*
+ * Two different signatures noted at the time of writing.
+Newish kernel: (64TB address range support, starting with kernel version 3.7)
+|| `[0x0a0000000000, 0x3fffffffffff]` || HighMem    ||
+|| `[0x034000000000, 0x09ffffffffff]` || HighShadow ||
+|| `[0x024000000000, 0x033fffffffff]` || ShadowGap  ||
+|| `[0x020000000000, 0x023fffffffff]` || LowShadow  ||
+|| `[0x000000000000, 0x01ffffffffff]` || LowMem     ||
+
+Oldish kernel:
+|| `[0x040000000000, 0x0fffffffffff]` || HighMem    ||
+|| `[0x028000000000, 0x03ffffffffff]` || HighShadow ||
+|| `[0x024000000000, 0x027fffffffff]` || ShadowGap  ||
+|| `[0x020000000000, 0x023fffffffff]` || LowShadow  ||
+|| `[0x000000000000, 0x01ffffffffff]` || LowMem     ||
+*/
+
diff --git a/test/asan/TestCases/debug_report.cc b/test/asan/TestCases/debug_report.cc
new file mode 100644
index 0000000..acf52f9
--- /dev/null
+++ b/test/asan/TestCases/debug_report.cc
@@ -0,0 +1,48 @@
+// Checks that the ASan debugging API for getting report information
+// returns correct values.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  char *heap_ptr = (char *)malloc(10);
+  free(heap_ptr);
+  int present = __asan_report_present();
+  fprintf(stderr, "%s\n", (present == 0) ? "no report" : "");
+  // CHECK: no report
+  heap_ptr[0] = 'A'; // BOOM
+  return 0;
+}
+
+void __asan_on_error() {
+  int present = __asan_report_present();
+  void *pc = __asan_get_report_pc();
+  void *bp = __asan_get_report_bp();
+  void *sp = __asan_get_report_sp();
+  void *addr = __asan_get_report_address();
+  int is_write = __asan_get_report_access_type();
+  size_t access_size = __asan_get_report_access_size();
+  const char *description = __asan_get_report_description();
+
+  fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
+  // CHECK: report
+  fprintf(stderr, "pc: %p\n", pc);
+  // CHECK: pc: 0x[[PC:[0-9a-f]+]]
+  fprintf(stderr, "bp: %p\n", bp);
+  // CHECK: bp: 0x[[BP:[0-9a-f]+]]
+  fprintf(stderr, "sp: %p\n", sp);
+  // CHECK: sp: 0x[[SP:[0-9a-f]+]]
+  fprintf(stderr, "addr: %p\n", addr);
+  // CHECK: addr: 0x[[ADDR:[0-9a-f]+]]
+  fprintf(stderr, "type: %s\n", (is_write ? "write" : "read"));
+  // CHECK: type: write
+  fprintf(stderr, "access_size: %ld\n", access_size);
+  // CHECK: access_size: 1
+  fprintf(stderr, "description: %s\n", description);
+  // CHECK: description: heap-use-after-free
+}
+
+// CHECK: AddressSanitizer: heap-use-after-free on address {{0x0*}}[[ADDR]] at pc {{0x0*}}[[PC]] bp {{0x0*}}[[BP]] sp {{0x0*}}[[SP]]
+// CHECK: WRITE of size 1 at {{0x0*}}[[ADDR]] thread T0
diff --git a/test/asan/TestCases/debug_stacks.cc b/test/asan/TestCases/debug_stacks.cc
new file mode 100644
index 0000000..57bb546
--- /dev/null
+++ b/test/asan/TestCases/debug_stacks.cc
@@ -0,0 +1,62 @@
+// Check that the stack trace debugging API works and returns correct
+// malloc and free stacks.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char *mem;
+void func1() {
+  mem = (char *)malloc(10);
+}
+
+void func2() {
+  free(mem);
+}
+
+int main() {
+  func1();
+  func2();
+
+  void *trace[100];
+  size_t num_frames = 100;
+  int thread_id;
+  num_frames = __asan_get_alloc_stack(mem, trace, num_frames, &thread_id);
+
+  fprintf(stderr, "alloc stack retval %s\n", (num_frames > 0 && num_frames < 10)
+          ? "ok" : "");
+  // CHECK: alloc stack retval ok
+  fprintf(stderr, "thread id = %d\n", thread_id);
+  // CHECK: thread id = 0
+  fprintf(stderr, "0x%lx\n", trace[0]);
+  // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
+  fprintf(stderr, "0x%lx\n", trace[1]);
+  // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
+
+  num_frames = 100;
+  num_frames = __asan_get_free_stack(mem, trace, num_frames, &thread_id);
+
+  fprintf(stderr, "free stack retval %s\n", (num_frames > 0 && num_frames < 10)
+          ? "ok" : "");
+  // CHECK: free stack retval ok
+  fprintf(stderr, "thread id = %d\n", thread_id);
+  // CHECK: thread id = 0
+  fprintf(stderr, "0x%lx\n", trace[0]);
+  // CHECK: [[FREE_FRAME_0:0x[0-9a-f]+]]
+  fprintf(stderr, "0x%lx\n", trace[1]);
+  // CHECK: [[FREE_FRAME_1:0x[0-9a-f]+]]
+
+  mem[0] = 'A'; // BOOM
+
+  // CHECK: ERROR: AddressSanitizer: heap-use-after-free
+  // CHECK: WRITE of size 1 at 0x{{.*}}
+  // CHECK: freed by thread T0 here:
+  // CHECK: #0 [[FREE_FRAME_0]]
+  // CHECK: #1 [[FREE_FRAME_1]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK: #0 [[ALLOC_FRAME_0]]
+  // CHECK: #1 [[ALLOC_FRAME_1]]
+
+  return 0;
+}
diff --git a/test/asan/TestCases/deep_call_stack.cc b/test/asan/TestCases/deep_call_stack.cc
index c306775..789f234 100644
--- a/test/asan/TestCases/deep_call_stack.cc
+++ b/test/asan/TestCases/deep_call_stack.cc
@@ -1,7 +1,7 @@
 // Check that UAR mode can handle very deep recusrion.
 // export ASAN_OPTIONS=detect_stack_use_after_return=1
 // RUN: %clangxx_asan -O2 %s -o %t && \
-// RUN:   %run %t 2>&1 | FileCheck %s
+// RUN:   (ulimit -s 4096; %run %t) 2>&1 | FileCheck %s
 // Also check that use_sigaltstack+verbosity doesn't crash.
 // RUN: env ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %run %t  | FileCheck %s
 #include <stdio.h>
@@ -17,9 +17,9 @@
 }
 
 int main(int argc, char **argv) {
-  RecursiveFunc(40000, 0);
+  RecursiveFunc(15000, 0);
   return 0;
 }
-// CHECK: [40000] ptr:
-// CHECK: [20000] ptr:
-// CHECK: [00000] ptr
+// CHECK: [15000] ptr:
+// CHECK: [07000] ptr:
+// CHECK: [00000] ptr:
diff --git a/test/asan/TestCases/deep_stack_uaf.cc b/test/asan/TestCases/deep_stack_uaf.cc
index accb70c..3e88d69 100644
--- a/test/asan/TestCases/deep_stack_uaf.cc
+++ b/test/asan/TestCases/deep_stack_uaf.cc
@@ -3,6 +3,7 @@
 // RUN: %clangxx_asan -O0 %s -o %t 2>&1
 // RUN: env ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 #include <stdlib.h>
 #include <stdio.h>
 
@@ -26,7 +27,10 @@
   DeepFree<200>::free(x);
   return x[5];
   // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
-  // CHECK: DeepFree<36>
-  // CHECK: DeepFree<98>
-  // CHECK: DeepFree<115>
+  // The libcxxrt demangling procedure on FreeBSD 9.2 incorrectly appends
+  // extra 'E' characters to the end of template arguments; see:
+  // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=192115
+  // CHECK: {{DeepFree<36>|DeepFree<36E>}}
+  // CHECK: {{DeepFree<98>|DeepFree<98E>}}
+  // CHECK: {{DeepFree<115>|DeepFree<115E>}}
 }
diff --git a/test/asan/TestCases/describe_address.cc b/test/asan/TestCases/describe_address.cc
new file mode 100644
index 0000000..868c0eb
--- /dev/null
+++ b/test/asan/TestCases/describe_address.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+
+int global;
+
+int main(int argc, char *argv[]) {
+  int stack;
+  int *heap = new int[100];
+  __asan_describe_address(heap);
+  // CHECK: {{.*}} is located 0 bytes inside of 400-byte region
+  // CHECK: allocated by thread T{{.*}} here
+  __asan_describe_address(&stack);
+  // CHECK: Address {{.*}} is located in stack of thread T{{.*}} at offset {{.*}}
+  __asan_describe_address(&global);
+  // CHECK: {{.*}} is located 0 bytes inside of global variable 'global'
+  delete[] heap;
+  return 0;
+}
diff --git a/test/asan/TestCases/dlclose-test.cc b/test/asan/TestCases/dlclose-test.cc
index 07d57b1..094453f 100644
--- a/test/asan/TestCases/dlclose-test.cc
+++ b/test/asan/TestCases/dlclose-test.cc
@@ -15,13 +15,13 @@
 // REQUIRES: x86_64-supported-target,i386-supported-target
 
 // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O0 %s -ldl -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O1 %s -ldl -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O2 %s -ldl -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
-// RUN: %clangxx_asan -O3 %s -ldl -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
 
 #if !defined(SHARED_LIB)
 #include <assert.h>
@@ -66,7 +66,7 @@
   size_t page_beg = ((size_t)addr) & ~(PageSize - 1);
   void *res = mmap((void*)(page_beg), PageSize,
                    PROT_READ | PROT_WRITE,
-                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, -1, 0);
   if (res == (char*)-1L) {
     printf("failed to mmap\n");
     return 1;
diff --git a/test/asan/TestCases/double-free.cc b/test/asan/TestCases/double-free.cc
index 212d7ea..f0dd291 100644
--- a/test/asan/TestCases/double-free.cc
+++ b/test/asan/TestCases/double-free.cc
@@ -5,6 +5,7 @@
 // RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
 // RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/test/asan/TestCases/dump_instruction_bytes.cc b/test/asan/TestCases/dump_instruction_bytes.cc
new file mode 100644
index 0000000..981e3c3
--- /dev/null
+++ b/test/asan/TestCases/dump_instruction_bytes.cc
@@ -0,0 +1,20 @@
+// Check that ASan prints the faulting instruction bytes on
+// dump_instruction_bytes=1
+// RUN: %clangxx_asan  %s -o %t
+// RUN: env ASAN_OPTIONS=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP
+//
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+int main() {
+#if defined(__x86_64__)
+  asm("movq $0, %rax");
+  asm("movl $0xcafebabe, 0x0(%rax)");
+#elif defined(i386)
+  asm("movl $0, %eax");
+  asm("movl $0xcafebabe, 0x0(%eax)");
+#endif
+  // CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca
+  // CHECK-NODUMP-NOT: First 16 instruction bytes
+  return 0;
+}
diff --git a/test/asan/TestCases/gc-test.cc b/test/asan/TestCases/gc-test.cc
index ffbea85..08efd4f 100644
--- a/test/asan/TestCases/gc-test.cc
+++ b/test/asan/TestCases/gc-test.cc
@@ -2,6 +2,7 @@
 // RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
 // RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
 // REQUIRES: stable-runtime
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <assert.h>
 #include <stdio.h>
diff --git a/test/asan/TestCases/global-demangle.cc b/test/asan/TestCases/global-demangle.cc
index 2bfa0d1..5f7ff91 100644
--- a/test/asan/TestCases/global-demangle.cc
+++ b/test/asan/TestCases/global-demangle.cc
@@ -1,6 +1,3 @@
-// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=264
-// XFAIL: android
-//
 // RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
 
 namespace XXX {
diff --git a/test/asan/TestCases/global-location.cc b/test/asan/TestCases/global-location.cc
index 54f2055..795e50b 100644
--- a/test/asan/TestCases/global-location.cc
+++ b/test/asan/TestCases/global-location.cc
@@ -1,6 +1,3 @@
-// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=264
-// XFAIL: android
-
 // RUN: %clangxx_asan -O2 %s -o %t
 // RUN: not %run %t g 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=GLOB
 // RUN: not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CLASS_STATIC
@@ -27,7 +24,7 @@
   case 'c': return C::array[one * 11];
   case 'f':
     static int array[10];
-    // FUNC_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'main::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:16' {{.*}} of size 40
+    // FUNC_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:16' {{.*}} of size 40
     memset(array, 0, 10);
     return array[one * 11];
   case 'l':
diff --git a/test/asan/TestCases/heap-overflow-large.cc b/test/asan/TestCases/heap-overflow-large.cc
new file mode 100644
index 0000000..eb2fcc3
--- /dev/null
+++ b/test/asan/TestCases/heap-overflow-large.cc
@@ -0,0 +1,23 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=183
+
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 12 2>&1 | FileCheck %s
+// RUN: not %run %t 100 2>&1 | FileCheck %s
+// RUN: not %run %t 10000 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+  fprintf(stderr, "main\n");
+  int *x = new int[5];
+  memset(x, 0, sizeof(x[0]) * 5);
+  int index = atoi(argv[1]);
+  int res = x[index];
+  // CHECK: main
+  // CHECK-NOT: CHECK failed
+  delete[] x;
+  return res ? res : 1;
+}
diff --git a/test/asan/TestCases/Linux/heavy_uar_test.cc b/test/asan/TestCases/heavy_uar_test.cc
similarity index 97%
rename from test/asan/TestCases/Linux/heavy_uar_test.cc
rename to test/asan/TestCases/heavy_uar_test.cc
index bfea520..9068da2 100644
--- a/test/asan/TestCases/Linux/heavy_uar_test.cc
+++ b/test/asan/TestCases/heavy_uar_test.cc
@@ -7,6 +7,7 @@
 
 // FIXME: Fix this test under GCC.
 // REQUIRES: Clang
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdio.h>
 #include <string.h>
diff --git a/test/asan/TestCases/Linux/interception_failure_test.cc b/test/asan/TestCases/interception_failure_test.cc
similarity index 100%
rename from test/asan/TestCases/Linux/interception_failure_test.cc
rename to test/asan/TestCases/interception_failure_test.cc
diff --git a/test/asan/TestCases/intra-object-overflow.cc b/test/asan/TestCases/intra-object-overflow.cc
new file mode 100644
index 0000000..e48a261
--- /dev/null
+++ b/test/asan/TestCases/intra-object-overflow.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-field-padding=1  %s -o %t
+// RUN: not %run %t 11 2>&1 | FileCheck %s
+// RUN: %run %t 10
+//
+// FIXME: fix 32-bits.
+// REQUIRES: asan-64-bits
+#include <stdio.h>
+#include <stdlib.h>
+class Foo {
+ public:
+  Foo() : pre1(1), pre2(2), post1(3), post2(4) {
+  }
+  virtual ~Foo() {
+  }
+  void set(int i, int val) { a[i] = val; }
+// CHECK: ERROR: AddressSanitizer: intra-object-overflow
+// CHECK: #0 {{.*}}Foo::set{{.*}}intra-object-overflow.cc:[[@LINE-2]]
+ private:
+  int pre1, pre2;
+  int a[11];
+  int post1, post2;
+};
+
+int main(int argc, char **argv) {
+  int idx = argc == 2 ? atoi(argv[1]) : 0;
+  Foo *foo = new Foo;
+  foo->set(idx, 42);
+// CHECK: #1 {{.*}}main{{.*}}intra-object-overflow.cc:[[@LINE-1]]
+// CHECK: is located 84 bytes inside of 128-byte region
+  delete foo;
+}
diff --git a/test/asan/TestCases/invalid-free.cc b/test/asan/TestCases/invalid-free.cc
index 34018fb..cb545cc 100644
--- a/test/asan/TestCases/invalid-free.cc
+++ b/test/asan/TestCases/invalid-free.cc
@@ -5,6 +5,7 @@
 // RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
 // RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/test/asan/TestCases/large_func_test.cc b/test/asan/TestCases/large_func_test.cc
index 0d651f6..6b592f8 100644
--- a/test/asan/TestCases/large_func_test.cc
+++ b/test/asan/TestCases/large_func_test.cc
@@ -3,6 +3,7 @@
 // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 __attribute__((noinline))
diff --git a/test/asan/TestCases/longjmp.cc b/test/asan/TestCases/longjmp.cc
new file mode 100644
index 0000000..5472330
--- /dev/null
+++ b/test/asan/TestCases/longjmp.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sanitizer/asan_interface.h>
+
+static jmp_buf buf;
+
+int main() {
+  char x[32];
+  fprintf(stderr, "\nTestLongJmp\n");
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  if (0 == setjmp(buf))
+    longjmp(buf, 1);
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
diff --git a/test/asan/TestCases/lsan_annotations.cc b/test/asan/TestCases/lsan_annotations.cc
index 84c2878..f52b0ff 100644
--- a/test/asan/TestCases/lsan_annotations.cc
+++ b/test/asan/TestCases/lsan_annotations.cc
@@ -1,6 +1,3 @@
-// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
-// XFAIL: android
-//
 // Check that LSan annotations work fine.
 // RUN: %clangxx_asan -O0 %s -o %t && %run %t
 // RUN: %clangxx_asan -O3 %s -o %t && %run %t
diff --git a/test/asan/TestCases/malloc_context_size.cc b/test/asan/TestCases/malloc_context_size.cc
index fb158c6..0d9f315 100644
--- a/test/asan/TestCases/malloc_context_size.cc
+++ b/test/asan/TestCases/malloc_context_size.cc
@@ -1,31 +1,21 @@
 // RUN: %clangxx_asan -O0 %s -o %t
-// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
-// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
 // RUN: env ASAN_OPTIONS=malloc_context_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=TWO
 
 int main() {
   char *x = new char[20];
   delete[] x;
   return x[0];
-  // We need to keep duplicate lines with different 'CHECK-%os' prefixes,
-  // otherwise FileCheck barks on missing 'CHECK-%os' before 'CHECK-%os-NEXT'.
 
-  // CHECK-Linux: freed by thread T{{.*}} here:
-  // CHECK-Linux-NEXT: #0 0x{{.*}} in operator delete[]
-  // CHECK-Darwin: freed by thread T{{.*}} here:
-  // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__ZdaPv
-  // CHECK-Windows: freed by thread T{{.*}} here:
-  // CHECK-Windows-NEXT: #0 0x{{.*}} in operator delete[]
+  // CHECK: freed by thread T{{.*}} here:
+  // CHECK-NEXT: #0 0x{{.*}} in {{operator delete( )?\[\]|wrap__ZdaPv}}
   // CHECK-NOT: #1 0x{{.*}}
 
-  // CHECK-Linux: previously allocated by thread T{{.*}} here:
-  // CHECK-Linux-NEXT: #0 0x{{.*}} in operator new[]
-  // CHECK-Darwin: previously allocated by thread T{{.*}} here:
-  // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__Znam
-  // CHECK-Windows: previously allocated by thread T{{.*}} here:
-  // CHECK-Windows-NEXT: #0 0x{{.*}} in operator new[]
+  // CHECK: previously allocated by thread T{{.*}} here:
+  // CHECK-NEXT: #0 0x{{.*}} in {{operator new( )?\[\]|wrap__Znam}}
   // CHECK-NOT: #1 0x{{.*}}
 
   // CHECK: SUMMARY: AddressSanitizer: heap-use-after-free
diff --git a/test/asan/TestCases/mmap_limit_mb.cc b/test/asan/TestCases/mmap_limit_mb.cc
index 1d697ef..d4ffb2e 100644
--- a/test/asan/TestCases/mmap_limit_mb.cc
+++ b/test/asan/TestCases/mmap_limit_mb.cc
@@ -1,12 +1,12 @@
 // Test the mmap_limit_mb flag.
 //
 // RUN: %clangxx_asan -O2 %s -o %t
-// RUN: %run %t 100 16
-// RUN: %run %t 100 1000000
-// RUN: env ASAN_OPTIONS=mmap_limit_mb=500 %run %t 50 16
-// RUN: env ASAN_OPTIONS=mmap_limit_mb=500 %run %t 50 1000000
-// RUN: env ASAN_OPTIONS=mmap_limit_mb=500 not %run %t 500 16 2>&1 | FileCheck %s
-// RUN: env ASAN_OPTIONS=mmap_limit_mb=500 not %run %t 500 1000000 2>&1 | FileCheck %s
+// RUN: %run %t 20 16
+// RUN: %run %t 30 1000000
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 %run %t 20 16
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 %run %t 20 1000000
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 not %run %t 500 16 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 not %run %t 500 1000000 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
 
 #include <assert.h>
diff --git a/test/asan/TestCases/null_deref.cc b/test/asan/TestCases/null_deref.cc
index e80657f..875d65f 100644
--- a/test/asan/TestCases/null_deref.cc
+++ b/test/asan/TestCases/null_deref.cc
@@ -1,19 +1,19 @@
-// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
 
 __attribute__((noinline))
 static void NullDeref(int *ptr) {
   // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
   // CHECK:   {{0x0*000.. .*pc 0x.*}}
   ptr[10]++;  // BOOM
-  // atos on Mac cannot extract the symbol name correctly.
-  // CHECK-Linux: {{    #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]]
-  // CHECK-Darwin: {{    #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
+  // atos on Mac cannot extract the symbol name correctly. Also, on FreeBSD 9.2
+  // the demangling function rejects local names with 'L' in front of them.
+  // CHECK: {{    #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
 }
 int main() {
   NullDeref((int*)0);
   // CHECK: {{    #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
-  // CHECK: {{AddressSanitizer can not provide additional info.}}
+  // CHECK: AddressSanitizer can not provide additional info.
 }
diff --git a/test/asan/TestCases/sanity_check_pure_c.c b/test/asan/TestCases/sanity_check_pure_c.c
index 01d87e7..c3a43c8 100644
--- a/test/asan/TestCases/sanity_check_pure_c.c
+++ b/test/asan/TestCases/sanity_check_pure_c.c
@@ -6,6 +6,7 @@
 // RUN: %clang_asan -O2 %s -pie -fPIE -o %t
 // RUN: not %run %t 2>&1 | FileCheck %s
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 int main() {
diff --git a/test/asan/TestCases/stack-overflow.cc b/test/asan/TestCases/stack-overflow.cc
index 234e3c7..9d7c72c 100644
--- a/test/asan/TestCases/stack-overflow.cc
+++ b/test/asan/TestCases/stack-overflow.cc
@@ -74,7 +74,7 @@
   if (y)
     recursive_func(buf);
   x = 1; // prevent tail call optimization
-  // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* sp 0x.* bp 0x.* T.*\)}}
+  // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}}
   // If stack overflow happens during function prologue, stack trace may be
   // corrupted. Unwind tables are not always 100% exact there.
   // For this reason, we don't do any further checks.
diff --git a/test/asan/TestCases/strncpy-overflow.cc b/test/asan/TestCases/strncpy-overflow.cc
index 8001047..651ae22 100644
--- a/test/asan/TestCases/strncpy-overflow.cc
+++ b/test/asan/TestCases/strncpy-overflow.cc
@@ -5,6 +5,7 @@
 
 // REQUIRES: compiler-rt-optimized
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <string.h>
 #include <stdlib.h>
diff --git a/test/asan/TestCases/throw_catch.cc b/test/asan/TestCases/throw_catch.cc
index f35378d..7e0d76d 100644
--- a/test/asan/TestCases/throw_catch.cc
+++ b/test/asan/TestCases/throw_catch.cc
@@ -4,10 +4,7 @@
 // XFAIL: win32
 
 #include <assert.h>
-#include <setjmp.h>
-#include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
 #include <sanitizer/asan_interface.h>
 
 __attribute__((noinline))
@@ -31,6 +28,7 @@
   char x[32];
   fprintf(stderr, "Before: %p poisoned: %d\n", &x,
           __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
   ThrowAndCatch();
   fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
           __asan_address_is_poisoned(x + 32));
@@ -43,6 +41,7 @@
   char x[32];
   fprintf(stderr, "Before: %p poisoned: %d\n", &x,
           __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
   try {
     Throw();
   } catch(...) {
@@ -55,24 +54,7 @@
   assert(!__asan_address_is_poisoned(x + 32));
 }
 
-static jmp_buf buf;
-
-void TestLongJmp() {
-  char x[32];
-  fprintf(stderr, "\nTestLongJmp\n");
-  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
-          __asan_address_is_poisoned(x + 32));
-  if (0 == setjmp(buf))
-    longjmp(buf, 1);
-  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
-          __asan_address_is_poisoned(x + 32));
-  // FIXME: Invert this assertion once we fix
-  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
-  assert(!__asan_address_is_poisoned(x + 32));
-}
-
 int main(int argc, char **argv) {
-  TestThrow();
   TestThrowInline();
-  TestLongJmp();
+  TestThrow();
 }
diff --git a/test/asan/TestCases/use-after-delete.cc b/test/asan/TestCases/use-after-delete.cc
index f22e9e5..8fdec8d 100644
--- a/test/asan/TestCases/use-after-delete.cc
+++ b/test/asan/TestCases/use-after-delete.cc
@@ -3,6 +3,7 @@
 // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 int main() {
diff --git a/test/asan/TestCases/use-after-free-right.cc b/test/asan/TestCases/use-after-free-right.cc
index 68ac158..f714b44 100644
--- a/test/asan/TestCases/use-after-free-right.cc
+++ b/test/asan/TestCases/use-after-free-right.cc
@@ -3,6 +3,7 @@
 // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 // Test use-after-free report in the case when access is at the right border of
 // the allocation.
diff --git a/test/asan/TestCases/use-after-free.cc b/test/asan/TestCases/use-after-free.cc
index 0cd87ee..7bc225b 100644
--- a/test/asan/TestCases/use-after-free.cc
+++ b/test/asan/TestCases/use-after-free.cc
@@ -3,6 +3,7 @@
 // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
 // XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <stdlib.h>
 int main() {
diff --git a/test/asan/TestCases/zero_page_pc.cc b/test/asan/TestCases/zero_page_pc.cc
new file mode 100644
index 0000000..5810a9f
--- /dev/null
+++ b/test/asan/TestCases/zero_page_pc.cc
@@ -0,0 +1,12 @@
+// Check that ASan correctly detects SEGV on the zero page.
+// RUN: %clangxx_asan %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+typedef void void_f();
+int main() {
+  void_f *func = (void_f *)0x4;
+  func();
+  // x86 reports the SEGV with both address=4 and pc=4.
+  // PowerPC64 reports it with address=4 but pc still in main().
+  // CHECK: {{AddressSanitizer: SEGV.*(address|pc) 0x0*4}}
+  return 0;
+}
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index db2459f..2acc542 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -26,18 +26,23 @@
 # GCC-ASan doesn't link in all the necessary libraries automatically, so
 # we have to do it ourselves.
 if config.compiler_id == 'GNU':
-  extra_linkflags = ["-pthread", "-lstdc++", "-ldl"]
+  extra_linkflags = ["-pthread", "-lstdc++"]
 else:
   extra_linkflags = []
+
+# There is no libdl on FreeBSD.
+if config.compiler_id == 'GNU' and config.host_os != 'FreeBSD':
+  extra_linkflags += ["-ldl"]
+
 # Setup default compiler flags used with -fsanitize=address option.
 # FIXME: Review the set of required flags and check if it can be reduced.
 target_cflags = [get_required_attr(config, "target_cflags")] + extra_linkflags
 target_cxxflags = config.cxx_mode_flags + target_cflags
-clang_asan_static_cflags = ["-fsanitize=address",
+clang_asan_static_cflags = (["-fsanitize=address",
                             "-mno-omit-leaf-frame-pointer",
                             "-fno-omit-frame-pointer",
-                            "-fno-optimize-sibling-calls",
-                            "-g"] + target_cflags
+                            "-fno-optimize-sibling-calls"] +
+                            config.debug_info_flags + target_cflags)
 clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags
 
 if config.asan_dynamic:
@@ -50,7 +55,7 @@
   config.available_features.add("asan-static-runtime")
 
 asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir")
-if config.android == "TRUE":
+if config.android == "1":
   config.available_features.add('android')
   clang_wrapper = os.path.join(asan_lit_source_dir,
                                "android_commands", "android_compile.py") + " "
@@ -76,9 +81,13 @@
                             "-WX",
                             "-D_HAS_EXCEPTIONS=0",
                             "-Zi"] + target_cflags
+  if config.asan_dynamic:
+    clang_cl_asan_cxxflags.append("-MD")
   clang_invocation = build_invocation(clang_cl_asan_cxxflags)
   clang_cl_invocation = clang_invocation.replace("clang.exe","clang-cl.exe")
   config.substitutions.append( ("%clang_cl_asan ", clang_cl_invocation) )
+  config.substitutions.append( ("%asan_dll_thunk",
+                               os.path.join(config.compiler_rt_libdir, "clang_rt.asan_dll_thunk-i386.lib")))
 
 # FIXME: De-hardcode this path.
 asan_source_dir = os.path.join(
@@ -99,13 +108,11 @@
 config.substitutions.append( ("%sancov", python_exec + " " + sancov + " ") )
 
 # Determine kernel bitness
-if config.host_arch.find('64') != -1 and config.android != "TRUE":
+if config.host_arch.find('64') != -1 and config.android != "1":
   kernel_bits = '64'
 else:
   kernel_bits = '32'
 
-# Define CHECK-%os to check for OS-dependent output.
-config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
 config.substitutions.append( ('CHECK-%kernel_bits', ("CHECK-kernel-" + kernel_bits + "-bits")))
 
 config.available_features.add("asan-" + config.bits + "-bits")
@@ -134,6 +141,7 @@
 if config.host_os == 'Darwin':
   config.suffixes.append('.mm')
 
-# AddressSanitizer tests are currently supported on Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
+# AddressSanitizer tests are currently supported on Linux, Darwin and
+# FreeBSD only.
+if config.host_os not in ['Linux', 'Darwin', 'FreeBSD']:
   config.unsupported = True
diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in
index 76e0c55..332f9ad 100644
--- a/test/asan/lit.site.cfg.in
+++ b/test/asan/lit.site.cfg.in
@@ -6,9 +6,9 @@
 config.asan_lit_source_dir = "@ASAN_LIT_SOURCE_DIR@"
 config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@"
 config.clang = "@ASAN_TEST_TARGET_CC@"
-config.llvm_tools_dir = "@ASAN_TEST_LLVM_TOOLS_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_BINARY_DIR@"
 config.bits = "@ASAN_TEST_BITS@"
-config.android = "@CAN_TARGET_arm_android@"
+config.android = "@ANDROID@"
 config.asan_dynamic = @ASAN_TEST_DYNAMIC@
 config.target_arch = "@ASAN_TEST_TARGET_ARCH@"
 
diff --git a/test/dfsan/custom.c b/test/dfsan/custom.cc
similarity index 80%
rename from test/dfsan/custom.c
rename to test/dfsan/custom.cc
index 8a7a548..d7bb3e3 100644
--- a/test/dfsan/custom.c
+++ b/test/dfsan/custom.cc
@@ -5,7 +5,6 @@
 
 // Tests custom implementations of various glibc functions.
 
-#define _GNU_SOURCE
 #include <sanitizer/dfsan_interface.h>
 
 #include <arpa/inet.h>
@@ -18,6 +17,7 @@
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/select.h>
@@ -256,12 +256,12 @@
   // With any luck this sequence of calls will cause calloc to return the same
   // pointer both times.  This is probably the best we can do to test this
   // function.
-  char *crv = calloc(4096, 1);
+  char *crv = (char *) calloc(4096, 1);
   ASSERT_ZERO_LABEL(crv[0]);
   dfsan_set_label(i_label, crv, 100);
   free(crv);
 
-  crv = calloc(4096, 1);
+  crv = (char *) calloc(4096, 1);
   ASSERT_ZERO_LABEL(crv[0]);
   free(crv);
 }
@@ -342,14 +342,14 @@
 
 static int write_callback_count = 0;
 static int last_fd;
-static const void *last_buf;
+static const unsigned char *last_buf;
 static size_t last_count;
 
 void write_callback(int fd, const void *buf, size_t count) {
   write_callback_count++;
 
   last_fd = fd;
-  last_buf = buf;
+  last_buf = (const unsigned char*) buf;
   last_count = count;
 }
 
@@ -376,7 +376,7 @@
   dfsan_set_label(i_label, &fd, sizeof(fd));
   dfsan_set_label(j_label, &(buf[3]), 1);
   dfsan_set_label(k_label, &buf_len, sizeof(buf_len));
-  
+
   res = write(fd, buf, buf_len);
   assert(write_callback_count == 2);
   ASSERT_READ_ZERO_LABEL(&res, sizeof(res));
@@ -694,11 +694,11 @@
   dfsan_set_label(i_label, &str1[3], 1);
   dfsan_set_label(j_label, &str1[4], 1);
 
-  char *crv = memchr(str1, 'r', sizeof(str1));
+  char *crv = (char *) memchr(str1, 'r', sizeof(str1));
   assert(crv == &str1[2]);
   ASSERT_ZERO_LABEL(crv);
 
-  crv = memchr(str1, '1', sizeof(str1));
+  crv = (char *) memchr(str1, '1', sizeof(str1));
   assert(crv == &str1[3]);
 #ifdef STRICT_DATA_DEPENDENCIES
   ASSERT_ZERO_LABEL(crv);
@@ -706,7 +706,7 @@
   ASSERT_LABEL(crv, i_label);
 #endif
 
-  crv = memchr(str1, 'x', sizeof(str1));
+  crv = (char *) memchr(str1, 'x', sizeof(str1));
   assert(!crv);
 #ifdef STRICT_DATA_DEPENDENCIES
   ASSERT_ZERO_LABEL(crv);
@@ -774,6 +774,129 @@
   close(fd);
 }
 
+template <class T>
+void test_sprintf_chunk(const char* expected, const char* format, T arg) {
+  char buf[512];
+  memset(buf, 'a', sizeof(buf));
+
+  char padded_expected[512];
+  strcpy(padded_expected, "foo ");
+  strcat(padded_expected, expected);
+  strcat(padded_expected, " bar");
+
+  char padded_format[512];
+  strcpy(padded_format, "foo ");
+  strcat(padded_format, format);
+  strcat(padded_format, " bar");
+
+  // Non labelled arg.
+  assert(sprintf(buf, padded_format,  arg) == strlen(padded_expected));
+  assert(strcmp(buf, padded_expected) == 0);
+  ASSERT_READ_LABEL(buf, strlen(padded_expected), 0);
+  memset(buf, 'a', sizeof(buf));
+
+  // Labelled arg.
+  dfsan_set_label(i_label, &arg, sizeof(arg));
+  assert(sprintf(buf, padded_format,  arg) == strlen(padded_expected));
+  assert(strcmp(buf, padded_expected) == 0);
+  ASSERT_READ_LABEL(buf, 4, 0);
+  ASSERT_READ_LABEL(buf + 4, strlen(padded_expected) - 8, i_label);
+  ASSERT_READ_LABEL(buf + (strlen(padded_expected) - 4), 4, 0);
+}
+
+void test_sprintf() {
+  char buf[2048];
+  memset(buf, 'a', sizeof(buf));
+
+  // Test formatting (no conversion specifier).
+  assert(sprintf(buf, "Hello world!") == 12);
+  assert(strcmp(buf, "Hello world!") == 0);
+  ASSERT_READ_LABEL(buf, sizeof(buf), 0);
+
+  // Test for extra arguments.
+  assert(sprintf(buf, "Hello world!", 42, "hello") == 12);
+  assert(strcmp(buf, "Hello world!") == 0);
+  ASSERT_READ_LABEL(buf, sizeof(buf), 0);
+
+  // Test formatting & label propagation (multiple conversion specifiers): %s,
+  // %d, %n, %f, and %%.
+  const char* s = "world";
+  int m = 8;
+  int d = 27;
+  dfsan_set_label(k_label, (void *) (s + 1), 2);
+  dfsan_set_label(i_label, &m, sizeof(m));
+  dfsan_set_label(j_label, &d, sizeof(d));
+  int n;
+  int r = sprintf(buf, "hello %s, %-d/%d/%d %f %% %n%d", s, 2014, m, d,
+                  12345.6781234, &n, 1000);
+  assert(r == 42);
+  assert(strcmp(buf, "hello world, 2014/8/27 12345.678123 % 1000") == 0);
+  ASSERT_READ_LABEL(buf, 7, 0);
+  ASSERT_READ_LABEL(buf + 7, 2, k_label);
+  ASSERT_READ_LABEL(buf + 9, 9, 0);
+  ASSERT_READ_LABEL(buf + 18, 1, i_label);
+  ASSERT_READ_LABEL(buf + 19, 1, 0);
+  ASSERT_READ_LABEL(buf + 20, 2, j_label);
+  ASSERT_READ_LABEL(buf + 22, 15, 0);
+  ASSERT_LABEL(r, 0);
+  assert(n == 38);
+
+  // Test formatting & label propagation (single conversion specifier, with
+  // additional length and precision modifiers).
+  test_sprintf_chunk("-559038737", "%d", 0xdeadbeef);
+  test_sprintf_chunk("3735928559", "%u", 0xdeadbeef);
+  test_sprintf_chunk("12345", "%i", 12345);
+  test_sprintf_chunk("751", "%o", 0751);
+  test_sprintf_chunk("babe", "%x", 0xbabe);
+  test_sprintf_chunk("0000BABE", "%.8X", 0xbabe);
+  test_sprintf_chunk("-17", "%hhd", 0xdeadbeef);
+  test_sprintf_chunk("-16657", "%hd", 0xdeadbeef);
+  test_sprintf_chunk("deadbeefdeadbeef", "%lx", 0xdeadbeefdeadbeef);
+  test_sprintf_chunk("0xdeadbeefdeadbeef", "%p",
+                 (void *)  0xdeadbeefdeadbeef);
+  test_sprintf_chunk("18446744073709551615", "%ju", (intmax_t) -1);
+  test_sprintf_chunk("18446744073709551615", "%zu", (size_t) -1);
+  test_sprintf_chunk("18446744073709551615", "%tu", (size_t) -1);
+
+  test_sprintf_chunk("0x1.f9acffa7eb6bfp-4", "%a", 0.123456);
+  test_sprintf_chunk("0X1.F9ACFFA7EB6BFP-4", "%A", 0.123456);
+  test_sprintf_chunk("0.12346", "%.5f", 0.123456);
+  test_sprintf_chunk("0.123456", "%g", 0.123456);
+  test_sprintf_chunk("1.234560e-01", "%e", 0.123456);
+  test_sprintf_chunk("1.234560E-01", "%E", 0.123456);
+  test_sprintf_chunk("0.1234567891234560", "%.16Lf",
+                     (long double) 0.123456789123456);
+
+  test_sprintf_chunk("z", "%c", 'z');
+
+  // %n, %s, %d, %f, and %% already tested
+}
+
+void test_snprintf() {
+  char buf[2048];
+  memset(buf, 'a', sizeof(buf));
+  dfsan_set_label(0, buf, sizeof(buf));
+  const char* s = "world";
+  int y = 2014;
+  int m = 8;
+  int d = 27;
+  dfsan_set_label(k_label, (void *) (s + 1), 2);
+  dfsan_set_label(i_label, &y, sizeof(y));
+  dfsan_set_label(j_label, &m, sizeof(m));
+  int r = snprintf(buf, 19, "hello %s, %-d/%d/%d %f", s, y, m, d,
+                   12345.6781234);
+  // The return value is the number of bytes that would have been written to
+  // the final string if enough space had been available.
+  assert(r == 35);
+  assert(memcmp(buf, "hello world, 2014/", 19) == 0);
+  ASSERT_READ_LABEL(buf, 7, 0);
+  ASSERT_READ_LABEL(buf + 7, 2, k_label);
+  ASSERT_READ_LABEL(buf + 9, 4, 0);
+  ASSERT_READ_LABEL(buf + 13, 4, i_label);
+  ASSERT_READ_LABEL(buf + 17, 2, 0);
+  ASSERT_LABEL(r, 0);
+}
+
 int main(void) {
   i_label = dfsan_create_label("i", 0);
   j_label = dfsan_create_label("j", 0);
@@ -810,7 +933,9 @@
   test_select();
   test_sigaction();
   test_sigemptyset();
+  test_snprintf();
   test_socketpair();
+  test_sprintf();
   test_stat();
   test_strcasecmp();
   test_strchr();
diff --git a/test/dfsan/dump_labels.c b/test/dfsan/dump_labels.c
new file mode 100644
index 0000000..67801af
--- /dev/null
+++ b/test/dfsan/dump_labels.c
@@ -0,0 +1,69 @@
+// RUN: %clang_dfsan -m64 %s -o %t
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout %run %t 2>&1 | FileCheck %s
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK-OOL
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t u 2>&1 | FileCheck %s --check-prefix=CHECK-OOL
+
+// Tests that labels are properly dumped at program termination.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+  int i = 1;
+  dfsan_label i_label = dfsan_create_label("i", 0);
+  dfsan_set_label(i_label, &i, sizeof(i));
+
+  int j = 2;
+  dfsan_label j_label = dfsan_create_label("j", 0);
+  dfsan_set_label(j_label, &j, sizeof(j));
+
+  int k = 3;
+  dfsan_label k_label = dfsan_create_label("k", 0);
+  dfsan_set_label(k_label, &k, sizeof(k));
+
+  dfsan_label ij_label = dfsan_get_label(i + j);
+  dfsan_label ijk_label = dfsan_get_label(i + j + k);
+
+  fprintf(stderr, "i %d j %d k %d ij %d ijk %d\n", i_label, j_label, k_label,
+          ij_label, ijk_label);
+
+  // CHECK: 1 0 0 i
+  // CHECK: 2 0 0 j
+  // CHECK: 3 0 0 k
+  // CHECK: 4 1 2
+  // CHECK: 5 3 4
+
+  if (argc > 1) {
+    // Exhaust the labels.
+    unsigned long num_labels = 1 << (sizeof(dfsan_label) * 8);
+    for (unsigned long i =  ijk_label + 1; i < num_labels - 2; ++i) {
+      dfsan_label l = dfsan_create_label("l", 0);
+      assert(l == i);
+    }
+
+    // Consume the last available label.
+    dfsan_label l = dfsan_union(5, 6);
+    assert(l == num_labels - 2);
+
+    // Try to allocate another label (either explicitly or by unioning two
+    // existing labels), but expect a crash.
+    if (argv[1][0] == 'c') {
+      l = dfsan_create_label("l", 0);
+    } else {
+      l = dfsan_union(6, 7);
+    }
+
+    // CHECK-OOL: FATAL: DataFlowSanitizer: out of labels
+    // CHECK-OOL: 1 0 0 i
+    // CHECK-OOL: 2 0 0 j
+    // CHECK-OOL: 3 0 0 k
+    // CHECK-OOL: 4 1 2
+    // CHECK-OOL: 5 3 4
+    // CHECK-OOL: 6 0 0
+    // CHECK-OOL: 65534 5 6
+    // CHECK-OOL: 65535 0 0 <init label>
+  }
+
+  return 0;
+}
diff --git a/test/dfsan/vararg.c b/test/dfsan/vararg.c
new file mode 100644
index 0000000..2227ba7
--- /dev/null
+++ b/test/dfsan/vararg.c
@@ -0,0 +1,24 @@
+// RUN: %clang_dfsan -m64 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %run %t foo
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %run %t foo
+
+#include <stdio.h>
+
+int do_nothing(const char *format, ...) {
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int (*fp)(const char *, ...);
+
+  if (argc > 1)
+    fp = do_nothing;
+  else
+    fp = printf;
+
+  // CHECK: FATAL: DataFlowSanitizer: unsupported indirect call to vararg function printf
+  fp("hello %s\n", "world");
+}
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
index adf65ee..0ee2b84 100644
--- a/test/lit.common.cfg
+++ b/test/lit.common.cfg
@@ -25,8 +25,12 @@
     config.cxx_mode_flags = ["--driver-mode=g++"]
   else:
     config.cxx_mode_flags = []
+  # We assume that sanitizers should provide good enough error
+  # reports and stack traces even with minimal debug info.
+  config.debug_info_flags = ["-gline-tables-only"]
 elif compiler_id == 'GNU':
   config.cxx_mode_flags = ["-x c++"]
+  config.debug_info_flags = ["-g"]
 else:
   lit_config.fatal("Unsupported compiler id: %r" % compiler_id)
 # Add compiler ID to the list of available features.
@@ -69,6 +73,9 @@
 # Allow tests to be executed on a simulator or remotely.
 config.substitutions.append( ('%run', config.emulator) )
 
+# Define CHECK-%os to check for OS-dependent output.
+config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
+
 # Add supported compiler_rt architectures to a list of available features.
 compiler_rt_arch = getattr(config, 'compiler_rt_arch', None)
 if compiler_rt_arch:
diff --git a/test/lsan/TestCases/ignore_object.cc b/test/lsan/TestCases/ignore_object.cc
index 133ccc7..38d76e6 100644
--- a/test/lsan/TestCases/ignore_object.cc
+++ b/test/lsan/TestCases/ignore_object.cc
@@ -1,7 +1,7 @@
 // Test for __lsan_ignore_object().
 // RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=2"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE ASAN_OPTIONS=$ASAN_OPTIONS:"verbosity=2" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc
index 7ca2a4f..39b9b02 100644
--- a/test/lsan/TestCases/ignore_object_errors.cc
+++ b/test/lsan/TestCases/ignore_object_errors.cc
@@ -1,7 +1,7 @@
 // Test for incorrect use of __lsan_ignore_object().
 // RUN: LSAN_BASE="verbosity=2"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: LSAN_OPTIONS=$LSAN_BASE ASAN_OPTIONS=$ASAN_OPTIONS:verbosity=2 %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc
index 3e4ccd7..fe3f70e 100644
--- a/test/lsan/TestCases/leak_check_at_exit.cc
+++ b/test/lsan/TestCases/leak_check_at_exit.cc
@@ -3,8 +3,8 @@
 // RUN: %clangxx_lsan %s -o %t
 // RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
 // RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: LSAN_OPTIONS=%LSAN_BASE:"leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS=%LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/test/lsan/TestCases/register_root_region.cc b/test/lsan/TestCases/register_root_region.cc
index acc8e1b..6fc84c2 100644
--- a/test/lsan/TestCases/register_root_region.cc
+++ b/test/lsan/TestCases/register_root_region.cc
@@ -16,7 +16,7 @@
 int main(int argc, char *argv[]) {
   size_t size = getpagesize() * 2;
   void *p =
-      mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
   assert(p);
   // Make half of the memory inaccessible. LSan must not crash trying to read it.
   assert(0 == mprotect((char *)p + size / 2, size / 2, PROT_NONE));
diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc
index 1bb6057..f7e95ed 100644
--- a/test/lsan/TestCases/swapcontext.cc
+++ b/test/lsan/TestCases/swapcontext.cc
@@ -6,6 +6,11 @@
 // RUN: not %run %t foo 2>&1 | FileCheck %s
 
 #include <stdio.h>
+#if defined(__APPLE__)
+// Note: ucontext.h is deprecated on OSX, so this test may stop working
+// someday. We define _XOPEN_SOURCE to keep using ucontext.h for now.
+#define _XOPEN_SOURCE 1
+#endif
 #include <ucontext.h>
 #include <unistd.h>
 
diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc
index d436144..ce11c3f 100644
--- a/test/lsan/TestCases/use_registers.cc
+++ b/test/lsan/TestCases/use_registers.cc
@@ -7,6 +7,7 @@
 
 #include <assert.h>
 #include <pthread.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -33,7 +34,7 @@
   fflush(stderr);
   __sync_fetch_and_xor(sync, 1);
   while (true)
-    pthread_yield();
+    sched_yield();
 }
 
 int main() {
@@ -42,7 +43,7 @@
   int res = pthread_create(&thread_id, 0, registers_thread_func, &sync);
   assert(res == 0);
   while (!__sync_fetch_and_xor(&sync, 0))
-    pthread_yield();
+    sched_yield();
   return 0;
 }
 // CHECK: Test alloc: [[ADDR:.*]].
diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc
index fc4e661..a1d4383 100644
--- a/test/lsan/TestCases/use_stacks_threaded.cc
+++ b/test/lsan/TestCases/use_stacks_threaded.cc
@@ -7,6 +7,7 @@
 
 #include <assert.h>
 #include <pthread.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -18,7 +19,7 @@
   fflush(stderr);
   __sync_fetch_and_xor(sync, 1);
   while (true)
-    pthread_yield();
+    sched_yield();
 }
 
 int main() {
@@ -27,7 +28,7 @@
   int res = pthread_create(&thread_id, 0, stacks_thread_func, &sync);
   assert(res == 0);
   while (!__sync_fetch_and_xor(&sync, 0))
-    pthread_yield();
+    sched_yield();
   return 0;
 }
 // CHECK: Test alloc: [[ADDR:.*]].
diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg
index 7411d7a..e11c90a 100644
--- a/test/lsan/lit.common.cfg
+++ b/test/lsan/lit.common.cfg
@@ -29,7 +29,7 @@
 else:
   lit_config.fatal("Unknown LSan test mode: %r" % lsan_lit_test_mode)
 
-clang_cflags = ["-g", "-O0", "-m64"]
+clang_cflags = ["-O0", "-m64"] + config.debug_info_flags
 clang_cxxflags = config.cxx_mode_flags + clang_cflags
 clang_lsan_cflags = clang_cflags + lsan_cflags
 clang_lsan_cxxflags = clang_cxxflags + lsan_cflags
diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc
index 39b893b..4dd97e7 100644
--- a/test/msan/Linux/syscalls.cc
+++ b/test/msan/Linux/syscalls.cc
@@ -10,6 +10,7 @@
 #include <linux/aio_abi.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
+#include <sys/uio.h>
 
 #include <sanitizer/linux_syscall_hooks.h>
 #include <sanitizer/msan_interface.h>
@@ -84,17 +85,24 @@
   assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(void *));
 
   __msan_poison(buf, sizeof(buf));
-  struct iocb iocb[2];
-  struct iocb *iocbp[2] = { &iocb[0], &iocb[1] };
+  struct iocb iocb[3];
+  struct iocb *iocbp[3] = { &iocb[0], &iocb[1], &iocb[2] };
   memset(iocb, 0, sizeof(iocb));
   iocb[0].aio_lio_opcode = IOCB_CMD_PREAD;
   iocb[0].aio_buf = (__u64)buf;
-  iocb[0].aio_nbytes = kFortyTwo;
+  iocb[0].aio_nbytes = 10;
   iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
-  iocb[1].aio_buf = (__u64)(&buf[kFortyTwo]);
-  iocb[1].aio_nbytes = kFortyTwo;
-  __sanitizer_syscall_pre_io_submit(0, 2, &iocbp);
-  assert(__msan_test_shadow(buf, sizeof(buf)) == 2 * kFortyTwo);
+  iocb[1].aio_buf = (__u64)(&buf[20]);
+  iocb[1].aio_nbytes = 15;
+  struct iovec vec[2] = { {&buf[40], 3}, {&buf[50], 20} };
+  iocb[2].aio_lio_opcode = IOCB_CMD_PREADV;
+  iocb[2].aio_buf = (__u64)(&vec);
+  iocb[2].aio_nbytes = 2;
+  __sanitizer_syscall_pre_io_submit(0, 3, &iocbp);
+  assert(__msan_test_shadow(buf, sizeof(buf)) == 10);
+  assert(__msan_test_shadow(buf + 20, sizeof(buf) - 20) == 15);
+  assert(__msan_test_shadow(buf + 40, sizeof(buf) - 40) == 3);
+  assert(__msan_test_shadow(buf + 50, sizeof(buf) - 50) == 20);
 
   __msan_poison(buf, sizeof(buf));
   char *p = buf;
diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc
index a8621f3..0cc57f3 100644
--- a/test/msan/chained_origin_limits.cc
+++ b/test/msan/chained_origin_limits.cc
@@ -12,6 +12,9 @@
 // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
 // RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
 
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
 // Stack origin.
 // RUN: %clangxx_msan -DSTACK -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
 
@@ -24,6 +27,9 @@
 // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
 // RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
 
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
 
 // Heap origin, with calls.
 // RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
@@ -37,6 +43,9 @@
 // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
 // RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
 
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
 
 // Stack origin, with calls.
 // RUN: %clangxx_msan -DSTACK -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
@@ -50,6 +59,9 @@
 // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
 // RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
 
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -143,3 +155,24 @@
 // CHECK-PER-STACK: Uninitialized value was stored to memory at
 // CHECK-PER-STACK: in fn1
 // CHECK-PER-STACK: Uninitialized value was created
+
+// CHECK-UNLIMITED: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was created
diff --git a/test/msan/chained_origin_with_signals.cc b/test/msan/chained_origin_with_signals.cc
index ef98385..2841e34 100644
--- a/test/msan/chained_origin_with_signals.cc
+++ b/test/msan/chained_origin_with_signals.cc
@@ -25,9 +25,9 @@
   int volatile z;
   x = z;
 
-  signal(SIGUSR1, SignalHandler);
-  kill(getpid(), SIGUSR1);
-  signal(SIGUSR1, SIG_DFL);
+  signal(SIGHUP, SignalHandler);
+  kill(getpid(), SIGHUP);
+  signal(SIGHUP, SIG_DFL);
 
   return y;
 }
diff --git a/test/msan/fork.cc b/test/msan/fork.cc
new file mode 100644
index 0000000..10de8a9
--- /dev/null
+++ b/test/msan/fork.cc
@@ -0,0 +1,121 @@
+// Test that chained origins are fork-safe.
+// Run a number of threads that create new chained origins, then fork
+// and verify that origin reads do not deadlock in the child process.
+
+// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -m64 -O3 %s -o %t
+// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s
+
+// Fun fact: if test output is redirected to a file (as opposed to
+// being piped directly to FileCheck), we may lose some "done"s due to
+// a kernel bug:
+// https://lkml.org/lkml/2014/2/17/324
+
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sanitizer/msan_interface.h>
+
+int done;
+
+void copy_uninit_thread2() {
+  volatile int x;
+  volatile int v;
+  while (true) {
+    v = x;
+    x = v;
+    if (__atomic_load_n(&done, __ATOMIC_RELAXED))
+      return;
+  }
+}
+
+void copy_uninit_thread1(int level) {
+  if (!level)
+    copy_uninit_thread2();
+  else
+    copy_uninit_thread1(level - 1);
+}
+
+void *copy_uninit_thread(void *id) {
+  copy_uninit_thread1((long)id);
+  return 0;
+}
+
+// Run through stackdepot in the child process.
+// If any of the hash table cells are locked, this may deadlock.
+void child() {
+  volatile int x;
+  volatile int v;
+  for (int i = 0; i < 10000; ++i) {
+    v = x;
+    x = v;
+  }
+  write(2, "done\n", 5);
+}
+
+void test() {
+  const int kThreads = 10;
+  pthread_t t[kThreads];
+  for (int i = 0; i < kThreads; ++i)
+    pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i);
+  usleep(100000);
+  pid_t pid = fork();
+  if (pid) {
+    // parent
+    __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
+    pid_t p;
+    while ((p = wait(NULL)) == -1) {  }
+  } else {
+    // child
+    child();
+  }
+}
+
+int main() {
+  const int kChildren = 20;
+  for (int i = 0; i < kChildren; ++i) {
+    pid_t pid = fork();
+    if (pid) {
+      // parent
+    } else {
+      test();
+      exit(0);
+    }
+  }
+  
+  for (int i = 0; i < kChildren; ++i) {
+    pid_t p;
+    while ((p = wait(NULL)) == -1) {  }
+  }
+
+  return 0;
+}
+
+// Expect 20 (== kChildren) "done" messages.
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg
index 3143608..f425e25 100644
--- a/test/msan/lit.cfg
+++ b/test/msan/lit.cfg
@@ -13,8 +13,7 @@
                      "-mno-omit-leaf-frame-pointer",
                      "-fno-omit-frame-pointer",
                      "-fno-optimize-sibling-calls",
-                     "-g",
-                     "-m64"]
+                     "-m64"] + config.debug_info_flags
 clang_msan_cxxflags = config.cxx_mode_flags + clang_msan_cflags
 
 def build_invocation(compile_flags):
diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc
new file mode 100644
index 0000000..869afc9
--- /dev/null
+++ b/test/msan/param_tls_limit.cc
@@ -0,0 +1,74 @@
+// ParamTLS has limited size. Everything that does not fit is considered fully
+// initialized.
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+#include <assert.h>
+
+// This test assumes that ParamTLS size is 800 bytes.
+
+// This test passes poisoned values through function argument list.
+// In case of overflow, argument is unpoisoned.
+#define OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == -1)
+// In case of no overflow, it is still poisoned.
+#define NO_OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == 0)
+
+template<int N>
+struct S {
+  char x[N];
+};
+
+void f100(S<100> s) {
+  NO_OVERFLOW(s);
+}
+
+void f800(S<800> s) {
+  NO_OVERFLOW(s);
+}
+
+void f801(S<801> s) {
+  OVERFLOW(s);
+}
+
+void f1000(S<1000> s) {
+  OVERFLOW(s);
+}
+
+void f_many(int a, double b, S<800> s, int c, double d) {
+  NO_OVERFLOW(a);
+  NO_OVERFLOW(b);
+  OVERFLOW(s);
+  OVERFLOW(c);
+  OVERFLOW(d);
+}
+
+// -8 bytes for "int a", aligned by 8
+// -2 to make "int c" a partial fit
+void f_many2(int a, S<800 - 8 - 2> s, int c, double d) {
+  NO_OVERFLOW(a);
+  NO_OVERFLOW(s);
+  OVERFLOW(c);
+  OVERFLOW(d);
+}
+
+int main(void) {
+  S<100> s100;
+  S<800> s800;
+  S<801> s801;
+  S<1000> s1000;
+  f100(s100);
+  f800(s800);
+  f801(s801);
+  f1000(s1000);
+
+  int i;
+  double d;
+  f_many(i, d, s800, i, d);
+
+  S<800 - 8 - 2> s788;
+  f_many2(i, s788, i, d);
+  return 0;
+}
diff --git a/test/msan/report-demangling.cc b/test/msan/report-demangling.cc
new file mode 100644
index 0000000..e6d5c27
--- /dev/null
+++ b/test/msan/report-demangling.cc
@@ -0,0 +1,19 @@
+// Test that function name is mangled in the "created by an allocation" line,
+// and demangled in the single-frame "stack trace" that follows.
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+__attribute__((noinline))
+int f() {
+  int x;
+  int *volatile p = &x;
+  return *p;
+}
+
+int main(int argc, char **argv) {
+  return f();
+  // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+  // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function '_Z1fv'
+  // CHECK: #0 {{.*}} in f() {{.*}}report-demangling.cc:[[@LINE-10]]
+}
diff --git a/test/msan/wrap_indirect_calls.cc b/test/msan/wrap_indirect_calls.cc
deleted file mode 100644
index be17bd8..0000000
--- a/test/msan/wrap_indirect_calls.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Test indirect call wrapping in MemorySanitizer.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/two.cc -fPIC -shared -o %t-two-so.so
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/wrapper.cc -fPIC -shared -o %t-wrapper-so.so
-
-// Disable fast path.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN:     %t-two-so.so %t-wrapper-so.so \
-// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=0 \
-// RUN:     -DSLOW=1 \
-// RUN:     -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %run %t
-
-// Enable fast path, call from executable, -O0.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN:     %t-two-so.so %t-wrapper-so.so \
-// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN:     -DSLOW=0 \
-// RUN:     -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %run %t
-
-// Enable fast path, call from executable, -O3.
-
-// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc %s \
-// RUN:     %t-two-so.so %t-wrapper-so.so \
-// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN:     -DSLOW=0 \
-// RUN:     -Wl,--defsym=__executable_start=0 -o %t
-// RUN: %run %t
-
-// Enable fast path, call from DSO, -O0.
-
-// RUN: %clangxx_msan -O0 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
-// RUN:     %t-two-so.so %t-wrapper-so.so \
-// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN:     -DSLOW=0 \
-// RUN:     -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
-// RUN: %clangxx_msan -O0 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
-// RUN: %run %t
-
-// Enable fast path, call from DSO, -O3.
-
-// RUN: %clangxx_msan -O3 %p/wrap_indirect_calls/caller.cc %p/wrap_indirect_calls/one.cc -shared \
-// RUN:     %t-two-so.so %t-wrapper-so.so \
-// RUN:     -mllvm -msan-wrap-indirect-calls=wrapper \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=1 \
-// RUN:     -DSLOW=0 \
-// RUN:     -Wl,--defsym=__executable_start=0 -o %t-caller-so.so
-// RUN: %clangxx_msan -O3 %s %t-caller-so.so %t-two-so.so %t-wrapper-so.so -o %t
-// RUN: %run %t
-
-// The actual test is in multiple files in wrap_indirect_calls/ directory.
-void run_test();
-
-int main() {
-  run_test();
-  return 0;
-}
diff --git a/test/msan/wrap_indirect_calls/caller.cc b/test/msan/wrap_indirect_calls/caller.cc
deleted file mode 100644
index a0af8b7..0000000
--- a/test/msan/wrap_indirect_calls/caller.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Indirectly call a bunch of functions.
-
-#include <assert.h>
-
-extern int cnt;
-
-typedef int (*F)(int, int);
-
-// A function in the same object.
-int f_local(int x, int y) {
-  return x + y;
-}
-
-// A function in another object.
-int f_other_object(int x, int y);
-
-// A function in another DSO.
-int f_dso(int x, int y);
-
-// A function in another DSO that is replaced by the wrapper.
-int f_replaced(int x, int y);
-
-void run_test(void) {
-  int x;
-  int expected_cnt = 0;
-  volatile F f;
-
-  if (SLOW) ++expected_cnt;
-  f = &f_local;
-  x = f(1, 2);
-  assert(x == 3);
-  assert(cnt == expected_cnt);
-
-  if (SLOW) ++expected_cnt;
-  f = &f_other_object;
-  x = f(2, 3);
-  assert(x == 6);
-  assert(cnt == expected_cnt);
-
-  ++expected_cnt;
-  f = &f_dso;
-  x = f(2, 3);
-  assert(x == 7);
-  assert(cnt == expected_cnt);
-
-  ++expected_cnt;
-  f = &f_replaced;
-  x = f(2, 3);
-  assert(x == 11);
-  assert(cnt == expected_cnt);
-}
diff --git a/test/msan/wrap_indirect_calls/lit.local.cfg b/test/msan/wrap_indirect_calls/lit.local.cfg
deleted file mode 100644
index 5e01230..0000000
--- a/test/msan/wrap_indirect_calls/lit.local.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-# Sources in this directory are used by tests in parent directory.
-
-config.suffixes = []
diff --git a/test/msan/wrap_indirect_calls/one.cc b/test/msan/wrap_indirect_calls/one.cc
deleted file mode 100644
index ab7bf41..0000000
--- a/test/msan/wrap_indirect_calls/one.cc
+++ /dev/null
@@ -1,3 +0,0 @@
-int f_other_object(int x, int y) {
-  return x * y;
-}
diff --git a/test/msan/wrap_indirect_calls/two.cc b/test/msan/wrap_indirect_calls/two.cc
deleted file mode 100644
index c939a99..0000000
--- a/test/msan/wrap_indirect_calls/two.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-int f_dso(int x, int y) {
-  return 2 * x + y;
-}
-
-int f_replaced(int x, int y) {
-  return x + y + 5;
-}
-
-int f_replacement(int x, int y) {
-  return x + y + 6;
-}
diff --git a/test/msan/wrap_indirect_calls/wrapper.cc b/test/msan/wrap_indirect_calls/wrapper.cc
deleted file mode 100644
index 8fcd0c6..0000000
--- a/test/msan/wrap_indirect_calls/wrapper.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-int f_replaced(int x, int y);
-int f_replacement(int x, int y);
-
-int cnt;
-
-extern "C" void *wrapper(void *p) {
-  ++cnt;
-  if (p == (void *)f_replaced)
-    return (void *)f_replacement;
-  return p;
-}
diff --git a/test/msan/wrap_indirect_calls2.cc b/test/msan/wrap_indirect_calls2.cc
deleted file mode 100644
index fb4e6c7..0000000
--- a/test/msan/wrap_indirect_calls2.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Test __msan_set_indirect_call_wrapper.
-
-// RUN: %clangxx_msan -mllvm -msan-wrap-indirect-calls=__msan_wrap_indirect_call \
-// RUN:     -mllvm -msan-wrap-indirect-calls-fast=0 \
-// RUN:     -O0 -g -rdynamic -Wl,--defsym=__executable_start=0 %s -o %t && %run %t
-
-// This test disables -msan-wrap-indirect-calls-fast, otherwise indirect calls
-// inside the same module are short-circuited and are never seen by the wrapper.
-
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdint.h>
-
-extern "C" void __msan_set_indirect_call_wrapper(uintptr_t);
-
-bool done_f, done_g;
-
-void f(void) {
-  assert(!done_g);
-  done_f = true;
-}
-
-void g(void) {
-  assert(done_f);
-  done_g = true;
-}
-
-typedef void (*Fn)(void);
-extern "C" Fn my_wrapper(Fn target) {
-  if (target == f) return g;
-  return target;
-}
-
-int main(void) {
-  volatile Fn fp;
-  fp = &f;
-  fp();
-  __msan_set_indirect_call_wrapper((uintptr_t)my_wrapper);
-  fp();
-  return !(done_f && done_g);
-}
diff --git a/test/msan/wrap_indirect_calls_in_rtl.cc b/test/msan/wrap_indirect_calls_in_rtl.cc
deleted file mode 100644
index 040ff13..0000000
--- a/test/msan/wrap_indirect_calls_in_rtl.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Test indirect call wrapping in MemorySanitizer runtime.
-
-// RUN: %clangxx_msan -O0 -g -rdynamic %s -o %t && %run %t
-
-#include <assert.h>
-#include <math.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <sys/time.h>
-
-extern "C" void __msan_set_indirect_call_wrapper(uintptr_t);
-
-bool pthread_create_done;
-
-void *ThreadFn(void *) {
-  printf("bad threadfn\n");
-  return 0;
-}
-
-void *ThreadFn2(void *) {
-  printf("good threadfn\n");
-  pthread_create_done = true;
-  return 0;
-}
-
-bool in_gettimeofday;
-bool in_lgamma;
-
-int my_gettimeofday(struct timeval *p, void *q) {
-  p->tv_sec = 1;
-  p->tv_usec = 2;
-  return 42;
-}
-
-double my_lgamma(double x) {
-  return x;
-}
-
-extern "C" uintptr_t my_wrapper(uintptr_t f) {
-  if (f == (uintptr_t)ThreadFn)
-    return (uintptr_t)&ThreadFn2;
-  if (in_gettimeofday)
-    return (uintptr_t)my_gettimeofday;
-  if (in_lgamma)
-    return (uintptr_t)my_lgamma;
-  return f;
-}
-
-int main(void) {
-  __msan_set_indirect_call_wrapper((uintptr_t)my_wrapper);
-
-  // ThreadFn is called indirectly from a wrapper function in MSan rtl and
-  // is subject to indirect call wrapping (it could be an native-to-translated
-  // edge).
-  pthread_t t;
-  pthread_create(&t, 0, ThreadFn, 0);
-  pthread_join(t, 0);
-  assert(pthread_create_done);
-
-  // gettimeofday is intercepted in msan_interceptors.cc and the real one (from
-  // libc) is called indirectly.
-  struct timeval tv;
-  in_gettimeofday = true;
-  int res = gettimeofday(&tv, NULL);
-  in_gettimeofday = false;
-  assert(tv.tv_sec == 1);
-  assert(tv.tv_usec == 2);
-  assert(res == 42);
-
-  // lgamma is intercepted in sanitizer_common_interceptors.inc and is also
-  // called indirectly.
-  in_lgamma = true;
-  double dres = lgamma(1.1);
-  in_lgamma = false;
-  assert(dres == 1.1);
-  
-  return 0;
-}
diff --git a/test/profile/instrprof-basic.c b/test/profile/instrprof-basic.c
index 3db0831..fd3516c 100644
--- a/test/profile/instrprof-basic.c
+++ b/test/profile/instrprof-basic.c
@@ -3,10 +3,29 @@
 // RUN: llvm-profdata merge -o %t.profdata %t.profraw
 // RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s
 
+int begin(int i) {
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
+  if (i)
+    return 0;
+  return 1;
+}
+
+int end(int i) {
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
+  if (i)
+    return 0;
+  return 1;
+}
+
 int main(int argc, const char *argv[]) {
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  begin(0);
+  end(1);
+
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
   if (argc)
     return 0;
   return 1;
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 2, i32 1}
+
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
diff --git a/test/profile/instrprof-dlopen.test b/test/profile/instrprof-dlopen.test
index f0c067f..ba386e3 100644
--- a/test/profile/instrprof-dlopen.test
+++ b/test/profile/instrprof-dlopen.test
@@ -1,8 +1,8 @@
 RUN: mkdir -p %t.d
 RUN: %clang_profgen -o %t.d/func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c
 RUN: %clang_profgen -o %t.d/func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c
-RUN: %clang -o %t-local -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_LOCAL" %S/Inputs/instrprof-dlopen-main.c -ldl
-RUN: %clang -o %t-global -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_GLOBAL" %S/Inputs/instrprof-dlopen-main.c -ldl
+RUN: %clang -o %t-local -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_LOCAL" %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang -o %t-global -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_GLOBAL" %S/Inputs/instrprof-dlopen-main.c
 
 RUN: %clang -c -o %t.d/main.o %S/Inputs/instrprof-dlopen-main.c
 RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dlopen-func.c %S/Inputs/instrprof-dlopen-func2.c %t.d/main.o
diff --git a/test/profile/instrprof-set-filename.c b/test/profile/instrprof-set-filename.c
index 51de14f..0458218 100644
--- a/test/profile/instrprof-set-filename.c
+++ b/test/profile/instrprof-set-filename.c
@@ -5,10 +5,10 @@
 
 void __llvm_profile_set_filename(const char *);
 int main(int argc, const char *argv[]) {
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
   if (argc < 2)
     return 1;
   __llvm_profile_set_filename(argv[1]);
   return 0;
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-without-libc.c b/test/profile/instrprof-without-libc.c
index ca83d46..60ca949 100644
--- a/test/profile/instrprof-without-libc.c
+++ b/test/profile/instrprof-without-libc.c
@@ -17,8 +17,8 @@
 int __llvm_profile_write_buffer(char *);
 int write_buffer(uint64_t, const char *);
 int main(int argc, const char *argv[]) {
-  // CHECK-LABEL: define i32 @main(
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  // CHECK-LABEL: define {{.*}} @main(
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
   if (argc < 2)
     return 1;
 
@@ -46,7 +46,7 @@
   return fclose(File);
 #endif
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
 
 // CHECK-SYMBOLS-NOT: ___cxx_global_var_init
 // CHECK-SYMBOLS-NOT: ___llvm_profile_register_write_file_atexit
diff --git a/test/profile/instrprof-write-file-atexit-explicitly.c b/test/profile/instrprof-write-file-atexit-explicitly.c
index 931a48b..ba229b9 100644
--- a/test/profile/instrprof-write-file-atexit-explicitly.c
+++ b/test/profile/instrprof-write-file-atexit-explicitly.c
@@ -8,10 +8,10 @@
 void __llvm_profile_set_filename(const char *);
 int main(int argc, const char *argv[]) {
   __llvm_profile_register_write_file_atexit();
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
   if (argc < 2)
     return 1;
   __llvm_profile_set_filename(argv[1]);
   return 0;
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-write-file-only.c b/test/profile/instrprof-write-file-only.c
index 65a2226..0dd61de 100644
--- a/test/profile/instrprof-write-file-only.c
+++ b/test/profile/instrprof-write-file-only.c
@@ -9,8 +9,8 @@
 void __llvm_profile_set_filename(const char *);
 int foo(int);
 int main(int argc, const char *argv[]) {
-  // CHECK-LABEL: define i32 @main
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  // CHECK-LABEL: define {{.*}} @main(
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
   if (argc > 1)
     return 1;
 
@@ -28,8 +28,8 @@
   // There should be no profiling information for @foo, since it was called
   // after the profile was written (and the atexit was suppressed by defining
   // profile_runtime).
-  // CHECK-LABEL: define i32 @foo
+  // CHECK-LABEL: define {{.*}} @foo(
   // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}}
   return X <= 0 ? -X : X;
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-write-file.c b/test/profile/instrprof-write-file.c
index f5c2958..12967cb 100644
--- a/test/profile/instrprof-write-file.c
+++ b/test/profile/instrprof-write-file.c
@@ -9,8 +9,8 @@
 void __llvm_profile_set_filename(const char *);
 int foo(int);
 int main(int argc, const char *argv[]) {
-  // CHECK-LABEL: define i32 @main
-  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !1
+  // CHECK-LABEL: define {{.*}} @main(
+  // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
   if (argc < 2)
     return 1;
 
@@ -25,10 +25,10 @@
   return Ret;
 }
 int foo(int X) {
-  // CHECK-LABEL: define i32 @foo
+  // CHECK-LABEL: define {{.*}} @foo(
   // CHECK1: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}}
-  // CHECK2: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof !2
+  // CHECK2: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
   return X <= 0 ? -X : X;
 }
-// CHECK: !1 = metadata !{metadata !"branch_weights", i32 1, i32 2}
-// CHECK2: !2 = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK2: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg
index 6e53b50..e4910ab 100644
--- a/test/profile/lit.cfg
+++ b/test/profile/lit.cfg
@@ -24,6 +24,11 @@
             lit_config.load_config(config, site_cfg)
             raise SystemExit
 
+if config.host_os in ['Linux']:
+  extra_linkflags = ["-ldl"]
+else:
+  extra_linkflags = []
+
 # Test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
 
@@ -31,7 +36,7 @@
 config.excludes = ['Inputs']
 
 # Clang flags.
-clang_cflags = [config.target_cflags]
+clang_cflags = [config.target_cflags] + extra_linkflags
 
 def build_invocation(compile_flags):
   return " " + " ".join([config.clang] + compile_flags) + " "
@@ -41,6 +46,8 @@
 config.substitutions.append( ("%clang_profgen ", build_invocation(clang_cflags) + " -fprofile-instr-generate ") )
 config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") )
 
-# Profile tests are currently supported on Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
+if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']:
+  config.unsupported = True
+
+if config.target_arch in ['armv7l']:
   config.unsupported = True
diff --git a/test/sanitizer_common/TestCases/Linux/clock_gettime.c b/test/sanitizer_common/TestCases/Linux/clock_gettime.c
new file mode 100644
index 0000000..ec1386e
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/clock_gettime.c
@@ -0,0 +1,11 @@
+// RUN: %clang %s -Wl,-as-needed -o %t && %run %t
+// Regression test for PR15823
+// (http://llvm.org/bugs/show_bug.cgi?id=15823).
+#include <stdio.h>
+#include <time.h>
+
+int main() {
+  struct timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/getpass.cc b/test/sanitizer_common/TestCases/Linux/getpass.cc
new file mode 100644
index 0000000..c9a2276
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/getpass.cc
@@ -0,0 +1,32 @@
+// RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t | FileCheck %s
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <pty.h>
+
+int
+main (int argc, char** argv)
+{
+    int master;
+    int pid = forkpty(&master, NULL, NULL, NULL);
+
+    if(pid == -1) {
+      fprintf(stderr, "forkpty failed\n");
+      return 1;
+    } else if (pid > 0) {
+      char buf[1024];
+      int res = read(master, buf, sizeof(buf));
+      write(1, buf, res);
+      write(master, "password\n", 9);
+      while ((res = read(master, buf, sizeof(buf))) > 0) write(1, buf, res);
+    } else {
+      char *s = getpass("prompt");
+      assert(strcmp(s, "password") == 0);
+      write(1, "done\n", 5);
+    }
+    return 0;
+}
+
+// CHECK: prompt
+// CHECK: done
diff --git a/test/sanitizer_common/TestCases/Linux/mlock_test.cc b/test/sanitizer_common/TestCases/Linux/mlock_test.cc
new file mode 100644
index 0000000..69ea7cb
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/mlock_test.cc
@@ -0,0 +1,13 @@
+// RUN: %clang  %s -o %t && %run %t
+// XFAIL: lsan
+
+#include <assert.h>
+#include <sys/mman.h>
+
+int main() {
+  assert(0 == mlockall(MCL_CURRENT));
+  assert(0 == mlock((void *)0x12345, 0x5678));
+  assert(0 == munlockall());
+  assert(0 == munlock((void *)0x987, 0x654));
+}
+
diff --git a/test/sanitizer_common/TestCases/Linux/ptrace.cc b/test/sanitizer_common/TestCases/Linux/ptrace.cc
index 797e7b4..2bf0fd2 100644
--- a/test/sanitizer_common/TestCases/Linux/ptrace.cc
+++ b/test/sanitizer_common/TestCases/Linux/ptrace.cc
@@ -1,5 +1,4 @@
 // RUN: %clangxx -O0 %s -o %t && %run %t
-// XFAIL: arm-linux-gnueabi
 
 #include <assert.h>
 #include <signal.h>
@@ -18,8 +17,10 @@
     execl("/bin/true", "true", NULL);
   } else {
     wait(NULL);
-    user_regs_struct regs;
     int res;
+
+#if __x86_64__
+    user_regs_struct regs;
     res = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
     assert(!res);
     if (regs.rip)
@@ -30,6 +31,21 @@
     assert(!res);
     if (fpregs.mxcsr)
       printf("%x\n", fpregs.mxcsr);
+#endif // __x86_64__
+
+#if __powerpc64__
+    struct pt_regs regs;
+    res = ptrace((enum __ptrace_request)PTRACE_GETREGS, pid, NULL, &regs);
+    assert(!res);
+    if (regs.nip)
+      printf("%lx\n", regs.nip);
+
+    elf_fpregset_t fpregs;
+    res = ptrace((enum __ptrace_request)PTRACE_GETFPREGS, pid, NULL, &fpregs);
+    assert(!res);
+    if ((elf_greg_t)fpregs[32]) // fpscr
+      printf("%lx\n", (elf_greg_t)fpregs[32]);
+#endif // __powerpc64__
 
     siginfo_t siginfo;
     res = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
diff --git a/test/sanitizer_common/TestCases/Linux/timerfd.cc b/test/sanitizer_common/TestCases/Linux/timerfd.cc
new file mode 100644
index 0000000..e7613bb
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/timerfd.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t | FileCheck %s
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+int main (int argc, char** argv)
+{
+  int fd = timerfd_create(CLOCK_REALTIME, 0);
+  assert(fd >= 0);
+
+  struct itimerspec its;
+  its.it_value.tv_sec = 0;
+  its.it_value.tv_nsec = 1000000;
+  its.it_interval.tv_sec = its.it_value.tv_sec;
+  its.it_interval.tv_nsec = its.it_value.tv_nsec;
+
+  int res = timerfd_settime(fd, 0, &its, NULL);
+  assert(res != -1);
+
+  struct itimerspec its2;
+  res = timerfd_settime(fd, 0, &its, &its2);
+  assert(res != -1);
+  assert(its2.it_interval.tv_sec == its.it_interval.tv_sec);
+  assert(its2.it_interval.tv_nsec == its.it_interval.tv_nsec);
+  assert(its2.it_value.tv_sec <= its.it_value.tv_sec);
+  assert(its2.it_value.tv_nsec <= its.it_value.tv_nsec);
+
+  struct itimerspec its3;
+  res = timerfd_gettime(fd, &its3);
+  assert(res != -1);
+  assert(its3.it_interval.tv_sec == its.it_interval.tv_sec);
+  assert(its3.it_interval.tv_nsec == its.it_interval.tv_nsec);
+  assert(its3.it_value.tv_sec <= its.it_value.tv_sec);
+  assert(its3.it_value.tv_nsec <= its.it_value.tv_nsec);
+
+
+  unsigned long long buf;
+  res = read(fd, &buf, sizeof(buf));
+  assert(res == 8);
+  assert(buf >= 1);
+
+  res = close(fd);
+  assert(res != -1);
+
+  printf("DONE\n");
+  // CHECK: DONE
+  
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/corelimit.cc b/test/sanitizer_common/TestCases/corelimit.cc
new file mode 100644
index 0000000..8f54940
--- /dev/null
+++ b/test/sanitizer_common/TestCases/corelimit.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx -O0 %s -o %t && %run %t
+// XFAIL: lsan
+
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int main() {
+  struct rlimit lim_core;
+  getrlimit(RLIMIT_CORE, &lim_core);
+  void *p;
+  if (sizeof(p) == 8) {
+    assert(0 == lim_core.rlim_max);
+  }
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/malloc_hook.cc b/test/sanitizer_common/TestCases/malloc_hook.cc
index 686e098..9702249 100644
--- a/test/sanitizer_common/TestCases/malloc_hook.cc
+++ b/test/sanitizer_common/TestCases/malloc_hook.cc
@@ -1,7 +1,7 @@
 // RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
 
-// Malloc/free hooks are not supported on Windows and doesn't work in LSan.
-// XFAIL: win32, lsan
+// Malloc/free hooks are not supported on Windows.
+// XFAIL: win32
 
 #include <stdlib.h>
 #include <unistd.h>
diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc
index c84d0da..1251f67 100644
--- a/test/sanitizer_common/TestCases/print-stack-trace.cc
+++ b/test/sanitizer_common/TestCases/print-stack-trace.cc
@@ -1,13 +1,11 @@
-// RUN: %clangxx -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
-//
-// Not yet implemented for TSan.
-// https://code.google.com/p/address-sanitizer/issues/detail?id=243
-// XFAIL: tsan,lsan
+// RUN: %clangxx -O0 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -O3 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s
+// RUN: %tool_options='stack_trace_format="frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM
+// RUN: %tool_options=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE
 
 #include <sanitizer/common_interface_defs.h>
 
-void FooBarBaz() {
+static inline void FooBarBaz() {
   __sanitizer_print_stack_trace();
 }
 
@@ -16,5 +14,11 @@
   return 0;
 }
 // CHECK: {{    #0 0x.* in __sanitizer_print_stack_trace}}
-// CHECK: {{    #1 0x.* in FooBarBaz\(\) .*print-stack-trace.cc:11}}
-// CHECK: {{    #2 0x.* in main.*print-stack-trace.cc:15}}
+// CHECK: {{    #1 0x.* in FooBarBaz(\(\))? .*print-stack-trace.cc:9}}
+// CHECK: {{    #2 0x.* in main.*print-stack-trace.cc:13}}
+
+// CUSTOM: frame:1 lineno:9
+// CUSTOM: frame:2 lineno:13
+
+// NOINLINE: #0 0x{{.*}} in __sanitizer_print_stack_trace
+// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:9
diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg
index 6e768b1..fb37815 100644
--- a/test/sanitizer_common/lit.common.cfg
+++ b/test/sanitizer_common/lit.common.cfg
@@ -7,18 +7,22 @@
 
 if config.tool_name == "asan":
   tool_cflags = ["-fsanitize=address"]
+  tool_options = "ASAN_OPTIONS"
 elif config.tool_name == "tsan":
   tool_cflags = ["-fsanitize=thread"]
+  tool_options = "TSAN_OPTIONS"
 elif config.tool_name == "msan":
   tool_cflags = ["-fsanitize=memory"]
+  tool_options = "MSAN_OPTIONS"
 elif config.tool_name == "lsan":
   tool_cflags = ["-fsanitize=leak"]
+  tool_options = "LSAN_OPTIONS"
 else:
   lit_config.fatal("Unknown tool for sanitizer_common tests: %r" % config.tool_name)
 
 config.available_features.add(config.tool_name)
 
-clang_cflags = ["-g"] + tool_cflags + [config.target_cflags]
+clang_cflags = config.debug_info_flags + tool_cflags + [config.target_cflags]
 clang_cxxflags = config.cxx_mode_flags + clang_cflags
 
 def build_invocation(compile_flags):
@@ -26,9 +30,9 @@
 
 config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) )
 config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) )
+config.substitutions.append( ("%tool_options", tool_options) )
 
 config.suffixes = ['.c', '.cc', '.cpp']
 
 if config.host_os not in ['Linux', 'Darwin']:
   config.unsupported = True
-
diff --git a/test/tsan/Linux/lit.local.cfg b/test/tsan/Linux/lit.local.cfg
new file mode 100644
index 0000000..57271b8
--- /dev/null
+++ b/test/tsan/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+  if not config.parent:
+    return config
+  return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+  config.unsupported = True
diff --git a/test/tsan/mutex_robust.cc b/test/tsan/Linux/mutex_robust.cc
similarity index 100%
rename from test/tsan/mutex_robust.cc
rename to test/tsan/Linux/mutex_robust.cc
diff --git a/test/tsan/mutex_robust2.cc b/test/tsan/Linux/mutex_robust2.cc
similarity index 100%
rename from test/tsan/mutex_robust2.cc
rename to test/tsan/Linux/mutex_robust2.cc
diff --git a/test/tsan/user_fopen.cc b/test/tsan/Linux/user_fopen.cc
similarity index 97%
rename from test/tsan/user_fopen.cc
rename to test/tsan/Linux/user_fopen.cc
index f350a99..c0ff267 100644
--- a/test/tsan/user_fopen.cc
+++ b/test/tsan/Linux/user_fopen.cc
@@ -2,7 +2,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-// defined by tsan.
+// Defined by tsan.
 extern "C" FILE *__interceptor_fopen(const char *file, const char *mode);
 extern "C" int __interceptor_fileno(FILE *f);
 
diff --git a/test/tsan/user_malloc.cc b/test/tsan/Linux/user_malloc.cc
similarity index 96%
rename from test/tsan/user_malloc.cc
rename to test/tsan/Linux/user_malloc.cc
index 2106770..c671bfc 100644
--- a/test/tsan/user_malloc.cc
+++ b/test/tsan/Linux/user_malloc.cc
@@ -1,7 +1,7 @@
 // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 #include <stdio.h>
 
-// defined by tsan.
+// Defined by tsan.
 extern "C" void *__interceptor_malloc(unsigned long size);
 extern "C" void __interceptor_free(void *p);
 
diff --git a/test/tsan/atexit.cc b/test/tsan/atexit.cc
new file mode 100644
index 0000000..69acb4d
--- /dev/null
+++ b/test/tsan/atexit.cc
@@ -0,0 +1,29 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+class Logger {
+ public:
+  Logger() {
+    fprintf(stderr, "Logger ctor\n");
+  }
+
+  ~Logger() {
+    fprintf(stderr, "Logger dtor\n");
+  }
+};
+
+Logger logger;
+
+void log_from_atexit() {
+  fprintf(stderr, "In log_from_atexit\n");
+}
+
+int main() {
+  atexit(log_from_atexit);
+}
+
+// CHECK: Logger ctor
+// CHECK: In log_from_atexit
+// CHECK: Logger dtor
diff --git a/test/tsan/atexit2.cc b/test/tsan/atexit2.cc
new file mode 100644
index 0000000..6f74c5f
--- /dev/null
+++ b/test/tsan/atexit2.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int n;
+const int N = 10000;
+
+static void atexit1() {
+  n++;
+}
+
+static void atexit0() {
+  fprintf(stderr, "run count: %d\n", n);
+}
+
+int main() {
+  atexit(atexit0);
+  for (int i = 0; i < N; i++)
+    atexit(atexit1);
+}
+
+// CHECK-NOT: FATAL: ThreadSanitizer
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: run count: 10000
+
diff --git a/test/tsan/bench_shadow_flush.cc b/test/tsan/bench_shadow_flush.cc
index cdad477..0f412bb 100644
--- a/test/tsan/bench_shadow_flush.cc
+++ b/test/tsan/bench_shadow_flush.cc
@@ -11,6 +11,7 @@
 
 const long kSmallPage = 4 << 10;
 const long kLargePage = 2 << 20;
+const long kStride    = 1 << 10;
 
 typedef unsigned long uptr;
 
@@ -24,15 +25,20 @@
   int niter = 1;
   if (argc > 3)
     niter = atoi(argv[3]);
+  int stride2 = 1;
+  if (argc > 4)
+    stride2 = atoi(argv[4]);
 
-  void *p = mmap(0, mem_size + kLargePage, PROT_READ | PROT_WRITE,
-      MAP_ANON | MAP_PRIVATE, -1, 0);
+  uptr sz = mem_size + stride2 * kStride + kLargePage;
+  void *p = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
   uptr a = ((uptr)p + kLargePage - 1) & ~(kLargePage - 1);
   volatile char *mem = (volatile char *)a;
 
   for (int i = 0; i < niter; i++) {
-    for (uptr off = 0; off < mem_size; off += stride)
-      mem[off] = 42;
+    for (uptr off = 0; off < mem_size; off += stride) {
+      for (uptr off2 = 0; off2 < stride2; off2++)
+        mem[off + off2 * kStride] = 42;
+    }
   }
 
   fprintf(stderr, "DONE\n");
diff --git a/test/tsan/blacklist2.cc b/test/tsan/blacklist2.cc
index 1258208..1092561 100644
--- a/test/tsan/blacklist2.cc
+++ b/test/tsan/blacklist2.cc
@@ -22,7 +22,7 @@
 
 void TouchGlobal() {
   // CHECK: Previous write of size 4
-  // CHECK: #0 TouchGlobal(){{.*}}blacklist2.cc:[[@LINE+1]]
+  // CHECK: #0 TouchGlobal{{.*}}blacklist2.cc:[[@LINE+1]]
   Global--;
 }
 
diff --git a/test/tsan/dlclose.cc b/test/tsan/dlclose.cc
new file mode 100644
index 0000000..1a93fe6
--- /dev/null
+++ b/test/tsan/dlclose.cc
@@ -0,0 +1,58 @@
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// If we mention TSAN_OPTIONS, the test won't run from test_output.sh script.
+
+// Test case for
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=80
+
+#ifdef BUILD_SO
+
+#include <stdio.h>
+
+extern "C"
+void sofunc() {
+  fprintf(stderr, "HELLO FROM SO\n");
+}
+
+#else  // BUILD_SO
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string>
+
+void *lib;
+void *lib2;
+
+struct Closer {
+  ~Closer() {
+    dlclose(lib);
+    fprintf(stderr, "CLOSED SO\n");
+  }
+};
+static Closer c;
+
+int main(int argc, char *argv[]) {
+  lib = dlopen((std::string(argv[0]) + std::string("-so.so")).c_str(),
+      RTLD_NOW|RTLD_NODELETE);
+  if (lib == 0) {
+    printf("error in dlopen: %s\n", dlerror());
+    return 1;
+  }
+  void *f = dlsym(lib, "sofunc");
+  if (f == 0) {
+    printf("error in dlsym: %s\n", dlerror());
+    return 1;
+  }
+  ((void(*)())f)();
+  return 0;
+}
+
+#endif  // BUILD_SO
+
+// CHECK: HELLO FROM SO
+// CHECK-NOT: Inconsistency detected by ld.so
+// CHECK: CLOSED SO
+
diff --git a/test/tsan/getline_nohang.cc b/test/tsan/getline_nohang.cc
index ce9d358..89afbe1 100644
--- a/test/tsan/getline_nohang.cc
+++ b/test/tsan/getline_nohang.cc
@@ -2,6 +2,10 @@
 
 // Make sure TSan doesn't deadlock on a file stream lock at program shutdown.
 // See https://code.google.com/p/thread-sanitizer/issues/detail?id=47
+#ifdef __FreeBSD__
+#define _WITH_GETLINE  // to declare getline()
+#endif
+
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc
index 224ab22..e12bb1d 100644
--- a/test/tsan/global_race.cc
+++ b/test/tsan/global_race.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <stddef.h>
@@ -13,7 +13,9 @@
 }
 
 int main() {
-  fprintf(stderr, "addr=%p\n", GlobalData);
+  // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+  // match to the format used in the diagnotic message.
+  fprintf(stderr, "addr=0x%012lx\n", (unsigned long) GlobalData);
   pthread_t t;
   pthread_create(&t, 0, Thread, 0);
   GlobalData[2] = 43;
@@ -22,5 +24,5 @@
 
 // CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
 // CHECK: WARNING: ThreadSanitizer: data race
-// CHECK: Location is global 'GlobalData' of size 40 at [[ADDR]] ({{.*}}+0x{{[0-9,a-f]+}})
+// CHECK: Location is global 'GlobalData' of size 40 at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
 
diff --git a/test/tsan/global_race2.cc b/test/tsan/global_race2.cc
index b8352ba..ac994cc 100644
--- a/test/tsan/global_race2.cc
+++ b/test/tsan/global_race2.cc
@@ -13,7 +13,9 @@
 }
 
 int main() {
-  fprintf(stderr, "addr2=%p\n", &x);
+  // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+  // match to the format used in the diagnotic message.
+  fprintf(stderr, "addr2=0x%012lx\n", (unsigned long) &x);
   pthread_t t;
   pthread_create(&t, 0, Thread, 0);
   x = 0;
diff --git a/test/tsan/global_race3.cc b/test/tsan/global_race3.cc
index e37bf78..a3222bb 100644
--- a/test/tsan/global_race3.cc
+++ b/test/tsan/global_race3.cc
@@ -18,7 +18,9 @@
 }
 
 int main() {
-  fprintf(stderr, "addr3=%p\n", XXX::YYY::ZZZ);
+  // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+  // match to the format used in the diagnotic message.
+  fprintf(stderr, "addr3=0x%012lx\n", (unsigned long) XXX::YYY::ZZZ);
   pthread_t t;
   pthread_create(&t, 0, Thread, 0);
   XXX::YYY::ZZZ[0] = 0;
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index f7051b3..d27500f 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -29,11 +29,9 @@
   extra_cflags = []
 
 # Setup default compiler flags used with -fsanitize=thread option.
-# FIXME: Review the set of required flags and check if it can be reduced.
 clang_tsan_cflags = ["-fsanitize=thread",
-                     "-g",
                      "-Wall",
-                     "-m64"] + extra_cflags
+                     "-m64"] + config.debug_info_flags + extra_cflags
 clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags
 # Add additional flags if we're using instrumented libc++.
 if config.has_libcxx:
@@ -62,6 +60,6 @@
 # Default test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp']
 
-# ThreadSanitizer tests are currently supported on Linux only.
-if config.host_os not in ['Linux']:
+# ThreadSanitizer tests are currently supported on FreeBSD and Linux only.
+if config.host_os not in ['FreeBSD', 'Linux']:
   config.unsupported = True
diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc
new file mode 100644
index 0000000..3a76fa2
--- /dev/null
+++ b/test/tsan/map32bit.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+// Test for issue:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=5
+
+void *Thread(void *ptr) {
+  *(int*)ptr = 42;
+  return 0;
+}
+
+int main() {
+  void *ptr = mmap(0, 128 << 10, PROT_READ|PROT_WRITE,
+      MAP_32BIT|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+  fprintf(stderr, "ptr=%p\n", ptr);
+  if (ptr == MAP_FAILED) {
+    fprintf(stderr, "mmap failed: %d\n", errno);
+    return 1;
+  }
+  if ((uintptr_t)ptr >= (1ull << 32)) {
+    fprintf(stderr, "ptr is too high\n");
+    return 1;
+  }
+  pthread_t t;
+  pthread_create(&t, 0, Thread, ptr);
+  sleep(1);
+  *(int*)ptr = 42;
+  pthread_join(t, 0);
+  munmap(ptr, 128 << 10);
+  fprintf(stderr, "DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
+
diff --git a/test/tsan/must_deadlock.cc b/test/tsan/must_deadlock.cc
new file mode 100644
index 0000000..1409800
--- /dev/null
+++ b/test/tsan/must_deadlock.cc
@@ -0,0 +1,50 @@
+// Test that the deadlock detector can find a deadlock that actually happened.
+// Currently we will fail to report such a deadlock because we check for
+// cycles in lock-order graph after pthread_mutex_lock.
+
+// RUN: %clangxx_tsan %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+pthread_mutex_t mu1, mu2;
+pthread_barrier_t barrier;
+
+void *Thread(void *p) {
+  // mu2 => mu1
+  pthread_mutex_lock(&mu2);
+  pthread_barrier_wait(&barrier);
+  pthread_mutex_lock(&mu1);
+  // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+  pthread_mutex_unlock(&mu1);
+  pthread_mutex_unlock(&mu2);
+  return p;
+}
+
+int main() {
+  pthread_mutex_init(&mu1, NULL);
+  pthread_mutex_init(&mu2, NULL);
+  pthread_barrier_init(&barrier, 0, 2);
+
+  fprintf(stderr, "This test is going to deadlock and die in 3 seconds\n");
+  alarm(3);
+
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+
+  // mu1 => mu2
+  pthread_mutex_lock(&mu1);
+  pthread_barrier_wait(&barrier);
+  pthread_mutex_lock(&mu2);
+  pthread_mutex_unlock(&mu2);
+  pthread_mutex_unlock(&mu1);
+
+  pthread_join(t, 0);
+
+  pthread_mutex_destroy(&mu1);
+  pthread_mutex_destroy(&mu2);
+  pthread_barrier_destroy(&barrier);
+  fprintf(stderr, "FAILED\n");
+}
diff --git a/test/tsan/pthread_atfork_deadlock.c b/test/tsan/pthread_atfork_deadlock.c
index 965de05..0f33b90 100644
--- a/test/tsan/pthread_atfork_deadlock.c
+++ b/test/tsan/pthread_atfork_deadlock.c
@@ -1,4 +1,4 @@
-// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clang_tsan -O1 %s -lpthread -o %t && %deflake %run %t | FileCheck %s
 // Regression test for
 // https://code.google.com/p/thread-sanitizer/issues/detail?id=61
 // When the data race was reported, pthread_atfork() handler used to be
diff --git a/test/tsan/signal_errno.cc b/test/tsan/signal_errno.cc
index 27d4ecd..1fa20f3 100644
--- a/test/tsan/signal_errno.cc
+++ b/test/tsan/signal_errno.cc
@@ -43,7 +43,7 @@
 }
 
 // CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
-// CHECK:     #0 MyHandler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
+// CHECK:     #0 MyHandler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
 // CHECK:     main
 // CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
 
diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc
new file mode 100644
index 0000000..84b0682
--- /dev/null
+++ b/test/tsan/signal_longjmp.cc
@@ -0,0 +1,69 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test case for longjumping out of signal handler:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=75
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+sigjmp_buf fault_jmp;
+volatile int fault_expected;
+
+void sigfault_handler(int sig) {
+  if (!fault_expected)
+    abort();
+
+  /* just return from sighandler to proper place */
+  fault_expected = 0;
+  siglongjmp(fault_jmp, 1);
+}
+
+#define MUST_FAULT(code) do { \
+  fault_expected = 1; \
+  if (!sigsetjmp(fault_jmp, 1)) { \
+    code; /* should pagefault -> sihandler does longjmp */ \
+    fprintf(stderr, "%s not faulted\n", #code); \
+    abort(); \
+  } else { \
+    fprintf(stderr, "%s faulted ok\n", #code); \
+  } \
+} while (0)
+
+int main() {
+  struct sigaction act;
+  act.sa_handler  = sigfault_handler;
+  act.sa_flags    = 0;
+  if (sigemptyset(&act.sa_mask)) {
+    perror("sigemptyset");
+    exit(1);
+  }
+
+  if (sigaction(SIGSEGV, &act, NULL)) {
+    perror("sigaction");
+    exit(1);
+  }
+
+  void *mem = mmap(0, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANON,
+      -1, 0);
+
+  MUST_FAULT(((volatile int *volatile)mem)[0] = 0);
+  MUST_FAULT(((volatile int *volatile)mem)[1] = 1);
+  MUST_FAULT(((volatile int *volatile)mem)[3] = 1);
+
+  // Ensure that tsan does not think that we are
+  // in a signal handler.
+  void *volatile p = malloc(10);
+  ((volatile int*)p)[1] = 1;
+  free((void*)p);
+
+  munmap(p, 4096);
+
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: DONE
diff --git a/test/tsan/signal_malloc.cc b/test/tsan/signal_malloc.cc
index db5e79b..06932fb 100644
--- a/test/tsan/signal_malloc.cc
+++ b/test/tsan/signal_malloc.cc
@@ -8,7 +8,7 @@
 static void handler(int, siginfo_t*, void*) {
   // CHECK: WARNING: ThreadSanitizer: signal-unsafe call inside of a signal
   // CHECK:     #0 malloc
-  // CHECK:     #{{(1|2)}} handler(int, siginfo{{(_t)?}}*, void*) {{.*}}signal_malloc.cc:[[@LINE+2]]
+  // CHECK:     #{{(1|2)}} handler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_malloc.cc:[[@LINE+2]]
   // CHECK: SUMMARY: ThreadSanitizer: signal-unsafe call inside of a signal{{.*}}handler
   volatile char *p = (char*)malloc(1);
   p[0] = 0;
diff --git a/test/tsan/signal_recursive.cc b/test/tsan/signal_recursive.cc
new file mode 100644
index 0000000..d92ba97
--- /dev/null
+++ b/test/tsan/signal_recursive.cc
@@ -0,0 +1,131 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test case for recursive signal handlers, adopted from:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=71
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static const int kSigSuspend = SIGUSR1;
+static const int kSigRestart = SIGUSR2;
+static sigset_t g_suspend_handler_mask;
+
+static sem_t g_thread_suspend_ack_sem;
+
+static bool g_busy_thread_received_restart;
+
+static volatile bool g_busy_thread_garbage_collected;
+
+static void SaveRegistersInStack() {
+  // Mono walks thread stacks to detect unreferenced objects.
+  // If last object reference is kept in register the object will be collected
+  // This is why threads can't be suspended with something like pthread_suspend
+};
+
+static void fail(const char *what) {
+  fprintf(stderr, "FAILED: %s (errno=%d)\n", what, errno);
+  exit(1);
+}
+
+static void SuspendHandler(int sig) {
+  int old_errno = errno;
+  SaveRegistersInStack();
+  // Acknowledge that thread is saved and suspended
+  if (sem_post(&g_thread_suspend_ack_sem) != 0)
+    fail("sem_post failed");
+
+  do {
+    g_busy_thread_received_restart = false;
+    if (sigsuspend(&g_suspend_handler_mask) != -1 || errno != EINTR)
+      fail("sigsuspend failed");
+  } while (!g_busy_thread_received_restart);
+
+  // Acknowledge that thread restarted
+  if (sem_post(&g_thread_suspend_ack_sem) != 0)
+    fail("sem_post failed");
+
+  g_busy_thread_garbage_collected = true;
+
+  errno = old_errno;
+}
+
+static void RestartHandler(int sig) {
+  g_busy_thread_received_restart = true;
+}
+
+static void StopWorld(pthread_t thread) {
+  int result = pthread_kill(thread, kSigSuspend);
+  if (result != 0)
+    fail("pthread_kill failed");
+
+  while ((result = sem_wait(&g_thread_suspend_ack_sem)) != 0) {
+    if (result != EINTR) {
+      fail("sem_wait failed");
+    }
+  }
+}
+
+static void StartWorld(pthread_t thread) {
+  int result = pthread_kill(thread, kSigRestart);
+  if (result != 0)
+    fail("pthread_kill failed");
+
+  while ((result = sem_wait(&g_thread_suspend_ack_sem)) != 0) {
+    if (result != EINTR) {
+      fail("sem_wait failed");
+    }
+  }
+}
+
+static void CollectGarbage(pthread_t thread) {
+  StopWorld(thread);
+  // Walk stacks
+    StartWorld(thread);
+}
+
+static void Init() {
+  if (sigfillset(&g_suspend_handler_mask) != 0)
+    fail("sigfillset failed");
+  if (sigdelset(&g_suspend_handler_mask, kSigRestart) != 0)
+    fail("sigdelset failed");
+  if (sem_init(&g_thread_suspend_ack_sem, 0, 0) != 0)
+    fail("sem_init failed");
+
+  struct sigaction act = {};
+  act.sa_flags = SA_RESTART;
+  sigfillset(&act.sa_mask);
+  act.sa_handler = &SuspendHandler;
+  if (sigaction(kSigSuspend, &act, NULL) != 0)
+    fail("sigaction failed");
+  act.sa_handler = &RestartHandler;
+  if (sigaction(kSigRestart, &act, NULL) != 0)
+    fail("sigaction failed");
+}
+
+void* BusyThread(void *arg) {
+  (void)arg;
+  while (!g_busy_thread_garbage_collected) {
+    usleep(100); // Tsan deadlocks without these sleeps
+  }
+  return NULL;
+}
+
+int main(int argc, const char *argv[]) {
+  Init();
+  pthread_t busy_thread;
+  pthread_create(&busy_thread, NULL, &BusyThread, NULL);
+  CollectGarbage(busy_thread);
+  pthread_join(busy_thread, 0);
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK-NOT: ThreadSanitizer CHECK failed
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/signal_sync.cc b/test/tsan/signal_sync.cc
new file mode 100644
index 0000000..15387b7
--- /dev/null
+++ b/test/tsan/signal_sync.cc
@@ -0,0 +1,58 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+
+volatile int X;
+
+static void handler(int sig) {
+  (void)sig;
+  if (X != 42)
+    printf("bad");
+}
+
+static void* thr(void *p) {
+  for (int i = 0; i != 1000; i++)
+    usleep(1000);
+  return 0;
+}
+
+int main() {
+  const int kThreads = 10;
+  pthread_t th[kThreads];
+  for (int i = 0; i < kThreads; i++)
+    pthread_create(&th[i], 0, thr, 0);
+
+  X = 42;
+
+  struct sigaction act = {};
+  act.sa_handler = &handler;
+  if (sigaction(SIGPROF, &act, 0)) {
+    perror("sigaction");
+    exit(1);
+  }
+
+  itimerval t;
+  t.it_value.tv_sec = 0;
+  t.it_value.tv_usec = 10;
+  t.it_interval = t.it_value;
+  if (setitimer(ITIMER_PROF, &t, 0)) {
+    perror("setitimer");
+    exit(1);
+  }
+
+  for (int i = 0; i < kThreads; i++)
+    pthread_join(th[i], 0);
+
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer:
diff --git a/test/tsan/signal_write.cc b/test/tsan/signal_write.cc
new file mode 100644
index 0000000..626d87a
--- /dev/null
+++ b/test/tsan/signal_write.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void handler(int, siginfo_t*, void*) {
+  const char *str = "HELLO FROM SIGNAL\n";
+  write(2, str, strlen(str));
+}
+
+int main() {
+  struct sigaction act = {};
+  act.sa_sigaction = &handler;
+  sigaction(SIGPROF, &act, 0);
+  kill(getpid(), SIGPROF);
+  sleep(1);
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: HELLO FROM SIGNAL
+// CHECK: DONE
+
diff --git a/test/tsan/sigsuspend.cc b/test/tsan/sigsuspend.cc
index f614c12..a5930d4 100644
--- a/test/tsan/sigsuspend.cc
+++ b/test/tsan/sigsuspend.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 
 // Always enable asserts.
 #ifdef NDEBUG
@@ -37,7 +37,7 @@
 
   // Restore the original set.
   assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
-  printf("DONE");
+  printf("DONE\n");
 }
 
 // CHECK: HANDLER
diff --git a/test/tsan/simple_stack.c b/test/tsan/simple_stack.c
index 899277f..8736703 100644
--- a/test/tsan/simple_stack.c
+++ b/test/tsan/simple_stack.c
@@ -53,7 +53,7 @@
 // CHECK-NEXT:     #1 bar1{{.*}} {{.*}}simple_stack.c:14{{(:3)?}} ({{.*}})
 // CHECK-NEXT:     #2 Thread1{{.*}} {{.*}}simple_stack.c:28{{(:3)?}} ({{.*}})
 // CHECK:        Previous read of size 4 at {{.*}} by thread T2:
-// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:26)?}} ({{.*}})
+// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:3)?}} ({{.*}})
 // CHECK-NEXT:     #1 bar2{{.*}} {{.*}}simple_stack.c:23{{(:3)?}} ({{.*}})
 // CHECK-NEXT:     #2 Thread2{{.*}} {{.*}}simple_stack.c:33{{(:3)?}} ({{.*}})
 // CHECK:        Thread T1 (tid={{.*}}, running) created by main thread at:
diff --git a/test/tsan/simple_stack2.cc b/test/tsan/simple_stack2.cc
index ba0303c..b07d863 100644
--- a/test/tsan/simple_stack2.cc
+++ b/test/tsan/simple_stack2.cc
@@ -1,4 +1,4 @@
-// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %T/simple_stack2.cc.exe && %deflake %run %T/simple_stack2.cc.exe | FileCheck %s
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -44,10 +44,10 @@
 
 // CHECK:      WARNING: ThreadSanitizer: data race
 // CHECK-NEXT:   Write of size 4 at {{.*}} by thread T1:
-// CHECK-NEXT:     #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} ({{.*}})
-// CHECK-NEXT:     #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} ({{.*}})
-// CHECK-NEXT:     #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} ({{.*}})
+// CHECK-NEXT:     #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT:     #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT:     #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
 // CHECK:        Previous read of size 4 at {{.*}} by main thread:
-// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:28)?}} ({{.*}})
-// CHECK-NEXT:     #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} ({{.*}})
-// CHECK-NEXT:     #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} ({{.*}})
+// CHECK-NEXT:     #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT:     #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT:     #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
diff --git a/test/tsan/sunrpc.cc b/test/tsan/sunrpc.cc
index 579eb72..579816d 100644
--- a/test/tsan/sunrpc.cc
+++ b/test/tsan/sunrpc.cc
@@ -1,6 +1,7 @@
 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 
 #include <pthread.h>
+#include <rpc/types.h>
 #include <rpc/xdr.h>
 #include <stdio.h>
 
diff --git a/test/tsan/test_output.sh b/test/tsan/test_output.sh
index 8b286f4..bce0fe8 100755
--- a/test/tsan/test_output.sh
+++ b/test/tsan/test_output.sh
@@ -12,8 +12,8 @@
 : ${FILECHECK:=FileCheck}
 
 # TODO: add testing for all of -O0...-O3
-CFLAGS="-fsanitize=thread -fPIE -O1 -g -Wall"
-LDFLAGS="-pie -pthread -ldl -lrt -lm -Wl,--whole-archive $TSAN_DIR/rtl/libtsan.a -Wl,--no-whole-archive"
+CFLAGS="-fsanitize=thread -O2 -g -Wall"
+LDFLAGS="-pthread -ldl -lrt -lm -Wl,--whole-archive $TSAN_DIR/rtl/libtsan.a -Wl,--no-whole-archive"
 
 test_file() {
   SRC=$1
@@ -48,6 +48,10 @@
       echo SKIPPING $c -- requires TSAN_OPTIONS
       continue
     fi
+    if [ "`grep "XFAIL" $c`" ]; then
+      echo SKIPPING $c -- has XFAIL
+      continue
+    fi
     COMPILER=$CXX
     case $c in
       *.c) COMPILER=$CC
diff --git a/test/tsan/thread_detach.c b/test/tsan/thread_detach.c
new file mode 100644
index 0000000..32cf641
--- /dev/null
+++ b/test/tsan/thread_detach.c
@@ -0,0 +1,20 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  sleep(1);
+  pthread_detach(t);
+  printf("PASS\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+// CHECK: PASS
diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc
index 05b0a35..a790c66 100644
--- a/test/tsan/thread_name.cc
+++ b/test/tsan/thread_name.cc
@@ -3,6 +3,16 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#if defined(__linux__)
+#define USE_PTHREAD_SETNAME_NP __GLIBC_PREREQ(2, 12)
+#elif defined(__FreeBSD__)
+#include <pthread_np.h>
+#define USE_PTHREAD_SETNAME_NP 1
+#define pthread_setname_np pthread_set_name_np
+#else
+#define USE_PTHREAD_SETNAME_NP 0
+#endif
+
 extern "C" void AnnotateThreadName(const char *f, int l, const char *name);
 
 int Global;
@@ -15,7 +25,7 @@
 }
 
 void *Thread2(void *x) {
-#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 12)
+#if USE_PTHREAD_SETNAME_NP
   pthread_setname_np(pthread_self(), "Thread2");
 #else
   AnnotateThreadName(__FILE__, __LINE__, "Thread2");
@@ -35,4 +45,3 @@
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK:   Thread T1 'Thread1'
 // CHECK:   Thread T2 'Thread2'
-
diff --git a/test/tsan/thread_name2.cc b/test/tsan/thread_name2.cc
index b9a5746..6a3dafe 100644
--- a/test/tsan/thread_name2.cc
+++ b/test/tsan/thread_name2.cc
@@ -3,6 +3,11 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#if defined(__FreeBSD__)
+#include <pthread_np.h>
+#define pthread_setname_np pthread_set_name_np
+#endif
+
 int Global;
 
 void *Thread1(void *x) {
@@ -29,4 +34,3 @@
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK:   Thread T1 'foobar1'
 // CHECK:   Thread T2 'foobar2'
-
diff --git a/test/tsan/vptr_harmful_race4.cc b/test/tsan/vptr_harmful_race4.cc
new file mode 100644
index 0000000..969c9d5
--- /dev/null
+++ b/test/tsan/vptr_harmful_race4.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+  virtual void F() {
+  }
+
+  virtual ~A() {
+  }
+};
+
+struct B : A {
+  virtual void F() {
+  }
+};
+
+void *Thread(void *x) {
+  sleep(1);
+  ((A*)x)->F();
+  return 0;
+}
+
+int main() {
+  A *obj = new B;
+  pthread_t t;
+  pthread_create(&t, 0, Thread, obj);
+  delete obj;
+  pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free (virtual call vs free)
+
diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt
index 4c6b0bc..1c0c929 100644
--- a/test/ubsan/CMakeLists.txt
+++ b/test/ubsan/CMakeLists.txt
@@ -6,7 +6,7 @@
   ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig/lit.site.cfg)
 set(UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig)
 
-if(ASAN_SUPPORTED_ARCH)
+if(COMPILER_RT_HAS_ASAN)
   set(UBSAN_LIT_TEST_MODE "AddressSanitizer")
   configure_lit_site_cfg(
     ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
index cc6f9ad..22991e0 100644
--- a/test/ubsan/TestCases/Float/cast-overflow.cpp
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -1,3 +1,4 @@
+// FIXME: run this (and other) UBSan tests in both 32- and 64-bit modes (?).
 // RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t
 // RUN: %run %t _
 // RUN: %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
@@ -8,25 +9,28 @@
 // RUN: %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5
 // RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
 // FIXME: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
-// RUN: %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
-// RUN: %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
-
-// FIXME: run all ubsan tests in 32- and 64-bit modes (?).
-// FIXME: %clangxx -fsanitize=float-cast-overflow -m32 %s -o %t
-// FIXME: %run %t _
-// FIXME: %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
-// FIXME: %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1
-// FIXME: %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2
-// FIXME: %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3
-// FIXME: %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4
-// FIXME: %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5
-// FIXME: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
-// FIXME: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
-// FIXME: %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
-// FIXME: %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
+// FIXME: not %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
+// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
 
 // This test assumes float and double are IEEE-754 single- and double-precision.
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
+#if defined(__APPLE__)
+# include <machine/endian.h>
+# define BYTE_ORDER __DARWIN_BYTE_ORDER
+# define BIG_ENDIAN __DARWIN_BIG_ENDIAN
+# define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
+#elif defined(__FreeBSD__)
+# include <sys/endian.h>
+# define BYTE_ORDER _BYTE_ORDER
+# define BIG_ENDIAN _BIG_ENDIAN
+# define LITTLE_ENDIAN _LITTLE_ENDIAN
+#else
+# include <endian.h>
+# define BYTE_ORDER __BYTE_ORDER
+# define BIG_ENDIAN __BIG_ENDIAN
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif  // __APPLE__
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -54,12 +58,20 @@
   unsigned Zero = NearlyMinusOne; // ok
 
   // Build a '+Inf'.
+#if BYTE_ORDER == LITTLE_ENDIAN
   char InfVal[] = { 0x00, 0x00, 0x80, 0x7f };
+#else
+  char InfVal[] = { 0x7f, 0x80, 0x00, 0x00 };
+#endif
   float Inf;
   memcpy(&Inf, InfVal, 4);
 
   // Build a 'NaN'.
+#if BYTE_ORDER == LITTLE_ENDIAN
   char NaNVal[] = { 0x01, 0x00, 0x80, 0x7f };
+#else
+  char NaNVal[] = { 0x7f, 0x80, 0x00, 0x01 };
+#endif
   float NaN;
   memcpy(&NaN, NaNVal, 4);
 
@@ -77,9 +89,12 @@
   case '1':
     // CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
     return MinFloatRepresentableAsInt - 0x100;
-  case '2':
+  case '2': {
     // CHECK-2: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
-    return (unsigned)-1.0;
+    volatile float f = -1.0;
+    volatile unsigned u = (unsigned)f;
+    return 0;
+  }
   case '3':
     // CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
     return (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
diff --git a/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp
index 90dfd2e..575bd0a 100644
--- a/test/ubsan/TestCases/Integer/no-recover.cpp
+++ b/test/ubsan/TestCases/Integer/no-recover.cpp
@@ -1,6 +1,6 @@
 // RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
 // RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
 
 #include <stdint.h>
 
diff --git a/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp
new file mode 100644
index 0000000..6e9aec6
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/summary.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=integer %s -o %t && %t 2>&1 | FileCheck %s
+// REQUIRES: ubsan-asan
+
+#include <stdint.h>
+
+int main() {
+  (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+  // CHECK: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]
+  return 0;
+}
diff --git a/test/ubsan/TestCases/Misc/bool.cpp b/test/ubsan/TestCases/Misc/bool.cpp
index 5fe5cf1..37ecea2 100644
--- a/test/ubsan/TestCases/Misc/bool.cpp
+++ b/test/ubsan/TestCases/Misc/bool.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -fsanitize=bool %s -O3 -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=bool %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s
 
 unsigned char NotABool = 123;
 
diff --git a/test/ubsan/TestCases/Misc/bounds.cpp b/test/ubsan/TestCases/Misc/bounds.cpp
index ea59b02..ffcac52 100644
--- a/test/ubsan/TestCases/Misc/bounds.cpp
+++ b/test/ubsan/TestCases/Misc/bounds.cpp
@@ -1,7 +1,7 @@
 // RUN: %clangxx -fsanitize=bounds %s -O3 -o %t
 // RUN: %run %t 0 0 0
 // RUN: %run %t 1 2 3
-// RUN: %run %t 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2
+// RUN: not --crash %run %t 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2
 // RUN: %run %t 0 3 0 2>&1 | FileCheck %s --check-prefix=CHECK-B-3
 // RUN: %run %t 0 0 4 2>&1 | FileCheck %s --check-prefix=CHECK-C-4
 
@@ -9,7 +9,7 @@
   int arr[2][3][4] = {};
 
   return arr[argv[1][0] - '0'][argv[2][0] - '0'][argv[3][0] - '0'];
-  // CHECK-A-2: bounds.cpp:11:10: runtime error: index 2 out of bounds for type 'int [2][3][4]'
-  // CHECK-B-3: bounds.cpp:11:10: runtime error: index 3 out of bounds for type 'int [3][4]'
-  // CHECK-C-4: bounds.cpp:11:10: runtime error: index 4 out of bounds for type 'int [4]'
+  // CHECK-A-2: bounds.cpp:[[@LINE-1]]:10: runtime error: index 2 out of bounds for type 'int [2][3][4]'
+  // CHECK-B-3: bounds.cpp:[[@LINE-2]]:10: runtime error: index 3 out of bounds for type 'int [3][4]'
+  // CHECK-C-4: bounds.cpp:[[@LINE-3]]:10: runtime error: index 4 out of bounds for type 'int [4]'
 }
diff --git a/test/ubsan/TestCases/Misc/enum.cpp b/test/ubsan/TestCases/Misc/enum.cpp
index c95ce82..49ac7c6 100644
--- a/test/ubsan/TestCases/Misc/enum.cpp
+++ b/test/ubsan/TestCases/Misc/enum.cpp
@@ -1,6 +1,6 @@
 // RUN: %clangxx -fsanitize=enum %s -O3 -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN
 // RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %run %t
-// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL
+// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL
 
 enum E { a = 1 } e;
 #undef E
diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp
index 04bc791..5d3d54d 100644
--- a/test/ubsan/TestCases/Misc/missing_return.cpp
+++ b/test/ubsan/TestCases/Misc/missing_return.cpp
@@ -1,7 +1,15 @@
-// RUN: %clangxx -fsanitize=return %s -O3 -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os-STACKTRACE
 
-// CHECK: missing_return.cpp:4:5: runtime error: execution reached the end of a value-returning function without returning a value
+// CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
 int f() {
+// Slow stack unwinding is disabled on Darwin for now, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+// CHECK-Linux-STACKTRACE: #0 {{.*}} in f(){{.*}}missing_return.cpp:[[@LINE-3]]
+// CHECK-FreeBSD-STACKTRACE: #0 {{.*}} in f(void){{.*}}missing_return.cpp:[[@LINE-4]]
+// Check for already checked line to avoid lit error reports.
+// CHECK-Darwin-STACKTRACE: missing_return.cpp
 }
 
 int main(int, char **argv) {
diff --git a/test/ubsan/TestCases/Misc/nonnull-arg.cpp b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
new file mode 100644
index 0000000..b1061b7
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
@@ -0,0 +1,58 @@
+// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover %s -O3 -o %t
+// RUN: %run %t nc
+// RUN: %run %t nm
+// RUN: %run %t nf
+// RUN: %run %t nv
+// RUN: not %run %t 0c 2>&1 | FileCheck %s --check-prefix=CTOR
+// RUN: not %run %t 0m 2>&1 | FileCheck %s --check-prefix=METHOD
+// RUN: not %run %t 0f 2>&1 | FileCheck %s --check-prefix=FUNC
+// RUN: not %run %t 0v 2>&1 | FileCheck %s --check-prefix=VARIADIC
+
+class C {
+  int *null_;
+  int *nonnull_;
+
+public:
+  C(int *null, __attribute__((nonnull)) int *nonnull)
+      : null_(null), nonnull_(nonnull) {}
+  int value() { return *nonnull_; }
+  int method(int *nonnull, int *null) __attribute__((nonnull(2))) {
+    return *nonnull_ + *nonnull;
+  }
+};
+
+__attribute__((nonnull)) int func(int *nonnull) { return *nonnull; }
+
+#include <stdarg.h>
+__attribute__((nonnull)) int variadic(int x, ...) {
+  va_list args;
+  va_start(args, x);
+  int *nonnull = va_arg(args, int*);
+  int res = *nonnull;
+  va_end(args);
+  return res;
+}
+
+int main(int argc, char *argv[]) {
+  int local = 0;
+  int *arg = (argv[1][0] == '0') ? 0x0 : &local;
+  switch (argv[1][1]) {
+    case 'c':
+      return C(0x0, arg).value();
+      // CTOR: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:21: runtime error: null pointer passed as argument 2, which is declared to never be null
+      // CTOR-NEXT: {{.*}}nonnull-arg.cpp:16:31: note: nonnull attribute specified here
+    case 'm':
+      return C(0x0, &local).method(arg, 0x0);
+      // METHOD: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:36: runtime error: null pointer passed as argument 1, which is declared to never be null
+      // METHOD-NEXT: {{.*}}nonnull-arg.cpp:19:54: note: nonnull attribute specified here
+    case 'f':
+      return func(arg);
+      // FUNC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+      // FUNC-NEXT: {{.*}}nonnull-arg.cpp:24:16: note: nonnull attribute specified here
+    case 'v':
+      return variadic(42, arg);
+    // VARIADIC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:27: runtime error: null pointer passed as argument 2, which is declared to never be null
+    // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here
+  }
+  return 0;
+}
diff --git a/test/ubsan/TestCases/Misc/nonnull.cpp b/test/ubsan/TestCases/Misc/nonnull.cpp
new file mode 100644
index 0000000..c3ab49c
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=returns-nonnull-attribute %s -O3 -o %t
+// RUN: %run %t foo
+// RUN: %run %t 2>&1 | FileCheck %s
+
+__attribute__((returns_nonnull)) char *foo(char *a);
+
+char *foo(char *a) {
+  return a;
+  // CHECK: nonnull.cpp:[[@LINE+2]]:1: runtime error: null pointer returned from function declared to never return null
+  // CHECK-NEXT: nonnull.cpp:[[@LINE-5]]:16: note: returns_nonnull attribute specified here
+}
+
+int main(int argc, char **argv) {
+  return foo(argv[1]) == 0;
+}
diff --git a/test/ubsan/TestCases/Misc/unreachable.cpp b/test/ubsan/TestCases/Misc/unreachable.cpp
index ba76063..e1206ed 100644
--- a/test/ubsan/TestCases/Misc/unreachable.cpp
+++ b/test/ubsan/TestCases/Misc/unreachable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s
 
 int main(int, char **argv) {
   // CHECK: unreachable.cpp:5:3: runtime error: execution reached a __builtin_unreachable() call
diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
index 33c2d1c..deca77d 100644
--- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp
+++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -1,5 +1,10 @@
 // RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
 // RUN: %run %t 2>&1 | FileCheck %s
+// Verify that we can disable symbolization if needed:
+// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
+
+// -fsanitize=function is unsupported on Darwin yet.
+// XFAIL: darwin
 
 #include <stdint.h>
 
@@ -9,7 +14,9 @@
 
 int main(void) {
   // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
-  // CHECK-NEXT: function.cpp:6: note: f() defined here
+  // CHECK-NEXT: function.cpp:11: note: f() defined here
+  // NOSYM: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+  // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
   reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
 
   // CHECK-NOT: runtime error: call to function g
diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
index 71d82e0..79f5136 100644
--- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp
+++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -1,11 +1,17 @@
-// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t
-// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0
+// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t
+// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0
 // RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
 // RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
 // RUN: %run %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
 // RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
 // RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
 // RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
+// RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
+
+// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t
+// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD
+// XFAIL: armv7l-unknown-linux-gnueabihf
 
 #include <new>
 
@@ -15,12 +21,19 @@
   int k;
 };
 
+struct T : S {
+  int t;
+};
+
 int main(int, char **argv) {
   char c[] __attribute__((aligned(8))) = { 0, 0, 0, 0, 1, 2, 3, 4, 5 };
 
   // Pointer value may be unspecified here, but behavior is not undefined.
   int *p = (int*)&c[4 + argv[1][1] - '0'];
   S *s = (S*)p;
+  T *t = (T*)p;
+
+  void *wild = reinterpret_cast<void *>(0x123L);
 
   (void)*p; // ok!
 
@@ -31,6 +44,11 @@
     // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04  05}}
     // CHECK-LOAD-NEXT: {{^             \^}}
     return *p && 0;
+    // Slow stack unwinding is disabled on Darwin for now, see
+    // https://code.google.com/p/address-sanitizer/issues/detail?id=137
+    // CHECK-Linux-STACK-LOAD: #0 {{.*}} in main{{.*}}misaligned.cpp
+    // Check for the already checked line to avoid lit error reports.
+    // CHECK-Darwin-STACK-LOAD: {{ }}
 
   case 's':
     // CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
@@ -63,11 +81,25 @@
     return s->f() && 0;
 
   case 'n':
-    // FIXME: Provide a better source location here.
-    // CHECK-NEW: misaligned{{.*}}+0x{{[0-9a-f]*}}): runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+    // CHECK-NEW: misaligned.cpp:[[@LINE+4]]:5: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
     // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
     // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04  05}}
     // CHECK-NEW-NEXT: {{^             \^}}
     return (new (s) S)->k && 0;
+
+  case 'u': {
+    // CHECK-UPCAST: misaligned.cpp:[[@LINE+4]]:17: runtime error: upcast of misaligned address [[PTR:0x[0-9a-f]*]] for type 'T', which requires 4 byte alignment
+    // CHECK-UPCAST-NEXT: [[PTR]]: note: pointer points here
+    // CHECK-UPCAST-NEXT: {{^ 00 00 00 01 02 03 04  05}}
+    // CHECK-UPCAST-NEXT: {{^             \^}}
+    S *s2 = (S*)t;
+    return s2->f();
+  }
+
+  case 'w':
+    // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment
+    // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here
+    // CHECK-WILD-NEXT: <memory cannot be printed>
+    return static_cast<S*>(wild)->k;
   }
 }
diff --git a/test/ubsan/TestCases/TypeCheck/null.cpp b/test/ubsan/TestCases/TypeCheck/null.cpp
index 47f5270..2a90f7f 100644
--- a/test/ubsan/TestCases/TypeCheck/null.cpp
+++ b/test/ubsan/TestCases/TypeCheck/null.cpp
@@ -1,6 +1,6 @@
 // RUN: %clangxx -fsanitize=null %s -O3 -o %t
 // RUN: %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD
-// RUN: %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
+// RUN: not --crash %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
 // RUN: %run %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
 // RUN: %run %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
 // RUN: %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
new file mode 100644
index 0000000..5261e71
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// FIXME: This test produces linker errors on Darwin.
+// XFAIL: darwin
+
+struct S { virtual int f() { return 0; } };
+struct T : virtual S {};
+
+struct Foo { virtual int f() { return 0; } };
+
+int main(int argc, char **argv) {
+  Foo foo;
+  T *t = (T*)&foo;
+  S *s = t;
+  // CHECK: vptr-virtual-base.cpp:[[@LINE-1]]:10: runtime error: cast to virtual base of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+  // CHECK-NEXT: [[PTR]]: note: object is of type 'Foo'
+  return s->f();
+}
diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp
index 4a8910c..3a6b155 100644
--- a/test/ubsan/TestCases/TypeCheck/vptr.cpp
+++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -fsanitize=vptr %s -O3 -o %t
+// RUN: %clangxx -fsanitize=vptr -g %s -O3 -o %t
 // RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
 // RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
 // RUN: %run %t rS && %run %t rV && %run %t oV
@@ -11,8 +11,27 @@
 // RUN: %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
 // RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
 
+// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t oU 2>&1
+
+// RUN: echo "vptr_check:S" > %t.loc-supp
+// RUN: ASAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
+
 // FIXME: This test produces linker errors on Darwin.
 // XFAIL: darwin
+// REQUIRES: stable-runtime
+
+extern "C" {
+const char *__ubsan_default_options() {
+  return "print_stacktrace=1";
+}
+}
 
 struct S {
   S() : a(0) {}
@@ -29,9 +48,15 @@
   virtual int v() { return 1; }
 };
 
-struct U : S, T { virtual int v() { return 2; } };
+struct X {};
+struct U : S, T, virtual X { virtual int v() { return 2; } };
 
-T *p = 0;  // Make p global so that lsan does not complain.
+struct V : S {};
+
+// Make p global so that lsan does not complain.
+T *p = 0;
+
+int access_p(T *p, char type);
 
 int main(int, char **argv) {
   T t;
@@ -70,18 +95,37 @@
     break;
   }
 
-  switch (argv[1][0]) {
+  access_p(p, argv[1][0]);
+  return 0;
+}
+
+int access_p(T *p, char type) {
+  switch (type) {
   case 'r':
     // Binding a reference to storage of appropriate size and alignment is OK.
     {T &r = *p;}
     break;
 
+  case 'x':
+    for (int i = 0; i < 2; i++) {
+      // Check that the first iteration ("S") succeeds, while the second ("V") fails.
+      p = reinterpret_cast<T*>((i == 0) ? new S : new V);
+      // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:7: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+      // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
+      // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
+      // CHECK-LOC-SUPPRESS-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+      // CHECK-LOC-SUPPRESS-NEXT: {{^              vptr for 'V'}}
+      p->g();
+    }
+    return 0;
+
   case 'm':
-    // CHECK-MEMBER: vptr.cpp:[[@LINE+5]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-MEMBER-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // CHECK-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
     return p->b;
 
     // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
@@ -89,29 +133,33 @@
     // CHECK-NULL-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
     // CHECK-NULL-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-NULL-MEMBER-NEXT: {{^              invalid vptr}}
+    // CHECK-NULL-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE-7]]
 
   case 'f':
-    // CHECK-MEMFUN: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-MEMFUN-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // TODO: Add check for stacktrace here.
     return p->g();
 
   case 'o':
-    // CHECK-OFFSET: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
+    // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
     // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
     // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
     // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
+    // CHECK-OFFSET-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
     return reinterpret_cast<U*>(p)->v() - 2;
 
   case 'c':
-    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+5]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-DOWNCAST-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // CHECK-DOWNCAST-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
     static_cast<T*>(reinterpret_cast<S*>(p));
     return 0;
   }
diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg
index a34a191..d28733a 100644
--- a/test/ubsan/lit.common.cfg
+++ b/test/ubsan/lit.common.cfg
@@ -18,10 +18,17 @@
 ubsan_lit_test_mode = get_required_attr(config, 'ubsan_lit_test_mode')
 if ubsan_lit_test_mode == "Standalone":
   config.name = 'UndefinedBehaviorSanitizer-Standalone'
+  config.available_features.add("ubsan-standalone")
   clang_ubsan_cflags = []
 elif ubsan_lit_test_mode == "AddressSanitizer":
+  if config.host_os == 'Darwin':
+    # ubsan-asan doesn't yet work on Darwin,
+    # see http://llvm.org/bugs/show_bug.cgi?id=21112.
+    config.unsupported = True
   config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer'
+  config.available_features.add("ubsan-asan")
   clang_ubsan_cflags = ["-fsanitize=address"]
+  config.environment['ASAN_OPTIONS'] = 'detect_leaks=0'
 else:
   lit_config.fatal("Unknown UBSan test mode: %r" % ubsan_lit_test_mode)
 
@@ -39,9 +46,11 @@
 # Default test suffixes.
 config.suffixes = ['.c', '.cc', '.cpp']
 
-# UndefinedBehaviorSanitizer tests are currently supported on
-# Linux and Darwin only.
-if config.host_os not in ['Linux', 'Darwin']:
+# Check that the host supports UndefinedBehaviorSanitizer tests
+if config.host_os not in ['Linux', 'Darwin', 'FreeBSD']:
   config.unsupported = True
 
-config.pipefail = False
+# Allow tests to use REQUIRES=stable-runtime.  For use when you cannot use XFAIL
+# because the test hangs or fails on one configuration and not the other.
+if config.target_arch.startswith('arm') == False:
+  config.available_features.add('stable-runtime')