Update compiler-rt aosp/master for 3.5 (r209699) rebase.

Change-Id: I158a30186f0faea2e2400e9dfdd878db2eb40e90
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 84c1e67..19c931a 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -4,26 +4,34 @@
 set(SANITIZER_SOURCES
   sanitizer_allocator.cc
   sanitizer_common.cc
-  sanitizer_coverage.cc
+  sanitizer_deadlock_detector1.cc
+  sanitizer_deadlock_detector2.cc
   sanitizer_flags.cc
   sanitizer_libc.cc
   sanitizer_libignore.cc
   sanitizer_linux.cc
   sanitizer_mac.cc
+  sanitizer_persistent_allocator.cc
   sanitizer_platform_limits_linux.cc
   sanitizer_platform_limits_posix.cc
   sanitizer_posix.cc
   sanitizer_printf.cc
+  sanitizer_procmaps_linux.cc
+  sanitizer_procmaps_mac.cc
   sanitizer_stackdepot.cc
   sanitizer_stacktrace.cc
   sanitizer_suppressions.cc
   sanitizer_symbolizer.cc
+  sanitizer_symbolizer_libbacktrace.cc
   sanitizer_symbolizer_win.cc
+  sanitizer_tls_get_addr.cc
   sanitizer_thread_registry.cc
   sanitizer_win.cc)
 
 set(SANITIZER_LIBCDEP_SOURCES
   sanitizer_common_libcdep.cc
+  sanitizer_coverage_libcdep.cc
+  sanitizer_coverage_mapping_libcdep.cc
   sanitizer_linux_libcdep.cc
   sanitizer_posix_libcdep.cc
   sanitizer_stacktrace_libcdep.cc
@@ -35,16 +43,21 @@
 # included in sanitizer_common source files, but we need to depend on
 # headers when building our custom unit tests.
 set(SANITIZER_HEADERS
+  sanitizer_addrhashmap.h
   sanitizer_allocator.h
   sanitizer_allocator_internal.h
+  sanitizer_atomic.h
   sanitizer_atomic_clang.h
   sanitizer_atomic_msvc.h
-  sanitizer_atomic.h
+  sanitizer_bitvector.h
+  sanitizer_bvgraph.h
   sanitizer_common.h
   sanitizer_common_interceptors.inc
   sanitizer_common_interceptors_ioctl.inc
-  sanitizer_common_interceptors_scanf.inc
+  sanitizer_common_interceptors_format.inc
   sanitizer_common_syscalls.inc
+  sanitizer_deadlock_detector.h
+  sanitizer_deadlock_detector_interface.h
   sanitizer_flags.h
   sanitizer_internal_defs.h
   sanitizer_lfstack.h
@@ -52,31 +65,44 @@
   sanitizer_libignore.h
   sanitizer_linux.h
   sanitizer_list.h
+  sanitizer_mac.h
   sanitizer_mutex.h
+  sanitizer_persistent_allocator.h
   sanitizer_placement_new.h
+  sanitizer_platform.h
   sanitizer_platform_interceptors.h
+  sanitizer_platform_limits_posix.h
   sanitizer_procmaps.h
   sanitizer_quarantine.h
   sanitizer_report_decorator.h
   sanitizer_stackdepot.h
+  sanitizer_stackdepotbase.h
   sanitizer_stacktrace.h
+  sanitizer_stoptheworld.h
+  sanitizer_suppressions.h
   sanitizer_symbolizer.h
+  sanitizer_symbolizer_libbacktrace.h
+  sanitizer_syscall_generic.inc
+  sanitizer_syscall_linux_x86_64.inc
   sanitizer_thread_registry.h)
 
-if (NOT MSVC)
-  set(SANITIZER_CFLAGS
-    ${SANITIZER_COMMON_CFLAGS}
-    -fno-rtti)
+set(SANITIZER_COMMON_DEFINITIONS)
+
+if(MSVC)
+  list(APPEND SANITIZER_COMMON_DEFINITIONS
+    SANITIZER_NEEDS_SEGV=0)
 else()
-  set(SANITIZER_CFLAGS
-    ${SANITIZER_COMMON_CFLAGS}
-    /GR-)
+  list(APPEND SANITIZER_COMMON_DEFINITIONS
+    SANITIZER_NEEDS_SEGV=1)
 endif()
 
-if(SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
-  list(APPEND SANITIZER_CFLAGS -Wglobal-constructors)
-endif()
+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)
+
+add_custom_target(sanitizer_common)
 set(SANITIZER_RUNTIME_LIBRARIES)
 if(APPLE)
   # Build universal binary on APPLE.
@@ -84,7 +110,8 @@
     add_compiler_rt_darwin_object_library(RTSanitizerCommon ${os}
       ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}
       SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES}
-      CFLAGS ${SANITIZER_CFLAGS})
+      CFLAGS ${SANITIZER_CFLAGS}
+      DEFS ${SANITIZER_COMMON_DEFINITIONS})
     list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os})
   endforeach()
 elseif(ANDROID)
@@ -92,24 +119,32 @@
     ${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})
     add_compiler_rt_object_library(RTSanitizerCommon ${arch}
-      SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
+      SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
+      DEFS ${SANITIZER_COMMON_DEFINITIONS})
     add_compiler_rt_object_library(RTSanitizerCommonLibc ${arch}
-      SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS})
-    add_compiler_rt_static_runtime(clang_rt.san-${arch} ${arch}
-      SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
-      CFLAGS ${SANITIZER_CFLAGS})
+      SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS}
+      DEFS ${SANITIZER_COMMON_DEFINITIONS})
     list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch}
                                             RTSanitizerCommonLibc.${arch})
+    add_compiler_rt_runtime(clang_rt.san-${arch} ${arch} STATIC
+      SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+      CFLAGS ${SANITIZER_CFLAGS}
+      DEFS ${SANITIZER_COMMON_DEFINITIONS})
+    add_dependencies(sanitizer_common clang_rt.san-${arch})
   endforeach()
 endif()
 
+add_dependencies(compiler-rt sanitizer_common)
+
 # Unit tests for common sanitizer runtime.
-if(LLVM_INCLUDE_TESTS)
+if(COMPILER_RT_INCLUDE_TESTS)
   add_subdirectory(tests)
 endif()
diff --git a/lib/sanitizer_common/sanitizer_addrhashmap.h b/lib/sanitizer_common/sanitizer_addrhashmap.h
new file mode 100644
index 0000000..acf4ff0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_addrhashmap.h
@@ -0,0 +1,342 @@
+//===-- sanitizer_addrhashmap.h ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Concurrent uptr->T hashmap.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ADDRHASHMAP_H
+#define SANITIZER_ADDRHASHMAP_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_allocator_internal.h"
+
+namespace __sanitizer {
+
+// Concurrent uptr->T hashmap.
+// T must be a POD type, kSize is preferably a prime but can be any number.
+// Usage example:
+//
+// typedef AddrHashMap<uptr, 11> Map;
+// Map m;
+// {
+//   Map::Handle h(&m, addr);
+//   use h.operator->() to access the data
+//   if h.created() then the element was just created, and the current thread
+//     has exclusive access to it
+//   otherwise the current thread has only read access to the data
+// }
+// {
+//   Map::Handle h(&m, addr, true);
+//   this will remove the data from the map in Handle dtor
+//   the current thread has exclusive access to the data
+//   if !h.exists() then the element never existed
+// }
+template<typename T, uptr kSize>
+class AddrHashMap {
+ private:
+  struct Cell {
+    atomic_uintptr_t addr;
+    T                val;
+  };
+
+  struct AddBucket {
+    uptr cap;
+    uptr size;
+    Cell cells[1];  // variable len
+  };
+
+  static const uptr kBucketSize = 3;
+
+  struct Bucket {
+    RWMutex          mtx;
+    atomic_uintptr_t add;
+    Cell             cells[kBucketSize];
+  };
+
+ public:
+  AddrHashMap();
+
+  class Handle {
+   public:
+    Handle(AddrHashMap<T, kSize> *map, uptr addr);
+    Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove);
+    Handle(AddrHashMap<T, kSize> *map, uptr addr, bool remove, bool create);
+
+    ~Handle();
+    T *operator->();
+    bool created() const;
+    bool exists() const;
+
+   private:
+    friend AddrHashMap<T, kSize>;
+    AddrHashMap<T, kSize> *map_;
+    Bucket                *bucket_;
+    Cell                  *cell_;
+    uptr                   addr_;
+    uptr                   addidx_;
+    bool                   created_;
+    bool                   remove_;
+    bool                   create_;
+  };
+
+ private:
+  friend class Handle;
+  Bucket *table_;
+
+  void acquire(Handle *h);
+  void release(Handle *h);
+  uptr calcHash(uptr addr);
+};
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr) {
+  map_ = map;
+  addr_ = addr;
+  remove_ = false;
+  create_ = true;
+  map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+    bool remove) {
+  map_ = map;
+  addr_ = addr;
+  remove_ = remove;
+  create_ = true;
+  map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::Handle(AddrHashMap<T, kSize> *map, uptr addr,
+    bool remove, bool create) {
+  map_ = map;
+  addr_ = addr;
+  remove_ = remove;
+  create_ = create;
+  map_->acquire(this);
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::Handle::~Handle() {
+  map_->release(this);
+}
+
+template <typename T, uptr kSize>
+T *AddrHashMap<T, kSize>::Handle::operator->() {
+  return &cell_->val;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::created() const {
+  return created_;
+}
+
+template<typename T, uptr kSize>
+bool AddrHashMap<T, kSize>::Handle::exists() const {
+  return cell_ != 0;
+}
+
+template<typename T, uptr kSize>
+AddrHashMap<T, kSize>::AddrHashMap() {
+  table_ = (Bucket*)MmapOrDie(kSize * sizeof(table_[0]), "AddrHashMap");
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::acquire(Handle *h) {
+  uptr addr = h->addr_;
+  uptr hash = calcHash(addr);
+  Bucket *b = &table_[hash];
+
+  h->created_ = false;
+  h->addidx_ = -1U;
+  h->bucket_ = b;
+  h->cell_ = 0;
+
+  // If we want to remove the element, we need exclusive access to the bucket,
+  // so skip the lock-free phase.
+  if (h->remove_)
+    goto locked;
+
+ retry:
+  // First try to find an existing element w/o read mutex.
+  CHECK(!h->remove_);
+  // Check the embed cells.
+  for (uptr i = 0; i < kBucketSize; i++) {
+    Cell *c = &b->cells[i];
+    uptr addr1 = atomic_load(&c->addr, memory_order_acquire);
+    if (addr1 == addr) {
+      h->cell_ = c;
+      return;
+    }
+  }
+
+  // Check the add cells with read lock.
+  if (atomic_load(&b->add, memory_order_relaxed)) {
+    b->mtx.ReadLock();
+    AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+    for (uptr i = 0; i < add->size; i++) {
+      Cell *c = &add->cells[i];
+      uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+      if (addr1 == addr) {
+        h->addidx_ = i;
+        h->cell_ = c;
+        return;
+      }
+    }
+    b->mtx.ReadUnlock();
+  }
+
+ locked:
+  // Re-check existence under write lock.
+  // Embed cells.
+  b->mtx.Lock();
+  for (uptr i = 0; i < kBucketSize; i++) {
+    Cell *c = &b->cells[i];
+    uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+    if (addr1 == addr) {
+      if (h->remove_) {
+        h->cell_ = c;
+        return;
+      }
+      b->mtx.Unlock();
+      goto retry;
+    }
+  }
+
+  // Add cells.
+  AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+  if (add) {
+    for (uptr i = 0; i < add->size; i++) {
+      Cell *c = &add->cells[i];
+      uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+      if (addr1 == addr) {
+        if (h->remove_) {
+          h->addidx_ = i;
+          h->cell_ = c;
+          return;
+        }
+        b->mtx.Unlock();
+        goto retry;
+      }
+    }
+  }
+
+  // The element does not exist, no need to create it if we want to remove.
+  if (h->remove_ || !h->create_) {
+    b->mtx.Unlock();
+    return;
+  }
+
+  // Now try to create it under the mutex.
+  h->created_ = true;
+  // See if we have a free embed cell.
+  for (uptr i = 0; i < kBucketSize; i++) {
+    Cell *c = &b->cells[i];
+    uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+    if (addr1 == 0) {
+      h->cell_ = c;
+      return;
+    }
+  }
+
+  // Store in the add cells.
+  if (add == 0) {
+    // Allocate a new add array.
+    const uptr kInitSize = 64;
+    add = (AddBucket*)InternalAlloc(kInitSize);
+    internal_memset(add, 0, kInitSize);
+    add->cap = (kInitSize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+    add->size = 0;
+    atomic_store(&b->add, (uptr)add, memory_order_relaxed);
+  }
+  if (add->size == add->cap) {
+    // Grow existing add array.
+    uptr oldsize = sizeof(*add) + (add->cap - 1) * sizeof(add->cells[0]);
+    uptr newsize = oldsize * 2;
+    AddBucket *add1 = (AddBucket*)InternalAlloc(newsize);
+    internal_memset(add1, 0, newsize);
+    add1->cap = (newsize - sizeof(*add)) / sizeof(add->cells[0]) + 1;
+    add1->size = add->size;
+    internal_memcpy(add1->cells, add->cells, add->size * sizeof(add->cells[0]));
+    InternalFree(add);
+    atomic_store(&b->add, (uptr)add1, memory_order_relaxed);
+    add = add1;
+  }
+  // Store.
+  uptr i = add->size++;
+  Cell *c = &add->cells[i];
+  CHECK_EQ(atomic_load(&c->addr, memory_order_relaxed), 0);
+  h->addidx_ = i;
+  h->cell_ = c;
+}
+
+template<typename T, uptr kSize>
+void AddrHashMap<T, kSize>::release(Handle *h) {
+  if (h->cell_ == 0)
+    return;
+  Bucket *b = h->bucket_;
+  Cell *c = h->cell_;
+  uptr addr1 = atomic_load(&c->addr, memory_order_relaxed);
+  if (h->created_) {
+    // Denote completion of insertion.
+    CHECK_EQ(addr1, 0);
+    // After the following store, the element becomes available
+    // for lock-free reads.
+    atomic_store(&c->addr, h->addr_, memory_order_release);
+    b->mtx.Unlock();
+  } else if (h->remove_) {
+    // Denote that the cell is empty now.
+    CHECK_EQ(addr1, h->addr_);
+    atomic_store(&c->addr, 0, memory_order_release);
+    // See if we need to compact the bucket.
+    AddBucket *add = (AddBucket*)atomic_load(&b->add, memory_order_relaxed);
+    if (h->addidx_ == -1U) {
+      // Removed from embed array, move an add element into the freed cell.
+      if (add && add->size != 0) {
+        uptr last = --add->size;
+        Cell *c1 = &add->cells[last];
+        c->val = c1->val;
+        uptr addr1 = atomic_load(&c1->addr, memory_order_relaxed);
+        atomic_store(&c->addr, addr1, memory_order_release);
+        atomic_store(&c1->addr, 0, memory_order_release);
+      }
+    } else {
+      // Removed from add array, compact it.
+      uptr last = --add->size;
+      Cell *c1 = &add->cells[last];
+      if (c != c1) {
+        *c = *c1;
+        atomic_store(&c1->addr, 0, memory_order_relaxed);
+      }
+    }
+    if (add && add->size == 0) {
+      // FIXME(dvyukov): free add?
+    }
+    b->mtx.Unlock();
+  } else {
+    CHECK_EQ(addr1, h->addr_);
+    if (h->addidx_ != -1U)
+      b->mtx.ReadUnlock();
+  }
+}
+
+template<typename T, uptr kSize>
+uptr AddrHashMap<T, kSize>::calcHash(uptr addr) {
+  addr += addr << 10;
+  addr ^= addr >> 6;
+  return addr % kSize;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ADDRHASHMAP_H
diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc
index daaf7e1..47509f8 100644
--- a/lib/sanitizer_common/sanitizer_allocator.cc
+++ b/lib/sanitizer_common/sanitizer_allocator.cc
@@ -19,7 +19,7 @@
 namespace __sanitizer {
 
 // ThreadSanitizer for Go uses libc malloc/free.
-#if defined(SANITIZER_GO)
+#if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
 # if SANITIZER_LINUX && !SANITIZER_ANDROID
 extern "C" void *__libc_malloc(uptr size);
 extern "C" void __libc_free(void *ptr);
@@ -117,7 +117,7 @@
   if (allocated_end_ - allocated_current_ < (sptr)size) {
     uptr size_to_allocate = Max(size, GetPageSizeCached());
     allocated_current_ =
-        (char*)MmapOrDie(size_to_allocate, __FUNCTION__);
+        (char*)MmapOrDie(size_to_allocate, __func__);
     allocated_end_ = allocated_current_ + size_to_allocate;
     if (low_level_alloc_callback) {
       low_level_alloc_callback((uptr)allocated_current_,
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 6075cfe..a8debd9 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -587,7 +587,69 @@
   u8 map_[kSize];
 };
 
-// FIXME: Also implement TwoLevelByteMap.
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+  void TestOnlyInit() {
+    internal_memset(map1_, 0, sizeof(map1_));
+    mu_.Init();
+  }
+  void TestOnlyUnmap() {
+    for (uptr i = 0; i < kSize1; i++) {
+      u8 *p = Get(i);
+      if (!p) continue;
+      MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+      UnmapOrDie(p, kSize2);
+    }
+  }
+
+  uptr size() const { return kSize1 * kSize2; }
+  uptr size1() const { return kSize1; }
+  uptr size2() const { return kSize2; }
+
+  void set(uptr idx, u8 val) {
+    CHECK_LT(idx, kSize1 * kSize2);
+    u8 *map2 = GetOrCreate(idx / kSize2);
+    CHECK_EQ(0U, map2[idx % kSize2]);
+    map2[idx % kSize2] = val;
+  }
+
+  u8 operator[] (uptr idx) const {
+    CHECK_LT(idx, kSize1 * kSize2);
+    u8 *map2 = Get(idx / kSize2);
+    if (!map2) return 0;
+    return map2[idx % kSize2];
+  }
+
+ private:
+  u8 *Get(uptr idx) const {
+    CHECK_LT(idx, kSize1);
+    return reinterpret_cast<u8 *>(
+        atomic_load(&map1_[idx], memory_order_acquire));
+  }
+
+  u8 *GetOrCreate(uptr idx) {
+    u8 *res = Get(idx);
+    if (!res) {
+      SpinMutexLock l(&mu_);
+      if (!(res = Get(idx))) {
+        res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+        MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+        atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+                     memory_order_release);
+      }
+    }
+    return res;
+  }
+
+  atomic_uintptr_t map1_[kSize1];
+  StaticSpinMutex mu_;
+};
 
 // SizeClassAllocator32 -- allocator for 32-bit address space.
 // This allocator can theoretically be used on 64-bit arch, but there it is less
@@ -1184,14 +1246,15 @@
     if (alignment > 8)
       size = RoundUpTo(size, alignment);
     void *res;
-    if (primary_.CanAllocate(size, alignment))
+    bool from_primary = primary_.CanAllocate(size, alignment);
+    if (from_primary)
       res = cache->Allocate(&primary_, primary_.ClassID(size));
     else
       res = secondary_.Allocate(&stats_, size, alignment);
     if (alignment > 8)
       CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
-    if (cleared && res)
-      internal_memset(res, 0, size);
+    if (cleared && res && from_primary)
+      internal_bzero_aligned16(res, RoundUpTo(size, 16));
     return res;
   }
 
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index 5b24bfd..c5f9028 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -24,30 +24,33 @@
 typedef CompactSizeClassMap InternalSizeClassMap;
 
 static const uptr kInternalAllocatorSpace = 0;
+static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
 #if SANITIZER_WORDSIZE == 32
-static const u64 kInternalAllocatorSize = (1ULL << 32);
 static const uptr kInternalAllocatorRegionSizeLog = 20;
-#else
-static const u64 kInternalAllocatorSize = (1ULL << 47);
-static const uptr kInternalAllocatorRegionSizeLog = 24;
-#endif
-static const uptr kInternalAllocatorFlatByteMapSize =
+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,
-    kInternalAllocatorRegionSizeLog,
-    FlatByteMap<kInternalAllocatorFlatByteMapSize> > PrimaryInternalAllocator;
+    kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
 
 typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
     InternalAllocatorCache;
 
-// We don't want our internal allocator to do any map/unmap operations.
+// 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!");
+    RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!\n");
   }
   void OnUnmap(uptr p, uptr size) const {
-    RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!");
+    RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!\n");
   }
 };
 
diff --git a/lib/sanitizer_common/sanitizer_asm.h b/lib/sanitizer_common/sanitizer_asm.h
new file mode 100644
index 0000000..906012a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_asm.h
@@ -0,0 +1,40 @@
+//===-- sanitizer_asm.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various support for assemebler.
+//
+//===----------------------------------------------------------------------===//
+
+// Some toolchains do not support .cfi asm directives, so we have to hide
+// them inside macros.
+#if defined(__clang__) ||                                                      \
+    (defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM))
+  // GCC defined __GCC_HAVE_DWARF2_CFI_ASM if it supports CFI.
+  // Clang seems to support CFI by default (or not?).
+  // We need two versions of macros: for inline asm and standalone asm files.
+# define CFI_INL_ADJUST_CFA_OFFSET(n) ".cfi_adjust_cfa_offset " #n ";"
+
+# define CFI_STARTPROC .cfi_startproc
+# define CFI_ENDPROC .cfi_endproc
+# define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n
+# define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n
+# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg
+# define CFI_RESTORE(reg) .cfi_restore reg
+
+#else  // No CFI
+# define CFI_INL_ADJUST_CFA_OFFSET(n)
+# define CFI_STARTPROC
+# define CFI_ENDPROC
+# define CFI_ADJUST_CFA_OFFSET(n)
+# define CFI_REL_OFFSET(reg, n)
+# define CFI_DEF_CFA_REGISTER(reg)
+# define CFI_RESTORE(reg)
+#endif
+
+
diff --git a/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h
index 61e6dfd..6643c54 100644
--- a/lib/sanitizer_common/sanitizer_atomic.h
+++ b/lib/sanitizer_common/sanitizer_atomic.h
@@ -44,7 +44,8 @@
 
 struct atomic_uint64_t {
   typedef u64 Type;
-  volatile Type val_dont_use;
+  // On 32-bit platforms u64 is not necessary aligned on 8 bytes.
+  volatile ALIGNED(8) Type val_dont_use;
 };
 
 struct atomic_uintptr_t {
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h
index c5aa939..38363e8 100644
--- a/lib/sanitizer_common/sanitizer_atomic_clang.h
+++ b/lib/sanitizer_common/sanitizer_atomic_clang.h
@@ -15,8 +15,26 @@
 #ifndef SANITIZER_ATOMIC_CLANG_H
 #define SANITIZER_ATOMIC_CLANG_H
 
+#if defined(__i386__) || defined(__x86_64__)
+# include "sanitizer_atomic_clang_x86.h"
+#else
+# include "sanitizer_atomic_clang_other.h"
+#endif
+
 namespace __sanitizer {
 
+// We would like to just use compiler builtin atomic operations
+// for loads and stores, but they are mostly broken in clang:
+// - they lead to vastly inefficient code generation
+// (http://llvm.org/bugs/show_bug.cgi?id=17281)
+// - 64-bit atomic operations are not implemented on x86_32
+// (http://llvm.org/bugs/show_bug.cgi?id=15034)
+// - they are not implemented on ARM
+// error: undefined reference to '__atomic_load_4'
+
+// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
+// for mappings of the memory model to different processors.
+
 INLINE void atomic_signal_fence(memory_order) {
   __asm__ __volatile__("" ::: "memory");
 }
@@ -25,59 +43,6 @@
   __sync_synchronize();
 }
 
-INLINE void proc_yield(int cnt) {
-  __asm__ __volatile__("" ::: "memory");
-#if defined(__i386__) || defined(__x86_64__)
-  for (int i = 0; i < cnt; i++)
-    __asm__ __volatile__("pause");
-#endif
-  __asm__ __volatile__("" ::: "memory");
-}
-
-template<typename T>
-INLINE typename T::Type atomic_load(
-    const volatile T *a, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_consume
-      | memory_order_acquire | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-  typename T::Type v;
-  // FIXME:
-  // 64-bit atomic operations are not atomic on 32-bit platforms.
-  // The implementation lacks necessary memory fences on ARM/PPC.
-  // We would like to use compiler builtin atomic operations,
-  // but they are mostly broken:
-  // - they lead to vastly inefficient code generation
-  // (http://llvm.org/bugs/show_bug.cgi?id=17281)
-  // - 64-bit atomic operations are not implemented on x86_32
-  // (http://llvm.org/bugs/show_bug.cgi?id=15034)
-  // - they are not implemented on ARM
-  // error: undefined reference to '__atomic_load_4'
-  if (mo == memory_order_relaxed) {
-    v = a->val_dont_use;
-  } else {
-    atomic_signal_fence(memory_order_seq_cst);
-    v = a->val_dont_use;
-    atomic_signal_fence(memory_order_seq_cst);
-  }
-  return v;
-}
-
-template<typename T>
-INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_release
-      | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-  if (mo == memory_order_relaxed) {
-    a->val_dont_use = v;
-  } else {
-    atomic_signal_fence(memory_order_seq_cst);
-    a->val_dont_use = v;
-    atomic_signal_fence(memory_order_seq_cst);
-  }
-  if (mo == memory_order_seq_cst)
-    atomic_thread_fence(memory_order_seq_cst);
-}
-
 template<typename T>
 INLINE typename T::Type atomic_fetch_add(volatile T *a,
     typename T::Type v, memory_order mo) {
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h
new file mode 100644
index 0000000..099b9f7
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -0,0 +1,97 @@
+//===-- sanitizer_atomic_clang_other.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 a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
+#define SANITIZER_ATOMIC_CLANG_OTHER_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+  __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+    const volatile T *a, memory_order mo) {
+  DCHECK(mo & (memory_order_relaxed | memory_order_consume
+      | memory_order_acquire | memory_order_seq_cst));
+  DCHECK(!((uptr)a % sizeof(*a)));
+  typename T::Type v;
+
+  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+    // Assume that aligned loads are atomic.
+    if (mo == memory_order_relaxed) {
+      v = a->val_dont_use;
+    } else if (mo == memory_order_consume) {
+      // Assume that processor respects data dependencies
+      // (and that compiler won't break them).
+      __asm__ __volatile__("" ::: "memory");
+      v = a->val_dont_use;
+      __asm__ __volatile__("" ::: "memory");
+    } else if (mo == memory_order_acquire) {
+      __asm__ __volatile__("" ::: "memory");
+      v = a->val_dont_use;
+      __sync_synchronize();
+    } else {  // seq_cst
+      // E.g. on POWER we need a hw fence even before the store.
+      __sync_synchronize();
+      v = a->val_dont_use;
+      __sync_synchronize();
+    }
+  } else {
+    // 64-bit load on 32-bit platform.
+    // Gross, but simple and reliable.
+    // Assume that it is not in read-only memory.
+    v = __sync_fetch_and_add(
+        const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+  }
+  return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+  DCHECK(mo & (memory_order_relaxed | memory_order_release
+      | memory_order_seq_cst));
+  DCHECK(!((uptr)a % sizeof(*a)));
+
+  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+    // Assume that aligned loads are atomic.
+    if (mo == memory_order_relaxed) {
+      a->val_dont_use = v;
+    } else if (mo == memory_order_release) {
+      __sync_synchronize();
+      a->val_dont_use = v;
+      __asm__ __volatile__("" ::: "memory");
+    } else {  // seq_cst
+      __sync_synchronize();
+      a->val_dont_use = v;
+      __sync_synchronize();
+    }
+  } else {
+    // 64-bit store on 32-bit platform.
+    // Gross, but simple and reliable.
+    typename T::Type cmp = a->val_dont_use;
+    typename T::Type cur;
+    for (;;) {
+      cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
+      if (cmp == v)
+        break;
+      cmp = cur;
+    }
+  }
+}
+
+}  // namespace __sanitizer
+
+#endif  // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_x86.h b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
new file mode 100644
index 0000000..38feb29
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_atomic_clang_x86.h
@@ -0,0 +1,116 @@
+//===-- sanitizer_atomic_clang_x86.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 a part of ThreadSanitizer/AddressSanitizer runtime.
+// Not intended for direct inclusion. Include sanitizer_atomic.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ATOMIC_CLANG_X86_H
+#define SANITIZER_ATOMIC_CLANG_X86_H
+
+namespace __sanitizer {
+
+INLINE void proc_yield(int cnt) {
+  __asm__ __volatile__("" ::: "memory");
+  for (int i = 0; i < cnt; i++)
+    __asm__ __volatile__("pause");
+  __asm__ __volatile__("" ::: "memory");
+}
+
+template<typename T>
+INLINE typename T::Type atomic_load(
+    const volatile T *a, memory_order mo) {
+  DCHECK(mo & (memory_order_relaxed | memory_order_consume
+      | memory_order_acquire | memory_order_seq_cst));
+  DCHECK(!((uptr)a % sizeof(*a)));
+  typename T::Type v;
+
+  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+    // Assume that aligned loads are atomic.
+    if (mo == memory_order_relaxed) {
+      v = a->val_dont_use;
+    } else if (mo == memory_order_consume) {
+      // Assume that processor respects data dependencies
+      // (and that compiler won't break them).
+      __asm__ __volatile__("" ::: "memory");
+      v = a->val_dont_use;
+      __asm__ __volatile__("" ::: "memory");
+    } else if (mo == memory_order_acquire) {
+      __asm__ __volatile__("" ::: "memory");
+      v = a->val_dont_use;
+      // On x86 loads are implicitly acquire.
+      __asm__ __volatile__("" ::: "memory");
+    } else {  // seq_cst
+      // On x86 plain MOV is enough for seq_cst store.
+      __asm__ __volatile__("" ::: "memory");
+      v = a->val_dont_use;
+      __asm__ __volatile__("" ::: "memory");
+    }
+  } else {
+    // 64-bit load on 32-bit platform.
+    __asm__ __volatile__(
+        "movq %1, %%mm0;"  // Use mmx reg for 64-bit atomic moves
+        "movq %%mm0, %0;"  // (ptr could be read-only)
+        "emms;"            // Empty mmx state/Reset FP regs
+        : "=m" (v)
+        : "m" (a->val_dont_use)
+        : // mark the FP stack and mmx registers as clobbered
+          "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+          "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif  // #ifdef __MMX__
+          "memory");
+  }
+  return v;
+}
+
+template<typename T>
+INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+  DCHECK(mo & (memory_order_relaxed | memory_order_release
+      | memory_order_seq_cst));
+  DCHECK(!((uptr)a % sizeof(*a)));
+
+  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
+    // Assume that aligned loads are atomic.
+    if (mo == memory_order_relaxed) {
+      a->val_dont_use = v;
+    } else if (mo == memory_order_release) {
+      // On x86 stores are implicitly release.
+      __asm__ __volatile__("" ::: "memory");
+      a->val_dont_use = v;
+      __asm__ __volatile__("" ::: "memory");
+    } else {  // seq_cst
+      // On x86 stores are implicitly release.
+      __asm__ __volatile__("" ::: "memory");
+      a->val_dont_use = v;
+      __sync_synchronize();
+    }
+  } else {
+    // 64-bit store on 32-bit platform.
+    __asm__ __volatile__(
+        "movq %1, %%mm0;"  // Use mmx reg for 64-bit atomic moves
+        "movq %%mm0, %0;"
+        "emms;"            // Empty mmx state/Reset FP regs
+        : "=m" (a->val_dont_use)
+        : "m" (v)
+        : // mark the FP stack and mmx registers as clobbered
+          "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+#ifdef __MMX__
+          "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+#endif  // #ifdef __MMX__
+          "memory");
+    if (mo == memory_order_seq_cst)
+      __sync_synchronize();
+  }
+}
+
+}  // namespace __sanitizer
+
+#endif  // #ifndef SANITIZER_ATOMIC_CLANG_X86_H
diff --git a/lib/sanitizer_common/sanitizer_atomic_msvc.h b/lib/sanitizer_common/sanitizer_atomic_msvc.h
index dc22ef0..bff5593 100644
--- a/lib/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/lib/sanitizer_common/sanitizer_atomic_msvc.h
@@ -24,8 +24,20 @@
 extern "C" long _InterlockedExchangeAdd(  // NOLINT
     long volatile * Addend, long Value);  // NOLINT
 #pragma intrinsic(_InterlockedExchangeAdd)
+extern "C" short _InterlockedCompareExchange16(  // NOLINT
+    short volatile *Destination,                 // NOLINT
+    short Exchange, short Comparand);            // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange16)
+extern "C"
+long long _InterlockedCompareExchange64(  // NOLINT
+    long long volatile *Destination,              // NOLINT
+    long long Exchange, long long Comparand);     // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange64)
 
 #ifdef _WIN64
+extern "C" long long _InterlockedExchangeAdd64(     // NOLINT
+    long long volatile * Addend, long long Value);  // NOLINT
+#pragma intrinsic(_InterlockedExchangeAdd64)
 extern "C" void *_InterlockedCompareExchangePointer(
     void *volatile *Destination,
     void *Exchange, void *Comparand);
@@ -108,6 +120,40 @@
       (volatile long*)&a->val_dont_use, (long)v);  // NOLINT
 }
 
+INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
+    uptr v, memory_order mo) {
+  (void)mo;
+  DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+  return (uptr)_InterlockedExchangeAdd64(
+      (volatile long long*)&a->val_dont_use, (long long)v);  // NOLINT
+#else
+  return (uptr)_InterlockedExchangeAdd(
+      (volatile long*)&a->val_dont_use, (long)v);  // NOLINT
+#endif
+}
+
+INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
+    u32 v, memory_order mo) {
+  (void)mo;
+  DCHECK(!((uptr)a % sizeof(*a)));
+  return (u32)_InterlockedExchangeAdd(
+      (volatile long*)&a->val_dont_use, -(long)v);  // NOLINT
+}
+
+INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
+    uptr v, memory_order mo) {
+  (void)mo;
+  DCHECK(!((uptr)a % sizeof(*a)));
+#ifdef _WIN64
+  return (uptr)_InterlockedExchangeAdd64(
+      (volatile long long*)&a->val_dont_use, -(long long)v);  // NOLINT
+#else
+  return (uptr)_InterlockedExchangeAdd(
+      (volatile long*)&a->val_dont_use, -(long)v);  // NOLINT
+#endif
+}
+
 INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
     u8 v, memory_order mo) {
   (void)mo;
@@ -168,6 +214,45 @@
   return false;
 }
 
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
+                                           u16 *cmp,
+                                           u16 xchg,
+                                           memory_order mo) {
+  u16 cmpv = *cmp;
+  u16 prev = (u16)_InterlockedCompareExchange16(
+      (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
+  if (prev == cmpv)
+    return true;
+  *cmp = prev;
+  return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
+                                           u32 *cmp,
+                                           u32 xchg,
+                                           memory_order mo) {
+  u32 cmpv = *cmp;
+  u32 prev = (u32)_InterlockedCompareExchange(
+      (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
+  if (prev == cmpv)
+    return true;
+  *cmp = prev;
+  return false;
+}
+
+INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
+                                           u64 *cmp,
+                                           u64 xchg,
+                                           memory_order mo) {
+  u64 cmpv = *cmp;
+  u64 prev = (u64)_InterlockedCompareExchange64(
+      (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
+  if (prev == cmpv)
+    return true;
+  *cmp = prev;
+  return false;
+}
+
 template<typename T>
 INLINE bool atomic_compare_exchange_weak(volatile T *a,
                                          typename T::Type *cmp,
diff --git a/lib/sanitizer_common/sanitizer_bitvector.h b/lib/sanitizer_common/sanitizer_bitvector.h
new file mode 100644
index 0000000..d847273
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_bitvector.h
@@ -0,0 +1,351 @@
+//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Specializer BitVector implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BITVECTOR_H
+#define SANITIZER_BITVECTOR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+// Fixed size bit vector based on a single basic integer.
+template <class basic_int_t = uptr>
+class BasicBitVector {
+ public:
+  enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
+
+  uptr size() const { return kSize; }
+  // No CTOR.
+  void clear() { bits_ = 0; }
+  void setAll() { bits_ = ~(basic_int_t)0; }
+  bool empty() const { return bits_ == 0; }
+
+  // Returns true if the bit has changed from 0 to 1.
+  bool setBit(uptr idx) {
+    basic_int_t old = bits_;
+    bits_ |= mask(idx);
+    return bits_ != old;
+  }
+
+  // Returns true if the bit has changed from 1 to 0.
+  bool clearBit(uptr idx) {
+    basic_int_t old = bits_;
+    bits_ &= ~mask(idx);
+    return bits_ != old;
+  }
+
+  bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; }
+
+  uptr getAndClearFirstOne() {
+    CHECK(!empty());
+    uptr idx = LeastSignificantSetBitIndex(bits_);
+    clearBit(idx);
+    return idx;
+  }
+
+  // Do "this |= v" and return whether new bits have been added.
+  bool setUnion(const BasicBitVector &v) {
+    basic_int_t old = bits_;
+    bits_ |= v.bits_;
+    return bits_ != old;
+  }
+
+  // Do "this &= v" and return whether any bits have been removed.
+  bool setIntersection(const BasicBitVector &v) {
+    basic_int_t old = bits_;
+    bits_ &= v.bits_;
+    return bits_ != old;
+  }
+
+  // Do "this &= ~v" and return whether any bits have been removed.
+  bool setDifference(const BasicBitVector &v) {
+    basic_int_t old = bits_;
+    bits_ &= ~v.bits_;
+    return bits_ != old;
+  }
+
+  void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; }
+
+  // Returns true if 'this' intersects with 'v'.
+  bool intersectsWith(const BasicBitVector &v) const {
+    return (bits_ & v.bits_) != 0;
+  }
+
+  // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) {
+  //   uptr idx = it.next();
+  //   use(idx);
+  // }
+  class Iterator {
+   public:
+    Iterator() { }
+    explicit Iterator(const BasicBitVector &bv) : bv_(bv) {}
+    bool hasNext() const { return !bv_.empty(); }
+    uptr next() { return bv_.getAndClearFirstOne(); }
+    void clear() { bv_.clear(); }
+   private:
+    BasicBitVector bv_;
+  };
+
+ private:
+  basic_int_t mask(uptr idx) const {
+    CHECK_LT(idx, size());
+    return (basic_int_t)1UL << idx;
+  }
+  basic_int_t bits_;
+};
+
+// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
+// The implementation is optimized for better performance on
+// sparse bit vectors, i.e. the those with few set bits.
+template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
+class TwoLevelBitVector {
+  // This is essentially a 2-level bit vector.
+  // Set bit in the first level BV indicates that there are set bits
+  // in the corresponding BV of the second level.
+  // This structure allows O(kLevel1Size) time for clear() and empty(),
+  // as well fast handling of sparse BVs.
+ public:
+  enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
+  // No CTOR.
+
+  uptr size() const { return kSize; }
+
+  void clear() {
+    for (uptr i = 0; i < kLevel1Size; i++)
+      l1_[i].clear();
+  }
+
+  void setAll() {
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      l1_[i0].setAll();
+      for (uptr i1 = 0; i1 < BV::kSize; i1++)
+        l2_[i0][i1].setAll();
+    }
+  }
+
+  bool empty() const {
+    for (uptr i = 0; i < kLevel1Size; i++)
+      if (!l1_[i].empty())
+        return false;
+    return true;
+  }
+
+  // Returns true if the bit has changed from 0 to 1.
+  bool setBit(uptr idx) {
+    check(idx);
+    uptr i0 = idx0(idx);
+    uptr i1 = idx1(idx);
+    uptr i2 = idx2(idx);
+    if (!l1_[i0].getBit(i1)) {
+      l1_[i0].setBit(i1);
+      l2_[i0][i1].clear();
+    }
+    bool res = l2_[i0][i1].setBit(i2);
+    // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__,
+    // idx, i0, i1, i2, res);
+    return res;
+  }
+
+  bool clearBit(uptr idx) {
+    check(idx);
+    uptr i0 = idx0(idx);
+    uptr i1 = idx1(idx);
+    uptr i2 = idx2(idx);
+    bool res = false;
+    if (l1_[i0].getBit(i1)) {
+      res = l2_[i0][i1].clearBit(i2);
+      if (l2_[i0][i1].empty())
+        l1_[i0].clearBit(i1);
+    }
+    return res;
+  }
+
+  bool getBit(uptr idx) const {
+    check(idx);
+    uptr i0 = idx0(idx);
+    uptr i1 = idx1(idx);
+    uptr i2 = idx2(idx);
+    // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2);
+    return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
+  }
+
+  uptr getAndClearFirstOne() {
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      if (l1_[i0].empty()) continue;
+      uptr i1 = l1_[i0].getAndClearFirstOne();
+      uptr i2 = l2_[i0][i1].getAndClearFirstOne();
+      if (!l2_[i0][i1].empty())
+        l1_[i0].setBit(i1);
+      uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
+      // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
+      return res;
+    }
+    CHECK(0);
+    return 0;
+  }
+
+  // Do "this |= v" and return whether new bits have been added.
+  bool setUnion(const TwoLevelBitVector &v) {
+    bool res = false;
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      BV t = v.l1_[i0];
+      while (!t.empty()) {
+        uptr i1 = t.getAndClearFirstOne();
+        if (l1_[i0].setBit(i1))
+          l2_[i0][i1].clear();
+        if (l2_[i0][i1].setUnion(v.l2_[i0][i1]))
+          res = true;
+      }
+    }
+    return res;
+  }
+
+  // Do "this &= v" and return whether any bits have been removed.
+  bool setIntersection(const TwoLevelBitVector &v) {
+    bool res = false;
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      if (l1_[i0].setIntersection(v.l1_[i0]))
+        res = true;
+      if (!l1_[i0].empty()) {
+        BV t = l1_[i0];
+        while (!t.empty()) {
+          uptr i1 = t.getAndClearFirstOne();
+          if (l2_[i0][i1].setIntersection(v.l2_[i0][i1]))
+            res = true;
+          if (l2_[i0][i1].empty())
+            l1_[i0].clearBit(i1);
+        }
+      }
+    }
+    return res;
+  }
+
+  // Do "this &= ~v" and return whether any bits have been removed.
+  bool setDifference(const TwoLevelBitVector &v) {
+    bool res = false;
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      BV t = l1_[i0];
+      t.setIntersection(v.l1_[i0]);
+      while (!t.empty()) {
+        uptr i1 = t.getAndClearFirstOne();
+        if (l2_[i0][i1].setDifference(v.l2_[i0][i1]))
+          res = true;
+        if (l2_[i0][i1].empty())
+          l1_[i0].clearBit(i1);
+      }
+    }
+    return res;
+  }
+
+  void copyFrom(const TwoLevelBitVector &v) {
+    clear();
+    setUnion(v);
+  }
+
+  // Returns true if 'this' intersects with 'v'.
+  bool intersectsWith(const TwoLevelBitVector &v) const {
+    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
+      BV t = l1_[i0];
+      t.setIntersection(v.l1_[i0]);
+      while (!t.empty()) {
+        uptr i1 = t.getAndClearFirstOne();
+        if (!v.l1_[i0].getBit(i1)) continue;
+        if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1]))
+          return true;
+      }
+    }
+    return false;
+  }
+
+  // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) {
+  //   uptr idx = it.next();
+  //   use(idx);
+  // }
+  class Iterator {
+   public:
+    Iterator() { }
+    explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) {
+      it1_.clear();
+      it2_.clear();
+    }
+
+    bool hasNext() const {
+      if (it1_.hasNext()) return true;
+      for (uptr i = i0_; i < kLevel1Size; i++)
+        if (!bv_.l1_[i].empty()) return true;
+      return false;
+    }
+
+    uptr next() {
+      // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+      //       it2_.hasNext(), kSize);
+      if (!it1_.hasNext() && !it2_.hasNext()) {
+        for (; i0_ < kLevel1Size; i0_++) {
+          if (bv_.l1_[i0_].empty()) continue;
+          it1_ = typename BV::Iterator(bv_.l1_[i0_]);
+          // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+          //   it2_.hasNext(), kSize);
+          break;
+        }
+      }
+      if (!it2_.hasNext()) {
+        CHECK(it1_.hasNext());
+        i1_ = it1_.next();
+        it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]);
+        // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(),
+        //       it2_.hasNext(), kSize);
+      }
+      CHECK(it2_.hasNext());
+      uptr i2 = it2_.next();
+      uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2;
+      // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_,
+      //       it1_.hasNext(), it2_.hasNext(), kSize, res);
+      if (!it1_.hasNext() && !it2_.hasNext())
+        i0_++;
+      return res;
+    }
+
+   private:
+    const TwoLevelBitVector &bv_;
+    uptr i0_, i1_;
+    typename BV::Iterator it1_, it2_;
+  };
+
+ private:
+  void check(uptr idx) const { CHECK_LE(idx, size()); }
+
+  uptr idx0(uptr idx) const {
+    uptr res = idx / (BV::kSize * BV::kSize);
+    CHECK_LE(res, kLevel1Size);
+    return res;
+  }
+
+  uptr idx1(uptr idx) const {
+    uptr res = (idx / BV::kSize) % BV::kSize;
+    CHECK_LE(res, BV::kSize);
+    return res;
+  }
+
+  uptr idx2(uptr idx) const {
+    uptr res = idx % BV::kSize;
+    CHECK_LE(res, BV::kSize);
+    return res;
+  }
+
+  BV l1_[kLevel1Size];
+  BV l2_[kLevel1Size][BV::kSize];
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BITVECTOR_H
diff --git a/lib/sanitizer_common/sanitizer_bvgraph.h b/lib/sanitizer_common/sanitizer_bvgraph.h
new file mode 100644
index 0000000..df72f1c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_bvgraph.h
@@ -0,0 +1,165 @@
+//===-- sanitizer_bvgraph.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 a part of Sanitizer runtime.
+// BVGraph -- a directed graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_BVGRAPH_H
+#define SANITIZER_BVGRAPH_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bitvector.h"
+
+namespace __sanitizer {
+
+// Directed graph of fixed size implemented as an array of bit vectors.
+// Not thread-safe, all accesses should be protected by an external lock.
+template<class BV>
+class BVGraph {
+ public:
+  enum SizeEnum { kSize = BV::kSize };
+  uptr size() const { return kSize; }
+  // No CTOR.
+  void clear() {
+    for (uptr i = 0; i < size(); i++)
+      v[i].clear();
+  }
+
+  bool empty() const {
+    for (uptr i = 0; i < size(); i++)
+      if (!v[i].empty())
+        return false;
+    return true;
+  }
+
+  // Returns true if a new edge was added.
+  bool addEdge(uptr from, uptr to) {
+    check(from, to);
+    return v[from].setBit(to);
+  }
+
+  // Returns true if at least one new edge was added.
+  uptr addEdges(const BV &from, uptr to, uptr added_edges[],
+                uptr max_added_edges) {
+    uptr res = 0;
+    t1.copyFrom(from);
+    while (!t1.empty()) {
+      uptr node = t1.getAndClearFirstOne();
+      if (v[node].setBit(to))
+        if (res < max_added_edges)
+          added_edges[res++] = node;
+    }
+    return res;
+  }
+
+  // *EXPERIMENTAL*
+  // Returns true if an edge from=>to exist.
+  // This function does not use any global state except for 'this' itself,
+  // and thus can be called from different threads w/o locking.
+  // This would be racy.
+  // FIXME: investigate how much we can prove about this race being "benign".
+  bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); }
+
+  // Returns true if the edge from=>to was removed.
+  bool removeEdge(uptr from, uptr to) {
+    return v[from].clearBit(to);
+  }
+
+  // Returns true if at least one edge *=>to was removed.
+  bool removeEdgesTo(const BV &to) {
+    bool res = 0;
+    for (uptr from = 0; from < size(); from++) {
+      if (v[from].setDifference(to))
+        res = true;
+    }
+    return res;
+  }
+
+  // Returns true if at least one edge from=>* was removed.
+  bool removeEdgesFrom(const BV &from) {
+    bool res = false;
+    t1.copyFrom(from);
+    while (!t1.empty()) {
+      uptr idx = t1.getAndClearFirstOne();
+      if (!v[idx].empty()) {
+        v[idx].clear();
+        res = true;
+      }
+    }
+    return res;
+  }
+
+  void removeEdgesFrom(uptr from) {
+    return v[from].clear();
+  }
+
+  bool hasEdge(uptr from, uptr to) const {
+    check(from, to);
+    return v[from].getBit(to);
+  }
+
+  // Returns true if there is a path from the node 'from'
+  // to any of the nodes in 'targets'.
+  bool isReachable(uptr from, const BV &targets) {
+    BV &to_visit = t1,
+       &visited = t2;
+    to_visit.copyFrom(v[from]);
+    visited.clear();
+    visited.setBit(from);
+    while (!to_visit.empty()) {
+      uptr idx = to_visit.getAndClearFirstOne();
+      if (visited.setBit(idx))
+        to_visit.setUnion(v[idx]);
+    }
+    return targets.intersectsWith(visited);
+  }
+
+  // Finds a path from 'from' to one of the nodes in 'target',
+  // stores up to 'path_size' items of the path into 'path',
+  // returns the path length, or 0 if there is no path of size 'path_size'.
+  uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) {
+    if (path_size == 0)
+      return 0;
+    path[0] = from;
+    if (targets.getBit(from))
+      return 1;
+    // The function is recursive, so we don't want to create BV on stack.
+    // Instead of a getAndClearFirstOne loop we use the slower iterator.
+    for (typename BV::Iterator it(v[from]); it.hasNext(); ) {
+      uptr idx = it.next();
+      if (uptr res = findPath(idx, targets, path + 1, path_size - 1))
+        return res + 1;
+    }
+    return 0;
+  }
+
+  // Same as findPath, but finds a shortest path.
+  uptr findShortestPath(uptr from, const BV &targets, uptr *path,
+                        uptr path_size) {
+    for (uptr p = 1; p <= path_size; p++)
+      if (findPath(from, targets, path, p) == p)
+        return p;
+    return 0;
+  }
+
+ private:
+  void check(uptr idx1, uptr idx2) const {
+    CHECK_LT(idx1, size());
+    CHECK_LT(idx2, size());
+  }
+  BV v[kSize];
+  // Keep temporary vectors here since we can not create large objects on stack.
+  BV t1, t2;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_BVGRAPH_H
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 7e870ff..05bd876 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -42,6 +42,13 @@
 // child thread will be different from |report_fd_pid|.
 uptr report_fd_pid = 0;
 
+// PID of the tracer task in StopTheWorld. It shares the address space with the
+// main process, but has a different PID and thus requires special handling.
+uptr stoptheworld_tracer_pid = 0;
+// Cached pid of parent process - if the parent process dies, we want to keep
+// writing to the same log file.
+uptr stoptheworld_tracer_ppid = 0;
+
 static DieCallbackType DieCallback;
 void SetDieCallback(DieCallbackType callback) {
   DieCallback = callback;
@@ -86,7 +93,7 @@
     if (internal_iserror(openrv)) return 0;
     fd_t fd = openrv;
     UnmapOrDie(*buff, *buff_size);
-    *buff = (char*)MmapOrDie(size, __FUNCTION__);
+    *buff = (char*)MmapOrDie(size, __func__);
     *buff_size = size;
     // Read up to one page at a time.
     read_len = 0;
@@ -195,11 +202,11 @@
     return;
   AddressInfo ai;
 #if !SANITIZER_GO
-  if (stack->size > 0 && Symbolizer::Get()->IsAvailable()) {
+  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()->SymbolizeCode(pc, &ai, 1);
+    Symbolizer::Get()->SymbolizePC(pc, &ai, 1);
   }
 #endif
   ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
@@ -237,6 +244,25 @@
   return internal_strdup(short_module_name);
 }
 
+static atomic_uintptr_t g_total_mmaped;
+
+void IncreaseTotalMmap(uptr size) {
+  if (!common_flags()->mmap_limit_mb) return;
+  uptr total_mmaped =
+      atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
+  if ((total_mmaped >> 20) > common_flags()->mmap_limit_mb) {
+    // Since for now mmap_limit_mb is not a user-facing flag, just CHECK.
+    uptr mmap_limit_mb = common_flags()->mmap_limit_mb;
+    common_flags()->mmap_limit_mb = 0;  // Allow mmap in CHECK.
+    RAW_CHECK(total_mmaped >> 20 < mmap_limit_mb);
+  }
+}
+
+void DecreaseTotalMmap(uptr size) {
+  if (!common_flags()->mmap_limit_mb) return;
+  atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
+}
+
 }  // namespace __sanitizer
 
 using namespace __sanitizer;  // NOLINT
@@ -269,11 +295,6 @@
   }
 }
 
-void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
-  (void)reserved;
-  PrepareForSandboxing();
-}
-
 void __sanitizer_report_error_summary(const char *error_summary) {
   Printf("%s\n", error_summary);
 }
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index cf8a12d..44f56ff 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -19,6 +19,7 @@
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_mutex.h"
+#include "sanitizer_flags.h"
 
 namespace __sanitizer {
 struct StackTrace;
@@ -27,14 +28,12 @@
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
 const uptr kWordSizeInBits = 8 * kWordSize;
 
-#if defined(__powerpc__) || defined(__powerpc64__)
-const uptr kCacheLineSize = 128;
-#else
 const uptr kCacheLineSize = 64;
-#endif
 
 const uptr kMaxPathLength = 512;
 
+const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
+
 extern const char *SanitizerToolName;  // Can be changed by the tool.
 
 uptr GetPageSize();
@@ -53,6 +52,7 @@
 void *MmapOrDie(uptr size, const char *mem_type);
 void UnmapOrDie(void *addr, uptr size);
 void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
+void *MmapNoReserveOrDie(uptr size, const char *mem_type);
 void *MmapFixedOrDie(uptr fixed_addr, uptr size);
 void *Mprotect(uptr fixed_addr, uptr size);
 // Map aligned chunk of address space; size and alignment are powers of two.
@@ -60,6 +60,8 @@
 // Used to check if we can map shadow memory to a fixed location.
 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
 void FlushUnneededShadowMemory(uptr addr, uptr size);
+void IncreaseTotalMmap(uptr size);
+void DecreaseTotalMmap(uptr size);
 
 // InternalScopedBuffer can be used instead of large stack arrays to
 // keep frame size low.
@@ -125,9 +127,18 @@
 bool PrintsToTty();
 // Caching version of PrintsToTty(). Not thread-safe.
 bool PrintsToTtyCached();
+bool ColorizeReports();
 void Printf(const char *format, ...);
 void Report(const char *format, ...);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
+#define VReport(level, ...)                                              \
+  do {                                                                   \
+    if ((uptr)common_flags()->verbosity >= (level)) Report(__VA_ARGS__); \
+  } while (0)
+#define VPrintf(level, ...)                                              \
+  do {                                                                   \
+    if ((uptr)common_flags()->verbosity >= (level)) Printf(__VA_ARGS__); \
+  } while (0)
 
 // Can be used to prevent mixing error reports from different sanitizers.
 extern StaticSpinMutex CommonSanitizerReportMutex;
@@ -136,6 +147,8 @@
 extern bool log_to_file;
 extern char report_path_prefix[4096];
 extern uptr report_fd_pid;
+extern uptr stoptheworld_tracer_pid;
+extern uptr stoptheworld_tracer_ppid;
 
 uptr OpenFile(const char *filename, bool write);
 // Opens the file 'file_name" and reads up to 'max_len' bytes.
@@ -148,6 +161,7 @@
 // (or NULL if the mapping failes). Stores the size of mmaped region
 // in '*buff_size'.
 void *MapFileToMemory(const char *file_name, uptr *buff_size);
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset);
 
 // Error report formatting.
 const char *StripPathPrefix(const char *filepath,
@@ -169,7 +183,12 @@
 void ReExec();
 bool StackSizeIsUnlimited();
 void SetStackSizeLimitInBytes(uptr limit);
-void PrepareForSandboxing();
+void AdjustStackSize(void *attr);
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void SetSandboxingCallback(void (*f)());
+
+void CovUpdateMapping();
 
 void InitTlsSize();
 uptr GetTlsSize();
@@ -206,6 +225,14 @@
                                        u64, u64);
 void SetCheckFailedCallback(CheckFailedCallbackType callback);
 
+// Functions related to signal handling.
+typedef void (*SignalHandlerType)(int, void *, void *);
+bool IsDeadlySignal(int signum);
+void InstallDeadlySignalHandlers(SignalHandlerType handler);
+// Alternative signal stack (POSIX-only).
+void SetAlternateSignalStack();
+void UnsetAlternateSignalStack();
+
 // We don't want a summary too long.
 const int kMaxSummaryLength = 1024;
 // Construct a one-line string:
@@ -243,6 +270,19 @@
   return up;
 }
 
+INLINE uptr LeastSignificantSetBitIndex(uptr x) {
+  CHECK_NE(x, 0U);
+  unsigned long up;  // NOLINT
+#if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__)
+  up = __builtin_ctzl(x);
+#elif defined(_WIN64)
+  _BitScanForward64(&up, x);
+#else
+  _BitScanForward(&up, x);
+#endif
+  return up;
+}
+
 INLINE bool IsPowerOfTwo(uptr x) {
   return (x & (x - 1)) == 0;
 }
@@ -307,12 +347,6 @@
   return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
 }
 
-#if SANITIZER_WORDSIZE == 64
-# define FIRST_32_SECOND_64(a, b) (b)
-#else
-# define FIRST_32_SECOND_64(a, b) (a)
-#endif
-
 // A low-level vector based on mmap. May incur a significant memory overhead for
 // small vectors.
 // WARNING: The current implementation supports only POD types.
@@ -320,8 +354,7 @@
 class InternalMmapVector {
  public:
   explicit InternalMmapVector(uptr initial_capacity) {
-    CHECK_GT(initial_capacity, 0);
-    capacity_ = initial_capacity;
+    capacity_ = Max(initial_capacity, (uptr)1);
     size_ = 0;
     data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVector");
   }
@@ -449,6 +482,10 @@
   const char *full_name() const { return full_name_; }
   uptr base_address() const { return base_address_; }
 
+  uptr n_ranges() const { return n_ranges_; }
+  uptr address_range_start(int i) const { return ranges_[i].beg; }
+  uptr address_range_end(int i) const { return ranges_[i].end; }
+
  private:
   struct AddressRange {
     uptr beg;
@@ -478,6 +515,33 @@
 
 // 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
+void AndroidLogWrite(const char *buffer);
+void GetExtraActivationFlags(char *buf, uptr size);
+void SanitizerInitializeUnwinder();
+#else
+INLINE void AndroidLogWrite(const char *buffer_unused) {}
+INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
+INLINE void SanitizerInitializeUnwinder() {}
+#endif
 }  // namespace __sanitizer
 
 inline void *operator new(__sanitizer::operator_new_size_type size,
@@ -485,4 +549,9 @@
   return alloc.Allocate(size);
 }
 
+struct StackDepotStats {
+  uptr n_uniq_ids;
+  uptr allocated;
+};
+
 #endif  // SANITIZER_COMMON_H
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index d1c8976..4296ec0 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -25,18 +25,26 @@
 //   COMMON_INTERCEPTOR_MUTEX_UNLOCK
 //   COMMON_INTERCEPTOR_MUTEX_REPAIR
 //   COMMON_INTERCEPTOR_SET_PTHREAD_NAME
+//   COMMON_INTERCEPTOR_HANDLE_RECVMSG
 //===----------------------------------------------------------------------===//
 #include "interception/interception.h"
+#include "sanitizer_addrhashmap.h"
+#include "sanitizer_placement_new.h"
 #include "sanitizer_platform_interceptors.h"
+#include "sanitizer_tls_get_addr.h"
 
 #include <stdarg.h>
 
-#if SANITIZER_WINDOWS
+#if SANITIZER_WINDOWS && !defined(va_copy)
 #define va_copy(dst, src) ((dst) = (src))
 #endif // _WIN32
 
 #ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
-#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, p, size) {}
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_UNPOISON_PARAM
+#define COMMON_INTERCEPTOR_UNPOISON_PARAM(count) {}
 #endif
 
 #ifndef COMMON_INTERCEPTOR_FD_ACCESS
@@ -55,6 +63,95 @@
 #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
 #endif
 
+#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_OPEN
+#define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FILE_CLOSE
+#define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE
+#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \
+  COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__)
+#endif
+
+struct FileMetadata {
+  // For open_memstream().
+  char **addr;
+  SIZE_T *size;
+};
+
+struct CommonInterceptorMetadata {
+  enum {
+    CIMT_INVALID = 0,
+    CIMT_FILE
+  } type;
+  union {
+    FileMetadata file;
+  };
+};
+
+typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap;
+
+static MetadataHashMap *interceptor_metadata_map;
+
+#if SI_NOT_WINDOWS
+UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr,
+                                          const FileMetadata &file) {
+  MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr);
+  CHECK(h.created());
+  h->type = CommonInterceptorMetadata::CIMT_FILE;
+  h->file = file;
+}
+
+UNUSED static const FileMetadata *GetInterceptorMetadata(
+    __sanitizer_FILE *addr) {
+  MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr,
+                            /* remove */ false,
+                            /* create */ false);
+  if (h.exists()) {
+    CHECK(!h.created());
+    CHECK(h->type == CommonInterceptorMetadata::CIMT_FILE);
+    return &h->file;
+  } else {
+    return 0;
+  }
+}
+
+UNUSED static void DeleteInterceptorMetadata(void *addr) {
+  MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true);
+  CHECK(h.exists());
+}
+#endif  // SI_NOT_WINDOWS
+
+#if SANITIZER_INTERCEPT_TEXTDOMAIN
+INTERCEPTOR(char*, textdomain, const char *domainname) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
+  char* domain = REAL(textdomain)(domainname);
+  if (domain) {
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
+  }
+  return domain;
+}
+#define INIT_TEXTDOMAIN COMMON_INTERCEPT_FUNCTION(textdomain)
+#else
+#define INIT_TEXTDOMAIN
+#endif
+
 #if SANITIZER_INTERCEPT_STRCMP
 static inline int CharCmpX(unsigned char c1, unsigned char c2) {
   return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
@@ -141,6 +238,34 @@
 #define INIT_STRNCASECMP
 #endif
 
+#if SANITIZER_INTERCEPT_MEMCHR
+INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
+  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;
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
+  return res;
+}
+
+#define INIT_MEMCHR COMMON_INTERCEPT_FUNCTION(memchr)
+#else
+#define INIT_MEMCHR
+#endif
+
+#if SANITIZER_INTERCEPT_MEMRCHR
+INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, memrchr, s, c, n);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, s, n);
+  return REAL(memrchr)(s, c, n);
+}
+
+#define INIT_MEMRCHR COMMON_INTERCEPT_FUNCTION(memrchr)
+#else
+#define INIT_MEMRCHR
+#endif
+
 #if SANITIZER_INTERCEPT_FREXP
 INTERCEPTOR(double, frexp, double x, int *exp) {
   void *ctx;
@@ -430,7 +555,7 @@
   if (tm->tm_zone) {
     // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
     // can point to shared memory and tsan would report a data race.
-    COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, tm->tm_zone,
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone,
                                         REAL(strlen(tm->tm_zone)) + 1);
   }
 }
@@ -514,6 +639,20 @@
   }
   return res;
 }
+INTERCEPTOR(long, mktime, __sanitizer_tm *tm) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mktime, tm);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_sec, sizeof(tm->tm_sec));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_min, sizeof(tm->tm_min));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_hour, sizeof(tm->tm_hour));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mday, sizeof(tm->tm_mday));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_mon, sizeof(tm->tm_mon));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_year, sizeof(tm->tm_year));
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, &tm->tm_isdst, sizeof(tm->tm_isdst));
+  long res = REAL(mktime)(tm);
+  if (res != -1) unpoison_tm(ctx, tm);
+  return res;
+}
 #define INIT_LOCALTIME_AND_FRIENDS        \
   COMMON_INTERCEPT_FUNCTION(localtime);   \
   COMMON_INTERCEPT_FUNCTION(localtime_r); \
@@ -522,7 +661,8 @@
   COMMON_INTERCEPT_FUNCTION(ctime);       \
   COMMON_INTERCEPT_FUNCTION(ctime_r);     \
   COMMON_INTERCEPT_FUNCTION(asctime);     \
-  COMMON_INTERCEPT_FUNCTION(asctime_r);
+  COMMON_INTERCEPT_FUNCTION(asctime_r);   \
+  COMMON_INTERCEPT_FUNCTION(mktime);
 #else
 #define INIT_LOCALTIME_AND_FRIENDS
 #endif  // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
@@ -548,9 +688,23 @@
 #define INIT_STRPTIME
 #endif
 
-#if SANITIZER_INTERCEPT_SCANF
+#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF
+#include "sanitizer_common_interceptors_format.inc"
 
-#include "sanitizer_common_interceptors_scanf.inc"
+#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...)                              \
+  {                                                                            \
+    void *ctx;                                                                 \
+    va_list ap;                                                                \
+    va_start(ap, format);                                                      \
+    COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap);                     \
+    int res = WRAP(vname)(__VA_ARGS__, ap);                                    \
+    va_end(ap);                                                                \
+    return res;                                                                \
+  }
+
+#endif
+
+#if SANITIZER_INTERCEPT_SCANF
 
 #define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...)                    \
   {                                                                            \
@@ -586,35 +740,24 @@
 VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
 #endif  // SANITIZER_INTERCEPT_ISOC99_SCANF
 
-#define SCANF_INTERCEPTOR_IMPL(name, vname, ...)                               \
-  {                                                                            \
-    void *ctx;                                                                 \
-    va_list ap;                                                                \
-    va_start(ap, format);                                                      \
-    COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap);                     \
-    int res = vname(__VA_ARGS__, ap);                                          \
-    va_end(ap);                                                                \
-    return res;                                                                \
-  }
-
 INTERCEPTOR(int, scanf, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
+FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format)
 
 INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
 
 INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
 
 #if SANITIZER_INTERCEPT_ISOC99_SCANF
 INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
 
 INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
 
 INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
-SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
 #endif
 
 #endif
@@ -643,6 +786,171 @@
 #define INIT_ISOC99_SCANF
 #endif
 
+#if SANITIZER_INTERCEPT_PRINTF
+
+#define VPRINTF_INTERCEPTOR_ENTER(vname, ...)                                  \
+  void *ctx;                                                                   \
+  COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__);                           \
+  va_list aq;                                                                  \
+  va_copy(aq, ap);
+
+#define VPRINTF_INTERCEPTOR_RETURN()                                           \
+  va_end(aq);
+
+#define VPRINTF_INTERCEPTOR_IMPL(vname, ...)                                   \
+  {                                                                            \
+    VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__);                             \
+    if (common_flags()->check_printf)                                          \
+      printf_common(ctx, format, aq);                                          \
+    int res = REAL(vname)(__VA_ARGS__);                                        \
+    VPRINTF_INTERCEPTOR_RETURN();                                              \
+    return res;                                                                \
+  }
+
+#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...)                             \
+  {                                                                            \
+    VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__)                         \
+    if (common_flags()->check_printf) {                                        \
+      printf_common(ctx, format, aq);                                          \
+    }                                                                          \
+    int res = REAL(vname)(str, __VA_ARGS__);                                   \
+    if (res >= 0) {                                                            \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1);                       \
+    }                                                                          \
+    VPRINTF_INTERCEPTOR_RETURN();                                              \
+    return res;                                                                \
+  }
+
+#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...)                      \
+  {                                                                            \
+    VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__)                   \
+    if (common_flags()->check_printf) {                                        \
+      printf_common(ctx, format, aq);                                          \
+    }                                                                          \
+    int res = REAL(vname)(str, size, __VA_ARGS__);                             \
+    if (res >= 0) {                                                            \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, Min(size, (SIZE_T)(res + 1)));  \
+    }                                                                          \
+    VPRINTF_INTERCEPTOR_RETURN();                                              \
+    return res;                                                                \
+  }
+
+#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...)                           \
+  {                                                                            \
+    VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__)                        \
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *));                 \
+    if (common_flags()->check_printf) {                                        \
+      printf_common(ctx, format, aq);                                          \
+    }                                                                          \
+    int res = REAL(vname)(strp, __VA_ARGS__);                                  \
+    if (res >= 0) {                                                            \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1);                     \
+    }                                                                          \
+    VPRINTF_INTERCEPTOR_RETURN();                                              \
+    return res;                                                                \
+  }
+
+INTERCEPTOR(int, vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap)
+
+INTERCEPTOR(int, vfprintf, __sanitizer_FILE *stream, const char *format,
+            va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format,
+            va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
+
+INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
+VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfprintf, __sanitizer_FILE *stream,
+            const char *format, va_list ap)
+VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format,
+            va_list ap)
+VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap)
+
+INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format,
+            va_list ap)
+VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format,
+                          ap)
+
+#endif  // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+INTERCEPTOR(int, printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format)
+
+INTERCEPTOR(int, fprintf, __sanitizer_FILE *stream, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format)
+
+INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT
+FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT
+
+INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format)
+
+INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
+
+INTERCEPTOR(int, __isoc99_fprintf, __sanitizer_FILE *stream, const char *format,
+            ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format)
+
+INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size,
+            const char *format, ...)
+FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
+                        format)
+
+#endif  // SANITIZER_INTERCEPT_ISOC99_PRINTF
+
+#endif  // SANITIZER_INTERCEPT_PRINTF
+
+#if SANITIZER_INTERCEPT_PRINTF
+#define INIT_PRINTF                     \
+  COMMON_INTERCEPT_FUNCTION(printf);    \
+  COMMON_INTERCEPT_FUNCTION(sprintf);   \
+  COMMON_INTERCEPT_FUNCTION(snprintf);  \
+  COMMON_INTERCEPT_FUNCTION(asprintf);  \
+  COMMON_INTERCEPT_FUNCTION(fprintf);   \
+  COMMON_INTERCEPT_FUNCTION(vprintf);   \
+  COMMON_INTERCEPT_FUNCTION(vsprintf);  \
+  COMMON_INTERCEPT_FUNCTION(vsnprintf); \
+  COMMON_INTERCEPT_FUNCTION(vasprintf); \
+  COMMON_INTERCEPT_FUNCTION(vfprintf);
+#else
+#define INIT_PRINTF
+#endif
+
+#if SANITIZER_INTERCEPT_ISOC99_PRINTF
+#define INIT_ISOC99_PRINTF                       \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_printf);    \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf);   \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf);  \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf);   \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf);   \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf);  \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \
+  COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf);
+#else
+#define INIT_ISOC99_PRINTF
+#endif
+
 #if SANITIZER_INTERCEPT_IOCTL
 #include "sanitizer_common_interceptors_ioctl.inc"
 INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
@@ -656,7 +964,14 @@
   if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg);
 
   const ioctl_desc *desc = ioctl_lookup(request);
-  if (!desc) Printf("WARNING: unknown ioctl %x\n", request);
+  ioctl_desc decoded_desc;
+  if (!desc) {
+    VPrintf(2, "Decoding unknown ioctl 0x%x\n", request);
+    if (!ioctl_decode(request, &decoded_desc))
+      Printf("WARNING: failed decoding unknown ioctl 0x%x\n", request);
+    else
+      desc = &decoded_desc;
+  }
 
   if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
   int res = REAL(ioctl)(d, request, arg);
@@ -671,35 +986,85 @@
 #define INIT_IOCTL
 #endif
 
+#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
+    SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
+static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
+  if (pwd) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
+    if (pwd->pw_name)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_name,
+                                          REAL(strlen)(pwd->pw_name) + 1);
+    if (pwd->pw_passwd)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_passwd,
+                                          REAL(strlen)(pwd->pw_passwd) + 1);
+#if !SANITIZER_ANDROID
+    if (pwd->pw_gecos)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_gecos,
+                                          REAL(strlen)(pwd->pw_gecos) + 1);
+#endif
+#if SANITIZER_MAC
+    if (pwd->pw_class)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_class,
+                                          REAL(strlen)(pwd->pw_class) + 1);
+#endif
+    if (pwd->pw_dir)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_dir,
+                                          REAL(strlen)(pwd->pw_dir) + 1);
+    if (pwd->pw_shell)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_shell,
+                                          REAL(strlen)(pwd->pw_shell) + 1);
+  }
+}
+
+static void unpoison_group(void *ctx, __sanitizer_group *grp) {
+  if (grp) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp));
+    if (grp->gr_name)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_name,
+                                          REAL(strlen)(grp->gr_name) + 1);
+    if (grp->gr_passwd)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_passwd,
+                                          REAL(strlen)(grp->gr_passwd) + 1);
+    char **p = grp->gr_mem;
+    for (; *p; ++p) {
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(*p, REAL(strlen)(*p) + 1);
+    }
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_mem,
+                                        (p - grp->gr_mem + 1) * sizeof(*p));
+  }
+}
+#endif  // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
+        // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
+
 #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
-INTERCEPTOR(void *, getpwnam, const char *name) {
+INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
   COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
-  void *res = REAL(getpwnam)(name);
-  if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  __sanitizer_passwd *res = REAL(getpwnam)(name);
+  if (res != 0) unpoison_passwd(ctx, res);
   return res;
 }
-INTERCEPTOR(void *, getpwuid, u32 uid) {
+INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
-  void *res = REAL(getpwuid)(uid);
-  if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+  __sanitizer_passwd *res = REAL(getpwuid)(uid);
+  if (res != 0) unpoison_passwd(ctx, res);
   return res;
 }
-INTERCEPTOR(void *, getgrnam, const char *name) {
+INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
   COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
-  void *res = REAL(getgrnam)(name);
-  if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  __sanitizer_group *res = REAL(getgrnam)(name);
+  if (res != 0) unpoison_group(ctx, res);
   return res;
 }
-INTERCEPTOR(void *, getgrgid, u32 gid) {
+INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
-  void *res = REAL(getgrgid)(gid);
-  if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+  __sanitizer_group *res = REAL(getgrgid)(gid);
+  if (res != 0) unpoison_group(ctx, res);
   return res;
 }
 #define INIT_GETPWNAM_AND_FRIENDS      \
@@ -712,50 +1077,54 @@
 #endif
 
 #if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
-INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, char *buf,
-            SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
+            char *buf, SIZE_T buflen, __sanitizer_passwd **result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
   COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
   int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
   if (!res) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    if (result && *result) unpoison_passwd(ctx, *result);
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
   }
+  if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
   return res;
 }
-INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen,
-            void **result) {
+INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
+            SIZE_T buflen, __sanitizer_passwd **result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
   int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
   if (!res) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
+    if (result && *result) unpoison_passwd(ctx, *result);
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
   }
+  if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
   return res;
 }
-INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, char *buf,
-            SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
+            char *buf, SIZE_T buflen, __sanitizer_group **result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
   COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
   int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
   if (!res) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    if (result && *result) unpoison_group(ctx, *result);
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
   }
+  if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
   return res;
 }
-INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
-            void **result) {
+INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
+            SIZE_T buflen, __sanitizer_group **result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
   int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
   if (!res) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
+    if (result && *result) unpoison_group(ctx, *result);
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
   }
+  if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
   return res;
 }
 #define INIT_GETPWNAM_R_AND_FRIENDS      \
@@ -767,6 +1136,141 @@
 #define INIT_GETPWNAM_R_AND_FRIENDS
 #endif
 
+#if SANITIZER_INTERCEPT_GETPWENT
+INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy);
+  __sanitizer_passwd *res = REAL(getpwent)(dummy);
+  if (res != 0) unpoison_passwd(ctx, res);
+  return res;
+}
+INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy);
+  __sanitizer_group *res = REAL(getgrent)(dummy);
+  if (res != 0) unpoison_group(ctx, res);;
+  return res;
+}
+#define INIT_GETPWENT                  \
+  COMMON_INTERCEPT_FUNCTION(getpwent); \
+  COMMON_INTERCEPT_FUNCTION(getgrent);
+#else
+#define INIT_GETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_FGETPWENT
+INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp);
+  __sanitizer_passwd *res = REAL(fgetpwent)(fp);
+  if (res != 0) unpoison_passwd(ctx, res);
+  return res;
+}
+INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp);
+  __sanitizer_group *res = REAL(fgetgrent)(fp);
+  if (res != 0) unpoison_group(ctx, res);
+  return res;
+}
+#define INIT_FGETPWENT                  \
+  COMMON_INTERCEPT_FUNCTION(fgetpwent); \
+  COMMON_INTERCEPT_FUNCTION(fgetgrent);
+#else
+#define INIT_FGETPWENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETPWENT_R
+INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
+            SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
+  int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
+  if (!res) {
+    if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+  return res;
+}
+INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
+            SIZE_T buflen, __sanitizer_passwd **pwbufp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
+  int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
+  if (!res) {
+    if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+  return res;
+}
+INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
+            __sanitizer_group **pwbufp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
+  int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
+  if (!res) {
+    if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+  return res;
+}
+INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
+            SIZE_T buflen, __sanitizer_group **pwbufp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
+  int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
+  if (!res) {
+    if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
+  }
+  if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
+  return res;
+}
+#define INIT_GETPWENT_R                   \
+  COMMON_INTERCEPT_FUNCTION(getpwent_r);  \
+  COMMON_INTERCEPT_FUNCTION(fgetpwent_r); \
+  COMMON_INTERCEPT_FUNCTION(getgrent_r);  \
+  COMMON_INTERCEPT_FUNCTION(fgetgrent_r);
+#else
+#define INIT_GETPWENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_SETPWENT
+// The only thing these interceptors do is disable any nested interceptors.
+// These functions may open nss modules and call uninstrumented functions from
+// them, and we don't want things like strlen() to trigger.
+INTERCEPTOR(void, setpwent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setpwent, dummy);
+  REAL(setpwent)(dummy);
+}
+INTERCEPTOR(void, endpwent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, endpwent, dummy);
+  REAL(endpwent)(dummy);
+}
+INTERCEPTOR(void, setgrent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setgrent, dummy);
+  REAL(setgrent)(dummy);
+}
+INTERCEPTOR(void, endgrent, int dummy) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, endgrent, dummy);
+  REAL(endgrent)(dummy);
+}
+#define INIT_SETPWENT                  \
+  COMMON_INTERCEPT_FUNCTION(setpwent); \
+  COMMON_INTERCEPT_FUNCTION(endpwent); \
+  COMMON_INTERCEPT_FUNCTION(setgrent); \
+  COMMON_INTERCEPT_FUNCTION(endgrent);
+#else
+#define INIT_SETPWENT
+#endif
+
 #if SANITIZER_INTERCEPT_CLOCK_GETTIME
 INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
   void *ctx;
@@ -842,34 +1346,33 @@
 }
 
 static THREADLOCAL __sanitizer_glob_t *pglob_copy;
-static THREADLOCAL void *glob_ctx;
 
 static void wrapped_gl_closedir(void *dir) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
-  pglob_copy->gl_closedir(dir);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+  IndirectExternCall(pglob_copy->gl_closedir)(dir);
 }
 
 static void *wrapped_gl_readdir(void *dir) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
-  return pglob_copy->gl_readdir(dir);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+  return IndirectExternCall(pglob_copy->gl_readdir)(dir);
 }
 
 static void *wrapped_gl_opendir(const char *s) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
-  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
-  return pglob_copy->gl_opendir(s);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+  return IndirectExternCall(pglob_copy->gl_opendir)(s);
 }
 
 static int wrapped_gl_lstat(const char *s, void *st) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
-  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
-  return pglob_copy->gl_lstat(s, st);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+  return IndirectExternCall(pglob_copy->gl_lstat)(s, st);
 }
 
 static int wrapped_gl_stat(const char *s, void *st) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 2);
-  COMMON_INTERCEPTOR_WRITE_RANGE(glob_ctx, s, REAL(strlen)(s) + 1);
-  return pglob_copy->gl_stat(s, st);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(s, REAL(strlen)(s) + 1);
+  return IndirectExternCall(pglob_copy->gl_stat)(s, st);
 }
 
 INTERCEPTOR(int, glob, const char *pattern, int flags,
@@ -888,7 +1391,6 @@
     Swap(pglob->gl_lstat, glob_copy.gl_lstat);
     Swap(pglob->gl_stat, glob_copy.gl_stat);
     pglob_copy = &glob_copy;
-    glob_ctx = ctx;
   }
   int res = REAL(glob)(pattern, flags, errfunc, pglob);
   if (flags & glob_altdirfunc) {
@@ -899,7 +1401,6 @@
     Swap(pglob->gl_stat, glob_copy.gl_stat);
   }
   pglob_copy = 0;
-  glob_ctx = 0;
   if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
   return res;
 }
@@ -920,7 +1421,6 @@
     Swap(pglob->gl_lstat, glob_copy.gl_lstat);
     Swap(pglob->gl_stat, glob_copy.gl_stat);
     pglob_copy = &glob_copy;
-    glob_ctx = ctx;
   }
   int res = REAL(glob64)(pattern, flags, errfunc, pglob);
   if (flags & glob_altdirfunc) {
@@ -931,7 +1431,6 @@
     Swap(pglob->gl_stat, glob_copy.gl_stat);
   }
   pglob_copy = 0;
-  glob_ctx = 0;
   if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
   return res;
 }
@@ -981,6 +1480,19 @@
   }
   return res;
 }
+#if SANITIZER_ANDROID
+INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage);
+  int res = REAL(__wait4)(pid, status, options, rusage);
+  if (res != -1) {
+    if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+    if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+  }
+  return res;
+}
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(__wait4);
+#else
 INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
@@ -991,14 +1503,16 @@
   }
   return res;
 }
+#define INIT_WAIT4 COMMON_INTERCEPT_FUNCTION(wait4);
+#endif  // SANITIZER_ANDROID
 #define INIT_WAIT                     \
   COMMON_INTERCEPT_FUNCTION(wait);    \
   COMMON_INTERCEPT_FUNCTION(waitid);  \
   COMMON_INTERCEPT_FUNCTION(waitpid); \
-  COMMON_INTERCEPT_FUNCTION(wait3);   \
-  COMMON_INTERCEPT_FUNCTION(wait4);
+  COMMON_INTERCEPT_FUNCTION(wait3);
 #else
 #define INIT_WAIT
+#define INIT_WAIT4
 #endif
 
 #if SANITIZER_INTERCEPT_INET
@@ -1208,14 +1722,12 @@
   COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, result,
                            h_errnop);
   int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
-  if (res == 0) {
-    if (result) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
-      if (*result) write_hostent(ctx, *result);
-    }
-    if (h_errnop)
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  if (result) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (res == 0 && *result) write_hostent(ctx, *result);
   }
+  if (h_errnop)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
   return res;
 }
 
@@ -1228,14 +1740,12 @@
   COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
   int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
                                   h_errnop);
-  if (res == 0) {
-    if (result) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
-      if (*result) write_hostent(ctx, *result);
-    }
-    if (h_errnop)
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  if (result) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (res == 0 && *result) write_hostent(ctx, *result);
   }
+  if (h_errnop)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
   return res;
 }
 
@@ -1246,14 +1756,12 @@
   COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result,
                            h_errnop);
   int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
-  if (res == 0) {
-    if (result) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
-      if (*result) write_hostent(ctx, *result);
-    }
-    if (h_errnop)
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  if (result) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (res == 0 && *result) write_hostent(ctx, *result);
   }
+  if (h_errnop)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
   return res;
 }
 
@@ -1265,14 +1773,12 @@
                            result, h_errnop);
   int res =
       REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
-  if (res == 0) {
-    if (result) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
-      if (*result) write_hostent(ctx, *result);
-    }
-    if (h_errnop)
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
+  if (result) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+    if (res == 0 && *result) write_hostent(ctx, *result);
   }
+  if (h_errnop)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop));
   return res;
 }
 #define INIT_GETHOSTBYNAME_R                  \
@@ -1402,7 +1908,10 @@
   SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
   if (res >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
-    if (msg) write_msghdr(ctx, msg, res);
+    if (msg) {
+      write_msghdr(ctx, msg, res);
+      COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg);
+    }
   }
   return res;
 }
@@ -1812,7 +2321,7 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum);
   char *res = REAL(strerror)(errnum);
-  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
   return res;
 }
 #define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
@@ -1848,29 +2357,43 @@
 #define INIT_STRERROR_R
 #endif
 
+#if SANITIZER_INTERCEPT_XPG_STRERROR_R
+INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
+  int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
+  // This version always returns a null-terminated string.
+  if (buf && buflen)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+  return res;
+}
+#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r);
+#else
+#define INIT_XPG_STRERROR_R
+#endif
+
 #if SANITIZER_INTERCEPT_SCANDIR
 typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *);
 typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **,
                                 const struct __sanitizer_dirent **);
 
-static THREADLOCAL void *scandir_ctx;
 static THREADLOCAL scandir_filter_f scandir_filter;
 static THREADLOCAL scandir_compar_f scandir_compar;
 
 static int wrapped_scandir_filter(const struct __sanitizer_dirent *dir) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 1);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, dir, dir->d_reclen);
-  return scandir_filter(dir);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+  return IndirectExternCall(scandir_filter)(dir);
 }
 
 static int wrapped_scandir_compar(const struct __sanitizer_dirent **a,
                                   const struct __sanitizer_dirent **b) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir_ctx, 2);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, a, sizeof(*a));
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *a, (*a)->d_reclen);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, b, sizeof(*b));
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir_ctx, *b, (*b)->d_reclen);
-  return scandir_compar(a, b);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+  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);
 }
 
 INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
@@ -1878,13 +2401,10 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, scandir, dirp, namelist, filter, compar);
   if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
-  CHECK_EQ(0, scandir_ctx);
-  scandir_ctx = ctx;
   scandir_filter = filter;
   scandir_compar = compar;
   int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0,
                           compar ? wrapped_scandir_compar : 0);
-  scandir_ctx = 0;
   scandir_filter = 0;
   scandir_compar = 0;
   if (namelist && res > 0) {
@@ -1906,24 +2426,23 @@
 typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **,
                                   const struct __sanitizer_dirent64 **);
 
-static THREADLOCAL void *scandir64_ctx;
 static THREADLOCAL scandir64_filter_f scandir64_filter;
 static THREADLOCAL scandir64_compar_f scandir64_compar;
 
 static int wrapped_scandir64_filter(const struct __sanitizer_dirent64 *dir) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 1);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, dir, dir->d_reclen);
-  return scandir64_filter(dir);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, dir->d_reclen);
+  return IndirectExternCall(scandir64_filter)(dir);
 }
 
 static int wrapped_scandir64_compar(const struct __sanitizer_dirent64 **a,
                                     const struct __sanitizer_dirent64 **b) {
-  COMMON_INTERCEPTOR_UNPOISON_PARAM(scandir64_ctx, 2);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, a, sizeof(*a));
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *a, (*a)->d_reclen);
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, b, sizeof(*b));
-  COMMON_INTERCEPTOR_WRITE_RANGE(scandir64_ctx, *b, (*b)->d_reclen);
-  return scandir64_compar(a, b);
+  COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+  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);
 }
 
 INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
@@ -1931,14 +2450,11 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, scandir64, dirp, namelist, filter, compar);
   if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1);
-  CHECK_EQ(0, scandir64_ctx);
-  scandir64_ctx = ctx;
   scandir64_filter = filter;
   scandir64_compar = compar;
   int res =
       REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0,
                       compar ? wrapped_scandir64_compar : 0);
-  scandir64_ctx = 0;
   scandir64_filter = 0;
   scandir64_compar = 0;
   if (namelist && res > 0) {
@@ -2206,53 +2722,6 @@
 #define INIT_PTHREAD_MUTEX_UNLOCK
 #endif
 
-#if SANITIZER_INTERCEPT_PTHREAD_COND
-INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_wait, c, m);
-  COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
-  int res = REAL(pthread_cond_wait)(c, m);
-  COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
-  return res;
-}
-
-INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_init, c, a);
-  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, pthread_cond_t_sz);
-  return REAL(pthread_cond_init)(c, a);
-}
-
-INTERCEPTOR(int, pthread_cond_signal, void *c) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_signal, c);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
-  return REAL(pthread_cond_signal)(c);
-}
-
-INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_broadcast, c);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
-  return REAL(pthread_cond_broadcast)(c);
-}
-
-#define INIT_PTHREAD_COND_WAIT \
-  INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_INIT \
-  INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_SIGNAL \
-  INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2")
-#define INIT_PTHREAD_COND_BROADCAST \
-  INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2")
-#else
-#define INIT_PTHREAD_COND_WAIT
-#define INIT_PTHREAD_COND_INIT
-#define INIT_PTHREAD_COND_SIGNAL
-#define INIT_PTHREAD_COND_BROADCAST
-#endif
-
 #if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
 static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
@@ -2409,7 +2878,7 @@
   COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr);
   if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
   char *res = REAL(ether_ntoa)(addr);
-  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
   return res;
 }
 INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
@@ -2417,7 +2886,7 @@
   COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf);
   if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
   __sanitizer_ether_addr *res = REAL(ether_aton)(buf);
-  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, sizeof(*res));
+  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res));
   return res;
 }
 INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
@@ -2552,6 +3021,17 @@
   return res;
 }
 
+// We may need to call the real pthread_attr_getstack from the run-time
+// in sanitizer_common, but we don't want to include the interception headers
+// there. So, just define this function here.
+namespace __sanitizer {
+extern "C" {
+int real_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {
+  return REAL(pthread_attr_getstack)(attr, addr, size);
+}
+}  // extern "C"
+}  // namespace __sanitizer
+
 #define INIT_PTHREAD_ATTR_GET                             \
   COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
   COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize);   \
@@ -2600,7 +3080,7 @@
     if (s)
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
     else
-      COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
   }
   return res;
 }
@@ -2629,7 +3109,7 @@
   if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1);
   if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1);
   char *res = REAL(tempnam)(dir, pfx);
-  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
   return res;
 }
 #define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
@@ -2792,6 +3272,18 @@
 #define INIT_DRAND48_R
 #endif
 
+#if SANITIZER_INTERCEPT_RAND_R
+INTERCEPTOR(int, rand_r, unsigned *seedp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, rand_r, seedp);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, seedp, sizeof(*seedp));
+  return REAL(rand_r)(seedp);
+}
+#define INIT_RAND_R COMMON_INTERCEPT_FUNCTION(rand_r);
+#else
+#define INIT_RAND_R
+#endif
+
 #if SANITIZER_INTERCEPT_GETLINE
 INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
   void *ctx;
@@ -2823,113 +3315,903 @@
 #define INIT_GETLINE
 #endif
 
-#define SANITIZER_COMMON_INTERCEPTORS_INIT \
-  INIT_STRCMP;                             \
-  INIT_STRNCMP;                            \
-  INIT_STRCASECMP;                         \
-  INIT_STRNCASECMP;                        \
-  INIT_READ;                               \
-  INIT_PREAD;                              \
-  INIT_PREAD64;                            \
-  INIT_READV;                              \
-  INIT_PREADV;                             \
-  INIT_PREADV64;                           \
-  INIT_WRITE;                              \
-  INIT_PWRITE;                             \
-  INIT_PWRITE64;                           \
-  INIT_WRITEV;                             \
-  INIT_PWRITEV;                            \
-  INIT_PWRITEV64;                          \
-  INIT_PRCTL;                              \
-  INIT_LOCALTIME_AND_FRIENDS;              \
-  INIT_STRPTIME;                           \
-  INIT_SCANF;                              \
-  INIT_ISOC99_SCANF;                       \
-  INIT_FREXP;                              \
-  INIT_FREXPF_FREXPL;                      \
-  INIT_GETPWNAM_AND_FRIENDS;               \
-  INIT_GETPWNAM_R_AND_FRIENDS;             \
-  INIT_CLOCK_GETTIME;                      \
-  INIT_GETITIMER;                          \
-  INIT_TIME;                               \
-  INIT_GLOB;                               \
-  INIT_WAIT;                               \
-  INIT_INET;                               \
-  INIT_PTHREAD_GETSCHEDPARAM;              \
-  INIT_GETADDRINFO;                        \
-  INIT_GETNAMEINFO;                        \
-  INIT_GETSOCKNAME;                        \
-  INIT_GETHOSTBYNAME;                      \
-  INIT_GETHOSTBYNAME_R;                    \
-  INIT_GETSOCKOPT;                         \
-  INIT_ACCEPT;                             \
-  INIT_ACCEPT4;                            \
-  INIT_MODF;                               \
-  INIT_RECVMSG;                            \
-  INIT_GETPEERNAME;                        \
-  INIT_IOCTL;                              \
-  INIT_INET_ATON;                          \
-  INIT_SYSINFO;                            \
-  INIT_READDIR;                            \
-  INIT_READDIR64;                          \
-  INIT_PTRACE;                             \
-  INIT_SETLOCALE;                          \
-  INIT_GETCWD;                             \
-  INIT_GET_CURRENT_DIR_NAME;               \
-  INIT_STRTOIMAX;                          \
-  INIT_MBSTOWCS;                           \
-  INIT_MBSNRTOWCS;                         \
-  INIT_WCSTOMBS;                           \
-  INIT_WCSNRTOMBS;                         \
-  INIT_TCGETATTR;                          \
-  INIT_REALPATH;                           \
-  INIT_CANONICALIZE_FILE_NAME;             \
-  INIT_CONFSTR;                            \
-  INIT_SCHED_GETAFFINITY;                  \
-  INIT_STRERROR;                           \
-  INIT_STRERROR_R;                         \
-  INIT_SCANDIR;                            \
-  INIT_SCANDIR64;                          \
-  INIT_GETGROUPS;                          \
-  INIT_POLL;                               \
-  INIT_PPOLL;                              \
-  INIT_WORDEXP;                            \
-  INIT_SIGWAIT;                            \
-  INIT_SIGWAITINFO;                        \
-  INIT_SIGTIMEDWAIT;                       \
-  INIT_SIGSETOPS;                          \
-  INIT_SIGPENDING;                         \
-  INIT_SIGPROCMASK;                        \
-  INIT_BACKTRACE;                          \
-  INIT__EXIT;                              \
-  INIT_PTHREAD_MUTEX_LOCK;                 \
-  INIT_PTHREAD_MUTEX_UNLOCK;               \
-  INIT_PTHREAD_COND_WAIT;                  \
-  INIT_PTHREAD_COND_INIT;                  \
-  INIT_PTHREAD_COND_SIGNAL;                \
-  INIT_PTHREAD_COND_BROADCAST;             \
-  INIT_GETMNTENT;                          \
-  INIT_GETMNTENT_R;                        \
-  INIT_STATFS;                             \
-  INIT_STATFS64;                           \
-  INIT_STATVFS;                            \
-  INIT_STATVFS64;                          \
-  INIT_INITGROUPS;                         \
-  INIT_ETHER;                              \
-  INIT_ETHER_R;                            \
-  INIT_SHMCTL;                             \
-  INIT_RANDOM_R;                           \
-  INIT_PTHREAD_ATTR_GET;                   \
-  INIT_PTHREAD_ATTR_GETINHERITSCHED;       \
-  INIT_PTHREAD_ATTR_GETAFFINITY_NP;        \
-  INIT_TMPNAM;                             \
-  INIT_TMPNAM_R;                           \
-  INIT_TEMPNAM;                            \
-  INIT_PTHREAD_SETNAME_NP;                 \
-  INIT_SINCOS;                             \
-  INIT_REMQUO;                             \
-  INIT_LGAMMA;                             \
-  INIT_LGAMMA_R;                           \
-  INIT_DRAND48_R;                          \
-  INIT_GETLINE;                            \
-/**/
+#if SANITIZER_INTERCEPT_ICONV
+INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
+            char **outbuf, SIZE_T *outbytesleft) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf,
+                           outbytesleft);
+  if (inbytesleft)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft));
+  if (inbuf && inbytesleft)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
+  if (outbytesleft)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
+  void *outbuf_orig = outbuf ? *outbuf : 0;
+  SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
+  if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
+    SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
+  }
+  return res;
+}
+#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv);
+#else
+#define INIT_ICONV
+#endif
+
+#if SANITIZER_INTERCEPT_TIMES
+INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
+  __sanitizer_clock_t res = REAL(times)(tms);
+  if (res != (__sanitizer_clock_t)-1 && tms)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
+  return res;
+}
+#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times);
+#else
+#define INIT_TIMES
+#endif
+
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
+INTERCEPTOR(void *, __tls_get_addr, void *arg) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg);
+  void *res = REAL(__tls_get_addr)(arg);
+  DTLS_on_tls_get_addr(arg, res);
+  return res;
+}
+#else
+#define INIT_TLS_GET_ADDR
+#endif
+
+#if SANITIZER_INTERCEPT_LISTXATTR
+INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  SSIZE_T res = REAL(listxattr)(path, list, size);
+  // Here and below, size == 0 is a special case where nothing is written to the
+  // buffer, and res contains the desired buffer size.
+  if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+  return res;
+}
+INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, size);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  SSIZE_T res = REAL(llistxattr)(path, list, size);
+  if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+  return res;
+}
+INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size);
+  SSIZE_T res = REAL(flistxattr)(fd, list, size);
+  if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
+  return res;
+}
+#define INIT_LISTXATTR                   \
+  COMMON_INTERCEPT_FUNCTION(listxattr);  \
+  COMMON_INTERCEPT_FUNCTION(llistxattr); \
+  COMMON_INTERCEPT_FUNCTION(flistxattr);
+#else
+#define INIT_LISTXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETXATTR
+INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
+            SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  SSIZE_T res = REAL(getxattr)(path, name, value, size);
+  if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+  return res;
+}
+INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
+            SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
+  if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+  return res;
+}
+INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
+            SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size);
+  if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+  SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
+  if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
+  return res;
+}
+#define INIT_GETXATTR                   \
+  COMMON_INTERCEPT_FUNCTION(getxattr);  \
+  COMMON_INTERCEPT_FUNCTION(lgetxattr); \
+  COMMON_INTERCEPT_FUNCTION(fgetxattr);
+#else
+#define INIT_GETXATTR
+#endif
+
+#if SANITIZER_INTERCEPT_GETRESID
+INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid);
+  int res = REAL(getresuid)(ruid, euid, suid);
+  if (res >= 0) {
+    if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz);
+    if (euid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, euid, uid_t_sz);
+    if (suid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, suid, uid_t_sz);
+  }
+  return res;
+}
+INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid);
+  int res = REAL(getresgid)(rgid, egid, sgid);
+  if (res >= 0) {
+    if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz);
+    if (egid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, egid, gid_t_sz);
+    if (sgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sgid, gid_t_sz);
+  }
+  return res;
+}
+#define INIT_GETRESID                   \
+  COMMON_INTERCEPT_FUNCTION(getresuid); \
+  COMMON_INTERCEPT_FUNCTION(getresgid);
+#else
+#define INIT_GETRESID
+#endif
+
+#if SANITIZER_INTERCEPT_GETIFADDRS
+// As long as getifaddrs()/freeifaddrs() use calloc()/free(), we don't need to
+// intercept freeifaddrs(). If that ceases to be the case, we might need to
+// intercept it to poison the memory again.
+INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap);
+  int res = REAL(getifaddrs)(ifap);
+  if (res == 0 && ifap) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *));
+    __sanitizer_ifaddrs *p = *ifap;
+    while (p) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_ifaddrs));
+      if (p->ifa_name)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_name,
+                                       REAL(strlen)(p->ifa_name) + 1);
+      if (p->ifa_addr)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_addr, struct_sockaddr_sz);
+      if (p->ifa_netmask)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_netmask, struct_sockaddr_sz);
+      // On Linux this is a union, but the other member also points to a
+      // struct sockaddr, so the following is sufficient.
+      if (p->ifa_dstaddr)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ifa_dstaddr, struct_sockaddr_sz);
+      // FIXME(smatveev): Unpoison p->ifa_data as well.
+      p = p->ifa_next;
+    }
+  }
+  return res;
+}
+#define INIT_GETIFADDRS                  \
+  COMMON_INTERCEPT_FUNCTION(getifaddrs);
+#else
+#define INIT_GETIFADDRS
+#endif
+
+#if SANITIZER_INTERCEPT_IF_INDEXTONAME
+INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname);
+  char *res = REAL(if_indextoname)(ifindex, ifname);
+  if (res && ifname)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+  return res;
+}
+INTERCEPTOR(unsigned int, if_nametoindex, const char* ifname) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, if_nametoindex, ifname);
+  if (ifname)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
+  return REAL(if_nametoindex)(ifname);
+}
+#define INIT_IF_INDEXTONAME                  \
+  COMMON_INTERCEPT_FUNCTION(if_indextoname); \
+  COMMON_INTERCEPT_FUNCTION(if_nametoindex);
+#else
+#define INIT_IF_INDEXTONAME
+#endif
+
+#if SANITIZER_INTERCEPT_CAPGET
+INTERCEPTOR(int, capget, void *hdrp, void *datap) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap);
+  if (hdrp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
+  int res = REAL(capget)(hdrp, datap);
+  if (res == 0 && datap)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
+  // We can also return -1 and write to hdrp->version if the version passed in
+  // hdrp->version is unsupported. But that's not a trivial condition to check,
+  // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent.
+  return res;
+}
+INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap);
+  if (hdrp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
+  if (datap)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz);
+  return REAL(capset)(hdrp, datap);
+}
+#define INIT_CAPGET                  \
+  COMMON_INTERCEPT_FUNCTION(capget); \
+  COMMON_INTERCEPT_FUNCTION(capset);
+#else
+#define INIT_CAPGET
+#endif
+
+#if SANITIZER_INTERCEPT_AEABI_MEM
+DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr);
+DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr);
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+
+INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) {
+  return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) {
+  return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) {
+  return WRAP(memmove)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) {
+  return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) {
+  return WRAP(memcpy)(to, from, size);
+}
+INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) {
+  return WRAP(memcpy)(to, from, size);
+}
+// Note the argument order.
+INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) {
+  return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) {
+  return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) {
+  return WRAP(memset)(block, c, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) {
+  return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) {
+  return WRAP(memset)(block, 0, size);
+}
+INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) {
+  return WRAP(memset)(block, 0, size);
+}
+#define INIT_AEABI_MEM                         \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memmove);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy);   \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memset);   \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memset4);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memset8);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memclr);   \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4);  \
+  COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8);
+#else
+#define INIT_AEABI_MEM
+#endif  // SANITIZER_INTERCEPT_AEABI_MEM
+
+#if SANITIZER_INTERCEPT___BZERO
+DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
+
+INTERCEPTOR(void *, __bzero, void *block, uptr size) {
+  return WRAP(memset)(block, 0, size);
+}
+#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero);
+#else
+#define INIT___BZERO
+#endif  // SANITIZER_INTERCEPT___BZERO
+
+#if SANITIZER_INTERCEPT_FTIME
+INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp);
+  int res = REAL(ftime)(tp);
+  if (tp)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp));
+  return res;
+}
+#define INIT_FTIME COMMON_INTERCEPT_FUNCTION(ftime);
+#else
+#define INIT_FTIME
+#endif  // SANITIZER_INTERCEPT_FTIME
+
+#if SANITIZER_INTERCEPT_XDR
+INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr,
+            unsigned size, int op) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op);
+  REAL(xdrmem_create)(xdrs, addr, size, op);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
+  if (op == __sanitizer_XDR_ENCODE) {
+    // It's not obvious how much data individual xdr_ routines write.
+    // Simply unpoison the entire target buffer in advance.
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size);
+  }
+}
+
+INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op);
+  REAL(xdrstdio_create)(xdrs, file, op);
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
+}
+
+#define XDR_INTERCEPTOR(F, T)                             \
+  INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) {      \
+    void *ctx;                                            \
+    COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p);            \
+    if (p && xdrs->x_op == __sanitizer_XDR_ENCODE)        \
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));  \
+    int res = REAL(F)(xdrs, p);                           \
+    if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \
+    return res;                                           \
+  }
+
+XDR_INTERCEPTOR(xdr_short, short)
+XDR_INTERCEPTOR(xdr_u_short, unsigned short)
+XDR_INTERCEPTOR(xdr_int, int)
+XDR_INTERCEPTOR(xdr_u_int, unsigned)
+XDR_INTERCEPTOR(xdr_long, long)
+XDR_INTERCEPTOR(xdr_u_long, unsigned long)
+XDR_INTERCEPTOR(xdr_hyper, long long)
+XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long)
+XDR_INTERCEPTOR(xdr_longlong_t, long long)
+XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_int8_t, u8)
+XDR_INTERCEPTOR(xdr_uint8_t, u8)
+XDR_INTERCEPTOR(xdr_int16_t, u16)
+XDR_INTERCEPTOR(xdr_uint16_t, u16)
+XDR_INTERCEPTOR(xdr_int32_t, u32)
+XDR_INTERCEPTOR(xdr_uint32_t, u32)
+XDR_INTERCEPTOR(xdr_int64_t, u64)
+XDR_INTERCEPTOR(xdr_uint64_t, u64)
+XDR_INTERCEPTOR(xdr_quad_t, long long)
+XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long)
+XDR_INTERCEPTOR(xdr_bool, bool)
+XDR_INTERCEPTOR(xdr_enum, int)
+XDR_INTERCEPTOR(xdr_char, char)
+XDR_INTERCEPTOR(xdr_u_char, unsigned char)
+XDR_INTERCEPTOR(xdr_float, float)
+XDR_INTERCEPTOR(xdr_double, double)
+
+// FIXME: intercept xdr_array, opaque, union, vector, reference, pointer,
+// wrapstring, sizeof
+
+INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep,
+            unsigned maxsize) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize);
+  if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep));
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *sizep);
+  }
+  int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize);
+  if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep));
+    if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep);
+  }
+  return res;
+}
+
+INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
+            unsigned maxsize) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize);
+  if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p));
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+  }
+  int res = REAL(xdr_string)(xdrs, p, maxsize);
+  if (p && xdrs->x_op == __sanitizer_XDR_DECODE) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
+    if (res && *p)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1);
+  }
+  return res;
+}
+
+#define INIT_XDR                               \
+  COMMON_INTERCEPT_FUNCTION(xdrmem_create);    \
+  COMMON_INTERCEPT_FUNCTION(xdrstdio_create);  \
+  COMMON_INTERCEPT_FUNCTION(xdr_short);        \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_short);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_int);          \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_int);        \
+  COMMON_INTERCEPT_FUNCTION(xdr_long);         \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_long);       \
+  COMMON_INTERCEPT_FUNCTION(xdr_hyper);        \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_hyper);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_longlong_t);   \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \
+  COMMON_INTERCEPT_FUNCTION(xdr_int8_t);       \
+  COMMON_INTERCEPT_FUNCTION(xdr_uint8_t);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_int16_t);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_uint16_t);     \
+  COMMON_INTERCEPT_FUNCTION(xdr_int32_t);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_uint32_t);     \
+  COMMON_INTERCEPT_FUNCTION(xdr_int64_t);      \
+  COMMON_INTERCEPT_FUNCTION(xdr_uint64_t);     \
+  COMMON_INTERCEPT_FUNCTION(xdr_quad_t);       \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t);     \
+  COMMON_INTERCEPT_FUNCTION(xdr_bool);         \
+  COMMON_INTERCEPT_FUNCTION(xdr_enum);         \
+  COMMON_INTERCEPT_FUNCTION(xdr_char);         \
+  COMMON_INTERCEPT_FUNCTION(xdr_u_char);       \
+  COMMON_INTERCEPT_FUNCTION(xdr_float);        \
+  COMMON_INTERCEPT_FUNCTION(xdr_double);       \
+  COMMON_INTERCEPT_FUNCTION(xdr_bytes);        \
+  COMMON_INTERCEPT_FUNCTION(xdr_string);
+#else
+#define INIT_XDR
+#endif  // SANITIZER_INTERCEPT_XDR
+
+#if SANITIZER_INTERCEPT_TSEARCH
+INTERCEPTOR(void *, tsearch, void *key, void **rootp,
+            int (*compar)(const void *, const void *)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar);
+  void *res = REAL(tsearch)(key, rootp, compar);
+  if (res && *(void **)res == key)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *));
+  return res;
+}
+#define INIT_TSEARCH COMMON_INTERCEPT_FUNCTION(tsearch);
+#else
+#define INIT_TSEARCH
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS || SANITIZER_INTERCEPT_FOPEN || \
+    SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+void unpoison_file(__sanitizer_FILE *fp) {
+#if SANITIZER_HAS_STRUCT_FILE
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp, sizeof(*fp));
+  if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
+                                        fp->_IO_read_end - fp->_IO_read_base);
+#endif  // SANITIZER_HAS_STRUCT_FILE
+}
+#endif
+
+#if SANITIZER_INTERCEPT_LIBIO_INTERNALS
+// These guys are called when a .c source is built with -O2.
+INTERCEPTOR(int, __uflow, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __uflow, fp);
+  int res = REAL(__uflow)(fp);
+  unpoison_file(fp);
+  return res;
+}
+INTERCEPTOR(int, __underflow, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __underflow, fp);
+  int res = REAL(__underflow)(fp);
+  unpoison_file(fp);
+  return res;
+}
+INTERCEPTOR(int, __overflow, __sanitizer_FILE *fp, int ch) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __overflow, fp, ch);
+  int res = REAL(__overflow)(fp, ch);
+  unpoison_file(fp);
+  return res;
+}
+INTERCEPTOR(int, __wuflow, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wuflow, fp);
+  int res = REAL(__wuflow)(fp);
+  unpoison_file(fp);
+  return res;
+}
+INTERCEPTOR(int, __wunderflow, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wunderflow, fp);
+  int res = REAL(__wunderflow)(fp);
+  unpoison_file(fp);
+  return res;
+}
+INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __woverflow, fp, ch);
+  int res = REAL(__woverflow)(fp, ch);
+  unpoison_file(fp);
+  return res;
+}
+#define INIT_LIBIO_INTERNALS               \
+  COMMON_INTERCEPT_FUNCTION(__uflow);      \
+  COMMON_INTERCEPT_FUNCTION(__underflow);  \
+  COMMON_INTERCEPT_FUNCTION(__overflow);   \
+  COMMON_INTERCEPT_FUNCTION(__wuflow);     \
+  COMMON_INTERCEPT_FUNCTION(__wunderflow); \
+  COMMON_INTERCEPT_FUNCTION(__woverflow);
+#else
+#define INIT_LIBIO_INTERNALS
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN
+INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+  __sanitizer_FILE *res = REAL(fopen)(path, mode);
+  COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+  if (res) unpoison_file(res);
+  return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fdopen, int fd, const char *mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fdopen, fd, mode);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+  __sanitizer_FILE *res = REAL(fdopen)(fd, mode);
+  if (res) unpoison_file(res);
+  return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode,
+            __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+  COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+  __sanitizer_FILE *res = REAL(freopen)(path, mode, fp);
+  COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+  if (res) unpoison_file(res);
+  return res;
+}
+#define INIT_FOPEN                   \
+  COMMON_INTERCEPT_FUNCTION(fopen);  \
+  COMMON_INTERCEPT_FUNCTION(fdopen); \
+  COMMON_INTERCEPT_FUNCTION(freopen);
+#else
+#define INIT_FOPEN
+#endif
+
+#if SANITIZER_INTERCEPT_FOPEN64
+INTERCEPTOR(__sanitizer_FILE *, fopen64, const char *path, const char *mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fopen64, path, mode);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+  __sanitizer_FILE *res = REAL(fopen64)(path, mode);
+  COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+  if (res) unpoison_file(res);
+  return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode,
+            __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
+  COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+  __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp);
+  COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
+  if (res) unpoison_file(res);
+  return res;
+}
+#define INIT_FOPEN64                  \
+  COMMON_INTERCEPT_FUNCTION(fopen64); \
+  COMMON_INTERCEPT_FUNCTION(freopen64);
+#else
+#define INIT_FOPEN64
+#endif
+
+#if SANITIZER_INTERCEPT_OPEN_MEMSTREAM
+INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc);
+  __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc);
+  if (res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+    unpoison_file(res);
+    FileMetadata file = {ptr, sizeloc};
+    SetInterceptorMetadata(res, file);
+  }
+  return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, open_wmemstream, wchar_t **ptr,
+            SIZE_T *sizeloc) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, open_wmemstream, ptr, sizeloc);
+  __sanitizer_FILE *res = REAL(open_wmemstream)(ptr, sizeloc);
+  if (res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizeloc, sizeof(*sizeloc));
+    unpoison_file(res);
+    FileMetadata file = {(char **)ptr, sizeloc};
+    SetInterceptorMetadata(res, file);
+  }
+  return res;
+}
+INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size,
+            const char *mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode);
+  __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode);
+  if (res) unpoison_file(res);
+  return res;
+}
+#define INIT_OPEN_MEMSTREAM                   \
+  COMMON_INTERCEPT_FUNCTION(open_memstream);  \
+  COMMON_INTERCEPT_FUNCTION(open_wmemstream); \
+  COMMON_INTERCEPT_FUNCTION(fmemopen);
+#else
+#define INIT_OPEN_MEMSTREAM
+#endif
+
+#if SANITIZER_INTERCEPT_OBSTACK
+static void initialize_obstack(__sanitizer_obstack *obstack) {
+  COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack, sizeof(*obstack));
+  if (obstack->chunk)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(obstack->chunk,
+                                        sizeof(*obstack->chunk));
+}
+
+INTERCEPTOR(int, _obstack_begin_1, __sanitizer_obstack *obstack, int sz,
+            int align, void *(*alloc_fn)(uptr arg, uptr sz),
+            void (*free_fn)(uptr arg, void *p)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin_1, obstack, sz, align, alloc_fn,
+                           free_fn);
+  int res = REAL(_obstack_begin_1)(obstack, sz, align, alloc_fn, free_fn);
+  if (res) initialize_obstack(obstack);
+  return res;
+}
+INTERCEPTOR(int, _obstack_begin, __sanitizer_obstack *obstack, int sz,
+            int align, void *(*alloc_fn)(uptr sz), void (*free_fn)(void *p)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, _obstack_begin, obstack, sz, align, alloc_fn,
+                           free_fn);
+  int res = REAL(_obstack_begin)(obstack, sz, align, alloc_fn, free_fn);
+  if (res) initialize_obstack(obstack);
+  return res;
+}
+INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, _obstack_newchunk, obstack, length);
+  REAL(_obstack_newchunk)(obstack, length);
+  if (obstack->chunk)
+    COMMON_INTERCEPTOR_INITIALIZE_RANGE(
+        obstack->chunk, obstack->next_free - (char *)obstack->chunk);
+}
+#define INIT_OBSTACK                           \
+  COMMON_INTERCEPT_FUNCTION(_obstack_begin_1); \
+  COMMON_INTERCEPT_FUNCTION(_obstack_begin);   \
+  COMMON_INTERCEPT_FUNCTION(_obstack_newchunk);
+#else
+#define INIT_OBSTACK
+#endif
+
+#if SANITIZER_INTERCEPT_FFLUSH
+INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
+  int res = REAL(fflush)(fp);
+  // FIXME: handle fp == NULL
+  if (fp) {
+    const FileMetadata *m = GetInterceptorMetadata(fp);
+    if (m) COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+  }
+  return res;
+}
+#define INIT_FFLUSH COMMON_INTERCEPT_FUNCTION(fflush);
+#else
+#define INIT_FFLUSH
+#endif
+
+#if SANITIZER_INTERCEPT_FCLOSE
+INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
+  if (fp) {
+    COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
+    const FileMetadata *m = GetInterceptorMetadata(fp);
+    if (m) {
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
+      DeleteInterceptorMetadata(fp);
+    }
+  }
+  return REAL(fclose)(fp);
+}
+#define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose);
+#else
+#define INIT_FCLOSE
+#endif
+
+#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
+INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
+  void *res = REAL(dlopen)(filename, flag);
+  COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
+  return res;
+}
+
+INTERCEPTOR(int, dlclose, void *handle) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle);
+  int res = REAL(dlclose)(handle);
+  COMMON_INTERCEPTOR_LIBRARY_UNLOADED();
+  return res;
+}
+#define INIT_DLOPEN_DLCLOSE          \
+  COMMON_INTERCEPT_FUNCTION(dlopen); \
+  COMMON_INTERCEPT_FUNCTION(dlclose);
+#else
+#define INIT_DLOPEN_DLCLOSE
+#endif
+
+static void InitializeCommonInterceptors() {
+  static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
+  interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
+
+  INIT_TEXTDOMAIN;
+  INIT_STRCMP;
+  INIT_STRNCMP;
+  INIT_STRCASECMP;
+  INIT_STRNCASECMP;
+  INIT_MEMCHR;
+  INIT_MEMRCHR;
+  INIT_READ;
+  INIT_PREAD;
+  INIT_PREAD64;
+  INIT_READV;
+  INIT_PREADV;
+  INIT_PREADV64;
+  INIT_WRITE;
+  INIT_PWRITE;
+  INIT_PWRITE64;
+  INIT_WRITEV;
+  INIT_PWRITEV;
+  INIT_PWRITEV64;
+  INIT_PRCTL;
+  INIT_LOCALTIME_AND_FRIENDS;
+  INIT_STRPTIME;
+  INIT_SCANF;
+  INIT_ISOC99_SCANF;
+  INIT_PRINTF;
+  INIT_ISOC99_PRINTF;
+  INIT_FREXP;
+  INIT_FREXPF_FREXPL;
+  INIT_GETPWNAM_AND_FRIENDS;
+  INIT_GETPWNAM_R_AND_FRIENDS;
+  INIT_GETPWENT;
+  INIT_FGETPWENT;
+  INIT_GETPWENT_R;
+  INIT_SETPWENT;
+  INIT_CLOCK_GETTIME;
+  INIT_GETITIMER;
+  INIT_TIME;
+  INIT_GLOB;
+  INIT_WAIT;
+  INIT_WAIT4;
+  INIT_INET;
+  INIT_PTHREAD_GETSCHEDPARAM;
+  INIT_GETADDRINFO;
+  INIT_GETNAMEINFO;
+  INIT_GETSOCKNAME;
+  INIT_GETHOSTBYNAME;
+  INIT_GETHOSTBYNAME_R;
+  INIT_GETSOCKOPT;
+  INIT_ACCEPT;
+  INIT_ACCEPT4;
+  INIT_MODF;
+  INIT_RECVMSG;
+  INIT_GETPEERNAME;
+  INIT_IOCTL;
+  INIT_INET_ATON;
+  INIT_SYSINFO;
+  INIT_READDIR;
+  INIT_READDIR64;
+  INIT_PTRACE;
+  INIT_SETLOCALE;
+  INIT_GETCWD;
+  INIT_GET_CURRENT_DIR_NAME;
+  INIT_STRTOIMAX;
+  INIT_MBSTOWCS;
+  INIT_MBSNRTOWCS;
+  INIT_WCSTOMBS;
+  INIT_WCSNRTOMBS;
+  INIT_TCGETATTR;
+  INIT_REALPATH;
+  INIT_CANONICALIZE_FILE_NAME;
+  INIT_CONFSTR;
+  INIT_SCHED_GETAFFINITY;
+  INIT_STRERROR;
+  INIT_STRERROR_R;
+  INIT_XPG_STRERROR_R;
+  INIT_SCANDIR;
+  INIT_SCANDIR64;
+  INIT_GETGROUPS;
+  INIT_POLL;
+  INIT_PPOLL;
+  INIT_WORDEXP;
+  INIT_SIGWAIT;
+  INIT_SIGWAITINFO;
+  INIT_SIGTIMEDWAIT;
+  INIT_SIGSETOPS;
+  INIT_SIGPENDING;
+  INIT_SIGPROCMASK;
+  INIT_BACKTRACE;
+  INIT__EXIT;
+  INIT_PTHREAD_MUTEX_LOCK;
+  INIT_PTHREAD_MUTEX_UNLOCK;
+  INIT_GETMNTENT;
+  INIT_GETMNTENT_R;
+  INIT_STATFS;
+  INIT_STATFS64;
+  INIT_STATVFS;
+  INIT_STATVFS64;
+  INIT_INITGROUPS;
+  INIT_ETHER;
+  INIT_ETHER_R;
+  INIT_SHMCTL;
+  INIT_RANDOM_R;
+  INIT_PTHREAD_ATTR_GET;
+  INIT_PTHREAD_ATTR_GETINHERITSCHED;
+  INIT_PTHREAD_ATTR_GETAFFINITY_NP;
+  INIT_TMPNAM;
+  INIT_TMPNAM_R;
+  INIT_TEMPNAM;
+  INIT_PTHREAD_SETNAME_NP;
+  INIT_SINCOS;
+  INIT_REMQUO;
+  INIT_LGAMMA;
+  INIT_LGAMMA_R;
+  INIT_DRAND48_R;
+  INIT_RAND_R;
+  INIT_GETLINE;
+  INIT_ICONV;
+  INIT_TIMES;
+  INIT_TLS_GET_ADDR;
+  INIT_LISTXATTR;
+  INIT_GETXATTR;
+  INIT_GETRESID;
+  INIT_GETIFADDRS;
+  INIT_IF_INDEXTONAME;
+  INIT_CAPGET;
+  INIT_AEABI_MEM;
+  INIT___BZERO;
+  INIT_FTIME;
+  INIT_XDR;
+  INIT_TSEARCH;
+  INIT_LIBIO_INTERNALS;
+  INIT_FOPEN;
+  INIT_FOPEN64;
+  INIT_OPEN_MEMSTREAM;
+  INIT_OBSTACK;
+  INIT_FFLUSH;
+  INIT_FCLOSE;
+  INIT_DLOPEN_DLCLOSE;
+}
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
new file mode 100644
index 0000000..8f94802
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -0,0 +1,559 @@
+//===-- sanitizer_common_interceptors_format.inc ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Scanf/printf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// and http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html
+// with a few common GNU extensions.
+//
+//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
+static const char *parse_number(const char *p, int *out) {
+  *out = internal_atoll(p);
+  while (*p >= '0' && *p <= '9')
+    ++p;
+  return p;
+}
+
+static const char *maybe_parse_param_index(const char *p, int *out) {
+  // n$
+  if (*p >= '0' && *p <= '9') {
+    int number;
+    const char *q = parse_number(p, &number);
+    CHECK(q);
+    if (*q == '$') {
+      *out = number;
+      p = q + 1;
+    }
+  }
+
+  // Otherwise, do not change p. This will be re-parsed later as the field
+  // width.
+  return p;
+}
+
+static bool char_is_one_of(char c, const char *s) {
+  return !!internal_strchr(s, c);
+}
+
+static const char *maybe_parse_length_modifier(const char *p, char ll[2]) {
+  if (char_is_one_of(*p, "jztLq")) {
+    ll[0] = *p;
+    ++p;
+  } else if (*p == 'h') {
+    ll[0] = 'h';
+    ++p;
+    if (*p == 'h') {
+      ll[1] = 'h';
+      ++p;
+    }
+  } else if (*p == 'l') {
+    ll[0] = 'l';
+    ++p;
+    if (*p == 'l') {
+      ll[1] = 'l';
+      ++p;
+    }
+  }
+  return p;
+}
+
+// Returns true if the character is an integer conversion specifier.
+static bool format_is_integer_conv(char c) {
+  return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool format_is_float_conv(char c) {
+  return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int format_get_char_size(char convSpecifier,
+                                const char lengthModifier[2]) {
+  if (char_is_one_of(convSpecifier, "CS")) {
+    return sizeof(wchar_t);
+  }
+
+  if (char_is_one_of(convSpecifier, "cs[")) {
+    if (lengthModifier[0] == 'l' && lengthModifier[1] == '\0')
+      return sizeof(wchar_t);
+    else if (lengthModifier[0] == '\0')
+      return sizeof(char);
+  }
+
+  return 0;
+}
+
+enum FormatStoreSize {
+  // Store size not known in advance; can be calculated as wcslen() of the
+  // destination buffer.
+  FSS_WCSLEN = -2,
+  // Store size not known in advance; can be calculated as strlen() of the
+  // destination buffer.
+  FSS_STRLEN = -1,
+  // Invalid conversion specifier.
+  FSS_INVALID = 0
+};
+
+// Returns the memory size of a format directive (if >0), or a value of
+// FormatStoreSize.
+static int format_get_value_size(char convSpecifier,
+                                 const char lengthModifier[2],
+                                 bool promote_float) {
+  if (format_is_integer_conv(convSpecifier)) {
+    switch (lengthModifier[0]) {
+    case 'h':
+      return lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+    case 'l':
+      return lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+    case 'q':
+      return sizeof(long long);
+    case 'L':
+      return sizeof(long long);
+    case 'j':
+      return sizeof(INTMAX_T);
+    case 'z':
+      return sizeof(SIZE_T);
+    case 't':
+      return sizeof(PTRDIFF_T);
+    case 0:
+      return sizeof(int);
+    default:
+      return FSS_INVALID;
+    }
+  }
+
+  if (format_is_float_conv(convSpecifier)) {
+    switch (lengthModifier[0]) {
+    case 'L':
+    case 'q':
+      return sizeof(long double);
+    case 'l':
+      return lengthModifier[1] == 'l' ? sizeof(long double)
+                                           : sizeof(double);
+    case 0:
+      // Printf promotes floats to doubles but scanf does not
+      return promote_float ? sizeof(double) : sizeof(float);
+    default:
+      return FSS_INVALID;
+    }
+  }
+
+  if (convSpecifier == 'p') {
+    if (lengthModifier[0] != 0)
+      return FSS_INVALID;
+    return sizeof(void *);
+  }
+
+  return FSS_INVALID;
+}
+
+struct ScanfDirective {
+  int argIdx; // argument index, or -1 if not specified ("%n$")
+  int fieldWidth;
+  const char *begin;
+  const char *end;
+  bool suppressed; // suppress assignment ("*")
+  bool allocate;   // allocate space ("m")
+  char lengthModifier[2];
+  char convSpecifier;
+  bool maybeGnuMalloc;
+};
+
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+                                    ScanfDirective *dir) {
+  internal_memset(dir, 0, sizeof(*dir));
+  dir->argIdx = -1;
+
+  while (*p) {
+    if (*p != '%') {
+      ++p;
+      continue;
+    }
+    dir->begin = p;
+    ++p;
+    // %%
+    if (*p == '%') {
+      ++p;
+      continue;
+    }
+    if (*p == '\0') {
+      return 0;
+    }
+    // %n$
+    p = maybe_parse_param_index(p, &dir->argIdx);
+    CHECK(p);
+    // *
+    if (*p == '*') {
+      dir->suppressed = true;
+      ++p;
+    }
+    // Field width
+    if (*p >= '0' && *p <= '9') {
+      p = parse_number(p, &dir->fieldWidth);
+      CHECK(p);
+      if (dir->fieldWidth <= 0)  // Width if at all must be non-zero
+        return 0;
+    }
+    // m
+    if (*p == 'm') {
+      dir->allocate = true;
+      ++p;
+    }
+    // Length modifier.
+    p = maybe_parse_length_modifier(p, dir->lengthModifier);
+    // Conversion specifier.
+    dir->convSpecifier = *p++;
+    // Consume %[...] expression.
+    if (dir->convSpecifier == '[') {
+      if (*p == '^')
+        ++p;
+      if (*p == ']')
+        ++p;
+      while (*p && *p != ']')
+        ++p;
+      if (*p == 0)
+        return 0; // unexpected end of string
+                  // Consume the closing ']'.
+      ++p;
+    }
+    // This is unfortunately ambiguous between old GNU extension
+    // of %as, %aS and %a[...] and newer POSIX %a followed by
+    // letters s, S or [.
+    if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+        !dir->lengthModifier[0]) {
+      if (*p == 's' || *p == 'S') {
+        dir->maybeGnuMalloc = true;
+        ++p;
+      } else if (*p == '[') {
+        // Watch for %a[h-j%d], if % appears in the
+        // [...] range, then we need to give up, we don't know
+        // if scanf will parse it as POSIX %a [h-j %d ] or
+        // GNU allocation of string with range dh-j plus %.
+        const char *q = p + 1;
+        if (*q == '^')
+          ++q;
+        if (*q == ']')
+          ++q;
+        while (*q && *q != ']' && *q != '%')
+          ++q;
+        if (*q == 0 || *q == '%')
+          return 0;
+        p = q + 1; // Consume the closing ']'.
+        dir->maybeGnuMalloc = true;
+      }
+    }
+    dir->end = p;
+    break;
+  }
+  return p;
+}
+
+static int scanf_get_value_size(ScanfDirective *dir) {
+  if (dir->allocate) {
+    if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+      return FSS_INVALID;
+    return sizeof(char *);
+  }
+
+  if (dir->maybeGnuMalloc) {
+    if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+      return FSS_INVALID;
+    // This is ambiguous, so check the smaller size of char * (if it is
+    // a GNU extension of %as, %aS or %a[...]) and float (if it is
+    // POSIX %a followed by s, S or [ letters).
+    return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cCsS[")) {
+    bool needsTerminator = char_is_one_of(dir->convSpecifier, "sS[");
+    unsigned charSize =
+        format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+    if (charSize == 0)
+      return FSS_INVALID;
+    if (dir->fieldWidth == 0) {
+      if (!needsTerminator)
+        return charSize;
+      return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+    }
+    return (dir->fieldWidth + needsTerminator) * charSize;
+  }
+
+  return format_get_value_size(dir->convSpecifier, dir->lengthModifier, false);
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+                         const char *format, va_list aq) {
+  CHECK_GT(n_inputs, 0);
+  const char *p = format;
+
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+  while (*p) {
+    ScanfDirective dir;
+    p = scanf_parse_next(p, allowGnuMalloc, &dir);
+    if (!p)
+      break;
+    if (dir.convSpecifier == 0) {
+      // This can only happen at the end of the format string.
+      CHECK_EQ(*p, 0);
+      break;
+    }
+    // Here the directive is valid. Do what it says.
+    if (dir.argIdx != -1) {
+      // Unsupported.
+      break;
+    }
+    if (dir.suppressed)
+      continue;
+    int size = scanf_get_value_size(&dir);
+    if (size == FSS_INVALID) {
+      Report("WARNING: unexpected format specifier in scanf interceptor: "
+        "%.*s\n", dir.end - dir.begin, dir.begin);
+      break;
+    }
+    void *argp = va_arg(aq, void *);
+    if (dir.convSpecifier != 'n')
+      --n_inputs;
+    if (n_inputs < 0)
+      break;
+    if (size == FSS_STRLEN) {
+      size = internal_strlen((const char *)argp) + 1;
+    } else if (size == FSS_WCSLEN) {
+      // FIXME: actually use wcslen() to calculate it.
+      size = 0;
+    }
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+  }
+}
+
+#if SANITIZER_INTERCEPT_PRINTF
+
+struct PrintfDirective {
+  int fieldWidth;
+  int fieldPrecision;
+  int argIdx; // width argument index, or -1 if not specified ("%*n$")
+  int precisionIdx; // precision argument index, or -1 if not specified (".*n$")
+  const char *begin;
+  const char *end;
+  bool starredWidth;
+  bool starredPrecision;
+  char lengthModifier[2];
+  char convSpecifier;
+};
+
+static const char *maybe_parse_number(const char *p, int *out) {
+  if (*p >= '0' && *p <= '9')
+    p = parse_number(p, out);
+  return p;
+}
+
+static const char *maybe_parse_number_or_star(const char *p, int *out,
+                                              bool *star) {
+  if (*p == '*') {
+    *star = true;
+    ++p;
+  } else {
+    *star = false;
+    p = maybe_parse_number(p, out);
+  }
+  return p;
+}
+
+// Parse printf format string. Same as scanf_parse_next.
+static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
+  internal_memset(dir, 0, sizeof(*dir));
+  dir->argIdx = -1;
+  dir->precisionIdx = -1;
+
+  while (*p) {
+    if (*p != '%') {
+      ++p;
+      continue;
+    }
+    dir->begin = p;
+    ++p;
+    // %%
+    if (*p == '%') {
+      ++p;
+      continue;
+    }
+    if (*p == '\0') {
+      return 0;
+    }
+    // %n$
+    p = maybe_parse_param_index(p, &dir->precisionIdx);
+    CHECK(p);
+    // Flags
+    while (char_is_one_of(*p, "'-+ #0")) {
+      ++p;
+    }
+    // Field width
+    p = maybe_parse_number_or_star(p, &dir->fieldWidth,
+                                   &dir->starredWidth);
+    if (!p)
+      return 0;
+    // Precision
+    if (*p == '.') {
+      ++p;
+      // Actual precision is optional (surprise!)
+      p = maybe_parse_number_or_star(p, &dir->fieldPrecision,
+                                     &dir->starredPrecision);
+      if (!p)
+        return 0;
+      // m$
+      if (dir->starredPrecision) {
+        p = maybe_parse_param_index(p, &dir->precisionIdx);
+        CHECK(p);
+      }
+    }
+    // Length modifier.
+    p = maybe_parse_length_modifier(p, dir->lengthModifier);
+    // Conversion specifier.
+    dir->convSpecifier = *p++;
+    dir->end = p;
+    break;
+  }
+  return p;
+}
+
+static int printf_get_value_size(PrintfDirective *dir) {
+  if (dir->convSpecifier == 'm') {
+    return sizeof(char *);
+  }
+
+  if (char_is_one_of(dir->convSpecifier, "cCsS")) {
+    unsigned charSize =
+        format_get_char_size(dir->convSpecifier, dir->lengthModifier);
+    if (charSize == 0)
+      return FSS_INVALID;
+    if (char_is_one_of(dir->convSpecifier, "sS")) {
+      return (charSize == sizeof(char)) ? FSS_STRLEN : FSS_WCSLEN;
+    }
+    return charSize;
+  }
+
+  return format_get_value_size(dir->convSpecifier, dir->lengthModifier, true);
+}
+
+#define SKIP_SCALAR_ARG(aq, convSpecifier, size)                   \
+  do {                                                             \
+    if (format_is_float_conv(convSpecifier)) {                     \
+      switch (size) {                                              \
+      case 8:                                                      \
+        va_arg(*aq, double);                                       \
+        break;                                                     \
+      case 12:                                                     \
+        va_arg(*aq, long double);                                  \
+        break;                                                     \
+      case 16:                                                     \
+        va_arg(*aq, long double);                                  \
+        break;                                                     \
+      default:                                                     \
+        Report("WARNING: unexpected floating-point arg size"       \
+               " in printf interceptor: %d\n", size);              \
+        return;                                                    \
+      }                                                            \
+    } else {                                                       \
+      switch (size) {                                              \
+      case 1:                                                      \
+      case 2:                                                      \
+      case 4:                                                      \
+        va_arg(*aq, u32);                                          \
+        break;                                                     \
+      case 8:                                                      \
+        va_arg(*aq, u64);                                          \
+        break;                                                     \
+      default:                                                     \
+        Report("WARNING: unexpected arg size"                      \
+               " in printf interceptor: %d\n", size);              \
+        return;                                                    \
+      }                                                            \
+    }                                                              \
+  } while (0)
+
+// Common part of *printf interceptors.
+// Process format string and va_list, and report all load ranges.
+static void printf_common(void *ctx, const char *format, va_list aq) {
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, format, internal_strlen(format) + 1);
+
+  const char *p = format;
+
+  while (*p) {
+    PrintfDirective dir;
+    p = printf_parse_next(p, &dir);
+    if (!p)
+      break;
+    if (dir.convSpecifier == 0) {
+      // This can only happen at the end of the format string.
+      CHECK_EQ(*p, 0);
+      break;
+    }
+    // Here the directive is valid. Do what it says.
+    if (dir.argIdx != -1 || dir.precisionIdx != -1) {
+      // Unsupported.
+      break;
+    }
+    if (dir.starredWidth) {
+      // Dynamic width
+      SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+    }
+    if (dir.starredPrecision) {
+      // Dynamic precision
+      SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
+    }
+    int size = printf_get_value_size(&dir);
+    if (size == FSS_INVALID) {
+      Report("WARNING: unexpected format specifier in printf "
+             "interceptor: %.*s\n", dir.end - dir.begin, dir.begin);
+      break;
+    }
+    if (dir.convSpecifier == 'n') {
+      void *argp = va_arg(aq, void *);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
+      continue;
+    } else if (size == FSS_STRLEN) {
+      if (void *argp = va_arg(aq, void *)) {
+        if (dir.starredPrecision) {
+          // FIXME: properly support starred precision for strings.
+          size = 0;
+        } else if (dir.fieldPrecision > 0) {
+          // Won't read more than "precision" symbols.
+          size = internal_strnlen((const char *)argp, dir.fieldPrecision);
+          if (size < dir.fieldPrecision) size++;
+        } else {
+          // Whole string will be accessed.
+          size = internal_strlen((const char *)argp) + 1;
+        }
+        COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+      }
+    } else if (size == FSS_WCSLEN) {
+      if (void *argp = va_arg(aq, void *)) {
+        // FIXME: Properly support wide-character strings (via wcsrtombs).
+        size = 0;
+        COMMON_INTERCEPTOR_READ_RANGE(ctx, argp, size);
+      }
+    } else {
+      // Skip non-pointer args
+      SKIP_SCALAR_ARG(&aq, dir.convSpecifier, size);
+    }
+  }
+}
+
+#endif  // SANITIZER_INTERCEPT_PRINTF
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 4b90f8c..31b65ca 100755
--- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -14,14 +14,18 @@
 
 struct ioctl_desc {
   unsigned req;
-  // FIXME: support read+write arguments. Those are currently marked as WRITE.
+  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the
+  // same thing.
+  // XXX: The declarations below may use WRITE instead of READWRITE, unless
+  // explicitly noted.
   enum {
     NONE,
     READ,
     WRITE,
+    READWRITE,
     CUSTOM
-  } type : 2;
-  unsigned size : 30;
+  } type : 3;
+  unsigned size : 29;
   const char* name;
 };
 
@@ -489,11 +493,15 @@
 // Handle the most evil ioctls that encode argument value as part of request id.
 static unsigned ioctl_request_fixup(unsigned req) {
 #if SANITIZER_LINUX
-  if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT)
+  // Strip size and event number.
+  const unsigned kEviocgbitMask =
+      (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX;
+  if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT)
     return IOCTL_EVIOCGBIT;
-  if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+  // Strip absolute axis number.
+  if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS)
     return IOCTL_EVIOCGABS;
-  if ((req & ~0x3fU) == IOCTL_EVIOCSABS)
+  if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS)
     return IOCTL_EVIOCSABS;
 #endif
   return req;
@@ -515,24 +523,56 @@
     return 0;
 }
 
+static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
+  CHECK(desc);
+  desc->req = req;
+  desc->name = "<DECODED_IOCTL>";
+  desc->size = IOC_SIZE(req);
+  // Sanity check.
+  if (desc->size > 1024) return false;
+  unsigned dir = IOC_DIR(req);
+  switch (dir) {
+    case IOC_NONE:
+      desc->type = ioctl_desc::NONE;
+      break;
+    case IOC_READ | IOC_WRITE:
+      desc->type = ioctl_desc::READWRITE;
+      break;
+    case IOC_READ:
+      desc->type = ioctl_desc::WRITE;
+      break;
+    case IOC_WRITE:
+      desc->type = ioctl_desc::READ;
+      break;
+    default:
+      return false;
+  }
+  if (desc->type != IOC_NONE && desc->size == 0) return false;
+  char id = IOC_TYPE(req);
+  // Sanity check.
+  if (!(id >= 'a' && id <= 'z') && !(id >= 'A' && id <= 'Z')) return false;
+  return true;
+}
+
 static const ioctl_desc *ioctl_lookup(unsigned req) {
   req = ioctl_request_fixup(req);
   const ioctl_desc *desc = ioctl_table_lookup(req);
   if (desc) return desc;
 
   // Try stripping access size from the request id.
-  desc = ioctl_table_lookup(req & ~0x3fff0000U);
+  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));
   // Sanity check: requests that encode access size are either read or write and
   // have size of 0 in the table.
   if (desc && desc->size == 0 &&
-      (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READ))
+      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||
+       desc->type == ioctl_desc::READ))
     return desc;
   return 0;
 }
 
 static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
                              unsigned request, void *arg) {
-  if (desc->type == ioctl_desc::READ) {
+  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {
     unsigned size = desc->size ? desc->size : IOC_SIZE(request);
     COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);
   }
@@ -550,7 +590,7 @@
 
 static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,
                               unsigned request, void *arg) {
-  if (desc->type == ioctl_desc::WRITE) {
+  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {
     // FIXME: add verbose output
     unsigned size = desc->size ? desc->size : IOC_SIZE(request);
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc b/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
deleted file mode 100644
index 08752e6..0000000
--- a/lib/sanitizer_common/sanitizer_common_interceptors_scanf.inc
+++ /dev/null
@@ -1,311 +0,0 @@
-//===-- sanitizer_common_interceptors_scanf.inc -----------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Scanf implementation for use in *Sanitizer interceptors.
-// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
-// with a few common GNU extensions.
-//
-//===----------------------------------------------------------------------===//
-#include <stdarg.h>
-
-struct ScanfDirective {
-  int argIdx; // argument index, or -1 of not specified ("%n$")
-  int fieldWidth;
-  bool suppressed; // suppress assignment ("*")
-  bool allocate;   // allocate space ("m")
-  char lengthModifier[2];
-  char convSpecifier;
-  bool maybeGnuMalloc;
-};
-
-static const char *parse_number(const char *p, int *out) {
-  *out = internal_atoll(p);
-  while (*p >= '0' && *p <= '9')
-    ++p;
-  return p;
-}
-
-static bool char_is_one_of(char c, const char *s) {
-  return !!internal_strchr(s, c);
-}
-
-// Parse scanf format string. If a valid directive in encountered, it is
-// returned in dir. This function returns the pointer to the first
-// unprocessed character, or 0 in case of error.
-// In case of the end-of-string, a pointer to the closing \0 is returned.
-static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
-                                    ScanfDirective *dir) {
-  internal_memset(dir, 0, sizeof(*dir));
-  dir->argIdx = -1;
-
-  while (*p) {
-    if (*p != '%') {
-      ++p;
-      continue;
-    }
-    ++p;
-    // %%
-    if (*p == '%') {
-      ++p;
-      continue;
-    }
-    if (*p == '\0') {
-      return 0;
-    }
-    // %n$
-    if (*p >= '0' && *p <= '9') {
-      int number;
-      const char *q = parse_number(p, &number);
-      if (*q == '$') {
-        dir->argIdx = number;
-        p = q + 1;
-      }
-      // Otherwise, do not change p. This will be re-parsed later as the field
-      // width.
-    }
-    // *
-    if (*p == '*') {
-      dir->suppressed = true;
-      ++p;
-    }
-    // Field width.
-    if (*p >= '0' && *p <= '9') {
-      p = parse_number(p, &dir->fieldWidth);
-      if (dir->fieldWidth <= 0)
-        return 0;
-    }
-    // m
-    if (*p == 'm') {
-      dir->allocate = true;
-      ++p;
-    }
-    // Length modifier.
-    if (char_is_one_of(*p, "jztLq")) {
-      dir->lengthModifier[0] = *p;
-      ++p;
-    } else if (*p == 'h') {
-      dir->lengthModifier[0] = 'h';
-      ++p;
-      if (*p == 'h') {
-        dir->lengthModifier[1] = 'h';
-        ++p;
-      }
-    } else if (*p == 'l') {
-      dir->lengthModifier[0] = 'l';
-      ++p;
-      if (*p == 'l') {
-        dir->lengthModifier[1] = 'l';
-        ++p;
-      }
-    }
-    // Conversion specifier.
-    dir->convSpecifier = *p++;
-    // Consume %[...] expression.
-    if (dir->convSpecifier == '[') {
-      if (*p == '^')
-        ++p;
-      if (*p == ']')
-        ++p;
-      while (*p && *p != ']')
-        ++p;
-      if (*p == 0)
-        return 0; // unexpected end of string
-                  // Consume the closing ']'.
-      ++p;
-    }
-    // This is unfortunately ambiguous between old GNU extension
-    // of %as, %aS and %a[...] and newer POSIX %a followed by
-    // letters s, S or [.
-    if (allowGnuMalloc && dir->convSpecifier == 'a' &&
-        !dir->lengthModifier[0]) {
-      if (*p == 's' || *p == 'S') {
-        dir->maybeGnuMalloc = true;
-        ++p;
-      } else if (*p == '[') {
-        // Watch for %a[h-j%d], if % appears in the
-        // [...] range, then we need to give up, we don't know
-        // if scanf will parse it as POSIX %a [h-j %d ] or
-        // GNU allocation of string with range dh-j plus %.
-        const char *q = p + 1;
-        if (*q == '^')
-          ++q;
-        if (*q == ']')
-          ++q;
-        while (*q && *q != ']' && *q != '%')
-          ++q;
-        if (*q == 0 || *q == '%')
-          return 0;
-        p = q + 1; // Consume the closing ']'.
-        dir->maybeGnuMalloc = true;
-      }
-    }
-    break;
-  }
-  return p;
-}
-
-// Returns true if the character is an integer conversion specifier.
-static bool scanf_is_integer_conv(char c) {
-  return char_is_one_of(c, "diouxXn");
-}
-
-// Returns true if the character is an floating point conversion specifier.
-static bool scanf_is_float_conv(char c) {
-  return char_is_one_of(c, "aAeEfFgG");
-}
-
-// Returns string output character size for string-like conversions,
-// or 0 if the conversion is invalid.
-static int scanf_get_char_size(ScanfDirective *dir) {
-  if (char_is_one_of(dir->convSpecifier, "CS")) {
-    // wchar_t
-    return 0;
-  }
-
-  if (char_is_one_of(dir->convSpecifier, "cs[")) {
-    if (dir->lengthModifier[0] == 'l')
-      // wchar_t
-      return 0;
-    else if (dir->lengthModifier[0] == 0)
-      return sizeof(char);
-    else
-      return 0;
-  }
-
-  return 0;
-}
-
-enum ScanfStoreSize {
-  // Store size not known in advance; can be calculated as strlen() of the
-  // destination buffer.
-  SSS_STRLEN = -1,
-  // Invalid conversion specifier.
-  SSS_INVALID = 0
-};
-
-// Returns the store size of a scanf directive (if >0), or a value of
-// ScanfStoreSize.
-static int scanf_get_store_size(ScanfDirective *dir) {
-  if (dir->allocate) {
-    if (!char_is_one_of(dir->convSpecifier, "cCsS["))
-      return SSS_INVALID;
-    return sizeof(char *);
-  }
-
-  if (dir->maybeGnuMalloc) {
-    if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
-      return SSS_INVALID;
-    // This is ambiguous, so check the smaller size of char * (if it is
-    // a GNU extension of %as, %aS or %a[...]) and float (if it is
-    // POSIX %a followed by s, S or [ letters).
-    return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
-  }
-
-  if (scanf_is_integer_conv(dir->convSpecifier)) {
-    switch (dir->lengthModifier[0]) {
-    case 'h':
-      return dir->lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
-    case 'l':
-      return dir->lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
-    case 'L':
-      return sizeof(long long);
-    case 'j':
-      return sizeof(INTMAX_T);
-    case 'z':
-      return sizeof(SIZE_T);
-    case 't':
-      return sizeof(PTRDIFF_T);
-    case 0:
-      return sizeof(int);
-    default:
-      return SSS_INVALID;
-    }
-  }
-
-  if (scanf_is_float_conv(dir->convSpecifier)) {
-    switch (dir->lengthModifier[0]) {
-    case 'L':
-    case 'q':
-      return sizeof(long double);
-    case 'l':
-      return dir->lengthModifier[1] == 'l' ? sizeof(long double)
-                                           : sizeof(double);
-    case 0:
-      return sizeof(float);
-    default:
-      return SSS_INVALID;
-    }
-  }
-
-  if (char_is_one_of(dir->convSpecifier, "sS[")) {
-    unsigned charSize = scanf_get_char_size(dir);
-    if (charSize == 0)
-      return SSS_INVALID;
-    if (dir->fieldWidth == 0)
-      return SSS_STRLEN;
-    return (dir->fieldWidth + 1) * charSize;
-  }
-
-  if (char_is_one_of(dir->convSpecifier, "cC")) {
-    unsigned charSize = scanf_get_char_size(dir);
-    if (charSize == 0)
-      return SSS_INVALID;
-    if (dir->fieldWidth == 0)
-      return charSize;
-    return dir->fieldWidth * charSize;
-  }
-
-  if (dir->convSpecifier == 'p') {
-    if (dir->lengthModifier[1] != 0)
-      return SSS_INVALID;
-    return sizeof(void *);
-  }
-
-  return SSS_INVALID;
-}
-
-// Common part of *scanf interceptors.
-// Process format string and va_list, and report all store ranges.
-// Stops when "consuming" n_inputs input items.
-static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
-                         const char *format, va_list aq) {
-  CHECK_GT(n_inputs, 0);
-  const char *p = format;
-
-  while (*p) {
-    ScanfDirective dir;
-    p = scanf_parse_next(p, allowGnuMalloc, &dir);
-    if (!p)
-      break;
-    if (dir.convSpecifier == 0) {
-      // This can only happen at the end of the format string.
-      CHECK_EQ(*p, 0);
-      break;
-    }
-    // Here the directive is valid. Do what it says.
-    if (dir.argIdx != -1) {
-      // Unsupported.
-      break;
-    }
-    if (dir.suppressed)
-      continue;
-    int size = scanf_get_store_size(&dir);
-    if (size == SSS_INVALID)
-      break;
-    void *argp = va_arg(aq, void *);
-    if (dir.convSpecifier != 'n')
-      --n_inputs;
-    if (n_inputs < 0)
-      break;
-    if (size == SSS_STRLEN) {
-      size = internal_strlen((const char *)argp) + 1;
-    }
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
-  }
-}
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index f343007..e4b2d76 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 
 namespace __sanitizer {
 
@@ -34,4 +35,23 @@
   }
   return prints_to_tty;
 }
+
+bool ColorizeReports() {
+  const char *flag = common_flags()->color;
+  return internal_strcmp(flag, "always") == 0 ||
+         (internal_strcmp(flag, "auto") == 0 && PrintsToTtyCached());
+}
+
+static void (*sandboxing_callback)();
+void SetSandboxingCallback(void (*f)()) {
+  sandboxing_callback = f;
+}
+
 }  // namespace __sanitizer
+
+void NOINLINE
+__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
+  PrepareForSandboxing(args);
+  if (sandboxing_callback)
+    sandboxing_callback();
+}
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index 5f62832..4bae308 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -25,8 +25,16 @@
 //   COMMON_SYSCALL_POST_WRITE_RANGE
 //          Called in posthook for regions that were written to by the kernel
 //          and are now initialized.
+//   COMMON_SYSCALL_ACQUIRE(addr)
+//          Acquire memory visibility from addr.
+//   COMMON_SYSCALL_RELEASE(addr)
+//          Release memory visibility to addr.
 //   COMMON_SYSCALL_FD_CLOSE(fd)
 //          Called before closing file descriptor fd.
+//   COMMON_SYSCALL_FD_ACQUIRE(fd)
+//          Acquire memory visibility from fd.
+//   COMMON_SYSCALL_FD_RELEASE(fd)
+//          Release memory visibility to fd.
 //   COMMON_SYSCALL_PRE_FORK()
 //          Called before fork syscall.
 //   COMMON_SYSCALL_POST_FORK(long res)
@@ -48,16 +56,32 @@
 #define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
 #define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
 
+#ifndef COMMON_SYSCALL_ACQUIRE
+# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
+#endif
+
+#ifndef COMMON_SYSCALL_RELEASE
+# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
+#endif
+
 #ifndef COMMON_SYSCALL_FD_CLOSE
-# define COMMON_SYSCALL_FD_CLOSE(fd)
+# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_ACQUIRE
+# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_RELEASE
+# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
 #endif
 
 #ifndef COMMON_SYSCALL_PRE_FORK
-# define COMMON_SYSCALL_PRE_FORK()
+# define COMMON_SYSCALL_PRE_FORK() {}
 #endif
 
 #ifndef COMMON_SYSCALL_POST_FORK
-# define COMMON_SYSCALL_POST_FORK(res)
+# define COMMON_SYSCALL_POST_FORK(res) {}
 #endif
 
 // FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
@@ -364,24 +388,21 @@
 
 POST_SYSCALL(acct)(long res, const void *name) {}
 
-PRE_SYSCALL(capget)(void *header, void *dataptr) {}
+PRE_SYSCALL(capget)(void *header, void *dataptr) {
+  if (header) PRE_READ(header, __user_cap_header_struct_sz);
+}
 
 POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
-  if (res >= 0) {
-    if (header) POST_WRITE(header, __user_cap_header_struct_sz);
+  if (res >= 0)
     if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz);
-  }
 }
 
 PRE_SYSCALL(capset)(void *header, const void *data) {
+  if (header) PRE_READ(header, __user_cap_header_struct_sz);
   if (data) PRE_READ(data, __user_cap_data_struct_sz);
 }
 
-POST_SYSCALL(capset)(long res, void *header, const void *data) {
-  if (res >= 0) {
-    if (header) POST_WRITE(header, __user_cap_header_struct_sz);
-  }
-}
+POST_SYSCALL(capset)(long res, void *header, const void *data) {}
 
 PRE_SYSCALL(personality)(long personality) {}
 
@@ -986,8 +1007,8 @@
 
 POST_SYSCALL(getxattr)(long res, const void *path, const void *name,
                        void *value, long size) {
-  if (res >= 0) {
-    if (value) POST_WRITE(value, size);
+  if (size && res > 0) {
+    if (value) POST_WRITE(value, res);
   }
 }
 
@@ -1001,8 +1022,8 @@
 
 POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name,
                         void *value, long size) {
-  if (res >= 0) {
-    if (value) POST_WRITE(value, size);
+  if (size && res > 0) {
+    if (value) POST_WRITE(value, res);
   }
 }
 
@@ -1013,8 +1034,8 @@
 
 POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value,
                         long size) {
-  if (res >= 0) {
-    if (value) POST_WRITE(value, size);
+  if (size && res > 0) {
+    if (value) POST_WRITE(value, res);
   }
 }
 
@@ -1024,8 +1045,8 @@
 }
 
 POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) {
-  if (res >= 0) {
-    if (list) POST_WRITE(list, size);
+  if (size && res > 0) {
+    if (list) POST_WRITE(list, res);
   }
 }
 
@@ -1035,16 +1056,16 @@
 }
 
 POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) {
-  if (res >= 0) {
-    if (list) POST_WRITE(list, size);
+  if (size && res > 0) {
+    if (list) POST_WRITE(list, res);
   }
 }
 
 PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {}
 
 POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) {
-  if (res >= 0) {
-    if (list) POST_WRITE(list, size);
+  if (size && res > 0) {
+    if (list) POST_WRITE(list, res);
   }
 }
 
@@ -1251,11 +1272,17 @@
 
 POST_SYSCALL(flock)(long res, long fd, long cmd) {}
 
-PRE_SYSCALL(io_setup)(long nr_reqs, void *ctx) {}
+PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) {
+  if (ctx) PRE_WRITE(ctx, sizeof(*ctx));
+}
 
-POST_SYSCALL(io_setup)(long res, long nr_reqs, void *ctx) {
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) {
   if (res >= 0) {
-    if (ctx) POST_WRITE(ctx, sizeof(long));
+    if (ctx) POST_WRITE(ctx, sizeof(*ctx));
+    // (*ctx) is actually a pointer to a kernel mapped page, and there are
+    // people out there who are crazy enough to peek into that page's 32-byte
+    // header.
+    if (*ctx) POST_WRITE(*ctx, 32);
   }
 }
 
@@ -1263,44 +1290,70 @@
 
 POST_SYSCALL(io_destroy)(long res, long ctx) {}
 
-PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, void *events,
-                          void *timeout) {
+PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr,
+                          __sanitizer_io_event *ioevpp, void *timeout) {
   if (timeout) PRE_READ(timeout, struct_timespec_sz);
 }
 
 POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
-                           void *events, void *timeout) {
+                           __sanitizer_io_event *ioevpp, void *timeout) {
   if (res >= 0) {
-    if (events) POST_WRITE(events, res * struct_io_event_sz);
+    if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp));
     if (timeout) POST_WRITE(timeout, struct_timespec_sz);
   }
+  for (long i = 0; i < res; i++) {
+    // We synchronize io_submit -> io_getevents/io_cancel using the
+    // user-provided data context. Data is not necessary a pointer, it can be
+    // an int, 0 or whatever; acquire/release will correctly handle this.
+    // This scheme can lead to false negatives, e.g. when all operations
+    // synchronize on 0. But there does not seem to be a better solution
+    // (except wrapping all operations in own context, which is unreliable).
+    // We can not reliably extract fildes in io_getevents.
+    COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data);
+  }
 }
 
 PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
   for (long i = 0; i < nr; ++i) {
-    if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pwrite && iocbpp[i]->aio_buf &&
-        iocbpp[i]->aio_nbytes)
-      PRE_READ((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
+    uptr op = iocbpp[i]->aio_lio_opcode;
+    void *data = (void*)iocbpp[i]->aio_data;
+    void *buf = (void*)iocbpp[i]->aio_buf;
+    uptr len = (uptr)iocbpp[i]->aio_nbytes;
+    if (op == iocb_cmd_pwrite && buf && len) {
+      PRE_READ(buf, len);
+    } 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;
+      for (uptr v = 0; v < len; v++)
+        PRE_READ(iovec[i].iov_base, iovec[i].iov_len);
+    } else if (op == iocb_cmd_preadv) {
+      __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
+      for (uptr v = 0; v < len; v++)
+        POST_WRITE(iovec[i].iov_base, iovec[i].iov_len);
+    }
+    // See comment in io_getevents.
+    COMMON_SYSCALL_RELEASE(data);
   }
 }
 
 POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
-                        __sanitizer_iocb **iocbpp) {
-  if (res > 0 && iocbpp) {
-    for (long i = 0; i < res; ++i) {
-      if (iocbpp[i]->aio_lio_opcode == iocb_cmd_pread && iocbpp[i]->aio_buf &&
-          iocbpp[i]->aio_nbytes)
-        POST_WRITE((void *)iocbpp[i]->aio_buf, iocbpp[i]->aio_nbytes);
-    }
-  }
+    __sanitizer_iocb **iocbpp) {}
+
+PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb,
+    __sanitizer_io_event *result) {
 }
 
-PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *result) {}
-
-POST_SYSCALL(io_cancel)(long res, long ctx_id, void *iocb, void *result) {
-  if (res >= 0) {
-    if (iocb) POST_WRITE(iocb, sizeof(__sanitizer_iocb));
-    if (result) POST_WRITE(result, struct_io_event_sz);
+POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb,
+    __sanitizer_io_event *result) {
+  if (res == 0) {
+    if (result) {
+      // See comment in io_getevents.
+      COMMON_SYSCALL_ACQUIRE((void*)result->data);
+      POST_WRITE(result, sizeof(*result));
+    }
+    if (iocb)
+      POST_WRITE(iocb, sizeof(*iocb));
   }
 }
 
diff --git a/lib/sanitizer_common/sanitizer_coverage.cc b/lib/sanitizer_common/sanitizer_coverage.cc
deleted file mode 100644
index 9e7a0f8..0000000
--- a/lib/sanitizer_common/sanitizer_coverage.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-//===-- sanitizer_coverage.cc ---------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Sanitizer Coverage.
-// This file implements run-time support for a poor man's coverage tool.
-//
-// Compiler instrumentation:
-// For every function F the compiler injects the following code:
-// if (*Guard) {
-//    __sanitizer_cov(&F);
-//    *Guard = 1;
-// }
-// It's fine to call __sanitizer_cov more than once for a given function.
-//
-// Run-time:
-//  - __sanitizer_cov(pc): record that we've executed a given PC.
-//  - __sanitizer_cov_dump: dump the coverage data to disk.
-//  For every module of the current process that has coverage data
-//  this will create a file module_name.PID.sancov. The file format is simple:
-//  it's just a sorted sequence of 4-byte offsets in the module.
-//
-// Eventually, this coverage implementation should be obsoleted by a more
-// powerful general purpose Clang/LLVM coverage instrumentation.
-// Consider this implementation as prototype.
-//
-// FIXME: support (or at least test with) dlclose.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_common.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_flags.h"
-
-struct CovData {
-  BlockingMutex mu;
-  InternalMmapVector<uptr> v;
-};
-
-static uptr cov_data_placeholder[sizeof(CovData) / sizeof(uptr)];
-COMPILER_CHECK(sizeof(cov_data_placeholder) >= sizeof(CovData));
-static CovData *cov_data = reinterpret_cast<CovData*>(cov_data_placeholder);
-
-namespace __sanitizer {
-
-// Simply add the pc into the vector under lock. If the function is called more
-// than once for a given PC it will be inserted multiple times, which is fine.
-static void CovAdd(uptr pc) {
-  BlockingMutexLock lock(&cov_data->mu);
-  cov_data->v.push_back(pc);
-}
-
-static inline bool CompareLess(const uptr &a, const uptr &b) {
-  return a < b;
-}
-
-// Dump the coverage on disk.
-void CovDump() {
-#if !SANITIZER_WINDOWS
-  BlockingMutexLock lock(&cov_data->mu);
-  InternalMmapVector<uptr> &v = cov_data->v;
-  InternalSort(&v, v.size(), CompareLess);
-  InternalMmapVector<u32> offsets(v.size());
-  const uptr *vb = v.data();
-  const uptr *ve = vb + v.size();
-  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
-  uptr mb, me, off, prot;
-  InternalScopedBuffer<char> module(4096);
-  InternalScopedBuffer<char> path(4096 * 2);
-  for (int i = 0;
-       proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
-       i++) {
-    if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
-      continue;
-    if (vb >= ve) break;
-    if (mb <= *vb && *vb < me) {
-      offsets.clear();
-      const uptr *old_vb = vb;
-      CHECK_LE(off, *vb);
-      for (; vb < ve && *vb < me; vb++) {
-        uptr diff = *vb - (i ? mb : 0) + off;
-        CHECK_LE(diff, 0xffffffffU);
-        offsets.push_back(static_cast<u32>(diff));
-      }
-      char *module_name = StripModuleName(module.data());
-      internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
-                        module_name, internal_getpid());
-      InternalFree(module_name);
-      uptr fd = OpenFile(path.data(), true);
-      internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
-      internal_close(fd);
-      if (common_flags()->verbosity)
-        Report(" CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb);
-    }
-  }
-#endif  // !SANITIZER_WINDOWS
-}
-
-}  // namespace __sanitizer
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc) {
-  CovAdd(reinterpret_cast<uptr>(pc));
-}
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
-}  // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
new file mode 100644
index 0000000..64861d0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -0,0 +1,334 @@
+//===-- sanitizer_coverage.cc ---------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage.
+// This file implements run-time support for a poor man's coverage tool.
+//
+// Compiler instrumentation:
+// For every interesting basic block the compiler injects the following code:
+// if (*Guard) {
+//    __sanitizer_cov();
+//    *Guard = 1;
+// }
+// It's fine to call __sanitizer_cov more than once for a given block.
+//
+// Run-time:
+//  - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
+//  - __sanitizer_cov_dump: dump the coverage data to disk.
+//  For every module of the current process that has coverage data
+//  this will create a file module_name.PID.sancov. The file format is simple:
+//  it's just a sorted sequence of 4-byte offsets in the module.
+//
+// Eventually, this coverage implementation should be obsoleted by a more
+// powerful general purpose Clang/LLVM coverage instrumentation.
+// Consider this implementation as prototype.
+//
+// FIXME: support (or at least test with) dlclose.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_flags.h"
+
+atomic_uint32_t dump_once_guard;  // Ensure that CovDump runs only once.
+
+// 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.
+// 128M counters "ought to be enough for anybody" (4M on 32-bit).
+
+// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file.
+// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping()
+// dump current memory layout to another file.
+
+static bool cov_sandboxed = false;
+static int cov_fd = kInvalidFd;
+static unsigned int cov_max_block_size = 0;
+
+namespace __sanitizer {
+
+class CoverageData {
+ public:
+  void Init();
+  void Extend(uptr npcs);
+  void Add(uptr pc);
+
+  uptr *data();
+  uptr size();
+
+ private:
+  // Maximal size pc array may ever grow.
+  // We MmapNoReserve this space to ensure that the array is contiguous.
+  static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
+  // The amount file mapping for the pc array is grown by.
+  static const uptr kPcArrayMmapSize = 64 * 1024;
+
+  // pc_array is allocated with MmapNoReserveOrDie and so it uses only as
+  // much RAM as it really needs.
+  uptr *pc_array;
+  // Index of the first available pc_array slot.
+  atomic_uintptr_t pc_array_index;
+  // Array size.
+  atomic_uintptr_t pc_array_size;
+  // Current file mapped size of the pc array.
+  uptr pc_array_mapped_size;
+  // Descriptor of the file mapped pc array.
+  int pc_fd;
+  StaticSpinMutex mu;
+
+  void DirectInit();
+};
+
+static CoverageData coverage_data;
+
+void CoverageData::DirectInit() {
+  InternalScopedString path(64);
+  internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.raw",
+                    internal_getpid());
+  pc_fd = OpenFile(path.data(), true);
+  if (internal_iserror(pc_fd)) {
+    Report(" Coverage: failed to open %s for writing\n", path.data());
+    Die();
+  }
+
+  atomic_store(&pc_array_size, 0, memory_order_relaxed);
+  pc_array_mapped_size = 0;
+
+  CovUpdateMapping();
+}
+
+void CoverageData::Init() {
+  pc_array = reinterpret_cast<uptr *>(
+      MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
+  if (common_flags()->coverage_direct) {
+    DirectInit();
+  } else {
+    pc_fd = 0;
+    atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
+  }
+}
+
+// Extend coverage PC array to fit additional npcs elements.
+void CoverageData::Extend(uptr npcs) {
+  // If pc_fd=0, pc array is a huge anonymous mapping that does not need to be
+  // resized.
+  if (!pc_fd) return;
+  SpinMutexLock l(&mu);
+
+  uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+  size += npcs * sizeof(uptr);
+
+  if (size > pc_array_mapped_size) {
+    uptr new_mapped_size = pc_array_mapped_size;
+    while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize;
+
+    // Extend the file and map the new space at the end of pc_array.
+    uptr res = internal_ftruncate(pc_fd, new_mapped_size);
+    int err;
+    if (internal_iserror(res, &err)) {
+      Printf("failed to extend raw coverage file: %d\n", err);
+      Die();
+    }
+    void *p = MapWritableFileToMemory(pc_array + pc_array_mapped_size,
+                                      new_mapped_size - pc_array_mapped_size,
+                                      pc_fd, pc_array_mapped_size);
+    CHECK_EQ(p, pc_array + pc_array_mapped_size);
+    pc_array_mapped_size = new_mapped_size;
+  }
+
+  atomic_store(&pc_array_size, size, memory_order_release);
+}
+
+// Simply add the pc into the vector under lock. If the function is called more
+// than once for a given PC it will be inserted multiple times, which is fine.
+void CoverageData::Add(uptr pc) {
+  if (!pc_array) return;
+  uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed);
+  CHECK_LT(idx * sizeof(uptr),
+           atomic_load(&pc_array_size, memory_order_acquire));
+  pc_array[idx] = pc;
+}
+
+uptr *CoverageData::data() {
+  return pc_array;
+}
+
+uptr CoverageData::size() {
+  return atomic_load(&pc_array_index, memory_order_relaxed);
+}
+
+// Block layout for packed file format: header, followed by module name (no
+// trailing zero), followed by data blob.
+struct CovHeader {
+  int pid;
+  unsigned int module_name_length;
+  unsigned int data_length;
+};
+
+static void CovWritePacked(int pid, const char *module, const void *blob,
+                           unsigned int blob_size) {
+  if (cov_fd < 0) return;
+  unsigned module_name_length = internal_strlen(module);
+  CovHeader header = {pid, module_name_length, blob_size};
+
+  if (cov_max_block_size == 0) {
+    // Writing to a file. Just go ahead.
+    internal_write(cov_fd, &header, sizeof(header));
+    internal_write(cov_fd, module, module_name_length);
+    internal_write(cov_fd, blob, blob_size);
+  } else {
+    // Writing to a socket. We want to split the data into appropriately sized
+    // blocks.
+    InternalScopedBuffer<char> block(cov_max_block_size);
+    CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
+    uptr header_size_with_module = sizeof(header) + module_name_length;
+    CHECK_LT(header_size_with_module, cov_max_block_size);
+    unsigned int max_payload_size =
+        cov_max_block_size - header_size_with_module;
+    char *block_pos = block.data();
+    internal_memcpy(block_pos, &header, sizeof(header));
+    block_pos += sizeof(header);
+    internal_memcpy(block_pos, module, module_name_length);
+    block_pos += module_name_length;
+    char *block_data_begin = block_pos;
+    char *blob_pos = (char *)blob;
+    while (blob_size > 0) {
+      unsigned int payload_size = Min(blob_size, max_payload_size);
+      blob_size -= payload_size;
+      internal_memcpy(block_data_begin, blob_pos, payload_size);
+      blob_pos += payload_size;
+      ((CovHeader *)block.data())->data_length = payload_size;
+      internal_write(cov_fd, block.data(),
+                     header_size_with_module + payload_size);
+    }
+  }
+}
+
+// If packed = false: <name>.<pid>.<sancov> (name = module name).
+// If packed = true and name == 0: <pid>.<sancov>.<packed>.
+// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
+// user-supplied).
+static int CovOpenFile(bool packed, const char* name) {
+  InternalScopedBuffer<char> path(1024);
+  if (!packed) {
+    CHECK(name);
+    internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
+                      name, internal_getpid());
+  } else {
+    if (!name)
+      internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.packed",
+                        internal_getpid());
+    else
+      internal_snprintf((char *)path.data(), path.size(), "%s.sancov.packed",
+                        name);
+  }
+  uptr fd = OpenFile(path.data(), true);
+  if (internal_iserror(fd)) {
+    Report(" SanitizerCoverage: failed to open %s for writing\n", path.data());
+    return -1;
+  }
+  return fd;
+}
+
+// Dump the coverage on disk.
+static void CovDump() {
+  if (!common_flags()->coverage || common_flags()->coverage_direct) return;
+#if !SANITIZER_WINDOWS
+  if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
+    return;
+  uptr size = coverage_data.size();
+  InternalMmapVector<u32> offsets(size);
+  uptr *vb = coverage_data.data();
+  uptr *ve = vb + size;
+  SortArray(vb, size);
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+  uptr mb, me, off, prot;
+  InternalScopedBuffer<char> module(4096);
+  InternalScopedBuffer<char> path(4096 * 2);
+  for (int i = 0;
+       proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
+       i++) {
+    if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+      continue;
+    while (vb < ve && *vb < mb) vb++;
+    if (vb >= ve) break;
+    if (*vb < me) {
+      offsets.clear();
+      const uptr *old_vb = vb;
+      CHECK_LE(off, *vb);
+      for (; vb < ve && *vb < me; vb++) {
+        uptr diff = *vb - (i ? mb : 0) + off;
+        CHECK_LE(diff, 0xffffffffU);
+        offsets.push_back(static_cast<u32>(diff));
+      }
+      char *module_name = StripModuleName(module.data());
+      if (cov_sandboxed) {
+        if (cov_fd >= 0) {
+          CovWritePacked(internal_getpid(), module_name, offsets.data(),
+                         offsets.size() * sizeof(u32));
+          VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb);
+        }
+      } else {
+        // One file per module per process.
+        internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
+                          module_name, internal_getpid());
+        int fd = CovOpenFile(false /* packed */, module_name);
+        if (fd > 0) {
+          internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
+          internal_close(fd);
+          VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
+                  vb - old_vb);
+        }
+      }
+      InternalFree(module_name);
+    }
+  }
+  if (cov_fd >= 0)
+    internal_close(cov_fd);
+#endif  // !SANITIZER_WINDOWS
+}
+
+void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  if (!args) return;
+  if (!common_flags()->coverage) return;
+  cov_sandboxed = args->coverage_sandboxed;
+  if (!cov_sandboxed) return;
+  cov_fd = args->coverage_fd;
+  cov_max_block_size = args->coverage_max_block_size;
+  if (cov_fd < 0)
+    // Pre-open the file now. The sandbox won't allow us to do it later.
+    cov_fd = CovOpenFile(true /* packed */, 0);
+}
+
+int MaybeOpenCovFile(const char *name) {
+  CHECK(name);
+  if (!common_flags()->coverage) return -1;
+  return CovOpenFile(true /* packed */, name);
+}
+}  // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() {
+  coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()));
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
+  coverage_data.Init();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(uptr npcs) {
+  coverage_data.Extend(npcs);
+}
+SANITIZER_INTERFACE_ATTRIBUTE
+sptr __sanitizer_maybe_open_cov_file(const char *name) {
+  return MaybeOpenCovFile(name);
+}
+}  // extern "C"
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
new file mode 100644
index 0000000..75f6162
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -0,0 +1,97 @@
+//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Mmap-based implementation of sanitizer coverage.
+//
+// This is part of the implementation of code coverage that does not require
+// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
+//
+// $pid.sancov.map describes process memory layout in the following text-based
+// format:
+// <pointer size in bits>  // 1 line, 32 or 64
+// <mapping start> <mapping end> <base address> <dso name> // repeated
+// ...
+// Mapping lines are NOT sorted. This file is updated every time memory layout
+// is changed (i.e. in dlopen() and dlclose() interceptors).
+//
+// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
+// sorted. This file is extended by 64Kb at a time and mapped into memory. It
+// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
+//
+// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
+// $pid.sancov.raw.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+static const uptr kMaxNumberOfModules = 1 << 14;
+
+void CovUpdateMapping() {
+  if (!common_flags()->coverage || !common_flags()->coverage_direct) return;
+
+  int err;
+  InternalScopedString tmp_path(64);
+  internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
+                    "%zd.sancov.map.tmp", internal_getpid());
+  uptr map_fd = OpenFile(tmp_path.data(), true);
+  if (internal_iserror(map_fd)) {
+    Report(" Coverage: failed to open %s for writing\n", tmp_path.data());
+    Die();
+  }
+
+  InternalScopedBuffer<char> modules_data(kMaxNumberOfModules *
+                                          sizeof(LoadedModule));
+  LoadedModule *modules = (LoadedModule *)modules_data.data();
+  CHECK(modules);
+  int n_modules = GetListOfModules(modules, kMaxNumberOfModules,
+                                   /* filter */ 0);
+
+  InternalScopedString line(4096);
+  line.append("%d\n", sizeof(uptr) * 8);
+  uptr res = internal_write(map_fd, line.data(), line.length());
+  if (internal_iserror(res, &err)) {
+    Printf("sancov.map write failed: %d\n", err);
+    Die();
+  }
+  line.clear();
+
+  for (int i = 0; i < n_modules; ++i) {
+    char *module_name = StripModuleName(modules[i].full_name());
+    for (unsigned j = 0; j < modules[i].n_ranges(); ++j) {
+      line.append("%zx %zx %zx %s\n", modules[i].address_range_start(j),
+                  modules[i].address_range_end(j), modules[i].base_address(),
+                  module_name);
+      res = internal_write(map_fd, line.data(), line.length());
+      if (internal_iserror(res, &err)) {
+        Printf("sancov.map write failed: %d\n", err);
+        Die();
+      }
+      line.clear();
+    }
+    InternalFree(module_name);
+  }
+
+  internal_close(map_fd);
+
+  InternalScopedString path(64);
+  internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.map",
+                    internal_getpid());
+  res = internal_rename(tmp_path.data(), path.data());
+  if (internal_iserror(res, &err)) {
+    Printf("sancov.map rename failed: %d\n", err);
+    Die();
+  }
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector.h b/lib/sanitizer_common/sanitizer_deadlock_detector.h
new file mode 100644
index 0000000..90e1cc4
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector.h
@@ -0,0 +1,412 @@
+//===-- sanitizer_deadlock_detector.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 a part of Sanitizer runtime.
+// The deadlock detector maintains a directed graph of lock acquisitions.
+// When a lock event happens, the detector checks if the locks already held by
+// the current thread are reachable from the newly acquired lock.
+//
+// The detector can handle only a fixed amount of simultaneously live locks
+// (a lock is alive if it has been locked at least once and has not been
+// destroyed). When the maximal number of locks is reached the entire graph
+// is flushed and the new lock epoch is started. The node ids from the old
+// epochs can not be used with any of the detector methods except for
+// nodeBelongsToCurrentEpoch().
+//
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_H
+#define SANITIZER_DEADLOCK_DETECTOR_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_bvgraph.h"
+
+namespace __sanitizer {
+
+// Thread-local state for DeadlockDetector.
+// It contains the locks currently held by the owning thread.
+template <class BV>
+class DeadlockDetectorTLS {
+ public:
+  // No CTOR.
+  void clear() {
+    bv_.clear();
+    epoch_ = 0;
+    n_recursive_locks = 0;
+    n_all_locks_ = 0;
+  }
+
+  bool empty() const { return bv_.empty(); }
+
+  void ensureCurrentEpoch(uptr current_epoch) {
+    if (epoch_ == current_epoch) return;
+    bv_.clear();
+    epoch_ = current_epoch;
+  }
+
+  uptr getEpoch() const { return epoch_; }
+
+  // Returns true if this is the first (non-recursive) acquisition of this lock.
+  bool addLock(uptr lock_id, uptr current_epoch, u32 stk) {
+    // Printf("addLock: %zx %zx stk %u\n", lock_id, current_epoch, stk);
+    CHECK_EQ(epoch_, current_epoch);
+    if (!bv_.setBit(lock_id)) {
+      // The lock is already held by this thread, it must be recursive.
+      CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks));
+      recursive_locks[n_recursive_locks++] = lock_id;
+      return false;
+    }
+    CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_));
+    // lock_id < BV::kSize, can cast to a smaller int.
+    u32 lock_id_short = static_cast<u32>(lock_id);
+    LockWithContext l = {lock_id_short, stk};
+    all_locks_with_contexts_[n_all_locks_++] = l;
+    return true;
+  }
+
+  void removeLock(uptr lock_id) {
+    if (n_recursive_locks) {
+      for (sptr i = n_recursive_locks - 1; i >= 0; i--) {
+        if (recursive_locks[i] == lock_id) {
+          n_recursive_locks--;
+          Swap(recursive_locks[i], recursive_locks[n_recursive_locks]);
+          return;
+        }
+      }
+    }
+    // Printf("remLock: %zx %zx\n", lock_id, epoch_);
+    CHECK(bv_.clearBit(lock_id));
+    if (n_all_locks_) {
+      for (sptr i = n_all_locks_ - 1; i >= 0; i--) {
+        if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) {
+          Swap(all_locks_with_contexts_[i],
+               all_locks_with_contexts_[n_all_locks_ - 1]);
+          n_all_locks_--;
+          break;
+        }
+      }
+    }
+  }
+
+  u32 findLockContext(uptr lock_id) {
+    for (uptr i = 0; i < n_all_locks_; i++)
+      if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id))
+        return all_locks_with_contexts_[i].stk;
+    return 0;
+  }
+
+  const BV &getLocks(uptr current_epoch) const {
+    CHECK_EQ(epoch_, current_epoch);
+    return bv_;
+  }
+
+  uptr getNumLocks() const { return n_all_locks_; }
+  uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; }
+
+ private:
+  BV bv_;
+  uptr epoch_;
+  uptr recursive_locks[64];
+  uptr n_recursive_locks;
+  struct LockWithContext {
+    u32 lock;
+    u32 stk;
+  };
+  LockWithContext all_locks_with_contexts_[64];
+  uptr n_all_locks_;
+};
+
+// DeadlockDetector.
+// For deadlock detection to work we need one global DeadlockDetector object
+// and one DeadlockDetectorTLS object per evey thread.
+// This class is not thread safe, all concurrent accesses should be guarded
+// by an external lock.
+// Most of the methods of this class are not thread-safe (i.e. should
+// be protected by an external lock) unless explicitly told otherwise.
+template <class BV>
+class DeadlockDetector {
+ public:
+  typedef BV BitVector;
+
+  uptr size() const { return g_.size(); }
+
+  // No CTOR.
+  void clear() {
+    current_epoch_ = 0;
+    available_nodes_.clear();
+    recycled_nodes_.clear();
+    g_.clear();
+    n_edges_ = 0;
+  }
+
+  // Allocate new deadlock detector node.
+  // If we are out of available nodes first try to recycle some.
+  // If there is nothing to recycle, flush the graph and increment the epoch.
+  // Associate 'data' (opaque user's object) with the new node.
+  uptr newNode(uptr data) {
+    if (!available_nodes_.empty())
+      return getAvailableNode(data);
+    if (!recycled_nodes_.empty()) {
+      // Printf("recycling: n_edges_ %zd\n", n_edges_);
+      for (sptr i = n_edges_ - 1; i >= 0; i--) {
+        if (recycled_nodes_.getBit(edges_[i].from) ||
+            recycled_nodes_.getBit(edges_[i].to)) {
+          Swap(edges_[i], edges_[n_edges_ - 1]);
+          n_edges_--;
+        }
+      }
+      CHECK(available_nodes_.empty());
+      // removeEdgesFrom was called in removeNode.
+      g_.removeEdgesTo(recycled_nodes_);
+      available_nodes_.setUnion(recycled_nodes_);
+      recycled_nodes_.clear();
+      return getAvailableNode(data);
+    }
+    // We are out of vacant nodes. Flush and increment the current_epoch_.
+    current_epoch_ += size();
+    recycled_nodes_.clear();
+    available_nodes_.setAll();
+    g_.clear();
+    return getAvailableNode(data);
+  }
+
+  // Get data associated with the node created by newNode().
+  uptr getData(uptr node) const { return data_[nodeToIndex(node)]; }
+
+  bool nodeBelongsToCurrentEpoch(uptr node) {
+    return node && (node / size() * size()) == current_epoch_;
+  }
+
+  void removeNode(uptr node) {
+    uptr idx = nodeToIndex(node);
+    CHECK(!available_nodes_.getBit(idx));
+    CHECK(recycled_nodes_.setBit(idx));
+    g_.removeEdgesFrom(idx);
+  }
+
+  void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) {
+    dtls->ensureCurrentEpoch(current_epoch_);
+  }
+
+  // Returns true if there is a cycle in the graph after this lock event.
+  // Ideally should be called before the lock is acquired so that we can
+  // report a deadlock before a real deadlock happens.
+  bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+    ensureCurrentEpoch(dtls);
+    uptr cur_idx = nodeToIndex(cur_node);
+    return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_));
+  }
+
+  u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+    return dtls->findLockContext(nodeToIndex(node));
+  }
+
+  // Add cur_node to the set of locks held currently by dtls.
+  void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+    ensureCurrentEpoch(dtls);
+    uptr cur_idx = nodeToIndex(cur_node);
+    dtls->addLock(cur_idx, current_epoch_, stk);
+  }
+
+  // Experimental *racy* fast path function.
+  // Returns true if all edges from the currently held locks to cur_node exist.
+  bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
+    uptr local_epoch = dtls->getEpoch();
+    // Read from current_epoch_ is racy.
+    if (cur_node && local_epoch == current_epoch_ &&
+        local_epoch == nodeToEpoch(cur_node)) {
+      uptr cur_idx = nodeToIndexUnchecked(cur_node);
+      for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) {
+        if (!g_.hasEdge(dtls->getLock(i), cur_idx))
+          return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  // Adds edges from currently held locks to cur_node,
+  // returns the number of added edges, and puts the sources of added edges
+  // into added_edges[].
+  // Should be called before onLockAfter.
+  uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk,
+                int unique_tid) {
+    ensureCurrentEpoch(dtls);
+    uptr cur_idx = nodeToIndex(cur_node);
+    uptr added_edges[40];
+    uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx,
+                                     added_edges, ARRAY_SIZE(added_edges));
+    for (uptr i = 0; i < n_added_edges; i++) {
+      if (n_edges_ < ARRAY_SIZE(edges_)) {
+        Edge e = {(u16)added_edges[i], (u16)cur_idx,
+                  dtls->findLockContext(added_edges[i]), stk,
+                  unique_tid};
+        edges_[n_edges_++] = e;
+      }
+      // Printf("Edge%zd: %u %zd=>%zd in T%d\n",
+      //        n_edges_, stk, added_edges[i], cur_idx, unique_tid);
+    }
+    return n_added_edges;
+  }
+
+  bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to,
+                int *unique_tid) {
+    uptr from_idx = nodeToIndex(from_node);
+    uptr to_idx = nodeToIndex(to_node);
+    for (uptr i = 0; i < n_edges_; i++) {
+      if (edges_[i].from == from_idx && edges_[i].to == to_idx) {
+        *stk_from = edges_[i].stk_from;
+        *stk_to = edges_[i].stk_to;
+        *unique_tid = edges_[i].unique_tid;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Test-only function. Handles the before/after lock events,
+  // returns true if there is a cycle.
+  bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+    ensureCurrentEpoch(dtls);
+    bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node);
+    addEdges(dtls, cur_node, stk, 0);
+    onLockAfter(dtls, cur_node, stk);
+    return is_reachable;
+  }
+
+  // Handles the try_lock event, returns false.
+  // When a try_lock event happens (i.e. a try_lock call succeeds) we need
+  // to add this lock to the currently held locks, but we should not try to
+  // change the lock graph or to detect a cycle.  We may want to investigate
+  // whether a more aggressive strategy is possible for try_lock.
+  bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
+    ensureCurrentEpoch(dtls);
+    uptr cur_idx = nodeToIndex(cur_node);
+    dtls->addLock(cur_idx, current_epoch_, stk);
+    return false;
+  }
+
+  // Returns true iff dtls is empty (no locks are currently held) and we can
+  // add the node to the currently held locks w/o chanding the global state.
+  // This operation is thread-safe as it only touches the dtls.
+  bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+    if (!dtls->empty()) return false;
+    if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) {
+      dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+      return true;
+    }
+    return false;
+  }
+
+  // Finds a path between the lock 'cur_node' (currently not held in dtls)
+  // and some currently held lock, returns the length of the path
+  // or 0 on failure.
+  uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path,
+                      uptr path_size) {
+    tmp_bv_.copyFrom(dtls->getLocks(current_epoch_));
+    uptr idx = nodeToIndex(cur_node);
+    CHECK(!tmp_bv_.getBit(idx));
+    uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size);
+    for (uptr i = 0; i < res; i++)
+      path[i] = indexToNode(path[i]);
+    if (res)
+      CHECK_EQ(path[0], cur_node);
+    return res;
+  }
+
+  // Handle the unlock event.
+  // This operation is thread-safe as it only touches the dtls.
+  void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
+    if (dtls->getEpoch() == nodeToEpoch(node))
+      dtls->removeLock(nodeToIndexUnchecked(node));
+  }
+
+  // Tries to handle the lock event w/o writing to global state.
+  // Returns true on success.
+  // This operation is thread-safe as it only touches the dtls
+  // (modulo racy nature of hasAllEdges).
+  bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
+    if (hasAllEdges(dtls, node)) {
+      dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
+      return true;
+    }
+    return false;
+  }
+
+  bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
+    return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node));
+  }
+
+  uptr testOnlyGetEpoch() const { return current_epoch_; }
+  bool testOnlyHasEdge(uptr l1, uptr l2) {
+    return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2));
+  }
+  // idx1 and idx2 are raw indices to g_, not lock IDs.
+  bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) {
+    return g_.hasEdge(idx1, idx2);
+  }
+
+  void Print() {
+    for (uptr from = 0; from < size(); from++)
+      for (uptr to = 0; to < size(); to++)
+        if (g_.hasEdge(from, to))
+          Printf("  %zx => %zx\n", from, to);
+  }
+
+ private:
+  void check_idx(uptr idx) const { CHECK_LT(idx, size()); }
+
+  void check_node(uptr node) const {
+    CHECK_GE(node, size());
+    CHECK_EQ(current_epoch_, nodeToEpoch(node));
+  }
+
+  uptr indexToNode(uptr idx) const {
+    check_idx(idx);
+    return idx + current_epoch_;
+  }
+
+  uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
+
+  uptr nodeToIndex(uptr node) const {
+    check_node(node);
+    return nodeToIndexUnchecked(node);
+  }
+
+  uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
+
+  uptr getAvailableNode(uptr data) {
+    uptr idx = available_nodes_.getAndClearFirstOne();
+    data_[idx] = data;
+    return indexToNode(idx);
+  }
+
+  struct Edge {
+    u16 from;
+    u16 to;
+    u32 stk_from;
+    u32 stk_to;
+    int unique_tid;
+  };
+
+  uptr current_epoch_;
+  BV available_nodes_;
+  BV recycled_nodes_;
+  BV tmp_bv_;
+  BVGraph<BV> g_;
+  uptr data_[BV::kSize];
+  Edge edges_[BV::kSize * 32];
+  uptr n_edges_;
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_H
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
new file mode 100644
index 0000000..b931edc
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -0,0 +1,189 @@
+//===-- sanitizer_deadlock_detector1.cc -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on NxN adjacency bit matrix.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_deadlock_detector.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+
+namespace __sanitizer {
+
+typedef TwoLevelBitVector<> DDBV;  // DeadlockDetector's bit vector.
+
+struct DDPhysicalThread {
+};
+
+struct DDLogicalThread {
+  u64 ctx;
+  DeadlockDetectorTLS<DDBV> dd;
+  DDReport rep;
+  bool report_pending;
+};
+
+struct DD : public DDetector {
+  SpinMutex mtx;
+  DeadlockDetector<DDBV> dd;
+  DDFlags flags;
+
+  explicit DD(const DDFlags *flags);
+
+  DDPhysicalThread* CreatePhysicalThread();
+  void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+  DDLogicalThread* CreateLogicalThread(u64 ctx);
+  void DestroyLogicalThread(DDLogicalThread *lt);
+
+  void MutexInit(DDCallback *cb, DDMutex *m);
+  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock);
+  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+  DDReport *GetReport(DDCallback *cb);
+
+  void MutexEnsureID(DDLogicalThread *lt, DDMutex *m);
+  void ReportDeadlock(DDCallback *cb, DDMutex *m);
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+  (void)flags;
+  void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+  return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+    : flags(*flags) {
+  dd.clear();
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+  return 0;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+  DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(sizeof(*lt));
+  lt->ctx = ctx;
+  lt->dd.clear();
+  lt->report_pending = false;
+  return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+  lt->~DDLogicalThread();
+  InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+  m->id = 0;
+  m->stk = cb->Unwind();
+}
+
+void DD::MutexEnsureID(DDLogicalThread *lt, DDMutex *m) {
+  if (!dd.nodeBelongsToCurrentEpoch(m->id))
+    m->id = dd.newNode(reinterpret_cast<uptr>(m));
+  dd.ensureCurrentEpoch(&lt->dd);
+}
+
+void DD::MutexBeforeLock(DDCallback *cb,
+    DDMutex *m, bool wlock) {
+  DDLogicalThread *lt = cb->lt;
+  if (lt->dd.empty()) return;  // This will be the first lock held by lt.
+  if (dd.hasAllEdges(&lt->dd, m->id)) return;  // We already have all edges.
+  SpinMutexLock lk(&mtx);
+  MutexEnsureID(lt, m);
+  if (dd.isHeld(&lt->dd, m->id))
+    return;  // FIXME: allow this only for recursive locks.
+  if (dd.onLockBefore(&lt->dd, m->id)) {
+    // Actually add this edge now so that we have all the stack traces.
+    dd.addEdges(&lt->dd, m->id, cb->Unwind(), cb->UniqueTid());
+    ReportDeadlock(cb, m);
+  }
+}
+
+void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) {
+  DDLogicalThread *lt = cb->lt;
+  uptr path[10];
+  uptr len = dd.findPathToLock(&lt->dd, m->id, path, ARRAY_SIZE(path));
+  CHECK_GT(len, 0U);  // Hm.. cycle of 10 locks? I'd like to see that.
+  CHECK_EQ(m->id, path[0]);
+  lt->report_pending = true;
+  DDReport *rep = &lt->rep;
+  rep->n = len;
+  for (uptr i = 0; i < len; i++) {
+    uptr from = path[i];
+    uptr to = path[(i + 1) % len];
+    DDMutex *m0 = (DDMutex*)dd.getData(from);
+    DDMutex *m1 = (DDMutex*)dd.getData(to);
+
+    u32 stk_from = -1U, stk_to = -1U;
+    int unique_tid = 0;
+    dd.findEdge(from, to, &stk_from, &stk_to, &unique_tid);
+    // Printf("Edge: %zd=>%zd: %u/%u T%d\n", from, to, stk_from, stk_to,
+    //    unique_tid);
+    rep->loop[i].thr_ctx = unique_tid;
+    rep->loop[i].mtx_ctx0 = m0->ctx;
+    rep->loop[i].mtx_ctx1 = m1->ctx;
+    rep->loop[i].stk[0] = stk_to;
+    rep->loop[i].stk[1] = stk_from;
+  }
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) {
+  DDLogicalThread *lt = cb->lt;
+  u32 stk = 0;
+  if (flags.second_deadlock_stack)
+    stk = cb->Unwind();
+  // Printf("T%p MutexLock:   %zx stk %u\n", lt, m->id, stk);
+  if (dd.onFirstLock(&lt->dd, m->id, stk))
+    return;
+  if (dd.onLockFast(&lt->dd, m->id, stk))
+    return;
+
+  SpinMutexLock lk(&mtx);
+  MutexEnsureID(lt, m);
+  if (wlock)  // Only a recursive rlock may be held.
+    CHECK(!dd.isHeld(&lt->dd, m->id));
+  if (!trylock)
+    dd.addEdges(&lt->dd, m->id, stk ? stk : cb->Unwind(), cb->UniqueTid());
+  dd.onLockAfter(&lt->dd, m->id, stk);
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+  // Printf("T%p MutexUnLock: %zx\n", cb->lt, m->id);
+  dd.onUnlock(&cb->lt->dd, m->id);
+}
+
+void DD::MutexDestroy(DDCallback *cb,
+    DDMutex *m) {
+  if (!m->id) return;
+  SpinMutexLock lk(&mtx);
+  if (dd.nodeBelongsToCurrentEpoch(m->id))
+    dd.removeNode(m->id);
+  m->id = 0;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+  if (!cb->lt->report_pending)
+    return 0;
+  cb->lt->report_pending = false;
+  return &cb->lt->rep;
+}
+
+}  // namespace __sanitizer
+#endif  // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector2.cc b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
new file mode 100644
index 0000000..2284362
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector2.cc
@@ -0,0 +1,429 @@
+//===-- sanitizer_deadlock_detector2.cc -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Deadlock detector implementation based on adjacency lists.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_mutex.h"
+
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+
+namespace __sanitizer {
+
+const int kMaxNesting = 64;
+const u32 kNoId = -1;
+const u32 kEndId = -2;
+const int kMaxLink = 8;
+const int kL1Size = 1024;
+const int kL2Size = 1024;
+const int kMaxMutex = kL1Size * kL2Size;
+
+struct Id {
+  u32 id;
+  u32 seq;
+
+  explicit Id(u32 id = 0, u32 seq = 0)
+      : id(id)
+      , seq(seq) {
+  }
+};
+
+struct Link {
+  u32 id;
+  u32 seq;
+  u32 tid;
+  u32 stk0;
+  u32 stk1;
+
+  explicit Link(u32 id = 0, u32 seq = 0, u32 tid = 0, u32 s0 = 0, u32 s1 = 0)
+      : id(id)
+      , seq(seq)
+      , tid(tid)
+      , stk0(s0)
+      , stk1(s1) {
+  }
+};
+
+struct DDPhysicalThread {
+  DDReport rep;
+  bool report_pending;
+  bool visited[kMaxMutex];
+  Link pending[kMaxMutex];
+  Link path[kMaxMutex];
+};
+
+struct ThreadMutex {
+  u32 id;
+  u32 stk;
+};
+
+struct DDLogicalThread {
+  u64         ctx;
+  ThreadMutex locked[kMaxNesting];
+  int         nlocked;
+};
+
+struct Mutex {
+  StaticSpinMutex mtx;
+  u32 seq;
+  int nlink;
+  Link link[kMaxLink];
+};
+
+struct DD : public DDetector {
+  explicit DD(const DDFlags *flags);
+
+  DDPhysicalThread* CreatePhysicalThread();
+  void DestroyPhysicalThread(DDPhysicalThread *pt);
+
+  DDLogicalThread* CreateLogicalThread(u64 ctx);
+  void DestroyLogicalThread(DDLogicalThread *lt);
+
+  void MutexInit(DDCallback *cb, DDMutex *m);
+  void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+      bool trylock);
+  void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock);
+  void MutexDestroy(DDCallback *cb, DDMutex *m);
+
+  DDReport *GetReport(DDCallback *cb);
+
+  void CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt, DDMutex *mtx);
+  void Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath);
+  u32 allocateId(DDCallback *cb);
+  Mutex *getMutex(u32 id);
+  u32 getMutexId(Mutex *m);
+
+  DDFlags flags;
+
+  Mutex* mutex[kL1Size];
+
+  SpinMutex mtx;
+  InternalMmapVector<u32> free_id;
+  int id_gen;
+};
+
+DDetector *DDetector::Create(const DDFlags *flags) {
+  (void)flags;
+  void *mem = MmapOrDie(sizeof(DD), "deadlock detector");
+  return new(mem) DD(flags);
+}
+
+DD::DD(const DDFlags *flags)
+    : flags(*flags)
+    , free_id(1024) {
+  id_gen = 0;
+}
+
+DDPhysicalThread* DD::CreatePhysicalThread() {
+  DDPhysicalThread *pt = (DDPhysicalThread*)MmapOrDie(sizeof(DDPhysicalThread),
+      "deadlock detector (physical thread)");
+  return pt;
+}
+
+void DD::DestroyPhysicalThread(DDPhysicalThread *pt) {
+  pt->~DDPhysicalThread();
+  UnmapOrDie(pt, sizeof(DDPhysicalThread));
+}
+
+DDLogicalThread* DD::CreateLogicalThread(u64 ctx) {
+  DDLogicalThread *lt = (DDLogicalThread*)InternalAlloc(
+      sizeof(DDLogicalThread));
+  lt->ctx = ctx;
+  lt->nlocked = 0;
+  return lt;
+}
+
+void DD::DestroyLogicalThread(DDLogicalThread *lt) {
+  lt->~DDLogicalThread();
+  InternalFree(lt);
+}
+
+void DD::MutexInit(DDCallback *cb, DDMutex *m) {
+  VPrintf(2, "#%llu: DD::MutexInit(%p)\n", cb->lt->ctx, m);
+  m->id = kNoId;
+  m->recursion = 0;
+  atomic_store(&m->owner, 0, memory_order_relaxed);
+}
+
+Mutex *DD::getMutex(u32 id) {
+  return &mutex[id / kL2Size][id % kL2Size];
+}
+
+u32 DD::getMutexId(Mutex *m) {
+  for (int i = 0; i < kL1Size; i++) {
+    Mutex *tab = mutex[i];
+    if (tab == 0)
+      break;
+    if (m >= tab && m < tab + kL2Size)
+      return i * kL2Size + (m - tab);
+  }
+  return -1;
+}
+
+u32 DD::allocateId(DDCallback *cb) {
+  u32 id = -1;
+  SpinMutexLock l(&mtx);
+  if (free_id.size() > 0) {
+    id = free_id.back();
+    free_id.pop_back();
+  } else {
+    CHECK_LT(id_gen, kMaxMutex);
+    if ((id_gen % kL2Size) == 0) {
+      mutex[id_gen / kL2Size] = (Mutex*)MmapOrDie(kL2Size * sizeof(Mutex),
+          "deadlock detector (mutex table)");
+    }
+    id = id_gen++;
+  }
+  CHECK_LE(id, kMaxMutex);
+  VPrintf(3, "#%llu: DD::allocateId assign id %d\n",
+      cb->lt->ctx, id);
+  return id;
+}
+
+void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {
+  VPrintf(2, "#%llu: DD::MutexBeforeLock(%p, wlock=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, cb->lt->nlocked);
+  DDPhysicalThread *pt = cb->pt;
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock recursive\n",
+        cb->lt->ctx);
+    return;
+  }
+
+  CHECK_LE(lt->nlocked, kMaxNesting);
+
+  // FIXME(dvyukov): don't allocate id if lt->nlocked == 0?
+  if (m->id == kNoId)
+    m->id = allocateId(cb);
+
+  ThreadMutex *tm = &lt->locked[lt->nlocked++];
+  tm->id = m->id;
+  if (flags.second_deadlock_stack)
+    tm->stk = cb->Unwind();
+  if (lt->nlocked == 1) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock first mutex\n",
+        cb->lt->ctx);
+    return;
+  }
+
+  bool added = false;
+  Mutex *mtx = getMutex(m->id);
+  for (int i = 0; i < lt->nlocked - 1; i++) {
+    u32 id1 = lt->locked[i].id;
+    u32 stk1 = lt->locked[i].stk;
+    Mutex *mtx1 = getMutex(id1);
+    SpinMutexLock l(&mtx1->mtx);
+    if (mtx1->nlink == kMaxLink) {
+      // FIXME(dvyukov): check stale links
+      continue;
+    }
+    int li = 0;
+    for (; li < mtx1->nlink; li++) {
+      Link *link = &mtx1->link[li];
+      if (link->id == m->id) {
+        if (link->seq != mtx->seq) {
+          link->seq = mtx->seq;
+          link->tid = lt->ctx;
+          link->stk0 = stk1;
+          link->stk1 = cb->Unwind();
+          added = true;
+          VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+              cb->lt->ctx, getMutexId(mtx1), m->id);
+        }
+        break;
+      }
+    }
+    if (li == mtx1->nlink) {
+      // FIXME(dvyukov): check stale links
+      Link *link = &mtx1->link[mtx1->nlink++];
+      link->id = m->id;
+      link->seq = mtx->seq;
+      link->tid = lt->ctx;
+      link->stk0 = stk1;
+      link->stk1 = cb->Unwind();
+      added = true;
+      VPrintf(3, "#%llu: DD::MutexBeforeLock added %d->%d link\n",
+          cb->lt->ctx, getMutexId(mtx1), m->id);
+    }
+  }
+
+  if (!added || mtx->nlink == 0) {
+    VPrintf(3, "#%llu: DD::MutexBeforeLock don't check\n",
+        cb->lt->ctx);
+    return;
+  }
+
+  CycleCheck(pt, lt, m);
+}
+
+void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+    bool trylock) {
+  VPrintf(2, "#%llu: DD::MutexAfterLock(%p, wlock=%d, try=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, trylock, cb->lt->nlocked);
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexAfterLock recursive\n", cb->lt->ctx);
+    CHECK(wlock);
+    m->recursion++;
+    return;
+  }
+  CHECK_EQ(owner, 0);
+  if (wlock) {
+    VPrintf(3, "#%llu: DD::MutexAfterLock set owner\n", cb->lt->ctx);
+    CHECK_EQ(m->recursion, 0);
+    m->recursion = 1;
+    atomic_store(&m->owner, (uptr)cb->lt, memory_order_relaxed);
+  }
+
+  if (!trylock)
+    return;
+
+  CHECK_LE(lt->nlocked, kMaxNesting);
+  if (m->id == kNoId)
+    m->id = allocateId(cb);
+  ThreadMutex *tm = &lt->locked[lt->nlocked++];
+  tm->id = m->id;
+  if (flags.second_deadlock_stack)
+    tm->stk = cb->Unwind();
+}
+
+void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {
+  VPrintf(2, "#%llu: DD::MutexBeforeUnlock(%p, wlock=%d) nlocked=%d\n",
+      cb->lt->ctx, m, wlock, cb->lt->nlocked);
+  DDLogicalThread *lt = cb->lt;
+
+  uptr owner = atomic_load(&m->owner, memory_order_relaxed);
+  if (owner == (uptr)cb->lt) {
+    VPrintf(3, "#%llu: DD::MutexBeforeUnlock recursive\n", cb->lt->ctx);
+    if (--m->recursion > 0)
+      return;
+    VPrintf(3, "#%llu: DD::MutexBeforeUnlock reset owner\n", cb->lt->ctx);
+    atomic_store(&m->owner, 0, memory_order_relaxed);
+  }
+  CHECK_NE(m->id, kNoId);
+  int last = lt->nlocked - 1;
+  for (int i = last; i >= 0; i--) {
+    if (cb->lt->locked[i].id == m->id) {
+      lt->locked[i] = lt->locked[last];
+      lt->nlocked--;
+      break;
+    }
+  }
+}
+
+void DD::MutexDestroy(DDCallback *cb, DDMutex *m) {
+  VPrintf(2, "#%llu: DD::MutexDestroy(%p)\n",
+      cb->lt->ctx, m);
+  DDLogicalThread *lt = cb->lt;
+
+  if (m->id == kNoId)
+    return;
+
+  // Remove the mutex from lt->locked if there.
+  int last = lt->nlocked - 1;
+  for (int i = last; i >= 0; i--) {
+    if (lt->locked[i].id == m->id) {
+      lt->locked[i] = lt->locked[last];
+      lt->nlocked--;
+      break;
+    }
+  }
+
+  // Clear and invalidate the mutex descriptor.
+  {
+    Mutex *mtx = getMutex(m->id);
+    SpinMutexLock l(&mtx->mtx);
+    mtx->seq++;
+    mtx->nlink = 0;
+  }
+
+  // Return id to cache.
+  {
+    SpinMutexLock l(&mtx);
+    free_id.push_back(m->id);
+  }
+}
+
+void DD::CycleCheck(DDPhysicalThread *pt, DDLogicalThread *lt,
+    DDMutex *m) {
+  internal_memset(pt->visited, 0, sizeof(pt->visited));
+  int npath = 0;
+  int npending = 0;
+  {
+    Mutex *mtx = getMutex(m->id);
+    SpinMutexLock l(&mtx->mtx);
+    for (int li = 0; li < mtx->nlink; li++)
+      pt->pending[npending++] = mtx->link[li];
+  }
+  while (npending > 0) {
+    Link link = pt->pending[--npending];
+    if (link.id == kEndId) {
+      npath--;
+      continue;
+    }
+    if (pt->visited[link.id])
+      continue;
+    Mutex *mtx1 = getMutex(link.id);
+    SpinMutexLock l(&mtx1->mtx);
+    if (mtx1->seq != link.seq)
+      continue;
+    pt->visited[link.id] = true;
+    if (mtx1->nlink == 0)
+      continue;
+    pt->path[npath++] = link;
+    pt->pending[npending++] = Link(kEndId);
+    if (link.id == m->id)
+      return Report(pt, lt, npath);  // Bingo!
+    for (int li = 0; li < mtx1->nlink; li++) {
+      Link *link1 = &mtx1->link[li];
+      // Mutex *mtx2 = getMutex(link->id);
+      // FIXME(dvyukov): fast seq check
+      // FIXME(dvyukov): fast nlink != 0 check
+      // FIXME(dvyukov): fast pending check?
+      // FIXME(dvyukov): npending can be larger than kMaxMutex
+      pt->pending[npending++] = *link1;
+    }
+  }
+}
+
+void DD::Report(DDPhysicalThread *pt, DDLogicalThread *lt, int npath) {
+  DDReport *rep = &pt->rep;
+  rep->n = npath;
+  for (int i = 0; i < npath; i++) {
+    Link *link = &pt->path[i];
+    Link *link0 = &pt->path[i ? i - 1 : npath - 1];
+    rep->loop[i].thr_ctx = link->tid;
+    rep->loop[i].mtx_ctx0 = link0->id;
+    rep->loop[i].mtx_ctx1 = link->id;
+    rep->loop[i].stk[0] = flags.second_deadlock_stack ? link->stk0 : 0;
+    rep->loop[i].stk[1] = link->stk1;
+  }
+  pt->report_pending = true;
+}
+
+DDReport *DD::GetReport(DDCallback *cb) {
+  if (!cb->pt->report_pending)
+    return 0;
+  cb->pt->report_pending = false;
+  return &cb->pt->rep;
+}
+
+}  // namespace __sanitizer
+#endif  // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
new file mode 100644
index 0000000..8cf26e0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -0,0 +1,93 @@
+//===-- sanitizer_deadlock_detector_interface.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 a part of Sanitizer runtime.
+// Abstract deadlock detector interface.
+// FIXME: this is work in progress, nothing really works yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+#define SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
+
+#ifndef SANITIZER_DEADLOCK_DETECTOR_VERSION
+# define SANITIZER_DEADLOCK_DETECTOR_VERSION 1
+#endif
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_atomic.h"
+
+namespace __sanitizer {
+
+// dd - deadlock detector.
+// lt - logical (user) thread.
+// pt - physical (OS) thread.
+
+struct DDPhysicalThread;
+struct DDLogicalThread;
+
+struct DDMutex {
+#if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1
+  uptr id;
+  u32  stk;  // creation stack
+#elif SANITIZER_DEADLOCK_DETECTOR_VERSION == 2
+  u32              id;
+  u32              recursion;
+  atomic_uintptr_t owner;
+#else
+# error "BAD SANITIZER_DEADLOCK_DETECTOR_VERSION"
+#endif
+  u64  ctx;
+};
+
+struct DDFlags {
+  bool second_deadlock_stack;
+};
+
+struct DDReport {
+  enum { kMaxLoopSize = 8 };
+  int n;  // number of entries in loop
+  struct {
+    u64 thr_ctx;   // user thread context
+    u64 mtx_ctx0;  // user mutex context, start of the edge
+    u64 mtx_ctx1;  // user mutex context, end of the edge
+    u32 stk[2];  // stack ids for the edge
+  } loop[kMaxLoopSize];
+};
+
+struct DDCallback {
+  DDPhysicalThread *pt;
+  DDLogicalThread  *lt;
+
+  virtual u32 Unwind() { return 0; }
+  virtual int UniqueTid() { return 0; }
+};
+
+struct DDetector {
+  static DDetector *Create(const DDFlags *flags);
+
+  virtual DDPhysicalThread* CreatePhysicalThread() { return 0; }
+  virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {}
+
+  virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; }
+  virtual void DestroyLogicalThread(DDLogicalThread *lt) {}
+
+  virtual void MutexInit(DDCallback *cb, DDMutex *m) {}
+  virtual void MutexBeforeLock(DDCallback *cb, DDMutex *m, bool wlock) {}
+  virtual void MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock,
+      bool trylock) {}
+  virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {}
+  virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {}
+
+  virtual DDReport *GetReport(DDCallback *cb) { return 0; }
+};
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_DEADLOCK_DETECTOR_INTERFACE_H
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index 924ed4b..406bb64 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -15,13 +15,24 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_list.h"
 
 namespace __sanitizer {
 
-void SetCommonFlagDefaults() {
-  CommonFlags *f = common_flags();
+CommonFlags common_flags_dont_use;
+
+struct FlagDescription {
+  const char *name;
+  const char *description;
+  FlagDescription *next;
+};
+
+IntrusiveList<FlagDescription> flag_descriptions;
+
+void SetCommonFlagsDefaults(CommonFlags *f) {
   f->symbolize = true;
-  f->external_symbolizer_path = "";
+  f->external_symbolizer_path = 0;
+  f->allow_addr2line = false;
   f->strip_path_prefix = "";
   f->fast_unwind_on_fatal = false;
   f->fast_unwind_on_malloc = true;
@@ -29,27 +40,101 @@
   f->malloc_context_size = 1;
   f->log_path = "stderr";
   f->verbosity = 0;
-  f->detect_leaks = false;
+  f->detect_leaks = true;
   f->leak_check_at_exit = true;
   f->allocator_may_return_null = false;
   f->print_summary = true;
+  f->check_printf = true;
+  // TODO(glider): tools may want to set different defaults for handle_segv.
+  f->handle_segv = SANITIZER_NEEDS_SEGV;
+  f->allow_user_segv_handler = false;
+  f->use_sigaltstack = true;
+  f->detect_deadlocks = false;
+  f->clear_shadow_mmap_threshold = 64 * 1024;
+  f->color = "auto";
+  f->legacy_pthread_cond = false;
+  f->intercept_tls_get_addr = false;
+  f->coverage = false;
+  f->coverage_direct = false;
+  f->full_address_space = false;
 }
 
-void ParseCommonFlagsFromString(const char *str) {
-  CommonFlags *f = common_flags();
-  ParseFlag(str, &f->symbolize, "symbolize");
-  ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path");
-  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
-  ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
-  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
-  ParseFlag(str, &f->handle_ioctl, "handle_ioctl");
-  ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
-  ParseFlag(str, &f->log_path, "log_path");
-  ParseFlag(str, &f->verbosity, "verbosity");
-  ParseFlag(str, &f->detect_leaks, "detect_leaks");
-  ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit");
-  ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null");
-  ParseFlag(str, &f->print_summary, "print_summary");
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
+  ParseFlag(str, &f->symbolize, "symbolize",
+      "If set, use the online symbolizer from common sanitizer runtime to turn "
+      "virtual addresses to file/line locations.");
+  ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path",
+      "Path to external symbolizer. If empty, the tool will search $PATH for "
+      "the symbolizer.");
+  ParseFlag(str, &f->allow_addr2line, "allow_addr2line",
+      "If set, allows online symbolizer to run addr2line binary to symbolize "
+      "stack traces (addr2line will only be used if llvm-symbolizer binary is "
+      "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_fatal, "fast_unwind_on_fatal",
+      "If available, use the fast frame-pointer-based unwinder on fatal "
+      "errors.");
+  ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc",
+      "If available, use the fast frame-pointer-based unwinder on "
+      "malloc/free.");
+  ParseFlag(str, &f->handle_ioctl, "handle_ioctl",
+      "Intercept and handle ioctl requests.");
+  ParseFlag(str, &f->malloc_context_size, "malloc_context_size",
+      "Max number of stack frames kept for each allocation/deallocation.");
+  ParseFlag(str, &f->log_path, "log_path",
+      "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
+      "\"stderr\". The default is \"stderr\".");
+  ParseFlag(str, &f->verbosity, "verbosity",
+      "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
+  ParseFlag(str, &f->detect_leaks, "detect_leaks",
+      "Enable memory leak detection.");
+  ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit",
+      "Invoke leak checking in an atexit handler. Has no effect if "
+      "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
+      "handler has a chance to run.");
+  ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null",
+      "If false, the allocator will crash instead of returning 0 on "
+      "out-of-memory.");
+  ParseFlag(str, &f->print_summary, "print_summary",
+      "If false, disable printing error summaries in addition to error "
+      "reports.");
+  ParseFlag(str, &f->check_printf, "check_printf",
+      "Check printf arguments.");
+  ParseFlag(str, &f->handle_segv, "handle_segv",
+      "If set, registers the tool's custom SEGV handler (both SIGBUS and "
+      "SIGSEGV on OSX).");
+  ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler",
+      "If set, allows user to register a SEGV handler even if the tool "
+      "registers one.");
+  ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack",
+      "If set, uses alternate stack for signal handling.");
+  ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks",
+      "If set, deadlock detection is enabled.");
+  ParseFlag(str, &f->clear_shadow_mmap_threshold,
+            "clear_shadow_mmap_threshold",
+      "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
+      "memset(). This is the threshold size in bytes.");
+  ParseFlag(str, &f->color, "color",
+      "Colorize reports: (always|never|auto).");
+  ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond",
+      "Enables support for dynamic libraries linked with libpthread 2.2.5.");
+  ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr",
+            "Intercept __tls_get_addr.");
+  ParseFlag(str, &f->help, "help", "Print the flag descriptions.");
+  ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb",
+            "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
+            "not a user-facing flag, used mosly for testing the tools");
+  ParseFlag(str, &f->coverage, "coverage",
+      "If set, coverage information will be dumped at program shutdown (if the "
+      "coverage instrumentation was enabled at compile time).");
+  ParseFlag(str, &f->coverage_direct, "coverage_direct",
+            "If set, coverage information will be dumped directly to a memory "
+            "mapped file. This way data is not lost even if the process is "
+            "suddenly killed.");
+  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");
 
   // Do a sanity check for certain flags.
   if (f->malloc_context_size < 1)
@@ -104,9 +189,40 @@
          (0 == internal_strncmp(flag, value, value_length));
 }
 
-void ParseFlag(const char *env, bool *flag, const char *name) {
+static LowLevelAllocator allocator_for_flags;
+
+// The linear scan is suboptimal, but the number of flags is relatively small.
+bool FlagInDescriptionList(const char *name) {
+  IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
+  while (it.hasNext()) {
+    if (!internal_strcmp(it.next()->name, name)) return true;
+  }
+  return false;
+}
+
+void AddFlagDescription(const char *name, const char *description) {
+  if (FlagInDescriptionList(name)) return;
+  FlagDescription *new_description = new(allocator_for_flags) FlagDescription;
+  new_description->name = name;
+  new_description->description = description;
+  flag_descriptions.push_back(new_description);
+}
+
+// TODO(glider): put the descriptions inside CommonFlags.
+void PrintFlagDescriptions() {
+  IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
+  Printf("Available flags for %s:\n", SanitizerToolName);
+  while (it.hasNext()) {
+    FlagDescription *descr = it.next();
+    Printf("\t%s\n\t\t- %s\n", descr->name, descr->description);
+  }
+}
+
+void ParseFlag(const char *env, bool *flag,
+               const char *name, const char *descr) {
   const char *value;
   int value_length;
+  AddFlagDescription(name, descr);
   if (!GetFlagValue(env, name, &value, &value_length))
     return;
   if (StartsWith(value, value_length, "0") ||
@@ -119,19 +235,31 @@
     *flag = true;
 }
 
-void ParseFlag(const char *env, int *flag, const char *name) {
+void ParseFlag(const char *env, int *flag,
+               const char *name, const char *descr) {
   const char *value;
   int value_length;
+  AddFlagDescription(name, descr);
   if (!GetFlagValue(env, name, &value, &value_length))
     return;
   *flag = static_cast<int>(internal_atoll(value));
 }
 
-static LowLevelAllocator allocator_for_flags;
-
-void ParseFlag(const char *env, const char **flag, const char *name) {
+void ParseFlag(const char *env, uptr *flag,
+               const char *name, const char *descr) {
   const char *value;
   int value_length;
+  AddFlagDescription(name, descr);
+  if (!GetFlagValue(env, name, &value, &value_length))
+    return;
+  *flag = static_cast<uptr>(internal_atoll(value));
+}
+
+void ParseFlag(const char *env, const char **flag,
+               const char *name, const char *descr) {
+  const char *value;
+  int value_length;
+  AddFlagDescription(name, descr);
   if (!GetFlagValue(env, name, &value, &value_length))
     return;
   // Copy the flag value. Don't use locks here, as flags are parsed at
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index 9461dff..1ad53dc 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -18,50 +18,54 @@
 
 namespace __sanitizer {
 
-void ParseFlag(const char *env, bool *flag, const char *name);
-void ParseFlag(const char *env, int *flag, const char *name);
-void ParseFlag(const char *env, const char **flag, const char *name);
+void ParseFlag(const char *env, bool *flag,
+    const char *name, const char *descr);
+void ParseFlag(const char *env, int *flag,
+    const char *name, const char *descr);
+void ParseFlag(const char *env, uptr *flag,
+    const char *name, const char *descr);
+void ParseFlag(const char *env, const char **flag,
+    const char *name, const char *descr);
 
 struct CommonFlags {
-  // If set, use the online symbolizer from common sanitizer runtime.
   bool symbolize;
-  // Path to external symbolizer.
   const char *external_symbolizer_path;
-  // Strips this prefix from file paths in error reports.
+  bool allow_addr2line;
   const char *strip_path_prefix;
-  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
   bool fast_unwind_on_fatal;
-  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
   bool fast_unwind_on_malloc;
-  // Intercept and handle ioctl requests.
   bool handle_ioctl;
-  // Max number of stack frames kept for each allocation/deallocation.
   int malloc_context_size;
-  // Write logs to "log_path.pid".
-  // The special values are "stdout" and "stderr".
-  // The default is "stderr".
   const char *log_path;
-  // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
   int  verbosity;
-  // Enable memory leak detection.
   bool detect_leaks;
-  // Invoke leak checking in an atexit handler. Has no effect if
-  // detect_leaks=false, or if __lsan_do_leak_check() is called before the
-  // handler has a chance to run.
   bool leak_check_at_exit;
-  // If false, the allocator will crash instead of returning 0 on out-of-memory.
   bool allocator_may_return_null;
-  // If false, disable printing error summaries in addition to error reports.
   bool print_summary;
+  bool check_printf;
+  bool handle_segv;
+  bool allow_user_segv_handler;
+  bool use_sigaltstack;
+  bool detect_deadlocks;
+  uptr clear_shadow_mmap_threshold;
+  const char *color;
+  bool legacy_pthread_cond;
+  bool intercept_tls_get_addr;
+  bool help;
+  uptr mmap_limit_mb;
+  bool coverage;
+  bool coverage_direct;
+  bool full_address_space;
 };
 
 inline CommonFlags *common_flags() {
-  static CommonFlags f;
-  return &f;
+  extern CommonFlags common_flags_dont_use;
+  return &common_flags_dont_use;
 }
 
-void SetCommonFlagDefaults();
-void ParseCommonFlagsFromString(const char *str);
+void SetCommonFlagsDefaults(CommonFlags *f);
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str);
+void PrintFlagDescriptions();
 
 }  // namespace __sanitizer
 
diff --git a/lib/sanitizer_common/sanitizer_interception.h b/lib/sanitizer_common/sanitizer_interception.h
new file mode 100644
index 0000000..b63462d
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_interception.h
@@ -0,0 +1,25 @@
+//===-- 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 daa724b..9db5f8f 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -34,10 +34,9 @@
 # define SANITIZER_SUPPORTS_WEAK_HOOKS 0
 #endif
 
-#if __LP64__ || defined(_WIN64)
-#  define SANITIZER_WORDSIZE 64
-#else
-#  define SANITIZER_WORDSIZE 32
+// If set, the tool will install its own SEGV signal handler.
+#ifndef SANITIZER_NEEDS_SEGV
+# define SANITIZER_NEEDS_SEGV 1
 #endif
 
 // GCC does not understand __has_feature
@@ -59,7 +58,7 @@
 typedef signed   long sptr;  // NOLINT
 #endif  // defined(_WIN64)
 #if defined(__x86_64__)
-// Since x32 uses ILP32 data model in 64-bit hardware mode,  we must use
+// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
 // 64-bit pointer to unwind stack frame.
 typedef unsigned long long uhwptr;  // NOLINT
 #else
@@ -99,11 +98,15 @@
   SANITIZER_INTERFACE_ATTRIBUTE
   void __sanitizer_set_report_path(const char *path);
 
-  // Notify the tools that the sandbox is going to be turned on. The reserved
-  // parameter will be used in the future to hold a structure with functions
-  // that the tools may call to bypass the sandbox.
-  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-  void __sanitizer_sandbox_on_notify(void *reserved);
+  typedef struct {
+      int coverage_sandboxed;
+      __sanitizer::sptr coverage_fd;
+      unsigned int coverage_max_block_size;
+  } __sanitizer_sandbox_arguments;
+
+  // Notify the tools that the sandbox is going to be turned on.
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+      __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
 
   // This function is called by the tool when it has just finished reporting
   // an error. 'error_summary' is a one-line string that summarizes
@@ -112,10 +115,16 @@
   void __sanitizer_report_error_summary(const char *error_summary);
 
   SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
-  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
+  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
+  SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov();
   SANITIZER_INTERFACE_ATTRIBUTE
-  void __sanitizer_annotate_contiguous_container(void *beg, void *end,
-                                                 void *old_mid, void *new_mid);
+  void __sanitizer_annotate_contiguous_container(const void *beg,
+                                                 const void *end,
+                                                 const void *old_mid,
+                                                 const void *new_mid);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+                                              const void *end);
 }  // extern "C"
 
 
@@ -141,8 +150,6 @@
 # define NOTHROW
 # define LIKELY(x) (x)
 # define UNLIKELY(x) (x)
-# define UNUSED
-# define USED
 # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
 #else  // _MSC_VER
 # define ALWAYS_INLINE inline __attribute__((always_inline))
@@ -157,8 +164,6 @@
 # define NOTHROW throw()
 # define LIKELY(x)     __builtin_expect(!!(x), 1)
 # define UNLIKELY(x)   __builtin_expect(!!(x), 0)
-# define UNUSED __attribute__((unused))
-# define USED __attribute__((used))
 # if defined(__i386__) || defined(__x86_64__)
 // __builtin_prefetch(x) generates prefetchnt0 on x86
 #  define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x))
@@ -167,6 +172,14 @@
 # endif
 #endif  // _MSC_VER
 
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#else
+# define UNUSED
+# define USED
+#endif
+
 // Unaligned versions of basic types.
 typedef ALIGNED(1) u16 uu16;
 typedef ALIGNED(1) u32 uu32;
@@ -197,7 +210,7 @@
 
 // Check macro
 #define RAW_CHECK_MSG(expr, msg) do { \
-  if (!(expr)) { \
+  if (UNLIKELY(!(expr))) { \
     RawWrite(msg); \
     Die(); \
   } \
@@ -209,7 +222,7 @@
   do { \
     __sanitizer::u64 v1 = (u64)(c1); \
     __sanitizer::u64 v2 = (u64)(c2); \
-    if (!(v1 op v2)) \
+    if (UNLIKELY(!(v1 op v2))) \
       __sanitizer::CheckFailed(__FILE__, __LINE__, \
         "(" #c1 ") " #op " (" #c2 ")", v1, v2); \
   } while (false) \
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index 72ddf0f..00596f5 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -16,6 +16,16 @@
 
 namespace __sanitizer {
 
+// Make the compiler think that something is going on there.
+static inline void break_optimization(void *arg) {
+#if _MSC_VER
+  // FIXME: make sure this is actually enough.
+  __asm;
+#else
+  __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
 s64 internal_atoll(const char *nptr) {
   return internal_simple_strtoll(nptr, (char**)0, 10);
 }
@@ -62,6 +72,16 @@
   return dest;
 }
 
+// Semi-fast bzero for 16-aligned data. Still far from peak performance.
+void internal_bzero_aligned16(void *s, uptr n) {
+  struct S16 { u64 a, b; } ALIGNED(16);
+  CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
+  for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
+    p->a = p->b = 0;
+    break_optimization(0);  // Make sure this does not become memset.
+  }
+}
+
 void *internal_memset(void* s, int c, uptr n) {
   // The next line prevents Clang from making a call to memset() instead of the
   // loop below.
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index 187a714..6995626 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -29,6 +29,8 @@
 int internal_memcmp(const void* s1, const void* s2, uptr n);
 void *internal_memcpy(void *dest, const void *src, uptr n);
 void *internal_memmove(void *dest, const void *src, uptr n);
+// Set [s, s + n) to 0. Both s and n should be 16-aligned.
+void internal_bzero_aligned16(void *s, uptr n);
 // Should not be used in performance-critical places.
 void *internal_memset(void *s, int c, uptr n);
 char* internal_strchr(const char *s, int c);
@@ -72,6 +74,7 @@
 
 uptr internal_read(fd_t fd, void *buf, uptr count);
 uptr internal_write(fd_t fd, const void *buf, uptr count);
+uptr internal_ftruncate(fd_t fd, uptr size);
 
 // OS
 uptr internal_filesize(fd_t fd);  // -1 on error.
@@ -81,6 +84,7 @@
 uptr internal_dup2(int oldfd, int newfd);
 uptr internal_readlink(const char *path, char *buf, uptr bufsize);
 uptr internal_unlink(const char *path);
+uptr internal_rename(const char *oldpath, const char *newpath);
 void NORETURN internal__exit(int exitcode);
 uptr internal_lseek(fd_t fd, OFF_T offset, int whence);
 
@@ -89,12 +93,16 @@
 uptr internal_getpid();
 uptr internal_getppid();
 
+int internal_fork();
+
 // Threading
 uptr internal_sched_yield();
 
 // Error handling
 bool internal_iserror(uptr retval, int *rverrno = 0);
 
+int internal_sigaction(int signum, const void *act, void *oldact);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_LIBC_H
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index 0f193a1..a0bb871 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -76,9 +76,10 @@
         loaded = true;
         if (lib->loaded)
           continue;
-        if (common_flags()->verbosity)
-          Report("Matched called_from_lib suppression '%s' against library"
-              " '%s'\n", lib->templ, module.data());
+        VReport(1,
+                "Matched called_from_lib suppression '%s' against library"
+                " '%s'\n",
+                lib->templ, module.data());
         lib->loaded = true;
         lib->name = internal_strdup(module.data());
         const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index b98ad0a..f27f22e 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -13,9 +13,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
 
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_linux.h"
@@ -25,7 +26,10 @@
 #include "sanitizer_stacktrace.h"
 #include "sanitizer_symbolizer.h"
 
+#if !SANITIZER_FREEBSD
 #include <asm/param.h>
+#endif
+
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -44,10 +48,25 @@
 #include <unistd.h>
 #include <unwind.h>
 
+#if SANITIZER_FREEBSD
+#include <machine/atomic.h>
+extern "C" {
+// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
+// FreeBSD 9.2 and 10.0.
+#include <sys/umtx.h>
+}
+#endif  // SANITIZER_FREEBSD
+
 #if !SANITIZER_ANDROID
 #include <sys/signal.h>
 #endif
 
+#if SANITIZER_ANDROID
+#include <android/log.h>
+#include <sys/system_properties.h>
+#endif
+
+#if SANITIZER_LINUX
 // <linux/time.h>
 struct kernel_timeval {
   long tv_sec;
@@ -57,11 +76,12 @@
 // <linux/futex.h> is broken on some linux distributions.
 const int FUTEX_WAIT = 0;
 const int FUTEX_WAKE = 1;
+#endif  // SANITIZER_LINUX
 
-// Are we using 32-bit or 64-bit syscalls?
+// Are we using 32-bit or 64-bit Linux syscalls?
 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
 // but it still needs to use 64-bit syscalls.
-#if defined(__x86_64__) || SANITIZER_WORDSIZE == 64
+#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
 #else
 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
@@ -69,7 +89,7 @@
 
 namespace __sanitizer {
 
-#ifdef __x86_64__
+#if SANITIZER_LINUX && defined(__x86_64__)
 #include "sanitizer_syscall_linux_x86_64.inc"
 #else
 #include "sanitizer_syscall_generic.inc"
@@ -78,48 +98,66 @@
 // --------------- sanitizer_libc.h
 uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                     int fd, u64 offset) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return internal_syscall(__NR_mmap, (uptr)addr, length, prot, flags, fd,
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
                           offset);
 #else
-  return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
+  return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
+                          offset);
 #endif
 }
 
 uptr internal_munmap(void *addr, uptr length) {
-  return internal_syscall(__NR_munmap, (uptr)addr, length);
+  return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
 }
 
 uptr internal_close(fd_t fd) {
-  return internal_syscall(__NR_close, fd);
+  return internal_syscall(SYSCALL(close), fd);
 }
 
 uptr internal_open(const char *filename, int flags) {
-  return internal_syscall(__NR_open, (uptr)filename, flags);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
+#else
+  return internal_syscall(SYSCALL(open), (uptr)filename, flags);
+#endif
 }
 
 uptr internal_open(const char *filename, int flags, u32 mode) {
-  return internal_syscall(__NR_open, (uptr)filename, flags, mode);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
+                          mode);
+#else
+  return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
+#endif
 }
 
 uptr OpenFile(const char *filename, bool write) {
   return internal_open(filename,
-      write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
+      write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
 }
 
 uptr internal_read(fd_t fd, void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, (uptr)buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
+               count));
   return res;
 }
 
 uptr internal_write(fd_t fd, const void *buf, uptr count) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, (uptr)buf, count));
+  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
+               count));
   return res;
 }
 
-#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS
+uptr internal_ftruncate(fd_t fd, uptr size) {
+  sptr res;
+  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
+  return res;
+}
+
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
 static void stat64_to_stat(struct stat64 *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
@@ -140,33 +178,43 @@
 #endif
 
 uptr internal_stat(const char *path, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return internal_syscall(__NR_stat, (uptr)path, (uptr)buf);
+#if SANITIZER_FREEBSD
+  return internal_syscall(SYSCALL(stat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+                          (uptr)buf, 0);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf);
 #else
   struct stat64 buf64;
-  int res = internal_syscall(__NR_stat64, path, &buf64);
+  int res = internal_syscall(SYSCALL(stat64), path, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
 #endif
 }
 
 uptr internal_lstat(const char *path, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return internal_syscall(__NR_lstat, (uptr)path, (uptr)buf);
+#if SANITIZER_FREEBSD
+  return internal_syscall(SYSCALL(lstat), path, buf);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
+                         (uptr)buf, AT_SYMLINK_NOFOLLOW);
+#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
 #else
   struct stat64 buf64;
-  int res = internal_syscall(__NR_lstat64, path, &buf64);
+  int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
 #endif
 }
 
 uptr internal_fstat(fd_t fd, void *buf) {
-#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
-  return internal_syscall(__NR_fstat, fd, (uptr)buf);
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+  return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
 #else
   struct stat64 buf64;
-  int res = internal_syscall(__NR_fstat64, fd, &buf64);
+  int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
 #endif
@@ -180,48 +228,89 @@
 }
 
 uptr internal_dup2(int oldfd, int newfd) {
-  return internal_syscall(__NR_dup2, oldfd, newfd);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
+#else
+  return internal_syscall(SYSCALL(dup2), oldfd, newfd);
+#endif
 }
 
 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
-  return internal_syscall(__NR_readlink, (uptr)path, (uptr)buf, bufsize);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
+                          (uptr)path, (uptr)buf, bufsize);
+#else
+  return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
+#endif
 }
 
 uptr internal_unlink(const char *path) {
-  return internal_syscall(__NR_unlink, (uptr)path);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
+#else
+  return internal_syscall(SYSCALL(unlink), (uptr)path);
+#endif
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
+                          (uptr)newpath);
+#else
+  return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
+#endif
 }
 
 uptr internal_sched_yield() {
-  return internal_syscall(__NR_sched_yield);
+  return internal_syscall(SYSCALL(sched_yield));
 }
 
 void internal__exit(int exitcode) {
-  internal_syscall(__NR_exit_group, exitcode);
+#if SANITIZER_FREEBSD
+  internal_syscall(SYSCALL(exit), exitcode);
+#else
+  internal_syscall(SYSCALL(exit_group), exitcode);
+#endif
   Die();  // Unreachable.
 }
 
 uptr internal_execve(const char *filename, char *const argv[],
                      char *const envp[]) {
-  return internal_syscall(__NR_execve, (uptr)filename, (uptr)argv, (uptr)envp);
+  return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
+                          (uptr)envp);
 }
 
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  struct stat st;
+  if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0))
+    return false;
+#else
   struct stat st;
   if (internal_stat(filename, &st))
     return false;
   // Sanity check: filename is a regular file.
   return S_ISREG(st.st_mode);
+#endif
 }
 
 uptr GetTid() {
-  return internal_syscall(__NR_gettid);
+#if SANITIZER_FREEBSD
+  return (uptr)pthread_self();
+#else
+  return internal_syscall(SYSCALL(gettid));
+#endif
 }
 
 u64 NanoTime() {
+#if SANITIZER_FREEBSD
+  timeval tv;
+#else
   kernel_timeval tv;
+#endif
   internal_memset(&tv, 0, sizeof(tv));
-  internal_syscall(__NR_gettimeofday, (uptr)&tv, 0);
+  internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
   return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
 }
 
@@ -305,225 +394,16 @@
   Die();
 }
 
-void PrepareForSandboxing() {
-  // 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
-  // process will be able to load additional libraries, so it's fine to use the
-  // cached mappings.
-  MemoryMappingLayout::CacheMemoryMappings();
-  // Same for /proc/self/exe in the symbolizer.
-#if !SANITIZER_GO
-  if (Symbolizer *sym = Symbolizer::GetOrNull())
-    sym->PrepareForSandboxing();
-#endif
+// Stub implementation of GetThreadStackAndTls for Go.
+#if SANITIZER_GO
+void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
+                          uptr *tls_addr, uptr *tls_size) {
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
 }
-
-// ----------------- sanitizer_procmaps.h
-// Linker initialized.
-ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
-StaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
-
-MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
-  proc_self_maps_.len =
-      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
-                       &proc_self_maps_.mmaped_size, 1 << 26);
-  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_;
-  cached_proc_self_maps_.len =
-      ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
-                       &cached_proc_self_maps_.mmaped_size, 1 << 26);
-  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_;
-  }
-}
-
-// 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;
-}
-
-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,
-                               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;
-  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
-  if (next_line == 0)
-    next_line = last;
-  // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
-  *start = ParseHex(&current_);
-  CHECK_EQ(*current_++, '-');
-  *end = ParseHex(&current_);
-  CHECK_EQ(*current_++, ' ');
-  uptr local_protection = 0;
-  CHECK(IsOneOf(*current_, '-', 'r'));
-  if (*current_++ == 'r')
-    local_protection |= kProtectionRead;
-  CHECK(IsOneOf(*current_, '-', 'w'));
-  if (*current_++ == 'w')
-    local_protection |= kProtectionWrite;
-  CHECK(IsOneOf(*current_, '-', 'x'));
-  if (*current_++ == 'x')
-    local_protection |= kProtectionExecute;
-  CHECK(IsOneOf(*current_, 's', 'p'));
-  if (*current_++ == 's')
-    local_protection |= kProtectionShared;
-  if (protection) {
-    *protection = local_protection;
-  }
-  CHECK_EQ(*current_++, ' ');
-  *offset = ParseHex(&current_);
-  CHECK_EQ(*current_++, ' ');
-  ParseHex(&current_);
-  CHECK_EQ(*current_++, ':');
-  ParseHex(&current_);
-  CHECK_EQ(*current_++, ' ');
-  while (IsDecimal(*current_))
-    current_++;
-  // Qemu may lack the trailing space.
-  // http://code.google.com/p/address-sanitizer/issues/detail?id=160
-  // CHECK_EQ(*current_++, ' ');
-  // Skip spaces.
-  while (current_ < next_line && *current_ == ' ')
-    current_++;
-  // Fill in the filename.
-  uptr i = 0;
-  while (current_ < next_line) {
-    if (filename && i < filename_size - 1)
-      filename[i++] = *current_;
-    current_++;
-  }
-  if (filename && i < filename_size)
-    filename[i] = 0;
-  current_ = next_line + 1;
-  return true;
-}
-
-// Gets the object name and the offset by walking MemoryMappingLayout.
-bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
-                                                 char filename[],
-                                                 uptr filename_size,
-                                                 uptr *protection) {
-  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
-                                       protection);
-}
-
-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);
-}
+#endif  // SANITIZER_GO
 
 enum MutexState {
   MtxUnlocked = 0,
@@ -543,16 +423,26 @@
   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
   if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
     return;
-  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
-    internal_syscall(__NR_futex, (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
+#if SANITIZER_FREEBSD
+    _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
+#else
+    internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
+#endif
+  }
 }
 
 void BlockingMutex::Unlock() {
   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
   u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
   CHECK_NE(v, MtxUnlocked);
-  if (v == MtxSleeping)
-    internal_syscall(__NR_futex, (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
+  if (v == MtxSleeping) {
+#if SANITIZER_FREEBSD
+    _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
+#else
+    internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
+#endif
+  }
 }
 
 void BlockingMutex::CheckLocked() {
@@ -565,71 +455,137 @@
 // Note that getdents64 uses a different structure format. We only provide the
 // 32-bit syscall here.
 struct linux_dirent {
+#if SANITIZER_X32
+  u64 d_ino;
+  u64 d_off;
+#else
   unsigned long      d_ino;
   unsigned long      d_off;
+#endif
   unsigned short     d_reclen;
   char               d_name[256];
 };
 
 // Syscall wrappers.
 uptr internal_ptrace(int request, int pid, void *addr, void *data) {
-  return internal_syscall(__NR_ptrace, request, pid, (uptr)addr, (uptr)data);
+  return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
+                          (uptr)data);
 }
 
 uptr internal_waitpid(int pid, int *status, int options) {
-  return internal_syscall(__NR_wait4, pid, (uptr)status, options,
+  return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
                           0 /* rusage */);
 }
 
 uptr internal_getpid() {
-  return internal_syscall(__NR_getpid);
+  return internal_syscall(SYSCALL(getpid));
 }
 
 uptr internal_getppid() {
-  return internal_syscall(__NR_getppid);
+  return internal_syscall(SYSCALL(getppid));
 }
 
 uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-  return internal_syscall(__NR_getdents, fd, (uptr)dirp, count);
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
+#else
+  return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
+#endif
 }
 
 uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
-  return internal_syscall(__NR_lseek, fd, offset, whence);
+  return internal_syscall(SYSCALL(lseek), fd, offset, whence);
 }
 
+#if SANITIZER_LINUX
 uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
-  return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
+  return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
 }
+#endif
 
 uptr internal_sigaltstack(const struct sigaltstack *ss,
                          struct sigaltstack *oss) {
-  return internal_syscall(__NR_sigaltstack, (uptr)ss, (uptr)oss);
+  return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
 }
 
-uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
-    __sanitizer_kernel_sigaction_t *oldact) {
-  return internal_syscall(__NR_rt_sigaction, signum, act, oldact,
-      sizeof(__sanitizer_kernel_sigset_t));
+int internal_fork() {
+#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+  return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
+#else
+  return internal_syscall(SYSCALL(fork));
+#endif
 }
 
-uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
-    __sanitizer_kernel_sigset_t *oldset) {
-  return internal_syscall(__NR_rt_sigprocmask, (uptr)how, &set->sig[0],
-      &oldset->sig[0], sizeof(__sanitizer_kernel_sigset_t));
+#if SANITIZER_LINUX
+// Doesn't set sa_restorer, use with caution (see below).
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
+  __sanitizer_kernel_sigaction_t k_act, k_oldact;
+  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;
+  __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact;
+  if (u_act) {
+    k_act.handler = u_act->handler;
+    k_act.sigaction = u_act->sigaction;
+    internal_memcpy(&k_act.sa_mask, &u_act->sa_mask,
+                    sizeof(__sanitizer_kernel_sigset_t));
+    k_act.sa_flags = u_act->sa_flags;
+    // FIXME: most often sa_restorer is unset, however the kernel requires it
+    // to point to a valid signal restorer that calls the rt_sigreturn syscall.
+    // If sa_restorer passed to the kernel is NULL, the program may crash upon
+    // signal delivery or fail to unwind the stack in the signal handler.
+    // libc implementation of sigaction() passes its own restorer to
+    // rt_sigaction, so we need to do the same (we'll need to reimplement the
+    // restorers; for x86_64 the restorer address can be obtained from
+    // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
+    k_act.sa_restorer = u_act->sa_restorer;
+  }
+
+  uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
+      (uptr)(u_act ? &k_act : NULL),
+      (uptr)(u_oldact ? &k_oldact : NULL),
+      (uptr)sizeof(__sanitizer_kernel_sigset_t));
+
+  if ((result == 0) && u_oldact) {
+    u_oldact->handler = k_oldact.handler;
+    u_oldact->sigaction = k_oldact.sigaction;
+    internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
+                    sizeof(__sanitizer_kernel_sigset_t));
+    u_oldact->sa_flags = k_oldact.sa_flags;
+    u_oldact->sa_restorer = k_oldact.sa_restorer;
+  }
+  return result;
+}
+#endif  // SANITIZER_LINUX
+
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+    __sanitizer_sigset_t *oldset) {
+#if SANITIZER_FREEBSD
+  return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
+#else
+  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+  __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
+  return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how,
+                          (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0],
+                          sizeof(__sanitizer_kernel_sigset_t));
+#endif
 }
 
-void internal_sigfillset(__sanitizer_kernel_sigset_t *set) {
+void internal_sigfillset(__sanitizer_sigset_t *set) {
   internal_memset(set, 0xff, sizeof(*set));
 }
 
-void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum) {
+#if SANITIZER_LINUX
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
   signum -= 1;
   CHECK_GE(signum, 0);
   CHECK_LT(signum, sizeof(*set) * 8);
-  const uptr idx = signum / (sizeof(set->sig[0]) * 8);
-  const uptr bit = signum % (sizeof(set->sig[0]) * 8);
-  set->sig[idx] &= ~(1 << bit);
+  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+  const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
+  const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
+  k_set->sig[idx] &= ~(1 << bit);
 }
+#endif  // SANITIZER_LINUX
 
 // ThreadLister implementation.
 ThreadLister::ThreadLister(int pid)
@@ -700,7 +656,7 @@
 }
 
 uptr GetPageSize() {
-#if defined(__x86_64__) || defined(__i386__)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
   return EXEC_PAGESIZE;
 #else
   return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
@@ -755,8 +711,10 @@
 #if !SANITIZER_ANDROID
 // Call cb for each region mapped by map.
 void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+#if !SANITIZER_FREEBSD
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
+#endif  // !SANITIZER_FREEBSD
   char *base = (char *)map->l_addr;
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
@@ -790,7 +748,7 @@
 }
 #endif
 
-#if defined(__x86_64__)
+#if defined(__x86_64__) && SANITIZER_LINUX
 // We cannot use glibc's clone wrapper, because it messes with the child
 // task's TLS. It writes the PID and TID of the child task to its thread
 // descriptor, but in our case the child task shares the thread descriptor with
@@ -809,7 +767,7 @@
   register void *r8 __asm__("r8") = newtls;
   register int *r10 __asm__("r10") = child_tidptr;
   __asm__ __volatile__(
-                       /* %rax = syscall(%rax = __NR_clone,
+                       /* %rax = syscall(%rax = SYSCALL(clone),
                         *                %rdi = flags,
                         *                %rsi = child_stack,
                         *                %rdx = parent_tidptr,
@@ -843,7 +801,7 @@
                        /* Return to parent. */
                      "1:\n"
                        : "=a" (res)
-                       : "a"(__NR_clone), "i"(__NR_exit),
+                       : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
                          "S"(child_stack),
                          "D"(flags),
                          "d"(parent_tidptr),
@@ -852,7 +810,38 @@
                        : "rsp", "memory", "r11", "rcx");
   return res;
 }
-#endif  // defined(__x86_64__)
+#endif  // defined(__x86_64__) && SANITIZER_LINUX
+
+#if SANITIZER_ANDROID
+// This thing is not, strictly speaking, async signal safe, but it does not seem
+// to cause any issues. Alternative is writing to log devices directly, but
+// their location and message format might change in the future, so we'd really
+// like to avoid that.
+void AndroidLogWrite(const char *buffer) {
+  char *copy = internal_strdup(buffer);
+  char *p = copy;
+  char *q;
+  // __android_log_write has an implicit message length limit.
+  // Print one line at a time.
+  do {
+    q = internal_strchr(p, '\n');
+    if (q) *q = '\0';
+    __android_log_write(ANDROID_LOG_INFO, NULL, p);
+    if (q) p = q + 1;
+  } while (q);
+  InternalFree(copy);
+}
+
+void GetExtraActivationFlags(char *buf, uptr size) {
+  CHECK(size > PROP_VALUE_MAX);
+  __system_property_get("asan.options", buf);
+}
+#endif
+
+bool IsDeadlySignal(int signum) {
+  return (signum == SIGSEGV) && common_flags()->handle_segv;
+}
+
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index a32e9bf..3013c25 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -14,7 +14,7 @@
 #define SANITIZER_LINUX_H
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform_limits_posix.h"
@@ -29,20 +29,25 @@
 
 // Syscall wrappers.
 uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
-uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
 uptr internal_sigaltstack(const struct sigaltstack* ss,
                           struct sigaltstack* oss);
-uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
-    __sanitizer_kernel_sigaction_t *oldact);
-uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
-    __sanitizer_kernel_sigset_t *oldset);
-void internal_sigfillset(__sanitizer_kernel_sigset_t *set);
-void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum);
+uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
+    __sanitizer_sigset_t *oldset);
+void internal_sigfillset(__sanitizer_sigset_t *set);
 
-#ifdef __x86_64__
+// Linux-only syscalls.
+#if SANITIZER_LINUX
+uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
+// Used only by sanitizer_stoptheworld. Signal handlers that are actually used
+// (like the process-wide error reporting SEGV handler) must use
+// internal_sigaction instead.
+int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
+void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
+#if defined(__x86_64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr);
 #endif
+#endif  // SANITIZER_LINUX
 
 // This class reads thread IDs from /proc/<pid>/task using only syscalls.
 class ThreadLister {
@@ -66,8 +71,6 @@
   int bytes_read_;
 };
 
-void AdjustStackSizeLinux(void *attr);
-
 // Exposed for testing.
 uptr ThreadDescriptorSize();
 uptr ThreadSelf();
@@ -86,5 +89,5 @@
 void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
 #endif  // SANITIZER_LINUX_H
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index 2940686..396a0a8 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
@@ -21,23 +21,58 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_symbolizer.h"
 
 #include <dlfcn.h>
 #include <pthread.h>
-#include <sys/prctl.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>
+#define pthread_getattr_np pthread_attr_get_np
+#endif
+
+#if SANITIZER_LINUX
+#include <sys/prctl.h>
+#endif
+
 #if !SANITIZER_ANDROID
 #include <elf.h>
 #include <link.h>
+#include <unistd.h>
 #endif
 
 namespace __sanitizer {
 
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE int
+real_pthread_attr_getstack(void *attr, void **addr, size_t *size);
+}  // extern "C"
+
+static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
+  if (real_pthread_attr_getstack)
+    return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+  return pthread_attr_getstack((pthread_attr_t *)attr, addr, size);
+}
+
+SANITIZER_WEAK_ATTRIBUTE int
+real_sigaction(int signum, const void *act, void *oldact);
+
+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);
+}
+
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom) {
-  static const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
   CHECK(stack_top);
   CHECK(stack_bottom);
   if (at_initialization) {
@@ -71,10 +106,11 @@
     return;
   }
   pthread_attr_t attr;
+  pthread_attr_init(&attr);
   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
   uptr stacksize = 0;
   void *stackaddr = 0;
-  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+  my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
   pthread_attr_destroy(&attr);
 
   CHECK_LE(stacksize, kMaxThreadStackSize);  // Sanity check.
@@ -82,8 +118,6 @@
   *stack_bottom = (uptr)stackaddr;
 }
 
-// Does not compile for Go because dlsym() requires -ldl
-#ifndef SANITIZER_GO
 bool SetEnv(const char *name, const char *value) {
   void *f = dlsym(RTLD_NEXT, "setenv");
   if (f == 0)
@@ -92,9 +126,8 @@
   setenv_ft setenv_f;
   CHECK_EQ(sizeof(setenv_f), sizeof(f));
   internal_memcpy(&setenv_f, &f, sizeof(f));
-  return setenv_f(name, value, 1) == 0;
+  return IndirectExternCall(setenv_f)(name, value, 1) == 0;
 }
-#endif
 
 bool SanitizerSetThreadName(const char *name) {
 #ifdef PR_SET_NAME
@@ -117,8 +150,52 @@
 #endif
 }
 
-#ifndef SANITIZER_GO
 //------------------------- 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
@@ -155,9 +232,8 @@
 }
 
 void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+  CHECK_GE(max_depth, 2);
   size = 0;
-  if (max_depth == 0)
-    return;
   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.
@@ -169,9 +245,35 @@
   trace[0] = pc;
 }
 
-#endif  // !SANITIZER_GO
+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
 
 #ifdef __i386__
 # define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
@@ -180,7 +282,7 @@
 #endif
 
 void InitTlsSize() {
-#if !defined(SANITIZER_GO) && !SANITIZER_ANDROID
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID
   typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
   get_tls_func get_tls;
   void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
@@ -190,27 +292,50 @@
   CHECK_NE(get_tls, 0);
   size_t tls_size = 0;
   size_t tls_align = 0;
-  get_tls(&tls_size, &tls_align);
+  IndirectExternCall(get_tls)(&tls_size, &tls_align);
   g_tls_size = tls_size;
-#endif
+#endif  // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
 }
 
-uptr GetTlsSize() {
-  return g_tls_size;
-}
-
-#if defined(__x86_64__) || defined(__i386__)
+#if (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
 // sizeof(struct thread) from glibc.
-// There has been a report of this being different on glibc 2.11 and 2.13. We
-// don't know when this change happened, so 2.14 is a conservative estimate.
-#if __GLIBC_PREREQ(2, 14)
-const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304);
-#else
-const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1168, 2304);
-#endif
+static atomic_uintptr_t kThreadDescriptorSize;
 
 uptr ThreadDescriptorSize() {
-  return kThreadDescriptorSize;
+  char buf[64];
+  uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
+  if (val)
+    return val;
+#ifdef _CS_GNU_LIBC_VERSION
+  uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
+  if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
+    char *end;
+    int minor = internal_simple_strtoll(buf + 8, &end, 10);
+    if (end != buf + 8 && (*end == '\0' || *end == '.')) {
+      /* sizeof(struct thread) values from various glibc versions.  */
+      if (SANITIZER_X32)
+        val = 1728;  // Assume only one particular version for x32.
+      else if (minor <= 3)
+        val = FIRST_32_SECOND_64(1104, 1696);
+      else if (minor == 4)
+        val = FIRST_32_SECOND_64(1120, 1728);
+      else if (minor == 5)
+        val = FIRST_32_SECOND_64(1136, 1728);
+      else if (minor <= 9)
+        val = FIRST_32_SECOND_64(1136, 1712);
+      else if (minor == 10)
+        val = FIRST_32_SECOND_64(1168, 1776);
+      else if (minor <= 12)
+        val = FIRST_32_SECOND_64(1168, 2288);
+      else
+        val = FIRST_32_SECOND_64(1216, 2304);
+    }
+    if (val)
+      atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+    return val;
+  }
+#endif
+  return 0;
 }
 
 // The offset at which pointer to self is located in the thread descriptor.
@@ -222,27 +347,79 @@
 
 uptr ThreadSelf() {
   uptr descr_addr;
-#ifdef __i386__
+# if defined(__i386__)
   asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#else
+# elif defined(__x86_64__)
   asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
-#endif
+# else
+#  error "unsupported CPU arch"
+# endif
   return descr_addr;
 }
-#endif  // defined(__x86_64__) || defined(__i386__)
+#endif  // (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
+
+#if SANITIZER_FREEBSD
+static void **ThreadSelfSegbase() {
+  void **segbase = 0;
+# if defined(__i386__)
+  // sysarch(I386_GET_GSBASE, segbase);
+  __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
+# elif defined(__x86_64__)
+  // sysarch(AMD64_GET_FSBASE, segbase);
+  __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
+# else
+#  error "unsupported CPU arch for FreeBSD platform"
+# endif
+  return segbase;
+}
+
+uptr ThreadSelf() {
+  return (uptr)ThreadSelfSegbase()[2];
+}
+#endif  // SANITIZER_FREEBSD
+
+static void GetTls(uptr *addr, uptr *size) {
+#if SANITIZER_LINUX
+# if defined(__x86_64__) || defined(__i386__)
+  *addr = ThreadSelf();
+  *size = GetTlsSize();
+  *addr -= *size;
+  *addr += ThreadDescriptorSize();
+# else
+  *addr = 0;
+  *size = 0;
+# endif
+#elif SANITIZER_FREEBSD
+  void** segbase = ThreadSelfSegbase();
+  *addr = 0;
+  *size = 0;
+  if (segbase != 0) {
+    // tcbalign = 16
+    // tls_size = round(tls_static_space, tcbalign);
+    // dtv = segbase[1];
+    // dtv[2] = segbase - tls_static_space;
+    void **dtv = (void**) segbase[1];
+    *addr = (uptr) dtv[2];
+    *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
+  }
+#else
+# error "Unknown OS"
+#endif
+}
+
+uptr GetTlsSize() {
+#if SANITIZER_FREEBSD
+  uptr addr, size;
+  GetTls(&addr, &size);
+  return size;
+#else
+  return g_tls_size;
+#endif
+}
 
 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
                           uptr *tls_addr, uptr *tls_size) {
-#ifndef SANITIZER_GO
-#if defined(__x86_64__) || defined(__i386__)
-  *tls_addr = ThreadSelf();
-  *tls_size = GetTlsSize();
-  *tls_addr -= *tls_size;
-  *tls_addr += kThreadDescriptorSize;
-#else
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif
+  GetTls(tls_addr, tls_size);
 
   uptr stack_top, stack_bottom;
   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
@@ -258,19 +435,13 @@
       *tls_addr = *stk_addr + *stk_size;
     }
   }
-#else  // SANITIZER_GO
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif  // SANITIZER_GO
 }
 
-void AdjustStackSizeLinux(void *attr_) {
+void AdjustStackSize(void *attr_) {
   pthread_attr_t *attr = (pthread_attr_t *)attr_;
   uptr stackaddr = 0;
   size_t stacksize = 0;
-  pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+  my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
   // GLibC will return (0 - stacksize) as the stack address in the case when
   // stacksize is set, but stackaddr is not.
   bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
@@ -278,10 +449,11 @@
   const uptr minstacksize = GetTlsSize() + 128*1024;
   if (stacksize < minstacksize) {
     if (!stack_set) {
-      if (common_flags()->verbosity && stacksize != 0)
-        Printf("Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
-               minstacksize);
-      pthread_attr_setstacksize(attr, minstacksize);
+      if (stacksize != 0) {
+        VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
+                minstacksize);
+        pthread_attr_setstacksize(attr, minstacksize);
+      }
     } else {
       Printf("Sanitizer: pre-allocated stack size is insufficient: "
              "%zu < %zu\n", stacksize, minstacksize);
@@ -293,10 +465,13 @@
 #if SANITIZER_ANDROID
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                       string_predicate_t filter) {
-  return 0;
+  MemoryMappingLayout memory_mapping(false);
+  return memory_mapping.DumpListOfModules(modules, max_modules, filter);
 }
 #else  // SANITIZER_ANDROID
+# if !SANITIZER_FREEBSD
 typedef ElfW(Phdr) Elf_Phdr;
+# endif
 
 struct DlIteratePhdrData {
   LoadedModule *modules;
@@ -347,6 +522,28 @@
 }
 #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
+  // process will be able to load additional libraries, so it's fine to use the
+  // cached mappings.
+  MemoryMappingLayout::CacheMemoryMappings();
+  // Same for /proc/self/exe in the symbolizer.
+#if !SANITIZER_GO
+  if (Symbolizer *sym = Symbolizer::GetOrNull())
+    sym->PrepareForSandboxing();
+  CovPrepareForSandboxing(args);
+#endif
+}
+
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_list.h b/lib/sanitizer_common/sanitizer_list.h
index f61d28f..a47bc7d 100644
--- a/lib/sanitizer_common/sanitizer_list.h
+++ b/lib/sanitizer_common/sanitizer_list.h
@@ -26,6 +26,8 @@
 // non-zero-initialized objects before using.
 template<class Item>
 struct IntrusiveList {
+  friend class Iterator;
+
   void clear() {
     first_ = last_ = 0;
     size_ = 0;
@@ -113,6 +115,21 @@
     }
   }
 
+  class Iterator {
+   public:
+    explicit Iterator(IntrusiveList<Item> *list)
+        : list_(list), current_(list->first_) { }
+    Item *next() {
+      Item *ret = current_;
+      if (current_) current_ = current_->next;
+      return ret;
+    }
+    bool hasNext() const { return current_ != 0; }
+   private:
+    IntrusiveList<Item> *list_;
+    Item *current_;
+  };
+
 // private, don't use directly.
   uptr size_;
   Item *first_;
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 87ad8b5..5985bd2 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -7,9 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries and implements mac-specific functions from
-// sanitizer_libc.h.
+// This file is shared between various sanitizers' runtime libraries and
+// implements OSX-specific functions.
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
@@ -23,20 +22,22 @@
 #include <stdio.h>
 
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
+#include "sanitizer_mac.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
 #include <crt_externs.h>  // for _NSGetEnviron
 #include <fcntl.h>
-#include <mach-o/dyld.h>
-#include <mach-o/loader.h>
 #include <pthread.h>
 #include <sched.h>
+#include <signal.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
+#include <sys/sysctl.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <libkern/OSAtomic.h>
@@ -120,6 +121,24 @@
   return getpid();
 }
 
+int internal_sigaction(int signum, const void *act, void *oldact) {
+  return sigaction(signum,
+                   (struct sigaction *)act, (struct sigaction *)oldact);
+}
+
+int internal_fork() {
+  // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
+  return fork();
+}
+
+uptr internal_rename(const char *oldpath, const char *newpath) {
+  return rename(oldpath, newpath);
+}
+
+uptr internal_ftruncate(fd_t fd, uptr size) {
+  return ftruncate(fd, size);
+}
+
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
   struct stat st;
@@ -138,6 +157,20 @@
   CHECK(stack_top);
   CHECK(stack_bottom);
   uptr stacksize = pthread_get_stacksize_np(pthread_self());
+  // 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 &&
+      stacksize == (1 << 19))  {
+    struct rlimit rl;
+    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
+    // Most often rl.rlim_cur will be the desired 8M.
+    if (rl.rlim_cur < kMaxThreadStackSize) {
+      stacksize = rl.rlim_cur;
+    } else {
+      stacksize = kMaxThreadStackSize;
+    }
+  }
   void *stackaddr = pthread_get_stackaddr_np(pthread_self());
   *stack_top = (uptr)stackaddr;
   *stack_bottom = *stack_top - stacksize;
@@ -171,7 +204,8 @@
   UNIMPLEMENTED();
 }
 
-void PrepareForSandboxing() {
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  (void)args;
   // Nothing here for now.
 }
 
@@ -179,148 +213,6 @@
   return sysconf(_SC_PAGESIZE);
 }
 
-// ----------------- sanitizer_procmaps.h
-
-MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
-  Reset();
-}
-
-MemoryMappingLayout::~MemoryMappingLayout() {
-}
-
-// More information about Mach-O headers can be found in mach-o/loader.h
-// Each Mach-O image has a header (mach_header or mach_header_64) starting with
-// a magic number, and a list of linker load commands directly following the
-// header.
-// A load command is at least two 32-bit words: the command type and the
-// command size in bytes. We're interested only in segment load commands
-// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
-// into the task's address space.
-// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
-// segment_command_64 correspond to the memory address, memory size and the
-// file offset of the current memory segment.
-// Because these fields are taken from the images as is, one needs to add
-// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
-
-void MemoryMappingLayout::Reset() {
-  // Count down from the top.
-  // TODO(glider): as per man 3 dyld, iterating over the headers with
-  // _dyld_image_count is thread-unsafe. We need to register callbacks for
-  // adding and removing images which will invalidate the MemoryMappingLayout
-  // state.
-  current_image_ = _dyld_image_count();
-  current_load_cmd_count_ = -1;
-  current_load_cmd_addr_ = 0;
-  current_magic_ = 0;
-  current_filetype_ = 0;
-}
-
-// static
-void MemoryMappingLayout::CacheMemoryMappings() {
-  // No-op on Mac for now.
-}
-
-void MemoryMappingLayout::LoadFromCache() {
-  // No-op on Mac for now.
-}
-
-// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
-// Google Perftools, http://code.google.com/p/google-perftools.
-
-// NextSegmentLoad scans the current image for the next segment load command
-// and returns the start and end addresses and file offset of the corresponding
-// segment.
-// Note that the segment addresses are not necessarily sorted.
-template<u32 kLCSegment, typename SegmentCommand>
-bool MemoryMappingLayout::NextSegmentLoad(
-    uptr *start, uptr *end, uptr *offset,
-    char filename[], uptr filename_size, uptr *protection) {
-  if (protection)
-    UNIMPLEMENTED();
-  const char* lc = current_load_cmd_addr_;
-  current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
-  if (((const load_command *)lc)->cmd == kLCSegment) {
-    const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
-    const SegmentCommand* sc = (const SegmentCommand *)lc;
-    if (start) *start = sc->vmaddr + dlloff;
-    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
-    if (offset) {
-      if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
-        *offset = sc->vmaddr;
-      } else {
-        *offset = sc->fileoff;
-      }
-    }
-    if (filename) {
-      internal_strncpy(filename, _dyld_get_image_name(current_image_),
-                       filename_size);
-    }
-    return true;
-  }
-  return false;
-}
-
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
-                               char filename[], uptr filename_size,
-                               uptr *protection) {
-  for (; current_image_ >= 0; current_image_--) {
-    const mach_header* hdr = _dyld_get_image_header(current_image_);
-    if (!hdr) continue;
-    if (current_load_cmd_count_ < 0) {
-      // Set up for this image;
-      current_load_cmd_count_ = hdr->ncmds;
-      current_magic_ = hdr->magic;
-      current_filetype_ = hdr->filetype;
-      switch (current_magic_) {
-#ifdef MH_MAGIC_64
-        case MH_MAGIC_64: {
-          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
-          break;
-        }
-#endif
-        case MH_MAGIC: {
-          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
-          break;
-        }
-        default: {
-          continue;
-        }
-      }
-    }
-
-    for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
-      switch (current_magic_) {
-        // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
-#ifdef MH_MAGIC_64
-        case MH_MAGIC_64: {
-          if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
-                  start, end, offset, filename, filename_size, protection))
-            return true;
-          break;
-        }
-#endif
-        case MH_MAGIC: {
-          if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
-                  start, end, offset, filename, filename_size, protection))
-            return true;
-          break;
-        }
-      }
-    }
-    // If we get here, no more load_cmd's in this image talk about
-    // segments.  Go on to the next image.
-  }
-  return false;
-}
-
-bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
-                                                 char filename[],
-                                                 uptr filename_size,
-                                                 uptr *protection) {
-  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
-                                       protection);
-}
-
 BlockingMutex::BlockingMutex(LinkerInitialized) {
   // We assume that OS_SPINLOCK_INIT is zero
 }
@@ -379,32 +271,49 @@
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                       string_predicate_t filter) {
   MemoryMappingLayout memory_mapping(false);
-  memory_mapping.Reset();
-  uptr cur_beg, cur_end, cur_offset;
-  InternalScopedBuffer<char> module_name(kMaxPathLength);
-  uptr n_modules = 0;
-  for (uptr i = 0;
-       n_modules < max_modules &&
-           memory_mapping.Next(&cur_beg, &cur_end, &cur_offset,
-                               module_name.data(), module_name.size(), 0);
-       i++) {
-    const char *cur_name = module_name.data();
-    if (cur_name[0] == '\0')
-      continue;
-    if (filter && !filter(cur_name))
-      continue;
-    LoadedModule *cur_module = 0;
-    if (n_modules > 0 &&
-        0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
-      cur_module = &modules[n_modules - 1];
-    } else {
-      void *mem = &modules[n_modules];
-      cur_module = new(mem) LoadedModule(cur_name, cur_beg);
-      n_modules++;
+  return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+}
+
+bool IsDeadlySignal(int signum) {
+  return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+}
+
+MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
+
+MacosVersion GetMacosVersionInternal() {
+  int mib[2] = { CTL_KERN, KERN_OSRELEASE };
+  char version[100];
+  uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
+  for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
+  // Get the version length.
+  CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
+  CHECK_LT(len, maxlen);
+  CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
+  switch (version[0]) {
+    case '9': return MACOS_VERSION_LEOPARD;
+    case '1': {
+      switch (version[1]) {
+        case '0': return MACOS_VERSION_SNOW_LEOPARD;
+        case '1': return MACOS_VERSION_LION;
+        case '2': return MACOS_VERSION_MOUNTAIN_LION;
+        case '3': return MACOS_VERSION_MAVERICKS;
+        default: return MACOS_VERSION_UNKNOWN;
+      }
     }
-    cur_module->addAddressRange(cur_beg, cur_end);
+    default: return MACOS_VERSION_UNKNOWN;
   }
-  return n_modules;
+}
+
+MacosVersion GetMacosVersion() {
+  atomic_uint32_t *cache =
+      reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
+  MacosVersion result =
+      static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
+  if (result == MACOS_VERSION_UNINITIALIZED) {
+    result = GetMacosVersionInternal();
+    atomic_store(cache, result, memory_order_release);
+  }
+  return result;
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h
new file mode 100644
index 0000000..fae784a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_mac.h
@@ -0,0 +1,36 @@
+//===-- sanitizer_mac.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries and
+// provides definitions for OSX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_MAC_H
+#define SANITIZER_MAC_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+
+namespace __sanitizer {
+
+enum MacosVersion {
+  MACOS_VERSION_UNINITIALIZED = 0,
+  MACOS_VERSION_UNKNOWN,
+  MACOS_VERSION_LEOPARD,
+  MACOS_VERSION_SNOW_LEOPARD,
+  MACOS_VERSION_LION,
+  MACOS_VERSION_MOUNTAIN_LION,
+  MACOS_VERSION_MAVERICKS
+};
+
+MacosVersion GetMacosVersion();
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_MAC
+#endif  // SANITIZER_MAC_H
diff --git a/lib/sanitizer_common/sanitizer_mutex.h b/lib/sanitizer_common/sanitizer_mutex.h
index e812fce..c7589f7 100644
--- a/lib/sanitizer_common/sanitizer_mutex.h
+++ b/lib/sanitizer_common/sanitizer_mutex.h
@@ -83,6 +83,88 @@
   uptr owner_;  // for debugging
 };
 
+// Reader-writer spin mutex.
+class RWMutex {
+ public:
+  RWMutex() {
+    atomic_store(&state_, kUnlocked, memory_order_relaxed);
+  }
+
+  ~RWMutex() {
+    CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+  }
+
+  void Lock() {
+    u32 cmp = kUnlocked;
+    if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
+                                       memory_order_acquire))
+      return;
+    LockSlow();
+  }
+
+  void Unlock() {
+    u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
+    DCHECK_NE(prev & kWriteLock, 0);
+    (void)prev;
+  }
+
+  void ReadLock() {
+    u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
+    if ((prev & kWriteLock) == 0)
+      return;
+    ReadLockSlow();
+  }
+
+  void ReadUnlock() {
+    u32 prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
+    DCHECK_EQ(prev & kWriteLock, 0);
+    DCHECK_GT(prev & ~kWriteLock, 0);
+    (void)prev;
+  }
+
+  void CheckLocked() {
+    CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked);
+  }
+
+ private:
+  atomic_uint32_t state_;
+
+  enum {
+    kUnlocked = 0,
+    kWriteLock = 1,
+    kReadLock = 2
+  };
+
+  void NOINLINE LockSlow() {
+    for (int i = 0;; i++) {
+      if (i < 10)
+        proc_yield(10);
+      else
+        internal_sched_yield();
+      u32 cmp = atomic_load(&state_, memory_order_relaxed);
+      if (cmp == kUnlocked &&
+          atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
+                                       memory_order_acquire))
+          return;
+    }
+  }
+
+  void NOINLINE ReadLockSlow() {
+    for (int i = 0;; i++) {
+      if (i < 10)
+        proc_yield(10);
+      else
+        internal_sched_yield();
+      u32 prev = atomic_load(&state_, memory_order_acquire);
+      if ((prev & kWriteLock) == 0)
+        return;
+    }
+  }
+
+  RWMutex(const RWMutex&);
+  void operator = (const RWMutex&);
+};
+
 template<typename MutexType>
 class GenericScopedLock {
  public:
@@ -123,6 +205,8 @@
 
 typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock;
 typedef GenericScopedLock<BlockingMutex> BlockingMutexLock;
+typedef GenericScopedLock<RWMutex> RWMutexLock;
+typedef GenericScopedReadLock<RWMutex> RWMutexReadLock;
 
 }  // namespace __sanitizer
 
diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.cc b/lib/sanitizer_common/sanitizer_persistent_allocator.cc
new file mode 100644
index 0000000..5fa533a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_persistent_allocator.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_persistent_allocator.cc -----------------------*- 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 AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+PersistentAllocator thePersistentAllocator;
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.h b/lib/sanitizer_common/sanitizer_persistent_allocator.h
new file mode 100644
index 0000000..326406b
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_persistent_allocator.h
@@ -0,0 +1,71 @@
+//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A fast memory allocator that does not support free() nor realloc().
+// All allocations are forever.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
+#define SANITIZER_PERSISTENT_ALLOCATOR_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+class PersistentAllocator {
+ public:
+  void *alloc(uptr size);
+
+ private:
+  void *tryAlloc(uptr size);
+  StaticSpinMutex mtx;  // Protects alloc of new blocks for region allocator.
+  atomic_uintptr_t region_pos;  // Region allocator for Node's.
+  atomic_uintptr_t region_end;
+};
+
+inline void *PersistentAllocator::tryAlloc(uptr size) {
+  // Optimisic lock-free allocation, essentially try to bump the region ptr.
+  for (;;) {
+    uptr cmp = atomic_load(&region_pos, memory_order_acquire);
+    uptr end = atomic_load(&region_end, memory_order_acquire);
+    if (cmp == 0 || cmp + size > end) return 0;
+    if (atomic_compare_exchange_weak(&region_pos, &cmp, cmp + size,
+                                     memory_order_acquire))
+      return (void *)cmp;
+  }
+}
+
+inline void *PersistentAllocator::alloc(uptr size) {
+  // First, try to allocate optimisitically.
+  void *s = tryAlloc(size);
+  if (s) return s;
+  // If failed, lock, retry and alloc new superblock.
+  SpinMutexLock l(&mtx);
+  for (;;) {
+    s = tryAlloc(size);
+    if (s) return s;
+    atomic_store(&region_pos, 0, memory_order_relaxed);
+    uptr allocsz = 64 * 1024;
+    if (allocsz < size) allocsz = size;
+    uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
+    atomic_store(&region_end, mem + allocsz, memory_order_release);
+    atomic_store(&region_pos, mem, memory_order_release);
+  }
+}
+
+extern PersistentAllocator thePersistentAllocator;
+inline void *PersistentAlloc(uptr sz) {
+  return thePersistentAllocator.alloc(sz);
+}
+
+} // namespace __sanitizer
+
+#endif  // SANITIZER_PERSISTENT_ALLOCATOR_H
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index fce721e..d9a7868 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -13,7 +13,8 @@
 #ifndef SANITIZER_PLATFORM_H
 #define SANITIZER_PLATFORM_H
 
-#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
+#if !defined(__linux__) && !defined(__FreeBSD__) && \
+  !defined(__APPLE__) && !defined(_WIN32)
 # error "This operating system is not supported"
 #endif
 
@@ -23,6 +24,12 @@
 # define SANITIZER_LINUX   0
 #endif
 
+#if defined(__FreeBSD__)
+# define SANITIZER_FREEBSD 1
+#else
+# define SANITIZER_FREEBSD 0
+#endif
+
 #if defined(__APPLE__)
 # define SANITIZER_MAC     1
 # include <TargetConditionals.h>
@@ -48,6 +55,58 @@
 # define SANITIZER_ANDROID 0
 #endif
 
-#define SANITIZER_POSIX (SANITIZER_LINUX || SANITIZER_MAC)
+#define SANITIZER_POSIX (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC)
+
+#if __LP64__ || defined(_WIN64)
+#  define SANITIZER_WORDSIZE 64
+#else
+#  define SANITIZER_WORDSIZE 32
+#endif
+
+#if SANITIZER_WORDSIZE == 64
+# define FIRST_32_SECOND_64(a, b) (b)
+#else
+# define FIRST_32_SECOND_64(a, b) (a)
+#endif
+
+#if defined(__x86_64__) && !defined(_LP64)
+# define SANITIZER_X32 1
+#else
+# define SANITIZER_X32 0
+#endif
+
+// By default we allow to use SizeClassAllocator64 on 64-bit platform.
+// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
+// does not work well and we need to fallback to SizeClassAllocator32.
+// 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__)
+#  define SANITIZER_CAN_USE_ALLOCATOR64 0
+# else
+#  define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
+# endif
+#endif
+
+// The range of addresses which can be returned my mmap.
+// FIXME: this value should be different on different platforms,
+// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work
+// but will consume more memory for TwoLevelByteMap.
+#if defined(__aarch64__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39)
+#else
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+#endif
+
+// The AArch64 linux port uses the canonical syscall set as mandated by
+// the upstream linux community for all new ports. Other ports may still
+// use legacy syscalls.
+#ifndef SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+# if defined(__aarch64__) && SANITIZER_LINUX
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 1
+# else
+# define SANITIZER_USES_CANONICAL_LINUX_SYSCALLS 0
+# endif
+#endif
 
 #endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 78d1f5a..a51a00c 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -47,13 +47,16 @@
 # define SI_IOS 0
 #endif
 
-# define SANITIZER_INTERCEPT_STRCMP 1
-# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRCMP 1
+#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MEMCHR 1
+#define SANITIZER_INTERCEPT_MEMRCHR SI_LINUX
 
-# define SANITIZER_INTERCEPT_READ   SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PREAD  SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_WRITE  SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READ   SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PREAD  SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WRITE  SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
 
 #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
@@ -66,105 +69,140 @@
 #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
 
-# define SANITIZER_INTERCEPT_PRCTL   SI_LINUX
+#define SANITIZER_INTERCEPT_PRCTL   SI_LINUX
 
-# define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
 
-# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
+#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
 
-# define SANITIZER_INTERCEPT_FREXP 1
-# define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
+#ifndef SANITIZER_INTERCEPT_PRINTF
+# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX
+#endif
 
-# define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
-    SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
-# define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
-# define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
-# define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
-# define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
-  (defined(__i386) || defined (__x86_64))  // NOLINT
-# define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
-# define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
-# define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_WORDEXP SI_MAC || SI_LINUX_NOT_ANDROID
-# 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_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
-# define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_STATFS64 \
-    (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SHMCTL SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
+#define SANITIZER_INTERCEPT_FREXP 1
+#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
+
+#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
   SI_MAC || SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_SINCOS SI_LINUX
-# define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
-# define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETPWENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SETPWENT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX
+#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX
+#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX
+#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
+#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
+   (defined(__i386) || defined (__x86_64))  // NOLINT
+#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX
+#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX
+#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WORDEXP (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#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_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
+#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STATFS64 \
+  (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SHMCTL \
+  (SI_LINUX_NOT_ANDROID && SANITIZER_WORDSIZE == 64)
+#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
+  SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SINCOS SI_LINUX
+#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
+#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS
 
 // FIXME: getline seems to be available on OSX 10.7
-# define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
 
-# define SANITIZER_INTERCEPT__EXIT SI_LINUX
+#define SANITIZER_INTERCEPT__EXIT SI_LINUX
 
-# define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_COND SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX
+#define SANITIZER_INTERCEPT_GETRESID SI_LINUX
+#define SANITIZER_INTERCEPT_GETIFADDRS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_IF_INDEXTONAME SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__)
+#define SANITIZER_INTERCEPT___BZERO SI_MAC
+#define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID
+#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
 
 #endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
index 4c9f12a..66c6ab9 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -29,6 +29,9 @@
 // are not defined anywhere in userspace headers. Fake them. This seems to work
 // fine with newer headers, too.
 #include <asm/posix_types.h>
+#if defined(__x86_64__)
+#include <sys/stat.h>
+#else
 #define ino_t __kernel_ino_t
 #define mode_t __kernel_mode_t
 #define nlink_t __kernel_nlink_t
@@ -43,6 +46,7 @@
 #undef uid_t
 #undef gid_t
 #undef off_t
+#endif
 
 #include <linux/aio_abi.h>
 
@@ -60,7 +64,7 @@
   unsigned struct_statfs64_sz = sizeof(struct statfs64);
 }  // namespace __sanitizer
 
-#if !defined(__powerpc64__)
+#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)
 COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
 #endif
 
@@ -70,7 +74,11 @@
 COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
 #endif
 
-COMPILER_CHECK(struct_io_event_sz == sizeof(struct io_event));
+CHECK_TYPE_SIZE(io_event);
+CHECK_SIZE_AND_OFFSET(io_event, data);
+CHECK_SIZE_AND_OFFSET(io_event, obj);
+CHECK_SIZE_AND_OFFSET(io_event, res);
+CHECK_SIZE_AND_OFFSET(io_event, res2);
 
 #if !SANITIZER_ANDROID
 COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
@@ -81,6 +89,10 @@
 
 COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
 COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
+COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);
+#endif
 
 CHECK_TYPE_SIZE(iocb);
 CHECK_SIZE_AND_OFFSET(iocb, aio_data);
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 3d9b76a..524eec3 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -14,10 +14,7 @@
 
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
-
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_platform_limits_posix.h"
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
 
 #include <arpa/inet.h>
 #include <dirent.h>
@@ -33,10 +30,12 @@
 #include <pwd.h>
 #include <signal.h>
 #include <stddef.h>
+#include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/timeb.h>
 #include <sys/times.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -44,12 +43,14 @@
 #include <time.h>
 #include <wchar.h>
 
+#if !SANITIZER_ANDROID
+#include <sys/mount.h>
+#endif
+
 #if SANITIZER_LINUX
+#include <malloc.h>
 #include <mntent.h>
 #include <netinet/ether.h>
-#include <utime.h>
-#include <sys/mount.h>
-#include <sys/ptrace.h>
 #include <sys/sysinfo.h>
 #include <sys/vt.h>
 #include <linux/cdrom.h>
@@ -64,18 +65,63 @@
 #include <linux/posix_types.h>
 #endif
 
+#if SANITIZER_FREEBSD
+# include <sys/mount.h>
+# include <sys/sockio.h>
+# include <sys/socket.h>
+# include <sys/filio.h>
+# include <sys/signal.h>
+# include <sys/timespec.h>
+# include <sys/timex.h>
+# include <sys/mqueue.h>
+# include <sys/msg.h>
+# include <sys/ipc.h>
+# include <sys/msg.h>
+# include <sys/statvfs.h>
+# include <sys/soundcard.h>
+# include <sys/mtio.h>
+# include <sys/consio.h>
+# include <sys/kbio.h>
+# include <sys/link_elf.h>
+# include <netinet/ip_mroute.h>
+# include <netinet/in.h>
+# include <netinet/ip_compat.h>
+# include <net/ethernet.h>
+# include <net/ppp_defs.h>
+# include <glob.h>
+# include <term.h>
+
+#define _KERNEL  // to declare 'shminfo' structure
+# include <sys/shm.h>
+#undef _KERNEL
+
+#undef INLINE  // to avoid clashes with sanitizers' definitions
+#endif
+
+#if SANITIZER_FREEBSD || SANITIZER_IOS
+#undef IOC_DIRMASK
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+# include <utime.h>
+# include <sys/ptrace.h>
+#endif
+
 #if !SANITIZER_ANDROID
+#include <ifaddrs.h>
 #include <sys/ucontext.h>
 #include <wordexp.h>
 #endif
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
 #include <glob.h>
+#include <obstack.h>
 #include <mqueue.h>
 #include <net/if_ppp.h>
 #include <netax25/ax25.h>
 #include <netipx/ipx.h>
 #include <netrom/netrom.h>
+#include <rpc/xdr.h>
 #include <scsi/scsi.h>
 #include <sys/mtio.h>
 #include <sys/kd.h>
@@ -94,7 +140,6 @@
 #include <linux/serial.h>
 #include <sys/msg.h>
 #include <sys/ipc.h>
-#include <sys/shm.h>
 #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
 #if SANITIZER_ANDROID
@@ -114,16 +159,19 @@
 #if SANITIZER_MAC
 #include <net/ethernet.h>
 #include <sys/filio.h>
-#include <sys/mount.h>
 #include <sys/sockio.h>
 #endif
 
+// Include these after system headers to avoid name clashes and ambiguities.
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
 namespace __sanitizer {
   unsigned struct_utsname_sz = sizeof(struct utsname);
   unsigned struct_stat_sz = sizeof(struct stat);
-#if !SANITIZER_IOS
+#if !SANITIZER_IOS && !SANITIZER_FREEBSD
   unsigned struct_stat64_sz = sizeof(struct stat64);
-#endif // !SANITIZER_IOS
+#endif  // !SANITIZER_IOS && !SANITIZER_FREEBSD
   unsigned struct_rusage_sz = sizeof(struct rusage);
   unsigned struct_tm_sz = sizeof(struct tm);
   unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -136,6 +184,7 @@
   unsigned pid_t_sz = sizeof(pid_t);
   unsigned timeval_sz = sizeof(timeval);
   unsigned uid_t_sz = sizeof(uid_t);
+  unsigned gid_t_sz = sizeof(gid_t);
   unsigned mbstate_t_sz = sizeof(mbstate_t);
   unsigned sigset_t_sz = sizeof(sigset_t);
   unsigned struct_timezone_sz = sizeof(struct timezone);
@@ -149,33 +198,40 @@
 #endif // SANITIZER_MAC && !SANITIZER_IOS
 
 #if !SANITIZER_ANDROID
+  unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
   unsigned ucontext_t_sz = sizeof(ucontext_t);
 #endif // !SANITIZER_ANDROID
 
 #if SANITIZER_LINUX
-  unsigned struct_rlimit_sz = sizeof(struct rlimit);
   unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
   unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
-  unsigned struct_timespec_sz = sizeof(struct timespec);
   unsigned __user_cap_header_struct_sz =
       sizeof(struct __user_cap_header_struct);
   unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct);
-  unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
   unsigned struct_new_utsname_sz = sizeof(struct new_utsname);
   unsigned struct_old_utsname_sz = sizeof(struct old_utsname);
   unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
+#endif  // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+  unsigned struct_rlimit_sz = sizeof(struct rlimit);
+  unsigned struct_timespec_sz = sizeof(struct timespec);
+  unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
   unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
-#endif // SANITIZER_LINUX
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_ustat_sz = sizeof(struct ustat);
   unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
+  unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   unsigned struct_timex_sz = sizeof(struct timex);
   unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
   unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
   unsigned struct_statvfs_sz = sizeof(struct statvfs);
-  unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 
   uptr sig_ign = (uptr)SIG_IGN;
   uptr sig_dfl = (uptr)SIG_DFL;
@@ -186,15 +242,17 @@
 #endif
 
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   unsigned struct_shminfo_sz = sizeof(struct shminfo);
   unsigned struct_shm_info_sz = sizeof(struct shm_info);
   int shmctl_ipc_stat = (int)IPC_STAT;
   int shmctl_ipc_info = (int)IPC_INFO;
   int shmctl_shm_info = (int)SHM_INFO;
-  int shmctl_shm_stat = (int)SHM_INFO;
+  int shmctl_shm_stat = (int)SHM_STAT;
 #endif
 
+  int map_fixed = MAP_FIXED;
+
   int af_inet = (int)AF_INET;
   int af_inet6 = (int)AF_INET6;
 
@@ -207,13 +265,13 @@
       return 0;
   }
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   int glob_nomatch = GLOB_NOMATCH;
   int glob_altdirfunc = GLOB_ALTDIRFUNC;
 #endif
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID && \
-      (defined(__i386) || defined (__x86_64))  // NOLINT
+    (defined(__i386) || defined(__x86_64))
   unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
 #ifdef __x86_64
@@ -231,15 +289,21 @@
   int ptrace_setfpregs = PTRACE_SETFPREGS;
   int ptrace_getfpxregs = PTRACE_GETFPXREGS;
   int ptrace_setfpxregs = PTRACE_SETFPXREGS;
+#if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) ||              \
+    (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO))
   int ptrace_getsiginfo = PTRACE_GETSIGINFO;
   int ptrace_setsiginfo = PTRACE_SETSIGINFO;
+#else
+  int ptrace_getsiginfo = -1;
+  int ptrace_setsiginfo = -1;
+#endif  // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO
 #if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET)
   int ptrace_getregset = PTRACE_GETREGSET;
   int ptrace_setregset = PTRACE_SETREGSET;
 #else
   int ptrace_getregset = -1;
   int ptrace_setregset = -1;
-#endif
+#endif  // PTRACE_GETREGSET/PTRACE_SETREGSET
 #endif
 
   unsigned path_max = PATH_MAX;
@@ -259,15 +323,6 @@
   unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry);
   unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr);
   unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl);
-#if SOUND_VERSION >= 0x040000
-  unsigned struct_copr_buffer_sz = 0;
-  unsigned struct_copr_debug_buf_sz = 0;
-  unsigned struct_copr_msg_sz = 0;
-#else
-  unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
-  unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
-  unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
-#endif
   unsigned struct_ff_effect_sz = sizeof(struct ff_effect);
   unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params);
   unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct);
@@ -281,23 +336,34 @@
   unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry);
   unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo);
   unsigned struct_input_id_sz = sizeof(struct input_id);
+  unsigned struct_mtpos_sz = sizeof(struct mtpos);
+  unsigned struct_termio_sz = sizeof(struct termio);
+  unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
+  unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
+  unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
+#endif  // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SOUND_VERSION >= 0x040000
+  unsigned struct_copr_buffer_sz = 0;
+  unsigned struct_copr_debug_buf_sz = 0;
+  unsigned struct_copr_msg_sz = 0;
+#else
+  unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+  unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+  unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+#endif
   unsigned struct_midi_info_sz = sizeof(struct midi_info);
   unsigned struct_mtget_sz = sizeof(struct mtget);
   unsigned struct_mtop_sz = sizeof(struct mtop);
-  unsigned struct_mtpos_sz = sizeof(struct mtpos);
   unsigned struct_rtentry_sz = sizeof(struct rtentry);
   unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
   unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
   unsigned struct_synth_info_sz = sizeof(struct synth_info);
-  unsigned struct_termio_sz = sizeof(struct termio);
-  unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
   unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
-  unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
-  unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
-#endif
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
   unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
   unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
 #if EV_VERSION > (0x010000)
@@ -312,7 +378,6 @@
   unsigned struct_kbsentry_sz = sizeof(struct kbsentry);
   unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo);
   unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct);
-  unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
   unsigned struct_scc_modem_sz = sizeof(struct scc_modem);
   unsigned struct_scc_stat_sz = sizeof(struct scc_stat);
   unsigned struct_serial_multiport_struct_sz
@@ -321,7 +386,12 @@
   unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
   unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
   unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
-#endif
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+  unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 
 #if !SANITIZER_ANDROID && !SANITIZER_MAC
   unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
@@ -374,10 +444,11 @@
   unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
   unsigned IOCTL_TIOCSTI = TIOCSTI;
   unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#if ((SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID)
   unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
   unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
 #endif
+
 #if SANITIZER_LINUX
   unsigned IOCTL_EVIOCGABS = EVIOCGABS(0);
   unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0);
@@ -468,9 +539,7 @@
   unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT;
   unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR;
   unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR;
-  unsigned IOCTL_MTIOCGET = MTIOCGET;
   unsigned IOCTL_MTIOCPOS = MTIOCPOS;
-  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
   unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP;
   unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG;
   unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS;
@@ -482,9 +551,7 @@
   unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
   unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
   unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
-  unsigned IOCTL_SIOCADDRT = SIOCADDRT;
   unsigned IOCTL_SIOCDARP = SIOCDARP;
-  unsigned IOCTL_SIOCDELRT = SIOCDELRT;
   unsigned IOCTL_SIOCDRARP = SIOCDRARP;
   unsigned IOCTL_SIOCGARP = SIOCGARP;
   unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP;
@@ -503,7 +570,7 @@
   unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM;
   unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE;
   unsigned IOCTL_SIOCSRARP = SIOCSRARP;
-#if SOUND_VERSION >= 0x040000
+# if SOUND_VERSION >= 0x040000
   unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT;
   unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT;
   unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT;
@@ -520,7 +587,7 @@
   unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT;
   unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT;
   unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT;
-#else
+# else  // SOUND_VERSION
   unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT;
   unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD;
   unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE;
@@ -537,7 +604,41 @@
   unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE;
   unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS;
   unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER;
-#endif
+#endif  // SOUND_VERSION
+  unsigned IOCTL_TCFLSH = TCFLSH;
+  unsigned IOCTL_TCGETA = TCGETA;
+  unsigned IOCTL_TCGETS = TCGETS;
+  unsigned IOCTL_TCSBRK = TCSBRK;
+  unsigned IOCTL_TCSBRKP = TCSBRKP;
+  unsigned IOCTL_TCSETA = TCSETA;
+  unsigned IOCTL_TCSETAF = TCSETAF;
+  unsigned IOCTL_TCSETAW = TCSETAW;
+  unsigned IOCTL_TCSETS = TCSETS;
+  unsigned IOCTL_TCSETSF = TCSETSF;
+  unsigned IOCTL_TCSETSW = TCSETSW;
+  unsigned IOCTL_TCXONC = TCXONC;
+  unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
+  unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
+  unsigned IOCTL_TIOCINQ = TIOCINQ;
+  unsigned IOCTL_TIOCLINUX = TIOCLINUX;
+  unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
+  unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
+  unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
+  unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
+  unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
+  unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
+  unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
+  unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
+  unsigned IOCTL_VT_RESIZE = VT_RESIZE;
+  unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
+  unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
+#endif // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+  unsigned IOCTL_MTIOCGET = MTIOCGET;
+  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+  unsigned IOCTL_SIOCADDRT = SIOCADDRT;
+  unsigned IOCTL_SIOCDELRT = SIOCDELRT;
   unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
   unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
   unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
@@ -622,40 +723,14 @@
   unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
   unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
   unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
-  unsigned IOCTL_TCFLSH = TCFLSH;
-  unsigned IOCTL_TCGETA = TCGETA;
-  unsigned IOCTL_TCGETS = TCGETS;
-  unsigned IOCTL_TCSBRK = TCSBRK;
-  unsigned IOCTL_TCSBRKP = TCSBRKP;
-  unsigned IOCTL_TCSETA = TCSETA;
-  unsigned IOCTL_TCSETAF = TCSETAF;
-  unsigned IOCTL_TCSETAW = TCSETAW;
-  unsigned IOCTL_TCSETS = TCSETS;
-  unsigned IOCTL_TCSETSF = TCSETSF;
-  unsigned IOCTL_TCSETSW = TCSETSW;
-  unsigned IOCTL_TCXONC = TCXONC;
-  unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS;
-  unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR;
-  unsigned IOCTL_TIOCINQ = TIOCINQ;
-  unsigned IOCTL_TIOCLINUX = TIOCLINUX;
-  unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG;
-  unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR;
-  unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD;
-  unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD;
-  unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS;
-  unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR;
   unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
-  unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE;
   unsigned IOCTL_VT_GETMODE = VT_GETMODE;
-  unsigned IOCTL_VT_GETSTATE = VT_GETSTATE;
   unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
   unsigned IOCTL_VT_RELDISP = VT_RELDISP;
-  unsigned IOCTL_VT_RESIZE = VT_RESIZE;
-  unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
-  unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
   unsigned IOCTL_VT_SETMODE = VT_SETMODE;
   unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
-#endif
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
+
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
   unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
@@ -687,37 +762,25 @@
   unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION;
   unsigned IOCTL_GIO_CMAP = GIO_CMAP;
   unsigned IOCTL_GIO_FONT = GIO_FONT;
-  unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
   unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP;
   unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP;
   unsigned IOCTL_KDADDIO = KDADDIO;
   unsigned IOCTL_KDDELIO = KDDELIO;
-  unsigned IOCTL_KDDISABIO = KDDISABIO;
-  unsigned IOCTL_KDENABIO = KDENABIO;
   unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE;
-  unsigned IOCTL_KDGETLED = KDGETLED;
-  unsigned IOCTL_KDGETMODE = KDGETMODE;
   unsigned IOCTL_KDGKBDIACR = KDGKBDIACR;
   unsigned IOCTL_KDGKBENT = KDGKBENT;
   unsigned IOCTL_KDGKBLED = KDGKBLED;
   unsigned IOCTL_KDGKBMETA = KDGKBMETA;
-  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
   unsigned IOCTL_KDGKBSENT = KDGKBSENT;
-  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
   unsigned IOCTL_KDMAPDISP = KDMAPDISP;
-  unsigned IOCTL_KDMKTONE = KDMKTONE;
   unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE;
-  unsigned IOCTL_KDSETLED = KDSETLED;
-  unsigned IOCTL_KDSETMODE = KDSETMODE;
   unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT;
   unsigned IOCTL_KDSKBDIACR = KDSKBDIACR;
   unsigned IOCTL_KDSKBENT = KDSKBENT;
   unsigned IOCTL_KDSKBLED = KDSKBLED;
   unsigned IOCTL_KDSKBMETA = KDSKBMETA;
-  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
   unsigned IOCTL_KDSKBSENT = KDSKBSENT;
   unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP;
-  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
   unsigned IOCTL_LPABORT = LPABORT;
   unsigned IOCTL_LPABORTOPEN = LPABORTOPEN;
   unsigned IOCTL_LPCAREFUL = LPCAREFUL;
@@ -732,7 +795,6 @@
   unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG;
   unsigned IOCTL_PIO_CMAP = PIO_CMAP;
   unsigned IOCTL_PIO_FONT = PIO_FONT;
-  unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
   unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
   unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
   unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
@@ -754,20 +816,40 @@
   unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
   unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
   unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
-  unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
-  unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
   unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
   unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
   unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
   unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
-#endif
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
 
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+  unsigned IOCTL_KDDISABIO = KDDISABIO;
+  unsigned IOCTL_KDENABIO = KDENABIO;
+  unsigned IOCTL_KDGETLED = KDGETLED;
+  unsigned IOCTL_KDGETMODE = KDGETMODE;
+  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+  unsigned IOCTL_KDMKTONE = KDMKTONE;
+  unsigned IOCTL_KDSETLED = KDSETLED;
+  unsigned IOCTL_KDSETMODE = KDSETMODE;
+  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+  unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+  unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+  unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
+#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+
+  const int errno_EINVAL = EINVAL;
 // EOWNERDEAD is not present in some older platforms.
 #if defined(EOWNERDEAD)
-  extern const int errno_EOWNERDEAD = EOWNERDEAD;
+  const int errno_EOWNERDEAD = EOWNERDEAD;
 #else
-  extern const int errno_EOWNERDEAD = -1;
+  const int errno_EOWNERDEAD = -1;
 #endif
+
+  const int si_SEGV_MAPERR = SEGV_MAPERR;
+  const int si_SEGV_ACCERR = SEGV_ACCERR;
 }  // namespace __sanitizer
 
 COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
@@ -776,6 +858,31 @@
 CHECK_TYPE_SIZE(pthread_key_t);
 
 #if SANITIZER_LINUX
+// FIXME: We define those on Linux and Mac, but only check on Linux.
+COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS);
+COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS);
+COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS);
+COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS);
+COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK);
+COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK);
+COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK);
+COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK);
+COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT);
+COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT);
+COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT);
+COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT);
+COMPILER_CHECK(IOC_NONE == _IOC_NONE);
+COMPILER_CHECK(IOC_WRITE == _IOC_WRITE);
+COMPILER_CHECK(IOC_READ == _IOC_READ);
+COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX);
+COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX);
+COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
+COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678));
+COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678));
+COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678));
+#endif  // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
 // There are more undocumented fields in dl_phdr_info that we are not interested
 // in.
 COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
@@ -783,11 +890,9 @@
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
 CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
 
-COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678));
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 CHECK_TYPE_SIZE(glob_t);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
 CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
@@ -839,6 +944,8 @@
 CHECK_SIZE_AND_OFFSET(dirent, d_ino);
 #if SANITIZER_MAC
 CHECK_SIZE_AND_OFFSET(dirent, d_seekoff);
+#elif SANITIZER_FREEBSD
+// There is no 'd_off' field on FreeBSD.
 #else
 CHECK_SIZE_AND_OFFSET(dirent, d_off);
 #endif
@@ -923,15 +1030,20 @@
 
 CHECK_TYPE_SIZE(ether_addr);
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 CHECK_TYPE_SIZE(ipc_perm);
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ipc_perm, key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, seq);
+# else
 CHECK_SIZE_AND_OFFSET(ipc_perm, __key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
+# endif
 CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
 CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
 CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
 CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
 CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
-CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
 
 CHECK_TYPE_SIZE(shmid_ds);
 CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
@@ -944,4 +1056,110 @@
 CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
 #endif
 
-#endif  // SANITIZER_LINUX || SANITIZER_MAC
+CHECK_TYPE_SIZE(clock_t);
+
+#if !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ifaddrs);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+// Compare against the union, because we can't reach into the union in a
+// compliant way.
+#ifdef ifa_dstaddr
+#undef ifa_dstaddr
+#endif
+# if SANITIZER_FREEBSD
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+# else
+COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) ==
+               sizeof(((ifaddrs *)NULL)->ifa_ifu));
+COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) ==
+               offsetof(ifaddrs, ifa_ifu));
+# endif  // SANITIZER_FREEBSD
+#else
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+#endif  // SANITIZER_LINUX
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
+#endif
+
+#if SANITIZER_LINUX
+COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo));
+#endif
+
+CHECK_TYPE_SIZE(timeb);
+CHECK_SIZE_AND_OFFSET(timeb, time);
+CHECK_SIZE_AND_OFFSET(timeb, millitm);
+CHECK_SIZE_AND_OFFSET(timeb, timezone);
+CHECK_SIZE_AND_OFFSET(timeb, dstflag);
+
+CHECK_TYPE_SIZE(passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_name);
+CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
+CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
+
+#if !SANITIZER_ANDROID
+CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
+#endif
+
+#if SANITIZER_MAC
+CHECK_SIZE_AND_OFFSET(passwd, pw_change);
+CHECK_SIZE_AND_OFFSET(passwd, pw_expire);
+CHECK_SIZE_AND_OFFSET(passwd, pw_class);
+#endif
+
+
+CHECK_TYPE_SIZE(group);
+CHECK_SIZE_AND_OFFSET(group, gr_name);
+CHECK_SIZE_AND_OFFSET(group, gr_passwd);
+CHECK_SIZE_AND_OFFSET(group, gr_gid);
+CHECK_SIZE_AND_OFFSET(group, gr_mem);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(XDR);
+CHECK_SIZE_AND_OFFSET(XDR, x_op);
+CHECK_SIZE_AND_OFFSET(XDR, x_ops);
+CHECK_SIZE_AND_OFFSET(XDR, x_public);
+CHECK_SIZE_AND_OFFSET(XDR, x_private);
+CHECK_SIZE_AND_OFFSET(XDR, x_base);
+CHECK_SIZE_AND_OFFSET(XDR, x_handy);
+COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE);
+COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
+COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
+CHECK_SIZE_AND_OFFSET(FILE, _flags);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base);
+CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
+CHECK_SIZE_AND_OFFSET(FILE, _markers);
+CHECK_SIZE_AND_OFFSET(FILE, _chain);
+CHECK_SIZE_AND_OFFSET(FILE, _fileno);
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
+CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
+CHECK_TYPE_SIZE(obstack);
+CHECK_SIZE_AND_OFFSET(obstack, chunk_size);
+CHECK_SIZE_AND_OFFSET(obstack, chunk);
+CHECK_SIZE_AND_OFFSET(obstack, object_base);
+CHECK_SIZE_AND_OFFSET(obstack, next_free);
+#endif
+
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 832e704..492daf2 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -21,12 +21,10 @@
 namespace __sanitizer {
   extern unsigned struct_utsname_sz;
   extern unsigned struct_stat_sz;
-#if !SANITIZER_IOS
+#if !SANITIZER_FREEBSD && !SANITIZER_IOS
   extern unsigned struct_stat64_sz;
 #endif
   extern unsigned struct_rusage_sz;
-  extern unsigned struct_passwd_sz;
-  extern unsigned struct_group_sz;
   extern unsigned siginfo_t_sz;
   extern unsigned struct_itimerval_sz;
   extern unsigned pthread_t_sz;
@@ -34,6 +32,7 @@
   extern unsigned pid_t_sz;
   extern unsigned timeval_sz;
   extern unsigned uid_t_sz;
+  extern unsigned gid_t_sz;
   extern unsigned mbstate_t_sz;
   extern unsigned struct_timezone_sz;
   extern unsigned struct_tms_sz;
@@ -42,6 +41,7 @@
   extern unsigned struct_sched_param_sz;
   extern unsigned struct_statfs_sz;
   extern unsigned struct_statfs64_sz;
+  extern unsigned struct_sockaddr_sz;
 
 #if !SANITIZER_ANDROID
   extern unsigned ucontext_t_sz;
@@ -50,46 +50,52 @@
 #if SANITIZER_LINUX
 
 #if defined(__x86_64__)
-  const unsigned struct___old_kernel_stat_sz = 32;
   const unsigned struct_kernel_stat_sz = 144;
   const unsigned struct_kernel_stat64_sz = 0;
 #elif defined(__i386__)
-  const unsigned struct___old_kernel_stat_sz = 32;
   const unsigned struct_kernel_stat_sz = 64;
   const unsigned struct_kernel_stat64_sz = 96;
 #elif defined(__arm__)
-  const unsigned struct___old_kernel_stat_sz = 32;
   const unsigned struct_kernel_stat_sz = 64;
   const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__aarch64__)
+  const unsigned struct_kernel_stat_sz = 128;
+  const unsigned struct_kernel_stat64_sz = 104;
 #elif defined(__powerpc__) && !defined(__powerpc64__)
-  const unsigned struct___old_kernel_stat_sz = 32;
   const unsigned struct_kernel_stat_sz = 72;
   const unsigned struct_kernel_stat64_sz = 104;
 #elif defined(__powerpc64__)
-  const unsigned struct___old_kernel_stat_sz = 0;
   const unsigned struct_kernel_stat_sz = 144;
   const unsigned struct_kernel_stat64_sz = 104;
 #endif
-  const unsigned struct_io_event_sz = 32;
   struct __sanitizer_perf_event_attr {
     unsigned type;
     unsigned size;
     // More fields that vary with the kernel version.
   };
 
-  extern unsigned struct_rlimit_sz;
   extern unsigned struct_epoll_event_sz;
   extern unsigned struct_sysinfo_sz;
-  extern unsigned struct_timespec_sz;
   extern unsigned __user_cap_header_struct_sz;
   extern unsigned __user_cap_data_struct_sz;
-  extern unsigned struct_utimbuf_sz;
   extern unsigned struct_new_utsname_sz;
   extern unsigned struct_old_utsname_sz;
   extern unsigned struct_oldold_utsname_sz;
 
-  const unsigned old_sigset_t_sz = sizeof(unsigned long);
   const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
+#endif  // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if defined(__powerpc64__)
+  const unsigned struct___old_kernel_stat_sz = 0;
+#else
+  const unsigned struct___old_kernel_stat_sz = 32;
+#endif
+
+  extern unsigned struct_rlimit_sz;
+  extern unsigned struct_utimbuf_sz;
+  extern unsigned struct_timespec_sz;
 
   struct __sanitizer_iocb {
     u64   aio_data;
@@ -105,8 +111,17 @@
     u64   aio_reserved3;
   };
 
+  struct __sanitizer_io_event {
+    u64 data;
+    u64 obj;
+    u64 res;
+    u64 res2;
+  };
+
   const unsigned iocb_cmd_pread = 0;
   const unsigned iocb_cmd_pwrite = 1;
+  const unsigned iocb_cmd_preadv = 7;
+  const unsigned iocb_cmd_pwritev = 8;
 
   struct __sanitizer___sysctl_args {
     int *name;
@@ -117,15 +132,23 @@
     uptr newlen;
     unsigned long ___unused[4];
   };
-#endif // SANITIZER_LINUX
+
+  const unsigned old_sigset_t_sz = sizeof(unsigned long);
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+
+#if SANITIZER_ANDROID
+  struct __sanitizer_mallinfo {
+    uptr v[10];
+  };
+#endif
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
+  struct __sanitizer_mallinfo {
+    int v[10];
+  };
+
   extern unsigned struct_ustat_sz;
   extern unsigned struct_rlimit64_sz;
-  extern unsigned struct_timex_sz;
-  extern unsigned struct_msqid_ds_sz;
-  extern unsigned struct_mq_attr_sz;
-  extern unsigned struct_statvfs_sz;
   extern unsigned struct_statvfs64_sz;
 
   struct __sanitizer_ipc_perm {
@@ -161,6 +184,11 @@
   #elif !defined(__powerpc64__)
     uptr __unused0;
   #endif
+  #if defined(__x86_64__) && !defined(_LP64)
+    u64 shm_atime;
+    u64 shm_dtime;
+    u64 shm_ctime;
+  #else
     uptr shm_atime;
   #ifndef _LP64
     uptr __unused1;
@@ -173,28 +201,137 @@
   #ifndef _LP64
     uptr __unused3;
   #endif
+  #endif
   #ifdef __powerpc__
     uptr shm_segsz;
   #endif
     int shm_cpid;
     int shm_lpid;
+  #if defined(__x86_64__) && !defined(_LP64)
+    u64 shm_nattch;
+    u64 __unused4;
+    u64 __unused5;
+  #else
     uptr shm_nattch;
     uptr __unused4;
     uptr __unused5;
+  #endif
   };
-  #endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+#elif SANITIZER_FREEBSD
+  struct __sanitizer_ipc_perm {
+    unsigned int cuid;
+    unsigned int cgid;
+    unsigned int uid;
+    unsigned int gid;
+    unsigned short mode;
+    unsigned short seq;
+    long key;
+  };
+
+  struct __sanitizer_shmid_ds {
+    __sanitizer_ipc_perm shm_perm;
+    unsigned long shm_segsz;
+    unsigned int shm_lpid;
+    unsigned int shm_cpid;
+    int shm_nattch;
+    unsigned long shm_atime;
+    unsigned long shm_dtime;
+    unsigned long shm_ctime;
+  };
+#endif
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  extern unsigned struct_msqid_ds_sz;
+  extern unsigned struct_mq_attr_sz;
+  extern unsigned struct_timex_sz;
+  extern unsigned struct_statvfs_sz;
+#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 
   struct __sanitizer_iovec {
-    void  *iov_base;
+    void *iov_base;
     uptr iov_len;
   };
 
+#if !SANITIZER_ANDROID
+  struct __sanitizer_ifaddrs {
+    struct __sanitizer_ifaddrs *ifa_next;
+    char *ifa_name;
+    unsigned int ifa_flags;
+    void *ifa_addr;    // (struct sockaddr *)
+    void *ifa_netmask; // (struct sockaddr *)
+    // This is a union on Linux.
+# ifdef ifa_dstaddr
+# undef ifa_dstaddr
+# endif
+    void *ifa_dstaddr; // (struct sockaddr *)
+    void *ifa_data;
+  };
+#endif  // !SANITIZER_ANDROID
+
 #if SANITIZER_MAC
   typedef unsigned long __sanitizer_pthread_key_t;
 #else
   typedef unsigned __sanitizer_pthread_key_t;
 #endif
 
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+
+  struct __sanitizer_XDR {
+    int x_op;
+    void *x_ops;
+    uptr x_public;
+    uptr x_private;
+    uptr x_base;
+    unsigned x_handy;
+  };
+
+  const int __sanitizer_XDR_ENCODE = 0;
+  const int __sanitizer_XDR_DECODE = 1;
+  const int __sanitizer_XDR_FREE = 2;
+#endif
+
+  struct __sanitizer_passwd {
+    char *pw_name;
+    char *pw_passwd;
+    int pw_uid;
+    int pw_gid;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+    long pw_change;
+    char *pw_class;
+#endif
+#if !SANITIZER_ANDROID
+    char *pw_gecos;
+#endif
+    char *pw_dir;
+    char *pw_shell;
+#if SANITIZER_MAC || SANITIZER_FREEBSD
+    long pw_expire;
+#endif
+#if SANITIZER_FREEBSD
+    int pw_fields;
+#endif
+  };
+
+  struct __sanitizer_group {
+    char *gr_name;
+    char *gr_passwd;
+    int gr_gid;
+    char **gr_mem;
+  };
+
+#if defined(__x86_64__) && !defined(_LP64)
+  typedef long long __sanitizer_time_t;
+#else
+  typedef long __sanitizer_time_t;
+#endif
+
+  struct __sanitizer_timeb {
+    __sanitizer_time_t time;
+    unsigned short millitm;
+    short timezone;
+    short dstflag;
+  };
+
   struct __sanitizer_ether_addr {
     u8 octet[6];
   };
@@ -224,7 +361,7 @@
   };
 #endif
 
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
   struct __sanitizer_msghdr {
     void *msg_name;
     unsigned msg_namelen;
@@ -263,6 +400,12 @@
     unsigned short d_reclen;
     // more fields that we don't care about
   };
+#elif SANITIZER_FREEBSD
+  struct __sanitizer_dirent {
+    unsigned int d_fileno;
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
 #elif SANITIZER_ANDROID || defined(__x86_64__)
   struct __sanitizer_dirent {
     unsigned long long d_ino;
@@ -288,7 +431,16 @@
   };
 #endif
 
-#if SANITIZER_LINUX
+// 'clock_t' is 32 bits wide on x64 FreeBSD
+#if SANITIZER_FREEBSD
+  typedef int __sanitizer_clock_t;
+#elif defined(__x86_64__) && !defined(_LP64)
+  typedef long long __sanitizer_clock_t;
+#else
+  typedef long __sanitizer_clock_t;
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
 #if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)
   typedef unsigned __sanitizer___kernel_uid_t;
   typedef unsigned __sanitizer___kernel_gid_t;
@@ -302,7 +454,7 @@
   typedef long __sanitizer___kernel_off_t;
 #endif
 
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__aarch64__)
   typedef unsigned int __sanitizer___kernel_old_uid_t;
   typedef unsigned int __sanitizer___kernel_old_gid_t;
 #else
@@ -333,28 +485,44 @@
     // The size is determined by looking at sizeof of real sigset_t on linux.
     uptr val[128 / sizeof(uptr)];
   };
+#elif SANITIZER_FREEBSD
+  struct __sanitizer_sigset_t {
+     // uint32_t * 4
+     unsigned int __bits[4];
+  };
 #endif
 
+  // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
   struct __sanitizer_sigaction {
     union {
-      void (*sa_handler)(int sig);
-      void (*sa_sigaction)(int sig, void *siginfo, void *uctx);
+      void (*sigaction)(int sig, void *siginfo, void *uctx);
+      void (*handler)(int sig);
     };
+#if SANITIZER_FREEBSD
+    int sa_flags;
+    __sanitizer_sigset_t sa_mask;
+#else
     __sanitizer_sigset_t sa_mask;
     int sa_flags;
+#endif
 #if SANITIZER_LINUX
     void (*sa_restorer)();
 #endif
   };
 
+#if SANITIZER_FREEBSD
+  typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+#else
   struct __sanitizer_kernel_sigset_t {
     u8 sig[8];
   };
+#endif
 
+  // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
   struct __sanitizer_kernel_sigaction_t {
     union {
-      void (*sigaction)(int signo, void *info, void *ctx);
       void (*handler)(int signo);
+      void (*sigaction)(int signo, void *info, void *ctx);
     };
     unsigned long sa_flags;
     void (*sa_restorer)(void);
@@ -373,7 +541,7 @@
   extern int af_inet6;
   uptr __sanitizer_in_addr_sz(int af);
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
   struct __sanitizer_dl_phdr_info {
     uptr dlpi_addr;
     const char *dlpi_name;
@@ -387,7 +555,7 @@
     int ai_family;
     int ai_socktype;
     int ai_protocol;
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
     unsigned ai_addrlen;
     char *ai_canonname;
     void *ai_addr;
@@ -413,13 +581,14 @@
     short revents;
   };
 
-#if SANITIZER_ANDROID || SANITIZER_MAC
+#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
   typedef unsigned __sanitizer_nfds_t;
 #else
   typedef unsigned long __sanitizer_nfds_t;
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID
+# if SANITIZER_LINUX
   struct __sanitizer_glob_t {
     uptr gl_pathc;
     char **gl_pathv;
@@ -432,10 +601,27 @@
     int (*gl_lstat)(const char *, void *);
     int (*gl_stat)(const char *, void *);
   };
+# elif SANITIZER_FREEBSD
+  struct __sanitizer_glob_t {
+    uptr gl_pathc;
+    uptr gl_matchc;
+    uptr gl_offs;
+    int gl_flags;
+    char **gl_pathv;
+    int (*gl_errfunc)(const char*, int);
+    void (*gl_closedir)(void *dirp);
+    struct dirent *(*gl_readdir)(void *dirp);
+    void *(*gl_opendir)(const char*);
+    int (*gl_lstat)(const char*, void* /* struct stat* */);
+    int (*gl_stat)(const char*, void* /* struct stat* */);
+  };
+# endif  // SANITIZER_FREEBSD
 
+# if SANITIZER_LINUX || SANITIZER_FREEBSD
   extern int glob_nomatch;
   extern int glob_altdirfunc;
-#endif
+# endif
+#endif  // !SANITIZER_ANDROID
 
   extern unsigned path_max;
 
@@ -443,10 +629,38 @@
     uptr we_wordc;
     char **we_wordv;
     uptr we_offs;
+#if SANITIZER_FREEBSD
+    char *we_strings;
+    uptr we_nbytes;
+#endif
   };
 
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+  struct __sanitizer_FILE {
+    int _flags;
+    char *_IO_read_ptr;
+    char *_IO_read_end;
+    char *_IO_read_base;
+    char *_IO_write_base;
+    char *_IO_write_ptr;
+    char *_IO_write_end;
+    char *_IO_buf_base;
+    char *_IO_buf_end;
+    char *_IO_save_base;
+    char *_IO_backup_base;
+    char *_IO_save_end;
+    void *_markers;
+    __sanitizer_FILE *_chain;
+    int _fileno;
+  };
+# define SANITIZER_HAS_STRUCT_FILE 1
+#else
+  typedef void __sanitizer_FILE;
+# define SANITIZER_HAS_STRUCT_FILE 0
+#endif
+
 #if SANITIZER_LINUX && !SANITIZER_ANDROID && \
-      (defined(__i386) || defined (__x86_64))  // NOLINT
+    (defined(__i386) || defined(__x86_64))
   extern unsigned struct_user_regs_struct_sz;
   extern unsigned struct_user_fpregs_struct_sz;
   extern unsigned struct_user_fpxregs_struct_sz;
@@ -466,7 +680,7 @@
   extern int ptrace_setregset;
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   extern unsigned struct_shminfo_sz;
   extern unsigned struct_shm_info_sz;
   extern int shmctl_ipc_stat;
@@ -475,6 +689,8 @@
   extern int shmctl_shm_stat;
 #endif
 
+  extern int map_fixed;
+
   // ioctl arguments
   struct __sanitizer_ifconf {
     int ifc_len;
@@ -487,7 +703,54 @@
   };
 #endif
 
-#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+struct __sanitizer__obstack_chunk {
+  char *limit;
+  struct __sanitizer__obstack_chunk *prev;
+};
+
+struct __sanitizer_obstack {
+  long chunk_size;
+  struct __sanitizer__obstack_chunk *chunk;
+  char *object_base;
+  char *next_free;
+  uptr more_fields[7];
+};
+#endif
+
+#define IOC_NRBITS 8
+#define IOC_TYPEBITS 8
+#if defined(__powerpc__) || defined(__powerpc64__)
+#define IOC_SIZEBITS 13
+#define IOC_DIRBITS 3
+#define IOC_NONE 1U
+#define IOC_WRITE 4U
+#define IOC_READ 2U
+#else
+#define IOC_SIZEBITS 14
+#define IOC_DIRBITS 2
+#define IOC_NONE 0U
+#define IOC_WRITE 1U
+#define IOC_READ 2U
+#endif
+#define IOC_NRMASK ((1 << IOC_NRBITS) - 1)
+#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1)
+#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1)
+#if defined(IOC_DIRMASK)
+#undef IOC_DIRMASK
+#endif
+#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1)
+#define IOC_NRSHIFT 0
+#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS)
+#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS)
+#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS)
+#define EVIOC_EV_MAX 0x1f
+#define EVIOC_ABS_MAX 0x3f
+
+#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
 
   extern unsigned struct_arpreq_sz;
   extern unsigned struct_ifreq_sz;
@@ -503,9 +766,6 @@
   extern unsigned struct_cdrom_tocentry_sz;
   extern unsigned struct_cdrom_tochdr_sz;
   extern unsigned struct_cdrom_volctrl_sz;
-  extern unsigned struct_copr_buffer_sz;
-  extern unsigned struct_copr_debug_buf_sz;
-  extern unsigned struct_copr_msg_sz;
   extern unsigned struct_ff_effect_sz;
   extern unsigned struct_floppy_drive_params_sz;
   extern unsigned struct_floppy_drive_struct_sz;
@@ -519,23 +779,28 @@
   extern unsigned struct_hd_geometry_sz;
   extern unsigned struct_input_absinfo_sz;
   extern unsigned struct_input_id_sz;
+  extern unsigned struct_mtpos_sz;
+  extern unsigned struct_termio_sz;
+  extern unsigned struct_vt_consize_sz;
+  extern unsigned struct_vt_sizes_sz;
+  extern unsigned struct_vt_stat_sz;
+#endif  // SANITIZER_LINUX
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+  extern unsigned struct_copr_buffer_sz;
+  extern unsigned struct_copr_debug_buf_sz;
+  extern unsigned struct_copr_msg_sz;
   extern unsigned struct_midi_info_sz;
   extern unsigned struct_mtget_sz;
   extern unsigned struct_mtop_sz;
-  extern unsigned struct_mtpos_sz;
   extern unsigned struct_rtentry_sz;
   extern unsigned struct_sbi_instrument_sz;
   extern unsigned struct_seq_event_rec_sz;
   extern unsigned struct_synth_info_sz;
-  extern unsigned struct_termio_sz;
-  extern unsigned struct_vt_consize_sz;
   extern unsigned struct_vt_mode_sz;
-  extern unsigned struct_vt_sizes_sz;
-  extern unsigned struct_vt_stat_sz;
-#endif
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-  extern unsigned struct_audio_buf_info_sz;
   extern unsigned struct_ax25_parms_struct_sz;
   extern unsigned struct_cyclades_monitor_sz;
   extern unsigned struct_input_keymap_entry_sz;
@@ -546,7 +811,6 @@
   extern unsigned struct_kbsentry_sz;
   extern unsigned struct_mtconfiginfo_sz;
   extern unsigned struct_nr_parms_struct_sz;
-  extern unsigned struct_ppp_stats_sz;
   extern unsigned struct_scc_modem_sz;
   extern unsigned struct_scc_stat_sz;
   extern unsigned struct_serial_multiport_struct_sz;
@@ -554,7 +818,12 @@
   extern unsigned struct_sockaddr_ax25_sz;
   extern unsigned struct_unimapdesc_sz;
   extern unsigned struct_unimapinit_sz;
-#endif
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  extern unsigned struct_audio_buf_info_sz;
+  extern unsigned struct_ppp_stats_sz;
+#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
 
 #if !SANITIZER_ANDROID && !SANITIZER_MAC
   extern unsigned struct_sioc_sg_req_sz;
@@ -611,7 +880,7 @@
   extern unsigned IOCTL_TIOCSPGRP;
   extern unsigned IOCTL_TIOCSTI;
   extern unsigned IOCTL_TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   extern unsigned IOCTL_SIOCGETSGCNT;
   extern unsigned IOCTL_SIOCGETVIFCNT;
 #endif
@@ -705,9 +974,7 @@
   extern unsigned IOCTL_HDIO_SET_MULTCOUNT;
   extern unsigned IOCTL_HDIO_SET_NOWERR;
   extern unsigned IOCTL_HDIO_SET_UNMASKINTR;
-  extern unsigned IOCTL_MTIOCGET;
   extern unsigned IOCTL_MTIOCPOS;
-  extern unsigned IOCTL_MTIOCTOP;
   extern unsigned IOCTL_PPPIOCGASYNCMAP;
   extern unsigned IOCTL_PPPIOCGDEBUG;
   extern unsigned IOCTL_PPPIOCGFLAGS;
@@ -719,9 +986,7 @@
   extern unsigned IOCTL_PPPIOCSMAXCID;
   extern unsigned IOCTL_PPPIOCSMRU;
   extern unsigned IOCTL_PPPIOCSXASYNCMAP;
-  extern unsigned IOCTL_SIOCADDRT;
   extern unsigned IOCTL_SIOCDARP;
-  extern unsigned IOCTL_SIOCDELRT;
   extern unsigned IOCTL_SIOCDRARP;
   extern unsigned IOCTL_SIOCGARP;
   extern unsigned IOCTL_SIOCGIFENCAP;
@@ -750,6 +1015,39 @@
   extern unsigned IOCTL_SNDCTL_COPR_SENDMSG;
   extern unsigned IOCTL_SNDCTL_COPR_WCODE;
   extern unsigned IOCTL_SNDCTL_COPR_WDATA;
+  extern unsigned IOCTL_TCFLSH;
+  extern unsigned IOCTL_TCGETA;
+  extern unsigned IOCTL_TCGETS;
+  extern unsigned IOCTL_TCSBRK;
+  extern unsigned IOCTL_TCSBRKP;
+  extern unsigned IOCTL_TCSETA;
+  extern unsigned IOCTL_TCSETAF;
+  extern unsigned IOCTL_TCSETAW;
+  extern unsigned IOCTL_TCSETS;
+  extern unsigned IOCTL_TCSETSF;
+  extern unsigned IOCTL_TCSETSW;
+  extern unsigned IOCTL_TCXONC;
+  extern unsigned IOCTL_TIOCGLCKTRMIOS;
+  extern unsigned IOCTL_TIOCGSOFTCAR;
+  extern unsigned IOCTL_TIOCINQ;
+  extern unsigned IOCTL_TIOCLINUX;
+  extern unsigned IOCTL_TIOCSERCONFIG;
+  extern unsigned IOCTL_TIOCSERGETLSR;
+  extern unsigned IOCTL_TIOCSERGWILD;
+  extern unsigned IOCTL_TIOCSERSWILD;
+  extern unsigned IOCTL_TIOCSLCKTRMIOS;
+  extern unsigned IOCTL_TIOCSSOFTCAR;
+  extern unsigned IOCTL_VT_DISALLOCATE;
+  extern unsigned IOCTL_VT_GETSTATE;
+  extern unsigned IOCTL_VT_RESIZE;
+  extern unsigned IOCTL_VT_RESIZEX;
+  extern unsigned IOCTL_VT_SENDSIG;
+#endif  // SANITIZER_LINUX
+#if SANITIZER_LINUX || SANITIZER_FREEBSD
+  extern unsigned IOCTL_MTIOCGET;
+  extern unsigned IOCTL_MTIOCTOP;
+  extern unsigned IOCTL_SIOCADDRT;
+  extern unsigned IOCTL_SIOCDELRT;
   extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
   extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
   extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
@@ -840,40 +1138,14 @@
   extern unsigned IOCTL_SOUND_PCM_READ_RATE;
   extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
   extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
-  extern unsigned IOCTL_TCFLSH;
-  extern unsigned IOCTL_TCGETA;
-  extern unsigned IOCTL_TCGETS;
-  extern unsigned IOCTL_TCSBRK;
-  extern unsigned IOCTL_TCSBRKP;
-  extern unsigned IOCTL_TCSETA;
-  extern unsigned IOCTL_TCSETAF;
-  extern unsigned IOCTL_TCSETAW;
-  extern unsigned IOCTL_TCSETS;
-  extern unsigned IOCTL_TCSETSF;
-  extern unsigned IOCTL_TCSETSW;
-  extern unsigned IOCTL_TCXONC;
-  extern unsigned IOCTL_TIOCGLCKTRMIOS;
-  extern unsigned IOCTL_TIOCGSOFTCAR;
-  extern unsigned IOCTL_TIOCINQ;
-  extern unsigned IOCTL_TIOCLINUX;
-  extern unsigned IOCTL_TIOCSERCONFIG;
-  extern unsigned IOCTL_TIOCSERGETLSR;
-  extern unsigned IOCTL_TIOCSERGWILD;
-  extern unsigned IOCTL_TIOCSERSWILD;
-  extern unsigned IOCTL_TIOCSLCKTRMIOS;
-  extern unsigned IOCTL_TIOCSSOFTCAR;
   extern unsigned IOCTL_VT_ACTIVATE;
-  extern unsigned IOCTL_VT_DISALLOCATE;
   extern unsigned IOCTL_VT_GETMODE;
-  extern unsigned IOCTL_VT_GETSTATE;
   extern unsigned IOCTL_VT_OPENQRY;
   extern unsigned IOCTL_VT_RELDISP;
-  extern unsigned IOCTL_VT_RESIZE;
-  extern unsigned IOCTL_VT_RESIZEX;
-  extern unsigned IOCTL_VT_SENDSIG;
   extern unsigned IOCTL_VT_SETMODE;
   extern unsigned IOCTL_VT_WAITACTIVE;
-#endif
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
+
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned IOCTL_CYGETDEFTHRESH;
   extern unsigned IOCTL_CYGETDEFTIMEOUT;
@@ -899,37 +1171,25 @@
   extern unsigned IOCTL_FS_IOC_SETVERSION;
   extern unsigned IOCTL_GIO_CMAP;
   extern unsigned IOCTL_GIO_FONT;
-  extern unsigned IOCTL_GIO_SCRNMAP;
   extern unsigned IOCTL_GIO_UNIMAP;
   extern unsigned IOCTL_GIO_UNISCRNMAP;
   extern unsigned IOCTL_KDADDIO;
   extern unsigned IOCTL_KDDELIO;
-  extern unsigned IOCTL_KDDISABIO;
-  extern unsigned IOCTL_KDENABIO;
   extern unsigned IOCTL_KDGETKEYCODE;
-  extern unsigned IOCTL_KDGETLED;
-  extern unsigned IOCTL_KDGETMODE;
   extern unsigned IOCTL_KDGKBDIACR;
   extern unsigned IOCTL_KDGKBENT;
   extern unsigned IOCTL_KDGKBLED;
   extern unsigned IOCTL_KDGKBMETA;
-  extern unsigned IOCTL_KDGKBMODE;
   extern unsigned IOCTL_KDGKBSENT;
-  extern unsigned IOCTL_KDGKBTYPE;
   extern unsigned IOCTL_KDMAPDISP;
-  extern unsigned IOCTL_KDMKTONE;
   extern unsigned IOCTL_KDSETKEYCODE;
-  extern unsigned IOCTL_KDSETLED;
-  extern unsigned IOCTL_KDSETMODE;
   extern unsigned IOCTL_KDSIGACCEPT;
   extern unsigned IOCTL_KDSKBDIACR;
   extern unsigned IOCTL_KDSKBENT;
   extern unsigned IOCTL_KDSKBLED;
   extern unsigned IOCTL_KDSKBMETA;
-  extern unsigned IOCTL_KDSKBMODE;
   extern unsigned IOCTL_KDSKBSENT;
   extern unsigned IOCTL_KDUNMAPDISP;
-  extern unsigned IOCTL_KIOCSOUND;
   extern unsigned IOCTL_LPABORT;
   extern unsigned IOCTL_LPABORTOPEN;
   extern unsigned IOCTL_LPCAREFUL;
@@ -944,7 +1204,6 @@
   extern unsigned IOCTL_MTIOCSETCONFIG;
   extern unsigned IOCTL_PIO_CMAP;
   extern unsigned IOCTL_PIO_FONT;
-  extern unsigned IOCTL_PIO_SCRNMAP;
   extern unsigned IOCTL_PIO_UNIMAP;
   extern unsigned IOCTL_PIO_UNIMAPCLR;
   extern unsigned IOCTL_PIO_UNISCRNMAP;
@@ -972,9 +1231,29 @@
   extern unsigned IOCTL_TIOCSERGETMULTI;
   extern unsigned IOCTL_TIOCSERSETMULTI;
   extern unsigned IOCTL_TIOCSSERIAL;
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+
+#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  extern unsigned IOCTL_GIO_SCRNMAP;
+  extern unsigned IOCTL_KDDISABIO;
+  extern unsigned IOCTL_KDENABIO;
+  extern unsigned IOCTL_KDGETLED;
+  extern unsigned IOCTL_KDGETMODE;
+  extern unsigned IOCTL_KDGKBMODE;
+  extern unsigned IOCTL_KDGKBTYPE;
+  extern unsigned IOCTL_KDMKTONE;
+  extern unsigned IOCTL_KDSETLED;
+  extern unsigned IOCTL_KDSETMODE;
+  extern unsigned IOCTL_KDSKBMODE;
+  extern unsigned IOCTL_KIOCSOUND;
+  extern unsigned IOCTL_PIO_SCRNMAP;
 #endif
 
+  extern const int errno_EINVAL;
   extern const int errno_EOWNERDEAD;
+
+  extern const int si_SEGV_MAPERR;
+  extern const int si_SEGV_ACCERR;
 }  // namespace __sanitizer
 
 #define CHECK_TYPE_SIZE(TYPE) \
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index ffe91df..8df1fa7 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
 
 #include "sanitizer_common.h"
 #include "sanitizer_libc.h"
@@ -22,6 +22,14 @@
 
 #include <sys/mman.h>
 
+#if SANITIZER_LINUX
+#include <sys/utsname.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <sys/personality.h>
+#endif
+
 namespace __sanitizer {
 
 // ------------- sanitizer_common.h
@@ -29,21 +37,65 @@
   return GetPageSize();
 }
 
+#if SANITIZER_WORDSIZE == 32
+// Take care of unusable kernel area in top gigabyte.
+static uptr GetKernelAreaSize() {
+#if SANITIZER_LINUX
+  const uptr gbyte = 1UL << 30;
+
+  // Firstly check if there are writable segments
+  // mapped to top gigabyte (e.g. stack).
+  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+  uptr end, prot;
+  while (proc_maps.Next(/*start*/0, &end,
+                        /*offset*/0, /*filename*/0,
+                        /*filename_size*/0, &prot)) {
+    if ((end >= 3 * gbyte)
+        && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
+      return 0;
+  }
+
+#if !SANITIZER_ANDROID
+  // Even if nothing is mapped, top Gb may still be accessible
+  // if we are running on 64-bit kernel.
+  // Uname may report misleading results if personality type
+  // is modified (e.g. under schroot) so check this as well.
+  struct utsname uname_info;
+  int pers = personality(0xffffffffUL);
+  if (!(pers & PER_MASK)
+      && uname(&uname_info) == 0
+      && internal_strstr(uname_info.machine, "64"))
+    return 0;
+#endif  // SANITIZER_ANDROID
+
+  // Top gigabyte is reserved for kernel.
+  return gbyte;
+#else
+  return 0;
+#endif  // SANITIZER_LINUX
+}
+#endif  // SANITIZER_WORDSIZE == 32
+
 uptr GetMaxVirtualAddress() {
 #if SANITIZER_WORDSIZE == 64
 # if defined(__powerpc64__)
   // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
-  // We somehow need to figure our which one we are using now and choose
+  // We somehow need to figure out which one we are using now and choose
   // 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
+# elif defined(__aarch64__)
+  return (1ULL << 39) - 1;
 # else
   return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
 # endif
 #else  // SANITIZER_WORDSIZE == 32
-  // FIXME: We can probably lower this on Android?
-  return (1ULL << 32) - 1;  // 0xffffffff;
+  uptr res = (1ULL << 32) - 1;  // 0xffffffff;
+  if (!common_flags()->full_address_space)
+    res -= GetKernelAreaSize();
+  CHECK_LT(reinterpret_cast<uptr>(&res), res);
+  return res;
 #endif  // SANITIZER_WORDSIZE
 }
 
@@ -62,11 +114,13 @@
       Die();
     }
     recursion_count++;
-    Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
+    Report("ERROR: %s failed to "
+           "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
            SanitizerToolName, size, size, mem_type, reserrno);
     DumpProcessMap();
     CHECK("unable to mmap" && 0);
   }
+  IncreaseTotalMmap(size);
   return (void *)res;
 }
 
@@ -78,6 +132,25 @@
            SanitizerToolName, size, size, addr);
     CHECK("unable to unmap" && 0);
   }
+  DecreaseTotalMmap(size);
+}
+
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+  uptr PageSize = GetPageSizeCached();
+  uptr p = internal_mmap(0,
+      RoundUpTo(size, PageSize),
+      PROT_READ | PROT_WRITE,
+      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+      -1, 0);
+  int reserrno;
+  if (internal_iserror(p, &reserrno)) {
+    Report("ERROR: %s failed to "
+           "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
+           SanitizerToolName, size, size, mem_type, reserrno);
+    CHECK("unable to mmap" && 0);
+  }
+  IncreaseTotalMmap(size);
+  return (void *)p;
 }
 
 void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
@@ -89,9 +162,10 @@
       -1, 0);
   int reserrno;
   if (internal_iserror(p, &reserrno))
-    Report("ERROR: "
-           "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+    Report("ERROR: %s failed to "
+           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
            SanitizerToolName, size, size, fixed_addr, reserrno);
+  IncreaseTotalMmap(size);
   return (void *)p;
 }
 
@@ -104,11 +178,12 @@
       -1, 0);
   int reserrno;
   if (internal_iserror(p, &reserrno)) {
-    Report("ERROR:"
-           " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+    Report("ERROR: %s failed to "
+           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
            SanitizerToolName, size, size, fixed_addr, reserrno);
     CHECK("unable to mmap" && 0);
   }
+  IncreaseTotalMmap(size);
   return (void *)p;
 }
 
@@ -131,6 +206,17 @@
   return internal_iserror(map) ? 0 : (void *)map;
 }
 
+void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+  uptr flags = MAP_SHARED;
+  if (addr) flags |= MAP_FIXED;
+  uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
+  if (internal_iserror(p)) {
+    Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset,
+           size, p);
+    return 0;
+  }
+  return (void *)p;
+}
 
 static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
                                         uptr start2, uptr end2) {
@@ -159,7 +245,7 @@
   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
   uptr start, end;
   const sptr kBufSize = 4095;
-  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
+  char *filename = (char*)MmapOrDie(kBufSize, __func__);
   Report("Process memory map follows:\n");
   while (proc_maps.Next(&start, &end, /* file_offset */0,
                         filename, kBufSize, /* protection */0)) {
@@ -198,10 +284,15 @@
 }
 
 void MaybeOpenReportFile() {
-  if (!log_to_file || (report_fd_pid == internal_getpid())) return;
+  if (!log_to_file) return;
+  uptr pid = internal_getpid();
+  // If in tracer, use the parent's file.
+  if (pid == stoptheworld_tracer_pid)
+    pid = stoptheworld_tracer_ppid;
+  if (report_fd_pid == pid) return;
   InternalScopedBuffer<char> report_path_full(4096);
   internal_snprintf(report_path_full.data(), report_path_full.size(),
-                    "%s.%d", report_path_prefix, internal_getpid());
+                    "%s.%zu", report_path_prefix, pid);
   uptr openrv = OpenFile(report_path_full.data(), true);
   if (internal_iserror(openrv)) {
     report_fd = kStderrFd;
@@ -214,7 +305,7 @@
     internal_close(report_fd);
   }
   report_fd = openrv;
-  report_fd_pid = internal_getpid();
+  report_fd_pid = pid;
 }
 
 void RawWrite(const char *buffer) {
@@ -230,12 +321,11 @@
 
 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
   uptr s, e, off, prot;
-  InternalMmapVector<char> fn(4096);
-  fn.push_back(0);
+  InternalScopedString buff(4096);
   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
-  while (proc_maps.Next(&s, &e, &off, &fn[0], fn.capacity(), &prot)) {
+  while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
     if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
-        && internal_strcmp(module, &fn[0]) == 0) {
+        && internal_strcmp(module, buff.data()) == 0) {
       *start = s;
       *end = e;
       return true;
@@ -246,4 +336,4 @@
 
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_LINUX || SANITIZER_MAC
+#endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 6032f52..e859959 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -14,12 +14,15 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_POSIX
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_stacktrace.h"
 
 #include <errno.h>
 #include <pthread.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
@@ -51,7 +54,7 @@
 bool StackSizeIsUnlimited() {
   struct rlimit rlim;
   CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
-  return (rlim.rlim_cur == (uptr)-1);
+  return ((uptr)rlim.rlim_cur == (uptr)-1);
 }
 
 void SetStackSizeLimitInBytes(uptr limit) {
@@ -89,6 +92,59 @@
   return isatty(fd);
 }
 
+#ifndef SANITIZER_GO
+// TODO(glider): different tools may require different altstack size.
+static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
+
+void SetAlternateSignalStack() {
+  stack_t altstack, oldstack;
+  CHECK_EQ(0, sigaltstack(0, &oldstack));
+  // If the alternate stack is already in place, do nothing.
+  // Android always sets an alternate stack, but it's too small for us.
+  if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
+  // TODO(glider): the mapped stack should have the MAP_STACK flag in the
+  // future. It is not required by man 2 sigaltstack now (they're using
+  // malloc()).
+  void* base = MmapOrDie(kAltStackSize, __func__);
+  altstack.ss_sp = (char*) base;
+  altstack.ss_flags = 0;
+  altstack.ss_size = kAltStackSize;
+  CHECK_EQ(0, sigaltstack(&altstack, 0));
+}
+
+void UnsetAlternateSignalStack() {
+  stack_t altstack, oldstack;
+  altstack.ss_sp = 0;
+  altstack.ss_flags = SS_DISABLE;
+  altstack.ss_size = kAltStackSize;  // Some sane value required on Darwin.
+  CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
+  UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
+}
+
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+static void MaybeInstallSigaction(int signum,
+                                  SignalHandlerType handler) {
+  if (!IsDeadlySignal(signum))
+    return;
+  struct sigaction sigact;
+  internal_memset(&sigact, 0, sizeof(sigact));
+  sigact.sa_sigaction = (sa_sigaction_t)handler;
+  sigact.sa_flags = SA_SIGINFO;
+  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);
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+  // Set the alternate signal stack for the main thread.
+  // This will cause SetAlternateSignalStack to be called twice, but the stack
+  // will be actually set only once.
+  if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
+  MaybeInstallSigaction(SIGSEGV, handler);
+  MaybeInstallSigaction(SIGBUS, handler);
+}
+#endif  // SANITIZER_GO
+
 }  // namespace __sanitizer
 
-#endif
+#endif  // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index bbdb24b..8018131 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -16,6 +16,7 @@
 
 
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
 
 #include <stdio.h>
@@ -94,11 +95,14 @@
                       minimal_num_length, pad_with_zero, negative);
 }
 
-static int AppendString(char **buff, const char *buff_end, const char *s) {
+static int AppendString(char **buff, const char *buff_end, int precision,
+                        const char *s) {
   if (s == 0)
     s = "<null>";
   int result = 0;
   for (; *s; s++) {
+    if (precision >= 0 && result >= precision)
+      break;
     result += AppendChar(buff, buff_end, *s);
   }
   return result;
@@ -106,7 +110,7 @@
 
 static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
   int result = 0;
-  result += AppendString(buff, buff_end, "0x");
+  result += AppendString(buff, buff_end, -1, "0x");
   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
                            (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
   return result;
@@ -115,7 +119,7 @@
 int VSNPrintf(char *buff, int buff_length,
               const char *format, va_list args) {
   static const char *kPrintfFormatsHelp =
-    "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
+    "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
   RAW_CHECK(format);
   RAW_CHECK(buff_length > 0);
   const char *buff_end = &buff[buff_length - 1];
@@ -135,6 +139,12 @@
         width = width * 10 + *cur++ - '0';
       }
     }
+    bool have_precision = (cur[0] == '.' && cur[1] == '*');
+    int precision = -1;
+    if (have_precision) {
+      cur += 2;
+      precision = va_arg(args, int);
+    }
     bool have_z = (*cur == 'z');
     cur += have_z;
     bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
@@ -142,6 +152,8 @@
     s64 dval;
     u64 uval;
     bool have_flags = have_width | have_z | have_ll;
+    // Only %s supports precision for now
+    CHECK(!(precision >= 0 && *cur != 's'));
     switch (*cur) {
       case 'd': {
         dval = have_ll ? va_arg(args, s64)
@@ -167,7 +179,7 @@
       }
       case 's': {
         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
-        result += AppendString(&buff, buff_end, va_arg(args, char*));
+        result += AppendString(&buff, buff_end, precision, va_arg(args, char*));
         break;
       }
       case 'c': {
@@ -260,6 +272,7 @@
     break;
   }
   RawWrite(buffer);
+  AndroidLogWrite(buffer);
   CallPrintfAndReportCallback(buffer);
   // If we had mapped any memory, clean up.
   if (buffer != local_buffer)
@@ -267,6 +280,7 @@
   va_end(args2);
 }
 
+FORMAT(1, 2)
 void Printf(const char *format, ...) {
   va_list args;
   va_start(args, format);
@@ -275,6 +289,7 @@
 }
 
 // Like Printf, but prints the current PID before the output string.
+FORMAT(1, 2)
 void Report(const char *format, ...) {
   va_list args;
   va_start(args, format);
@@ -286,6 +301,7 @@
 // Returns the number of symbols that should have been written to buffer
 // (not including trailing '\0'). Thus, the string is truncated
 // iff return value is not less than "length".
+FORMAT(3, 4)
 int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
   va_list args;
   va_start(args, format);
@@ -294,6 +310,7 @@
   return needed_length;
 }
 
+FORMAT(2, 3)
 void InternalScopedString::append(const char *format, ...) {
   CHECK_LT(length_, size());
   va_list args;
@@ -301,6 +318,7 @@
   VSNPrintf(data() + length_, size() - length_, format, args);
   va_end(args);
   length_ += internal_strlen(data() + length_);
+  CHECK_LT(length_, size());
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_procmaps.h b/lib/sanitizer_common/sanitizer_procmaps.h
index 65bcac6..c59a27c 100644
--- a/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/lib/sanitizer_common/sanitizer_procmaps.h
@@ -14,49 +14,35 @@
 #ifndef SANITIZER_PROCMAPS_H
 #define SANITIZER_PROCMAPS_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_mutex.h"
 
 namespace __sanitizer {
 
-#if SANITIZER_WINDOWS
-class MemoryMappingLayout {
- public:
-  explicit MemoryMappingLayout(bool cache_enabled) {
-    (void)cache_enabled;
-  }
-  bool GetObjectNameAndOffset(uptr addr, uptr *offset,
-                              char filename[], uptr filename_size,
-                              uptr *protection) {
-    UNIMPLEMENTED();
-  }
-};
-
-#else  // SANITIZER_WINDOWS
-#if SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX
 struct ProcSelfMapsBuff {
   char *data;
   uptr mmaped_size;
   uptr len;
 };
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
 
 class MemoryMappingLayout {
  public:
   explicit MemoryMappingLayout(bool cache_enabled);
+  ~MemoryMappingLayout();
   bool Next(uptr *start, uptr *end, uptr *offset,
             char filename[], uptr filename_size, uptr *protection);
   void Reset();
-  // Gets the object file name and the offset in that object for a given
-  // address 'addr'. Returns true on success.
-  bool GetObjectNameAndOffset(uptr addr, uptr *offset,
-                              char filename[], uptr filename_size,
-                              uptr *protection);
   // In some cases, e.g. when running under a sandbox on Linux, ASan is unable
   // to obtain the memory mappings. It should fall back to pre-cached data
   // instead of aborting.
   static void CacheMemoryMappings();
-  ~MemoryMappingLayout();
+
+  // Stores the list of mapped objects into an array.
+  uptr DumpListOfModules(LoadedModule *modules, uptr max_modules,
+                         string_predicate_t filter);
 
   // Memory protection masks.
   static const uptr kProtectionRead = 1;
@@ -66,39 +52,10 @@
 
  private:
   void LoadFromCache();
-  // Default implementation of GetObjectNameAndOffset.
-  // Quite slow, because it iterates through the whole process map for each
-  // lookup.
-  bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
-                                     char filename[], uptr filename_size,
-                                     uptr *protection) {
-    Reset();
-    uptr start, end, file_offset;
-    for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size,
-                         protection);
-         i++) {
-      if (addr >= start && addr < end) {
-        // Don't subtract 'start' for 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.
-        *offset = (addr - (i ? start : 0)) + file_offset;
-        return true;
-      }
-    }
-    if (filename_size)
-      filename[0] = '\0';
-    return false;
-  }
 
-# if SANITIZER_LINUX
+  // FIXME: Hide implementation details for different platforms in
+  // platform-specific files.
+# if SANITIZER_FREEBSD || SANITIZER_LINUX
   ProcSelfMapsBuff proc_self_maps_;
   char *current_;
 
@@ -129,8 +86,6 @@
 // Returns code range for the specified module.
 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
 
-#endif  // SANITIZER_WINDOWS
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_PROCMAPS_H
diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
new file mode 100644
index 0000000..4e8bf10
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -0,0 +1,304 @@
+//===-- sanitizer_procmaps_linux.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 (Linux-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FREEBSD || 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
+  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,
+                               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;
+#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;
+  // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
+  *start = ParseHex(&current_);
+  CHECK_EQ(*current_++, '-');
+  *end = ParseHex(&current_);
+  CHECK_EQ(*current_++, ' ');
+  CHECK(IsOneOf(*current_, '-', 'r'));
+  *protection = 0;
+  if (*current_++ == 'r')
+    *protection |= kProtectionRead;
+  CHECK(IsOneOf(*current_, '-', 'w'));
+  if (*current_++ == 'w')
+    *protection |= kProtectionWrite;
+  CHECK(IsOneOf(*current_, '-', 'x'));
+  if (*current_++ == 'x')
+    *protection |= kProtectionExecute;
+  CHECK(IsOneOf(*current_, 's', 'p'));
+  if (*current_++ == 's')
+    *protection |= kProtectionShared;
+  CHECK_EQ(*current_++, ' ');
+  *offset = ParseHex(&current_);
+  CHECK_EQ(*current_++, ' ');
+  ParseHex(&current_);
+  CHECK_EQ(*current_++, ':');
+  ParseHex(&current_);
+  CHECK_EQ(*current_++, ' ');
+  while (IsDecimal(*current_))
+    current_++;
+  // Qemu may lack the trailing space.
+  // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+  // CHECK_EQ(*current_++, ' ');
+  // Skip spaces.
+  while (current_ < next_line && *current_ == ' ')
+    current_++;
+  // Fill in the filename.
+  uptr i = 0;
+  while (current_ < next_line) {
+    if (filename && i < filename_size - 1)
+      filename[i++] = *current_;
+    current_++;
+  }
+  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;
+  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(), 0);
+       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);
+    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
diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
new file mode 100644
index 0000000..1eb02ab
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -0,0 +1,188 @@
+//===-- sanitizer_procmaps_mac.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 (Mac-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
+
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+
+namespace __sanitizer {
+
+MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
+  Reset();
+}
+
+MemoryMappingLayout::~MemoryMappingLayout() {
+}
+
+// More information about Mach-O headers can be found in mach-o/loader.h
+// Each Mach-O image has a header (mach_header or mach_header_64) starting with
+// a magic number, and a list of linker load commands directly following the
+// header.
+// A load command is at least two 32-bit words: the command type and the
+// command size in bytes. We're interested only in segment load commands
+// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
+// into the task's address space.
+// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
+// segment_command_64 correspond to the memory address, memory size and the
+// file offset of the current memory segment.
+// Because these fields are taken from the images as is, one needs to add
+// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
+
+void MemoryMappingLayout::Reset() {
+  // Count down from the top.
+  // TODO(glider): as per man 3 dyld, iterating over the headers with
+  // _dyld_image_count is thread-unsafe. We need to register callbacks for
+  // adding and removing images which will invalidate the MemoryMappingLayout
+  // state.
+  current_image_ = _dyld_image_count();
+  current_load_cmd_count_ = -1;
+  current_load_cmd_addr_ = 0;
+  current_magic_ = 0;
+  current_filetype_ = 0;
+}
+
+// static
+void MemoryMappingLayout::CacheMemoryMappings() {
+  // No-op on Mac for now.
+}
+
+void MemoryMappingLayout::LoadFromCache() {
+  // No-op on Mac for now.
+}
+
+// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
+// Google Perftools, http://code.google.com/p/google-perftools.
+
+// NextSegmentLoad scans the current image for the next segment load command
+// and returns the start and end addresses and file offset of the corresponding
+// segment.
+// Note that the segment addresses are not necessarily sorted.
+template<u32 kLCSegment, typename SegmentCommand>
+bool MemoryMappingLayout::NextSegmentLoad(
+    uptr *start, uptr *end, uptr *offset,
+    char filename[], uptr filename_size, uptr *protection) {
+  if (protection)
+    UNIMPLEMENTED();
+  const char* lc = current_load_cmd_addr_;
+  current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
+  if (((const load_command *)lc)->cmd == kLCSegment) {
+    const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
+    const SegmentCommand* sc = (const SegmentCommand *)lc;
+    if (start) *start = sc->vmaddr + dlloff;
+    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+    if (offset) {
+      if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
+        *offset = sc->vmaddr;
+      } else {
+        *offset = sc->fileoff;
+      }
+    }
+    if (filename) {
+      internal_strncpy(filename, _dyld_get_image_name(current_image_),
+                       filename_size);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
+                               char filename[], uptr filename_size,
+                               uptr *protection) {
+  for (; current_image_ >= 0; current_image_--) {
+    const mach_header* hdr = _dyld_get_image_header(current_image_);
+    if (!hdr) continue;
+    if (current_load_cmd_count_ < 0) {
+      // Set up for this image;
+      current_load_cmd_count_ = hdr->ncmds;
+      current_magic_ = hdr->magic;
+      current_filetype_ = hdr->filetype;
+      switch (current_magic_) {
+#ifdef MH_MAGIC_64
+        case MH_MAGIC_64: {
+          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+          break;
+        }
+#endif
+        case MH_MAGIC: {
+          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+          break;
+        }
+        default: {
+          continue;
+        }
+      }
+    }
+
+    for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
+      switch (current_magic_) {
+        // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
+#ifdef MH_MAGIC_64
+        case MH_MAGIC_64: {
+          if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
+                  start, end, offset, filename, filename_size, protection))
+            return true;
+          break;
+        }
+#endif
+        case MH_MAGIC: {
+          if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
+                  start, end, offset, filename, filename_size, protection))
+            return true;
+          break;
+        }
+      }
+    }
+    // If we get here, no more load_cmd's in this image talk about
+    // segments.  Go on to the next image.
+  }
+  return false;
+}
+
+uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
+                                            uptr max_modules,
+                                            string_predicate_t filter) {
+  Reset();
+  uptr cur_beg, cur_end;
+  InternalScopedBuffer<char> module_name(kMaxPathLength);
+  uptr n_modules = 0;
+  for (uptr i = 0; n_modules < max_modules &&
+                       Next(&cur_beg, &cur_end, 0, module_name.data(),
+                            module_name.size(), 0);
+       i++) {
+    const char *cur_name = module_name.data();
+    if (cur_name[0] == '\0')
+      continue;
+    if (filter && !filter(cur_name))
+      continue;
+    LoadedModule *cur_module = 0;
+    if (n_modules > 0 &&
+        0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
+      cur_module = &modules[n_modules - 1];
+    } else {
+      void *mem = &modules[n_modules];
+      cur_module = new(mem) LoadedModule(cur_name, cur_beg);
+      n_modules++;
+    }
+    cur_module->addAddressRange(cur_beg, cur_end);
+  }
+  return n_modules;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_report_decorator.h b/lib/sanitizer_common/sanitizer_report_decorator.h
index eef2b15..6e5b0ed 100644
--- a/lib/sanitizer_common/sanitizer_report_decorator.h
+++ b/lib/sanitizer_common/sanitizer_report_decorator.h
@@ -17,6 +17,8 @@
 #ifndef SANITIZER_REPORT_DECORATOR_H
 #define SANITIZER_REPORT_DECORATOR_H
 
+#include "sanitizer_common.h"
+
 namespace __sanitizer {
 class AnsiColorDecorator {
   // FIXME: This is not portable. It assumes the special strings are printed to
@@ -36,6 +38,15 @@
  private:
   bool ansi_;
 };
+
+class SanitizerCommonDecorator: protected AnsiColorDecorator {
+ public:
+  SanitizerCommonDecorator()
+      : __sanitizer::AnsiColorDecorator(ColorizeReports()) { }
+  const char *Warning()    { return Red(); }
+  const char *EndWarning() { return Default(); }
+};
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_REPORT_DECORATOR_H
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc
index 2793bd0..da5bd4a 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.cc
+++ b/lib/sanitizer_common/sanitizer_stackdepot.cc
@@ -12,193 +12,116 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_stackdepot.h"
+
 #include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_atomic.h"
+#include "sanitizer_stackdepotbase.h"
 
 namespace __sanitizer {
 
-const int kTabSize = 1024 * 1024;  // Hash table size.
-const int kPartBits = 8;
-const int kPartShift = sizeof(u32) * 8 - kPartBits - 1;
-const int kPartCount = 1 << kPartBits;  // Number of subparts in the table.
-const int kPartSize = kTabSize / kPartCount;
-const int kMaxId = 1 << kPartShift;
-
-struct StackDesc {
-  StackDesc *link;
-  u32 id;
-  u32 hash;
+struct StackDepotDesc {
+  const uptr *stack;
   uptr size;
-  uptr stack[1];  // [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; }
 };
 
-static struct {
-  StaticSpinMutex mtx;  // Protects alloc of new blocks for region allocator.
-  atomic_uintptr_t region_pos;  // Region allocator for StackDesc's.
-  atomic_uintptr_t region_end;
-  atomic_uintptr_t tab[kTabSize];  // Hash table of StackDesc's.
-  atomic_uint32_t seq[kPartCount];  // Unique id generators.
-} depot;
+struct StackDepotNode {
+  StackDepotNode *link;
+  u32 id;
+  atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20;
+  uptr size;
+  uptr stack[1];  // [size]
 
-static StackDepotStats stats;
+  static const u32 kUseCountBits = 20;
+  static const u32 kMaxUseCount = 1 << kUseCountBits;
+  static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
+  static const u32 kHashMask = ~kUseCountMask;
+
+  typedef StackDepotDesc 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;
+    }
+    return true;
+  }
+  static uptr storage_size(const args_type &args) {
+    return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
+  }
+  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));
+  }
+  args_type load() const {
+    args_type ret = {&stack[0], size};
+    return ret;
+  }
+  StackDepotHandle get_handle() { return StackDepotHandle(this); }
+
+  typedef StackDepotHandle handle_type;
+};
+
+COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount);
+
+u32 StackDepotHandle::id() { return node_->id; }
+int StackDepotHandle::use_count() {
+  return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) &
+         StackDepotNode::kUseCountMask;
+}
+void StackDepotHandle::inc_use_count_unsafe() {
+  u32 prev =
+      atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) &
+      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> StackDepot;
+static StackDepot theDepot;
 
 StackDepotStats *StackDepotGetStats() {
-  return &stats;
-}
-
-static u32 hash(const uptr *stack, uptr size) {
-  // 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;
-}
-
-static StackDesc *tryallocDesc(uptr memsz) {
-  // Optimisic lock-free allocation, essentially try to bump the region ptr.
-  for (;;) {
-    uptr cmp = atomic_load(&depot.region_pos, memory_order_acquire);
-    uptr end = atomic_load(&depot.region_end, memory_order_acquire);
-    if (cmp == 0 || cmp + memsz > end)
-      return 0;
-    if (atomic_compare_exchange_weak(
-        &depot.region_pos, &cmp, cmp + memsz,
-        memory_order_acquire))
-      return (StackDesc*)cmp;
-  }
-}
-
-static StackDesc *allocDesc(uptr size) {
-  // First, try to allocate optimisitically.
-  uptr memsz = sizeof(StackDesc) + (size - 1) * sizeof(uptr);
-  StackDesc *s = tryallocDesc(memsz);
-  if (s)
-    return s;
-  // If failed, lock, retry and alloc new superblock.
-  SpinMutexLock l(&depot.mtx);
-  for (;;) {
-    s = tryallocDesc(memsz);
-    if (s)
-      return s;
-    atomic_store(&depot.region_pos, 0, memory_order_relaxed);
-    uptr allocsz = 64 * 1024;
-    if (allocsz < memsz)
-      allocsz = memsz;
-    uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
-    stats.mapped += allocsz;
-    atomic_store(&depot.region_end, mem + allocsz, memory_order_release);
-    atomic_store(&depot.region_pos, mem, memory_order_release);
-  }
-}
-
-static u32 find(StackDesc *s, const uptr *stack, uptr size, u32 hash) {
-  // Searches linked list s for the stack, returns its id.
-  for (; s; s = s->link) {
-    if (s->hash == hash && s->size == size) {
-      uptr i = 0;
-      for (; i < size; i++) {
-        if (stack[i] != s->stack[i])
-          break;
-      }
-      if (i == size)
-        return s->id;
-    }
-  }
-  return 0;
-}
-
-static StackDesc *lock(atomic_uintptr_t *p) {
-  // Uses the pointer lsb as mutex.
-  for (int i = 0;; i++) {
-    uptr cmp = atomic_load(p, memory_order_relaxed);
-    if ((cmp & 1) == 0
-        && atomic_compare_exchange_weak(p, &cmp, cmp | 1,
-                                        memory_order_acquire))
-      return (StackDesc*)cmp;
-    if (i < 10)
-      proc_yield(10);
-    else
-      internal_sched_yield();
-  }
-}
-
-static void unlock(atomic_uintptr_t *p, StackDesc *s) {
-  DCHECK_EQ((uptr)s & 1, 0);
-  atomic_store(p, (uptr)s, memory_order_release);
+  return theDepot.GetStats();
 }
 
 u32 StackDepotPut(const uptr *stack, uptr size) {
-  if (stack == 0 || size == 0)
-    return 0;
-  uptr h = hash(stack, size);
-  atomic_uintptr_t *p = &depot.tab[h % kTabSize];
-  uptr v = atomic_load(p, memory_order_consume);
-  StackDesc *s = (StackDesc*)(v & ~1);
-  // First, try to find the existing stack.
-  u32 id = find(s, stack, size, h);
-  if (id)
-    return id;
-  // If failed, lock, retry and insert new.
-  StackDesc *s2 = lock(p);
-  if (s2 != s) {
-    id = find(s2, stack, size, h);
-    if (id) {
-      unlock(p, s2);
-      return id;
-    }
-  }
-  uptr part = (h % kTabSize) / kPartSize;
-  id = atomic_fetch_add(&depot.seq[part], 1, memory_order_relaxed) + 1;
-  stats.n_uniq_ids++;
-  CHECK_LT(id, kMaxId);
-  id |= part << kPartShift;
-  CHECK_NE(id, 0);
-  CHECK_EQ(id & (1u << 31), 0);
-  s = allocDesc(size);
-  s->id = id;
-  s->hash = h;
-  s->size = size;
-  internal_memcpy(s->stack, stack, size * sizeof(uptr));
-  s->link = s2;
-  unlock(p, s);
-  return id;
+  StackDepotDesc desc = {stack, size};
+  StackDepotHandle h = theDepot.Put(desc);
+  return h.valid() ? h.id() : 0;
+}
+
+StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) {
+  StackDepotDesc desc = {stack, size};
+  return theDepot.Put(desc);
 }
 
 const uptr *StackDepotGet(u32 id, uptr *size) {
-  if (id == 0)
-    return 0;
-  CHECK_EQ(id & (1u << 31), 0);
-  // High kPartBits contain part id, so we need to scan at most kPartSize lists.
-  uptr part = id >> kPartShift;
-  for (int i = 0; i != kPartSize; i++) {
-    uptr idx = part * kPartSize + i;
-    CHECK_LT(idx, kTabSize);
-    atomic_uintptr_t *p = &depot.tab[idx];
-    uptr v = atomic_load(p, memory_order_consume);
-    StackDesc *s = (StackDesc*)(v & ~1);
-    for (; s; s = s->link) {
-      if (s->id == id) {
-        *size = s->size;
-        return s->stack;
-      }
-    }
-  }
-  *size = 0;
-  return 0;
+  StackDepotDesc desc = theDepot.Get(id);
+  *size = desc.size;
+  return desc.stack;
 }
 
 bool StackDepotReverseMap::IdDescPair::IdComparator(
@@ -209,10 +132,10 @@
 
 StackDepotReverseMap::StackDepotReverseMap()
     : map_(StackDepotGetStats()->n_uniq_ids + 100) {
-  for (int idx = 0; idx < kTabSize; idx++) {
-    atomic_uintptr_t *p = &depot.tab[idx];
+  for (int idx = 0; idx < StackDepot::kTabSize; idx++) {
+    atomic_uintptr_t *p = &theDepot.tab[idx];
     uptr v = atomic_load(p, memory_order_consume);
-    StackDesc *s = (StackDesc*)(v & ~1);
+    StackDepotNode *s = (StackDepotNode*)(v & ~1);
     for (; s; s = s->link) {
       IdDescPair pair = {s->id, s};
       map_.push_back(pair);
@@ -230,7 +153,7 @@
     *size = 0;
     return 0;
   }
-  StackDesc *desc = map_[idx].desc;
+  StackDepotNode *desc = map_[idx].desc;
   *size = desc->size;
   return desc->stack;
 }
diff --git a/lib/sanitizer_common/sanitizer_stackdepot.h b/lib/sanitizer_common/sanitizer_stackdepot.h
index 4f77ff2..58cc91f 100644
--- a/lib/sanitizer_common/sanitizer_stackdepot.h
+++ b/lib/sanitizer_common/sanitizer_stackdepot.h
@@ -19,20 +19,26 @@
 namespace __sanitizer {
 
 // StackDepot efficiently stores huge amounts of stack traces.
-
-// Maps stack trace to an unique id.
-u32 StackDepotPut(const uptr *stack, uptr size);
-// Retrieves a stored stack trace by the id.
-const uptr *StackDepotGet(u32 id, uptr *size);
-
-struct StackDepotStats {
-  uptr n_uniq_ids;
-  uptr mapped;
+struct StackDepotNode;
+struct StackDepotHandle {
+  StackDepotNode *node_;
+  StackDepotHandle() : node_(0) {}
+  explicit StackDepotHandle(StackDepotNode *node) : node_(node) {}
+  bool valid() { return node_; }
+  u32 id();
+  int use_count();
+  void inc_use_count_unsafe();
+  uptr size();
+  uptr *stack();
 };
 
-StackDepotStats *StackDepotGetStats();
+const int kStackDepotMaxUseCount = 1U << 20;
 
-struct StackDesc;
+StackDepotStats *StackDepotGetStats();
+u32 StackDepotPut(const uptr *stack, uptr size);
+StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size);
+// Retrieves a stored stack trace by the id.
+const uptr *StackDepotGet(u32 id, uptr *size);
 
 // Instantiating this class creates a snapshot of StackDepot which can be
 // efficiently queried with StackDepotGet(). You can use it concurrently with
@@ -46,7 +52,7 @@
  private:
   struct IdDescPair {
     u32 id;
-    StackDesc *desc;
+    StackDepotNode *desc;
 
     static bool IdComparator(const IdDescPair &a, const IdDescPair &b);
   };
@@ -57,6 +63,7 @@
   StackDepotReverseMap(const StackDepotReverseMap&);
   void operator=(const StackDepotReverseMap&);
 };
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_STACKDEPOT_H
diff --git a/lib/sanitizer_common/sanitizer_stackdepotbase.h b/lib/sanitizer_common/sanitizer_stackdepotbase.h
new file mode 100644
index 0000000..07a973c
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_stackdepotbase.h
@@ -0,0 +1,153 @@
+//===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of a mapping from arbitrary values to unique 32-bit
+// identifiers.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKDEPOTBASE_H
+#define SANITIZER_STACKDEPOTBASE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_persistent_allocator.h"
+
+namespace __sanitizer {
+
+template <class Node, int kReservedBits>
+class StackDepotBase {
+ public:
+  typedef typename Node::args_type args_type;
+  typedef typename Node::handle_type handle_type;
+  // Maps stack trace to an unique id.
+  handle_type Put(args_type args, bool *inserted = 0);
+  // Retrieves a stored stack trace by the id.
+  args_type Get(u32 id);
+
+  StackDepotStats *GetStats() { return &stats; }
+
+ private:
+  static Node *find(Node *s, args_type args, u32 hash);
+  static Node *lock(atomic_uintptr_t *p);
+  static void unlock(atomic_uintptr_t *p, Node *s);
+
+  static const int kTabSize = 1024 * 1024;  // Hash table size.
+  static const int kPartBits = 8;
+  static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits;
+  static const int kPartCount =
+      1 << kPartBits;  // Number of subparts in the table.
+  static const int kPartSize = kTabSize / kPartCount;
+  static const int kMaxId = 1 << kPartShift;
+
+  atomic_uintptr_t tab[kTabSize];   // Hash table of Node's.
+  atomic_uint32_t seq[kPartCount];  // Unique id generators.
+
+  StackDepotStats stats;
+
+  friend class StackDepotReverseMap;
+};
+
+template <class Node, int kReservedBits>
+Node *StackDepotBase<Node, kReservedBits>::find(Node *s, args_type args,
+                                                u32 hash) {
+  // Searches linked list s for the stack, returns its id.
+  for (; s; s = s->link) {
+    if (s->eq(hash, args)) {
+      return s;
+    }
+  }
+  return 0;
+}
+
+template <class Node, int kReservedBits>
+Node *StackDepotBase<Node, kReservedBits>::lock(atomic_uintptr_t *p) {
+  // Uses the pointer lsb as mutex.
+  for (int i = 0;; i++) {
+    uptr cmp = atomic_load(p, memory_order_relaxed);
+    if ((cmp & 1) == 0 &&
+        atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire))
+      return (Node *)cmp;
+    if (i < 10)
+      proc_yield(10);
+    else
+      internal_sched_yield();
+  }
+}
+
+template <class Node, int kReservedBits>
+void StackDepotBase<Node, kReservedBits>::unlock(atomic_uintptr_t *p, Node *s) {
+  DCHECK_EQ((uptr)s & 1, 0);
+  atomic_store(p, (uptr)s, memory_order_release);
+}
+
+template <class Node, int kReservedBits>
+typename StackDepotBase<Node, kReservedBits>::handle_type
+StackDepotBase<Node, kReservedBits>::Put(args_type args, bool *inserted) {
+  if (inserted) *inserted = false;
+  if (!args.is_valid()) return handle_type();
+  uptr h = args.hash();
+  atomic_uintptr_t *p = &tab[h % kTabSize];
+  uptr v = atomic_load(p, memory_order_consume);
+  Node *s = (Node *)(v & ~1);
+  // First, try to find the existing stack.
+  Node *node = find(s, args, h);
+  if (node) return node->get_handle();
+  // If failed, lock, retry and insert new.
+  Node *s2 = lock(p);
+  if (s2 != s) {
+    node = find(s2, args, h);
+    if (node) {
+      unlock(p, s2);
+      return node->get_handle();
+    }
+  }
+  uptr part = (h % kTabSize) / kPartSize;
+  u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1;
+  stats.n_uniq_ids++;
+  CHECK_LT(id, kMaxId);
+  id |= part << kPartShift;
+  CHECK_NE(id, 0);
+  CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+  uptr memsz = Node::storage_size(args);
+  s = (Node *)PersistentAlloc(memsz);
+  stats.allocated += memsz;
+  s->id = id;
+  s->store(args, h);
+  s->link = s2;
+  unlock(p, s);
+  if (inserted) *inserted = true;
+  return s->get_handle();
+}
+
+template <class Node, int kReservedBits>
+typename StackDepotBase<Node, kReservedBits>::args_type
+StackDepotBase<Node, kReservedBits>::Get(u32 id) {
+  if (id == 0) {
+    return args_type();
+  }
+  CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
+  // High kPartBits contain part id, so we need to scan at most kPartSize lists.
+  uptr part = id >> kPartShift;
+  for (int i = 0; i != kPartSize; i++) {
+    uptr idx = part * kPartSize + i;
+    CHECK_LT(idx, kTabSize);
+    atomic_uintptr_t *p = &tab[idx];
+    uptr v = atomic_load(p, memory_order_consume);
+    Node *s = (Node *)(v & ~1);
+    for (; s; s = s->link) {
+      if (s->id == id) {
+        return s->load();
+      }
+    }
+  }
+  return args_type();
+}
+
+} // namespace __sanitizer
+#endif  // SANITIZER_STACKDEPOTBASE_H
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc
index 70ce26b..c608fbb 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace.cc
@@ -13,9 +13,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
-#include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -24,97 +22,13 @@
   // Cancel Thumb bit.
   pc = pc & (~1);
 #endif
-#if defined(__powerpc__) || defined(__powerpc64__)
-  // PCs are always 4 byte aligned.
-  return pc - 4;
-#elif defined(__sparc__)
+#if defined(__sparc__)
   return pc - 8;
 #else
   return pc - 1;
 #endif
 }
 
-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,
-                            SymbolizeCallback symbolize_callback) {
-  if (addr == 0) {
-    Printf("<empty stack>\n\n");
-    return;
-  }
-  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
-  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
-  InternalScopedBuffer<AddressInfo> addr_frames(64);
-  InternalScopedString frame_desc(GetPageSizeCached() * 2);
-  uptr frame_num = 0;
-  for (uptr i = 0; i < size && addr[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 addr_frames_num = 0;  // The number of stack frames for current
-                               // instruction address.
-    if (symbolize_callback) {
-      if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
-        addr_frames_num = 1;
-        frame_desc.clear();
-        PrintStackFramePrefix(&frame_desc, frame_num, pc);
-        // We can't know anything about the string returned by external
-        // symbolizer, but if it starts with filename, try to strip path prefix
-        // from it.
-        frame_desc.append(
-            " %s",
-            StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
-        Printf("%s\n", frame_desc.data());
-        frame_num++;
-      }
-    }
-    if (common_flags()->symbolize && addr_frames_num == 0) {
-      // Use our own (online) symbolizer, if necessary.
-      if (Symbolizer *sym = Symbolizer::GetOrNull())
-        addr_frames_num =
-            sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
-      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);
-        }
-        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);
-        }
-        Printf("%s\n", frame_desc.data());
-        frame_num++;
-        info.Clear();
-      }
-    }
-    if (addr_frames_num == 0) {
-      // If online symbolization failed, try to output at least module and
-      // offset for instruction.
-      frame_desc.clear();
-      PrintStackFramePrefix(&frame_desc, frame_num, pc);
-      uptr offset;
-      if (proc_maps.GetObjectNameAndOffset(pc, &offset,
-                                           buff.data(), buff.size(),
-                                           /* protection */0)) {
-        frame_desc.append(" ");
-        PrintModuleAndOffset(&frame_desc, buff.data(), offset);
-      }
-      Printf("%s\n", frame_desc.data());
-      frame_num++;
-    }
-  }
-  // Always print a trailing empty line after stack trace.
-  Printf("\n");
-}
-
 uptr StackTrace::GetCurrentPc() {
   return GET_CALLER_PC();
 }
@@ -122,10 +36,7 @@
 void StackTrace::FastUnwindStack(uptr pc, uptr bp,
                                  uptr stack_top, uptr stack_bottom,
                                  uptr max_depth) {
-  if (max_depth == 0) {
-    size = 0;
-    return;
-  }
+  CHECK_GE(max_depth, 2);
   trace[0] = pc;
   size = 1;
   uhwptr *frame = (uhwptr *)bp;
@@ -146,22 +57,22 @@
   }
 }
 
-void StackTrace::PopStackFrames(uptr count) {
-  CHECK(size >= count);
-  size -= count;
-  for (uptr i = 0; i < size; i++) {
-    trace[i] = trace[i + count];
-  }
-}
-
 static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
   return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
 }
 
+void StackTrace::PopStackFrames(uptr count) {
+  CHECK_LT(count, size);
+  size -= count;
+  for (uptr i = 0; i < size; ++i) {
+    trace[i] = trace[i + count];
+  }
+}
+
 uptr StackTrace::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 = 96;
+  const int kPcThreshold = 288;
   for (uptr i = 0; i < size; ++i) {
     if (MatchPc(pc, trace[i], kPcThreshold))
       return i;
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index 5042f23..c3ba193 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -19,10 +19,9 @@
 
 static const uptr kStackTraceMax = 256;
 
-#if SANITIZER_LINUX && (defined(__arm__) || \
-    defined(__powerpc__) || defined(__powerpc64__) || \
-    defined(__sparc__) || \
-    defined(__mips__))
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \
+                        defined(__powerpc64__) || defined(__sparc__) || \
+                        defined(__mips__))
 # define SANITIZER_CAN_FAST_UNWIND 0
 #elif SANITIZER_WINDOWS
 # define SANITIZER_CAN_FAST_UNWIND 0
@@ -38,8 +37,10 @@
   uptr trace[kStackTraceMax];
 
   // Prints a symbolized stacktrace, followed by an empty line.
-  static void PrintStack(const uptr *addr, uptr size,
-                         SymbolizeCallback symbolize_callback = 0);
+  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;
@@ -58,7 +59,7 @@
     return request_fast_unwind;
   }
 
-  void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
+  void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
               uptr stack_bottom, bool request_fast_unwind);
 
   static uptr GetCurrentPc();
@@ -68,6 +69,8 @@
   void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
                        uptr max_depth);
   void SlowUnwindStack(uptr pc, uptr max_depth);
+  void SlowUnwindStackWithContext(uptr pc, void *context,
+                                  uptr max_depth);
   void PopStackFrames(uptr count);
   uptr LocatePcInTrace(uptr pc);
 };
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index 58fa182..c68149d 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -11,18 +11,88 @@
 // run-time libraries.
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_common.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
-                        uptr stack_bottom, bool request_fast_unwind) {
-  if (!WillUseFastUnwind(request_fast_unwind))
-    SlowUnwindStack(pc, max_depth);
-  else
-    FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
+                                  uptr pc) {
+  buffer->append("    #%zu 0x%zx", frame_num, pc);
+}
 
-  top_frame_bp = size ? bp : 0;
+void StackTrace::PrintStack(const uptr *addr, uptr size) {
+  if (addr == 0 || size == 0) {
+    Printf("    <empty stack>\n\n");
+    return;
+  }
+  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
+  InternalScopedBuffer<AddressInfo> addr_frames(64);
+  InternalScopedString frame_desc(GetPageSizeCached() * 2);
+  uptr frame_num = 0;
+  for (uptr i = 0; i < size && addr[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 addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
+        pc, addr_frames.data(), addr_frames.size());
+    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;
+    }
+    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);
+      }
+      Printf("%s\n", frame_desc.data());
+      frame_num++;
+      info.Clear();
+    }
+  }
+  // Always print a trailing empty line after stack trace.
+  Printf("\n");
+}
+
+void StackTrace::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) {
+    size = 0;
+    return;
+  }
+  if (max_depth == 1) {
+    size = 1;
+    trace[0] = pc;
+    return;
+  }
+  if (!WillUseFastUnwind(request_fast_unwind)) {
+    if (context)
+      SlowUnwindStackWithContext(pc, context, max_depth);
+    else
+      SlowUnwindStack(pc, max_depth);
+  } else {
+    FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+  }
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index a34ddd8..d20b524 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -100,12 +100,11 @@
                        &pterrno)) {
     // Either the thread is dead, or something prevented us from attaching.
     // Log this event and move on.
-    if (common_flags()->verbosity)
-      Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
+    VReport(1, "Could not attach to thread %d (errno %d).\n", thread_id,
+            pterrno);
     return false;
   } else {
-    if (common_flags()->verbosity)
-      Report("Attached to thread %d.\n", thread_id);
+    VReport(1, "Attached to thread %d.\n", thread_id);
     // The thread is not guaranteed to stop before ptrace returns, so we must
     // wait on it.
     uptr waitpid_status;
@@ -114,9 +113,8 @@
     if (internal_iserror(waitpid_status, &wperrno)) {
       // Got a ECHILD error. I don't think this situation is possible, but it
       // doesn't hurt to report it.
-      if (common_flags()->verbosity)
-        Report("Waiting on thread %d failed, detaching (errno %d).\n",
-            thread_id, wperrno);
+      VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
+              thread_id, wperrno);
       internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
       return false;
     }
@@ -131,14 +129,12 @@
     int pterrno;
     if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
                           &pterrno)) {
-      if (common_flags()->verbosity)
-        Report("Detached from thread %d.\n", tid);
+      VReport(1, "Detached from thread %d.\n", tid);
     } else {
       // Either the thread is dead, or we are already detached.
       // The latter case is possible, for instance, if this function was called
       // from a signal handler.
-      if (common_flags()->verbosity)
-        Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
+      VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno);
     }
   }
 }
@@ -250,18 +246,18 @@
   // the mask we inherited from the caller thread.
   for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
        signal_index++) {
-    __sanitizer_kernel_sigaction_t new_sigaction;
+    __sanitizer_sigaction new_sigaction;
     internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
     new_sigaction.sigaction = TracerThreadSignalHandler;
     new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
     internal_sigfillset(&new_sigaction.sa_mask);
-    internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+    internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+                                  &new_sigaction, NULL);
   }
 
   int exit_code = 0;
   if (!thread_suspender.SuspendAllThreads()) {
-    if (common_flags()->verbosity)
-      Report("Failed suspending threads.\n");
+    VReport(1, "Failed suspending threads.\n");
     exit_code = 3;
   } else {
     tracer_thread_argument->callback(thread_suspender.suspended_threads_list(),
@@ -301,9 +297,9 @@
 
 // We have a limitation on the stack frame size, so some stuff had to be moved
 // into globals.
-static __sanitizer_kernel_sigset_t blocked_sigset;
-static __sanitizer_kernel_sigset_t old_sigset;
-static __sanitizer_kernel_sigaction_t old_sigactions
+static __sanitizer_sigset_t blocked_sigset;
+static __sanitizer_sigset_t old_sigset;
+static __sanitizer_sigaction old_sigactions
     [ARRAY_SIZE(kUnblockedSignals)];
 
 class StopTheWorldScope {
@@ -320,12 +316,12 @@
       // Remove the signal from the set of blocked signals.
       internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
       // Install the default handler.
-      __sanitizer_kernel_sigaction_t new_sigaction;
+      __sanitizer_sigaction new_sigaction;
       internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
       new_sigaction.handler = SIG_DFL;
       internal_sigfillset(&new_sigaction.sa_mask);
-      internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction,
-                      &old_sigactions[signal_index]);
+      internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+          &new_sigaction, &old_sigactions[signal_index]);
     }
     int sigprocmask_status =
         internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
@@ -346,8 +342,8 @@
     // Restore the signal handlers.
     for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
          signal_index++) {
-      internal_sigaction(kUnblockedSignals[signal_index],
-                &old_sigactions[signal_index], NULL);
+      internal_sigaction_norestorer(kUnblockedSignals[signal_index],
+                                    &old_sigactions[signal_index], NULL);
     }
     internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
   }
@@ -356,6 +352,20 @@
   int process_was_dumpable_;
 };
 
+// When sanitizer output is being redirected to file (i.e. by using log_path),
+// the tracer should write to the parent's log instead of trying to open a new
+// file. Alert the logging code to the fact that we have a tracer.
+struct ScopedSetTracerPID {
+  explicit ScopedSetTracerPID(uptr tracer_pid) {
+    stoptheworld_tracer_pid = tracer_pid;
+    stoptheworld_tracer_ppid = internal_getpid();
+  }
+  ~ScopedSetTracerPID() {
+    stoptheworld_tracer_pid = 0;
+    stoptheworld_tracer_ppid = 0;
+  }
+};
+
 void StopTheWorld(StopTheWorldCallback callback, void *argument) {
   StopTheWorldScope in_stoptheworld;
   // Prepare the arguments for TracerThread.
@@ -375,10 +385,10 @@
       /* child_tidptr */);
   int local_errno = 0;
   if (internal_iserror(tracer_pid, &local_errno)) {
-    if (common_flags()->verbosity)
-      Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
+    VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno);
     tracer_thread_argument.mutex.Unlock();
   } else {
+    ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid);
     // On some systems we have to explicitly declare that we want to be traced
     // by the tracer thread.
 #ifdef PR_SET_PTRACER
@@ -391,11 +401,9 @@
     // At this point, any signal will either be blocked or kill us, so waitpid
     // should never return (and set errno) while the tracer thread is alive.
     uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
-    if (internal_iserror(waitpid_status, &local_errno)) {
-      if (common_flags()->verbosity)
-        Report("Waiting on the tracer thread failed (errno %d).\n",
-            local_errno);
-    }
+    if (internal_iserror(waitpid_status, &local_errno))
+      VReport(1, "Waiting on the tracer thread failed (errno %d).\n",
+              local_errno);
   }
 }
 
@@ -436,9 +444,8 @@
   int pterrno;
   if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
                        &pterrno)) {
-    if (common_flags()->verbosity)
-      Report("Could not get registers from thread %d (errno %d).\n",
-           tid, pterrno);
+    VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
+            pterrno);
     return -1;
   }
 
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
index 5f3d2ce..87ccf7f 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -20,8 +20,8 @@
 namespace __sanitizer {
 
 static const char *const kTypeStrings[SuppressionTypeCount] = {
-  "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
-};
+    "none",   "race", "mutex",           "thread",
+    "signal", "leak", "called_from_lib", "deadlock"};
 
 bool TemplateMatch(char *templ, const char *str) {
   if (str == 0 || str[0] == 0)
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
index 92cb093..772b9aa 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -26,6 +26,7 @@
   SuppressionSignal,
   SuppressionLeak,
   SuppressionLib,
+  SuppressionDeadlock,
   SuppressionTypeCount
 };
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h
index 886fed2..7057a89 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer.h
@@ -27,23 +27,30 @@
 
 struct AddressInfo {
   uptr address;
+
   char *module;
   uptr module_offset;
+
+  static const uptr kUnknown = ~(uptr)0;
   char *function;
+  uptr function_offset;
+
   char *file;
   int line;
   int column;
 
   AddressInfo() {
     internal_memset(this, 0, sizeof(AddressInfo));
+    function_offset = kUnknown;
   }
 
-  // Deletes all strings and sets all fields to zero.
+  // Deletes all strings and resets all fields.
   void Clear() {
     InternalFree(module);
     InternalFree(function);
     InternalFree(file);
     internal_memset(this, 0, sizeof(AddressInfo));
+    function_offset = kUnknown;
   }
 
   void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
@@ -79,22 +86,20 @@
   /// reasons as this function will check $PATH for an external symbolizer.  Not
   /// thread safe.
   static Symbolizer *Init(const char* path_to_external = 0);
-  /// Initialize the symbolizer in a disabled state.  Not thread safe.
-  static Symbolizer *Disable();
   // 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.
-  virtual uptr SymbolizeCode(uptr address, AddressInfo *frames,
-                             uptr max_frames) {
+  virtual uptr SymbolizePC(uptr address, AddressInfo *frames, uptr max_frames) {
     return 0;
   }
   virtual bool SymbolizeData(uptr address, DataInfo *info) {
     return false;
   }
-  virtual bool IsAvailable() {
+  virtual bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                           uptr *module_address) {
     return false;
   }
-  virtual bool IsExternalAvailable() {
+  virtual bool CanReturnFileLineInfo() {
     return false;
   }
   // Release internal caches (if any).
@@ -121,6 +126,8 @@
   /// 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);
+  /// Initialize the symbolizer in a disabled state.  Not thread safe.
+  static Symbolizer *Disable();
 
   static Symbolizer *symbolizer_;
   static StaticSpinMutex init_mu_;
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
new file mode 100644
index 0000000..4ec6f0a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -0,0 +1,206 @@
+//===-- sanitizer_symbolizer_libbacktrace.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 AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Libbacktrace implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
+
+#if SANITIZER_LIBBACKTRACE
+# include "backtrace-supported.h"
+# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
+#  include "backtrace.h"
+#  if SANITIZER_CP_DEMANGLE
+#   undef ARRAY_SIZE
+#   include "demangle.h"
+#  endif
+# else
+#  define SANITIZER_LIBBACKTRACE 0
+# endif
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_LIBBACKTRACE
+
+namespace {
+
+# if SANITIZER_CP_DEMANGLE
+struct CplusV3DemangleData {
+  char *buf;
+  uptr size, allocated;
+};
+
+extern "C" {
+static void CplusV3DemangleCallback(const char *s, size_t l, void *vdata) {
+  CplusV3DemangleData *data = (CplusV3DemangleData *)vdata;
+  uptr needed = data->size + l + 1;
+  if (needed > data->allocated) {
+    data->allocated *= 2;
+    if (needed > data->allocated)
+      data->allocated = needed;
+    char *buf = (char *)InternalAlloc(data->allocated);
+    if (data->buf) {
+      internal_memcpy(buf, data->buf, data->size);
+      InternalFree(data->buf);
+    }
+    data->buf = buf;
+  }
+  internal_memcpy(data->buf + data->size, s, l);
+  data->buf[data->size + l] = '\0';
+  data->size += l;
+}
+}  // extern "C"
+
+char *CplusV3Demangle(const char *name) {
+  CplusV3DemangleData data;
+  data.buf = 0;
+  data.size = 0;
+  data.allocated = 0;
+  if (cplus_demangle_v3_callback(name, DMGL_PARAMS | DMGL_ANSI,
+                                 CplusV3DemangleCallback, &data)) {
+    if (data.size + 64 > data.allocated)
+      return data.buf;
+    char *buf = internal_strdup(data.buf);
+    InternalFree(data.buf);
+    return buf;
+  }
+  if (data.buf)
+    InternalFree(data.buf);
+  return 0;
+}
+# endif  // SANITIZER_CP_DEMANGLE
+
+struct SymbolizeCodeData {
+  AddressInfo *frames;
+  uptr n_frames;
+  uptr max_frames;
+  const char *module_name;
+  uptr module_offset;
+};
+
+extern "C" {
+static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
+                                       const char *filename, int lineno,
+                                       const char *function) {
+  SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
+  if (function) {
+    AddressInfo *info = &cdata->frames[cdata->n_frames++];
+    info->Clear();
+    info->FillAddressAndModuleInfo(addr, cdata->module_name,
+                                   cdata->module_offset);
+    info->function = LibbacktraceSymbolizer::Demangle(function, true);
+    if (filename)
+      info->file = internal_strdup(filename);
+    info->line = lineno;
+    if (cdata->n_frames == cdata->max_frames)
+      return 1;
+  }
+  return 0;
+}
+
+static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
+                                  const char *symname, uintptr_t, uintptr_t) {
+  SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
+  if (symname) {
+    AddressInfo *info = &cdata->frames[0];
+    info->Clear();
+    info->FillAddressAndModuleInfo(addr, cdata->module_name,
+                                   cdata->module_offset);
+    info->function = LibbacktraceSymbolizer::Demangle(symname, true);
+    cdata->n_frames = 1;
+  }
+}
+
+static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
+                                  uintptr_t symval, uintptr_t symsize) {
+  DataInfo *info = (DataInfo *)vdata;
+  if (symname && symval) {
+    info->name = LibbacktraceSymbolizer::Demangle(symname, true);
+    info->start = symval;
+    info->size = symsize;
+  }
+}
+
+static void ErrorCallback(void *, const char *, int) {}
+}  // extern "C"
+
+}  // namespace
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+  // State created in backtrace_create_state is leaked.
+  void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
+                                                ErrorCallback, NULL));
+  if (!state)
+    return 0;
+  return new(*alloc) LibbacktraceSymbolizer(state);
+}
+
+uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
+                                           uptr max_frames,
+                                           const char *module_name,
+                                           uptr module_offset) {
+  SymbolizeCodeData data;
+  data.frames = frames;
+  data.n_frames = 0;
+  data.max_frames = max_frames;
+  data.module_name = module_name;
+  data.module_offset = module_offset;
+  backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
+                   ErrorCallback, &data);
+  if (data.n_frames)
+    return data.n_frames;
+  backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
+                    ErrorCallback, &data);
+  return data.n_frames;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+  backtrace_syminfo((backtrace_state *)state_, info->address,
+                    SymbolizeDataCallback, ErrorCallback, info);
+  return true;
+}
+
+#else  // SANITIZER_LIBBACKTRACE
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+  return 0;
+}
+
+uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
+                                           uptr max_frames,
+                                           const char *module_name,
+                                           uptr module_offset) {
+  (void)state_;
+  return 0;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+  return false;
+}
+
+#endif  // SANITIZER_LIBBACKTRACE
+
+char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) {
+#if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE
+  if (char *demangled = CplusV3Demangle(name))
+    return demangled;
+#endif
+  if (always_alloc)
+    return internal_strdup(name);
+  return 0;
+}
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
new file mode 100644
index 0000000..6c536cc
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -0,0 +1,50 @@
+//===-- sanitizer_symbolizer_libbacktrace.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 AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Header for libbacktrace symbolizer.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+#define SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+#ifndef SANITIZER_LIBBACKTRACE
+# define SANITIZER_LIBBACKTRACE 0
+#endif
+
+#ifndef SANITIZER_CP_DEMANGLE
+# define SANITIZER_CP_DEMANGLE 0
+#endif
+
+namespace __sanitizer {
+
+class LibbacktraceSymbolizer {
+ public:
+  static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
+
+  uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames,
+                     const char *module_name, uptr module_offset);
+
+  bool SymbolizeData(DataInfo *info);
+
+  // May return NULL if demangling failed.
+  static char *Demangle(const char *name, bool always_alloc = false);
+
+ private:
+  explicit LibbacktraceSymbolizer(void *state) : state_(state) {}
+
+  void *state_;  // Leaked.
+};
+
+}  // namespace __sanitizer
+#endif  // SANITIZER_SYMBOLIZER_LIBBACKTRACE_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index de11832..ca47e3c 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -16,11 +16,13 @@
 #if SANITIZER_POSIX
 #include "sanitizer_allocator_internal.h"
 #include "sanitizer_common.h"
+#include "sanitizer_flags.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_linux.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -53,107 +55,6 @@
   return name;
 }
 
-#if defined(__x86_64__)
-static const char* const kSymbolizerArch = "--default-arch=x86_64";
-#elif defined(__i386__)
-static const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__)
-static const char* const kSymbolizerArch = "--default-arch=powerpc64";
-#else
-static const char* const kSymbolizerArch = "--default-arch=unknown";
-#endif
-
-static const int kSymbolizerStartupTimeMillis = 10;
-
-// Creates external symbolizer connected via pipe, user should write
-// to output_fd and read from input_fd.
-static bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
-                                      int *input_fd, int *output_fd) {
-  if (!FileExists(path_to_symbolizer)) {
-    Report("WARNING: invalid path to external symbolizer!\n");
-    return false;
-  }
-
-  int *infd = NULL;
-  int *outfd = NULL;
-  // The client program may close its stdin and/or stdout and/or stderr
-  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
-  // In this case the communication between the forked processes may be
-  // broken if either the parent or the child tries to close or duplicate
-  // these descriptors. The loop below produces two pairs of file
-  // descriptors, each greater than 2 (stderr).
-  int sock_pair[5][2];
-  for (int i = 0; i < 5; i++) {
-    if (pipe(sock_pair[i]) == -1) {
-      for (int j = 0; j < i; j++) {
-        internal_close(sock_pair[j][0]);
-        internal_close(sock_pair[j][1]);
-      }
-      Report("WARNING: Can't create a socket pair to start "
-             "external symbolizer (errno: %d)\n", errno);
-      return false;
-    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
-      if (infd == NULL) {
-        infd = sock_pair[i];
-      } else {
-        outfd = sock_pair[i];
-        for (int j = 0; j < i; j++) {
-          if (sock_pair[j] == infd) continue;
-          internal_close(sock_pair[j][0]);
-          internal_close(sock_pair[j][1]);
-        }
-        break;
-      }
-    }
-  }
-  CHECK(infd);
-  CHECK(outfd);
-
-  int pid = fork();
-  if (pid == -1) {
-    // Fork() failed.
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    Report("WARNING: failed to fork external symbolizer "
-           " (errno: %d)\n", errno);
-    return false;
-  } else if (pid == 0) {
-    // Child subprocess.
-    internal_close(STDOUT_FILENO);
-    internal_close(STDIN_FILENO);
-    internal_dup2(outfd[0], STDIN_FILENO);
-    internal_dup2(infd[1], STDOUT_FILENO);
-    internal_close(outfd[0]);
-    internal_close(outfd[1]);
-    internal_close(infd[0]);
-    internal_close(infd[1]);
-    for (int fd = getdtablesize(); fd > 2; fd--)
-      internal_close(fd);
-    execl(path_to_symbolizer, path_to_symbolizer, kSymbolizerArch, (char*)0);
-    internal__exit(1);
-  }
-
-  // Continue execution in parent process.
-  internal_close(outfd[0]);
-  internal_close(infd[1]);
-  *input_fd = infd[0];
-  *output_fd = outfd[1];
-
-  // Check that symbolizer subprocess started successfully.
-  int pid_status;
-  SleepForMillis(kSymbolizerStartupTimeMillis);
-  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
-  if (exited_pid != 0) {
-    // Either waitpid failed, or child has already exited.
-    Report("WARNING: external symbolizer didn't start up correctly!\n");
-    return false;
-  }
-
-  return true;
-}
-
 // Extracts the prefix of "str" that consists of any characters not
 // present in "delims" string, and copies this prefix to "result", allocating
 // space for it.
@@ -193,34 +94,63 @@
   return ret;
 }
 
-// ExternalSymbolizer encapsulates communication between the tool and
-// external symbolizer program, running in a different subprocess,
-// For now we assume the following protocol:
-// For each request of the form
-//   <module_name> <module_offset>
-// passed to STDIN, external symbolizer prints to STDOUT response:
-//   <function_name>
-//   <file_name>:<line_number>:<column_number>
-//   <function_name>
-//   <file_name>:<line_number>:<column_number>
-//   ...
-//   <empty line>
-class ExternalSymbolizer {
+class ExternalSymbolizerInterface {
  public:
-  ExternalSymbolizer(const char *path, int input_fd, int output_fd)
+  // Can't declare pure virtual functions in sanitizer runtimes:
+  // __cxa_pure_virtual might be unavailable.
+  virtual char *SendCommand(bool is_data, const char *module_name,
+                            uptr module_offset) {
+    UNIMPLEMENTED();
+  }
+};
+
+// SymbolizerProcess encapsulates communication between the tool and
+// external symbolizer program, running in a different subprocess.
+// SymbolizerProcess may not be used from two threads simultaneously.
+class SymbolizerProcess : public ExternalSymbolizerInterface {
+ public:
+  explicit SymbolizerProcess(const char *path)
       : path_(path),
-        input_fd_(input_fd),
-        output_fd_(output_fd),
-        times_restarted_(0) {
+        input_fd_(kInvalidFd),
+        output_fd_(kInvalidFd),
+        times_restarted_(0),
+        failed_to_start_(false),
+        reported_invalid_path_(false) {
     CHECK(path_);
-    CHECK_NE(input_fd_, kInvalidFd);
-    CHECK_NE(output_fd_, kInvalidFd);
+    CHECK_NE(path_[0], '\0');
   }
 
   char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+      // Start or restart symbolizer if we failed to send command to it.
+      if (char *res = SendCommandImpl(is_data, module_name, module_offset))
+        return res;
+      Restart();
+    }
+    if (!failed_to_start_) {
+      Report("WARNING: Failed to use and restart external symbolizer!\n");
+      failed_to_start_ = true;
+    }
+    return 0;
+  }
+
+ private:
+  bool Restart() {
+    if (input_fd_ != kInvalidFd)
+      internal_close(input_fd_);
+    if (output_fd_ != kInvalidFd)
+      internal_close(output_fd_);
+    return StartSymbolizerSubprocess();
+  }
+
+  char *SendCommandImpl(bool is_data, const char *module_name,
+                        uptr module_offset) {
+    if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+      return 0;
     CHECK(module_name);
-    internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
-                      is_data ? "DATA " : "", module_name, module_offset);
+    if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name,
+                            module_offset))
+      return 0;
     if (!writeToSymbolizer(buffer_, internal_strlen(buffer_)))
       return 0;
     if (!readFromSymbolizer(buffer_, kBufferSize))
@@ -228,25 +158,13 @@
     return buffer_;
   }
 
-  bool Restart() {
-    if (times_restarted_ >= kMaxTimesRestarted) return false;
-    times_restarted_++;
-    internal_close(input_fd_);
-    internal_close(output_fd_);
-    return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
-  }
-
-  void Flush() {
-  }
-
- private:
   bool readFromSymbolizer(char *buffer, uptr max_length) {
     if (max_length == 0)
       return true;
     uptr read_len = 0;
     while (true) {
       uptr just_read = internal_read(input_fd_, buffer + read_len,
-                                     max_length - read_len);
+                                     max_length - read_len - 1);
       // We can't read 0 bytes, as we don't expect external symbolizer to close
       // its stdout.
       if (just_read == 0 || just_read == (uptr)-1) {
@@ -254,12 +172,10 @@
         return false;
       }
       read_len += just_read;
-      // Empty line marks the end of symbolizer output.
-      if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
-                           buffer[read_len - 2] == '\n') {
+      if (ReachedEndOfOutput(buffer, read_len))
         break;
-      }
     }
+    buffer[read_len] = '\0';
     return true;
   }
 
@@ -274,6 +190,110 @@
     return true;
   }
 
+  bool StartSymbolizerSubprocess() {
+    if (!FileExists(path_)) {
+      if (!reported_invalid_path_) {
+        Report("WARNING: invalid path to external symbolizer!\n");
+        reported_invalid_path_ = true;
+      }
+      return false;
+    }
+
+    int *infd = NULL;
+    int *outfd = NULL;
+    // The client program may close its stdin and/or stdout and/or stderr
+    // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+    // In this case the communication between the forked processes may be
+    // broken if either the parent or the child tries to close or duplicate
+    // these descriptors. The loop below produces two pairs of file
+    // descriptors, each greater than 2 (stderr).
+    int sock_pair[5][2];
+    for (int i = 0; i < 5; i++) {
+      if (pipe(sock_pair[i]) == -1) {
+        for (int j = 0; j < i; j++) {
+          internal_close(sock_pair[j][0]);
+          internal_close(sock_pair[j][1]);
+        }
+        Report("WARNING: Can't create a socket pair to start "
+               "external symbolizer (errno: %d)\n", errno);
+        return false;
+      } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+        if (infd == NULL) {
+          infd = sock_pair[i];
+        } else {
+          outfd = sock_pair[i];
+          for (int j = 0; j < i; j++) {
+            if (sock_pair[j] == infd) continue;
+            internal_close(sock_pair[j][0]);
+            internal_close(sock_pair[j][1]);
+          }
+          break;
+        }
+      }
+    }
+    CHECK(infd);
+    CHECK(outfd);
+
+    // Real fork() may call user callbacks registered with pthread_atfork().
+    int pid = internal_fork();
+    if (pid == -1) {
+      // Fork() failed.
+      internal_close(infd[0]);
+      internal_close(infd[1]);
+      internal_close(outfd[0]);
+      internal_close(outfd[1]);
+      Report("WARNING: failed to fork external symbolizer "
+             " (errno: %d)\n", errno);
+      return false;
+    } else if (pid == 0) {
+      // Child subprocess.
+      internal_close(STDOUT_FILENO);
+      internal_close(STDIN_FILENO);
+      internal_dup2(outfd[0], STDIN_FILENO);
+      internal_dup2(infd[1], STDOUT_FILENO);
+      internal_close(outfd[0]);
+      internal_close(outfd[1]);
+      internal_close(infd[0]);
+      internal_close(infd[1]);
+      for (int fd = getdtablesize(); fd > 2; fd--)
+        internal_close(fd);
+      ExecuteWithDefaultArgs(path_);
+      internal__exit(1);
+    }
+
+    // Continue execution in parent process.
+    internal_close(outfd[0]);
+    internal_close(infd[1]);
+    input_fd_ = infd[0];
+    output_fd_ = outfd[1];
+
+    // Check that symbolizer subprocess started successfully.
+    int pid_status;
+    SleepForMillis(kSymbolizerStartupTimeMillis);
+    int exited_pid = waitpid(pid, &pid_status, WNOHANG);
+    if (exited_pid != 0) {
+      // Either waitpid failed, or child has already exited.
+      Report("WARNING: external symbolizer didn't start up correctly!\n");
+      return false;
+    }
+
+    return true;
+  }
+
+  virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+                                  const char *module_name,
+                                  uptr module_offset) const {
+    UNIMPLEMENTED();
+  }
+
+  virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+    UNIMPLEMENTED();
+  }
+
+  virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+    UNIMPLEMENTED();
+  }
+
   const char *path_;
   int input_fd_;
   int output_fd_;
@@ -282,7 +302,120 @@
   char buffer_[kBufferSize];
 
   static const uptr kMaxTimesRestarted = 5;
+  static const int kSymbolizerStartupTimeMillis = 10;
   uptr times_restarted_;
+  bool failed_to_start_;
+  bool reported_invalid_path_;
+};
+
+// For now we assume the following protocol:
+// For each request of the form
+//   <module_name> <module_offset>
+// passed to STDIN, external symbolizer prints to STDOUT response:
+//   <function_name>
+//   <file_name>:<line_number>:<column_number>
+//   <function_name>
+//   <file_name>:<line_number>:<column_number>
+//   ...
+//   <empty line>
+class LLVMSymbolizerProcess : public SymbolizerProcess {
+ public:
+  explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {}
+
+ private:
+  bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+                          const char *module_name, uptr module_offset) const {
+    internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n",
+                      is_data ? "DATA " : "", module_name, module_offset);
+    return true;
+  }
+
+  bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+    // Empty line marks the end of llvm-symbolizer output.
+    return length >= 2 && buffer[length - 1] == '\n' &&
+           buffer[length - 2] == '\n';
+  }
+
+  void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+#if defined(__x86_64__)
+    const char* const kSymbolizerArch = "--default-arch=x86_64";
+#elif defined(__i386__)
+    const char* const kSymbolizerArch = "--default-arch=i386";
+#elif defined(__powerpc64__)
+    const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#else
+    const char* const kSymbolizerArch = "--default-arch=unknown";
+#endif
+    execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0);
+  }
+};
+
+class Addr2LineProcess : public SymbolizerProcess {
+ public:
+  Addr2LineProcess(const char *path, const char *module_name)
+      : SymbolizerProcess(path), module_name_(internal_strdup(module_name)) {}
+
+  const char *module_name() const { return module_name_; }
+
+ private:
+  bool RenderInputCommand(char *buffer, uptr max_length, bool is_data,
+                          const char *module_name, uptr module_offset) const {
+    if (is_data)
+      return false;
+    CHECK_EQ(0, internal_strcmp(module_name, module_name_));
+    internal_snprintf(buffer, max_length, "0x%zx\n", module_offset);
+    return true;
+  }
+
+  bool ReachedEndOfOutput(const char *buffer, uptr length) const {
+    // Output should consist of two lines.
+    int num_lines = 0;
+    for (uptr i = 0; i < length; ++i) {
+      if (buffer[i] == '\n')
+        num_lines++;
+      if (num_lines >= 2)
+        return true;
+    }
+    return false;
+  }
+
+  void ExecuteWithDefaultArgs(const char *path_to_binary) const {
+    execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0);
+  }
+
+  const char *module_name_;  // Owned, leaked.
+};
+
+class Addr2LinePool : public ExternalSymbolizerInterface {
+ public:
+  explicit Addr2LinePool(const char *addr2line_path,
+                         LowLevelAllocator *allocator)
+      : addr2line_path_(addr2line_path), allocator_(allocator),
+        addr2line_pool_(16) {}
+
+  char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+    if (is_data)
+      return 0;
+    Addr2LineProcess *addr2line = 0;
+    for (uptr i = 0; i < addr2line_pool_.size(); ++i) {
+      if (0 ==
+          internal_strcmp(module_name, addr2line_pool_[i]->module_name())) {
+        addr2line = addr2line_pool_[i];
+        break;
+      }
+    }
+    if (!addr2line) {
+      addr2line =
+          new(*allocator_) Addr2LineProcess(addr2line_path_, module_name);
+      addr2line_pool_.push_back(addr2line);
+    }
+    return addr2line->SendCommand(is_data, module_name, module_offset);
+  }
+
+ private:
+  const char *addr2line_path_;
+  LowLevelAllocator *allocator_;
+  InternalMmapVector<Addr2LineProcess*> addr2line_pool_;
 };
 
 #if SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -366,24 +499,33 @@
 
 class POSIXSymbolizer : public Symbolizer {
  public:
-  POSIXSymbolizer(ExternalSymbolizer *external_symbolizer,
-                  InternalSymbolizer *internal_symbolizer)
+  POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer,
+                  InternalSymbolizer *internal_symbolizer,
+                  LibbacktraceSymbolizer *libbacktrace_symbolizer)
       : Symbolizer(),
         external_symbolizer_(external_symbolizer),
-        internal_symbolizer_(internal_symbolizer) {}
+        internal_symbolizer_(internal_symbolizer),
+        libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
 
-  uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+  uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) {
     BlockingMutexLock l(&mu_);
     if (max_frames == 0)
       return 0;
-    LoadedModule *module = FindModuleForAddress(addr);
-    if (module == 0)
+    const char *module_name;
+    uptr module_offset;
+    if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
       return 0;
-    const char *module_name = module->full_name();
-    uptr module_offset = addr - module->base_address();
+    // First, try to use libbacktrace symbolizer (if it's available).
+    if (libbacktrace_symbolizer_ != 0) {
+      mu_.CheckLocked();
+      uptr res = libbacktrace_symbolizer_->SymbolizeCode(
+          addr, frames, max_frames, module_name, module_offset);
+      if (res > 0)
+        return res;
+    }
     const char *str = SendCommand(false, module_name, module_offset);
     if (str == 0) {
-      // External symbolizer was not initialized or failed. Fill only data
+      // Symbolizer was not initialized or failed. Fill only data
       // about module name and offset.
       AddressInfo *info = &frames[0];
       info->Clear();
@@ -444,6 +586,12 @@
     info->address = addr;
     info->module = internal_strdup(module_name);
     info->module_offset = module_offset;
+    // First, try to use libbacktrace symbolizer (if it's available).
+    if (libbacktrace_symbolizer_ != 0) {
+      mu_.CheckLocked();
+      if (libbacktrace_symbolizer_->SymbolizeData(info))
+        return true;
+    }
     const char *str = SendCommand(true, module_name, module_offset);
     if (str == 0)
       return true;
@@ -454,12 +602,15 @@
     return true;
   }
 
-  bool IsAvailable() {
-    return internal_symbolizer_ != 0 || external_symbolizer_ != 0;
+  bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                   uptr *module_address) {
+    BlockingMutexLock l(&mu_);
+    return FindModuleNameAndOffsetForAddress(pc, module_name, module_address);
   }
 
-  bool IsExternalAvailable() {
-    return external_symbolizer_ != 0;
+  bool CanReturnFileLineInfo() {
+    return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
+           libbacktrace_symbolizer_ != 0;
   }
 
   void Flush() {
@@ -468,8 +619,6 @@
       SymbolizerScope sym_scope(this);
       internal_symbolizer_->Flush();
     }
-    if (external_symbolizer_ != 0)
-      external_symbolizer_->Flush();
   }
 
   const char *Demangle(const char *name) {
@@ -477,6 +626,11 @@
     // Run hooks even if we don't use internal symbolizer, as cxxabi
     // demangle may call system functions.
     SymbolizerScope sym_scope(this);
+    // Try to use libbacktrace demangler (if available).
+    if (libbacktrace_symbolizer_ != 0) {
+      if (const char *demangled = libbacktrace_symbolizer_->Demangle(name))
+        return demangled;
+    }
     if (internal_symbolizer_ != 0)
       return internal_symbolizer_->Demangle(name);
     return DemangleCXXABI(name);
@@ -500,26 +654,12 @@
                                                module_offset);
     }
     // Otherwise, fall back to external symbolizer.
-    if (external_symbolizer_ == 0) {
-      ReportExternalSymbolizerError(
-          "WARNING: Trying to symbolize code, but external "
-          "symbolizer is not initialized!\n");
-      return 0;
+    if (external_symbolizer_) {
+      SymbolizerScope sym_scope(this);
+      return external_symbolizer_->SendCommand(is_data, module_name,
+                                               module_offset);
     }
-    for (;;) {
-      char *reply = external_symbolizer_->SendCommand(is_data, module_name,
-          module_offset);
-      if (reply)
-        return reply;
-      // Try to restart symbolizer subprocess. If we don't succeed, forget
-      // about it and don't try to use it later.
-      if (!external_symbolizer_->Restart()) {
-        ReportExternalSymbolizerError(
-            "WARNING: Failed to use and restart external symbolizer!\n");
-        external_symbolizer_ = 0;
-        return 0;
-      }
-    }
+    return 0;
   }
 
   LoadedModule *FindModuleForAddress(uptr address) {
@@ -531,8 +671,7 @@
       CHECK(modules_);
       n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
                                     /* filter */ 0);
-      // FIXME: Return this check when GetListOfModules is implemented on Mac.
-      // CHECK_GT(n_modules_, 0);
+      CHECK_GT(n_modules_, 0);
       CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
       modules_fresh_ = true;
       modules_were_reloaded = true;
@@ -553,14 +692,15 @@
     return 0;
   }
 
-  void ReportExternalSymbolizerError(const char *msg) {
-    // Don't use atomics here for now, as SymbolizeCode can't be called
-    // from multiple threads anyway.
-    static bool reported;
-    if (!reported) {
-      Report(msg);
-      reported = true;
-    }
+  bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
+                                         uptr *module_offset) {
+    mu_.CheckLocked();
+    LoadedModule *module = FindModuleForAddress(address);
+    if (module == 0)
+      return false;
+    *module_name = module->full_name();
+    *module_offset = address - module->base_address();
+    return true;
   }
 
   // 16K loaded modules should be enough for everyone.
@@ -571,29 +711,46 @@
   bool modules_fresh_;
   BlockingMutex mu_;
 
-  ExternalSymbolizer *external_symbolizer_;        // Leaked.
-  InternalSymbolizer *const internal_symbolizer_;  // Leaked.
+  ExternalSymbolizerInterface *external_symbolizer_;  // Leaked.
+  InternalSymbolizer *const internal_symbolizer_;     // Leaked.
+  LibbacktraceSymbolizer *libbacktrace_symbolizer_;   // Leaked.
 };
 
 Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+  if (!common_flags()->symbolize) {
+    return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0);
+  }
   InternalSymbolizer* internal_symbolizer =
       InternalSymbolizer::get(&symbolizer_allocator_);
-  ExternalSymbolizer *external_symbolizer = 0;
+  ExternalSymbolizerInterface *external_symbolizer = 0;
+  LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
 
   if (!internal_symbolizer) {
-    if (!path_to_external || path_to_external[0] == '\0')
-      path_to_external = FindPathToBinary("llvm-symbolizer");
-
-    int input_fd, output_fd;
-    if (path_to_external &&
-        StartSymbolizerSubprocess(path_to_external, &input_fd, &output_fd)) {
-      external_symbolizer = new(symbolizer_allocator_)
-          ExternalSymbolizer(path_to_external, input_fd, output_fd);
+    libbacktrace_symbolizer =
+        LibbacktraceSymbolizer::get(&symbolizer_allocator_);
+    if (!libbacktrace_symbolizer) {
+      if (path_to_external && path_to_external[0] == '\0') {
+        // External symbolizer is explicitly disabled. Do nothing.
+      } else {
+        // Find path to llvm-symbolizer if it's not provided.
+        if (!path_to_external)
+          path_to_external = FindPathToBinary("llvm-symbolizer");
+        if (path_to_external) {
+          external_symbolizer = new(symbolizer_allocator_)
+              LLVMSymbolizerProcess(path_to_external);
+        } else if (common_flags()->allow_addr2line) {
+          // If llvm-symbolizer is not found, try to use addr2line.
+          if (const char *addr2line_path = FindPathToBinary("addr2line")) {
+            external_symbolizer = new(symbolizer_allocator_)
+                Addr2LinePool(addr2line_path, &symbolizer_allocator_);
+          }
+        }
+      }
     }
   }
 
-  return new(symbolizer_allocator_)
-      POSIXSymbolizer(external_symbolizer, internal_symbolizer);
+  return new(symbolizer_allocator_) POSIXSymbolizer(
+      external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
 }
 
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 5d451ef..dc4816b 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -14,11 +14,96 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_WINDOWS
+#include <windows.h>
+#include <dbghelp.h>
+#pragma comment(lib, "dbghelp.lib")
+
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { return 0; }
+class WinSymbolizer : public Symbolizer {
+ public:
+  WinSymbolizer() : initialized_(false) {}
+
+  uptr SymbolizePC(uptr addr, AddressInfo *frames, uptr max_frames) {
+    if (max_frames == 0)
+      return 0;
+
+    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?
+      initialized_ = true;
+    }
+
+    // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+    char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
+    PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
+    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+    symbol->MaxNameLen = MAX_SYM_NAME;
+    DWORD64 offset = 0;
+    BOOL got_objname = SymFromAddr(GetCurrentProcess(),
+                                   (DWORD64)addr, &offset, symbol);
+    if (!got_objname)
+      return 0;
+
+    DWORD unused;
+    IMAGEHLP_LINE64 line_info;
+    line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+    BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr,
+                                             &unused, &line_info);
+    AddressInfo *info = &frames[0];
+    info->Clear();
+    info->function = internal_strdup(symbol->Name);
+    info->function_offset = (uptr)offset;
+    if (got_fileline) {
+      info->file = internal_strdup(line_info.FileName);
+      info->line = line_info.LineNumber;
+    }
+
+    IMAGEHLP_MODULE64 mod_info;
+    internal_memset(&mod_info, 0, sizeof(mod_info));
+    mod_info.SizeOfStruct = sizeof(mod_info);
+    if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info))
+      info->FillAddressAndModuleInfo(addr, mod_info.ImageName,
+                                     addr - (uptr)mod_info.BaseOfImage);
+    return 1;
+  }
+
+  bool CanReturnFileLineInfo() {
+    return true;
+  }
+
+  const char *Demangle(const char *name) {
+    CHECK(initialized_);
+    static char demangle_buffer[1000];
+    if (name[0] == '\01' &&
+        UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer),
+                             UNDNAME_NAME_ONLY))
+      return demangle_buffer;
+    else
+      return name;
+  }
+
+  // FIXME: Implement GetModuleNameAndOffsetForPC().
+
+ private:
+  // 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) {
+  static bool called_once = false;
+  CHECK(!called_once && "Shouldn't create more than one symbolizer");
+  called_once = true;
+  return new(symbolizer_allocator_) WinSymbolizer();
+}
 
 }  // namespace __sanitizer
 
diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc
index aac20a5..88d237f 100644
--- a/lib/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -11,7 +11,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#define internal_syscall syscall
+#if SANITIZER_FREEBSD
+# define SYSCALL(name) SYS_ ## name
+#else
+# define SYSCALL(name) __NR_ ## name
+#endif
+
+#if SANITIZER_FREEBSD && defined(__x86_64__)
+# define internal_syscall __syscall
+# else
+# define internal_syscall syscall
+#endif
 
 bool internal_iserror(uptr retval, int *rverrno) {
   if (retval == (uptr)-1) {
diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
index 5ccb83a..9853a6a 100644
--- a/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -11,6 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#define SYSCALL(name) __NR_ ## name
+
 static uptr internal_syscall(u64 nr) {
   u64 retval;
   asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11",
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index bfa29a1..ed2c601 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -17,8 +17,9 @@
 namespace __sanitizer {
 
 ThreadContextBase::ThreadContextBase(u32 tid)
-    : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
-      detached(false), reuse_count(0), parent_tid(0), next(0) {
+    : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
+      status(ThreadStatusInvalid),
+      detached(false), parent_tid(0), next(0) {
   name[0] = '\0';
 }
 
@@ -78,7 +79,6 @@
 
 void ThreadContextBase::Reset() {
   status = ThreadStatusInvalid;
-  reuse_count++;
   SetName(0);
   OnReset();
 }
@@ -88,10 +88,11 @@
 const u32 ThreadRegistry::kUnknownTid = ~0U;
 
 ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
-                               u32 thread_quarantine_size)
+                               u32 thread_quarantine_size, u32 max_reuse)
     : context_factory_(factory),
       max_threads_(max_threads),
       thread_quarantine_size_(thread_quarantine_size),
+      max_reuse_(max_reuse),
       mtx_(),
       n_contexts_(0),
       total_threads_(0),
@@ -130,8 +131,13 @@
     tctx = context_factory_(tid);
     threads_[tid] = tctx;
   } else {
+#ifndef SANITIZER_GO
     Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
            SanitizerToolName, max_threads_);
+#else
+    Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
+        " dying\n", max_threads_);
+#endif
     Die();
   }
   CHECK_NE(tctx, 0);
@@ -277,6 +283,9 @@
   dead_threads_.pop_front();
   CHECK_EQ(tctx->status, ThreadStatusDead);
   tctx->Reset();
+  tctx->reuse_count++;
+  if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
+    return;
   invalid_threads_.push_back(tctx);
 }
 
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index a59bba5..8bb7ff3 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -38,13 +38,13 @@
 
   const u32 tid;  // Thread ID. Main thread should have tid = 0.
   u64 unique_id;  // Unique thread ID.
+  u32 reuse_count;  // Number of times this tid was reused.
   uptr os_id;     // PID (used for reporting).
   uptr user_id;   // Some opaque user thread id (e.g. pthread_t).
   char name[64];  // As annotated by user.
 
   ThreadStatus status;
   bool detached;
-  int reuse_count;
 
   u32 parent_tid;
   ThreadContextBase *next;  // For storing thread contexts in a list.
@@ -77,7 +77,7 @@
   static const u32 kUnknownTid;
 
   ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
-                 u32 thread_quarantine_size);
+                 u32 thread_quarantine_size, u32 max_reuse = 0);
   void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
   uptr GetMaxAliveThreads();
 
@@ -119,6 +119,7 @@
   const ThreadContextFactory context_factory_;
   const u32 max_threads_;
   const u32 thread_quarantine_size_;
+  const u32 max_reuse_;
 
   BlockingMutex mtx_;
 
diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc
new file mode 100644
index 0000000..42d7d1a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -0,0 +1,131 @@
+//===-- sanitizer_tls_get_addr.cc -----------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_tls_get_addr.h"
+
+#include "sanitizer_flags.h"
+#include "sanitizer_platform_interceptors.h"
+
+namespace __sanitizer {
+#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+// The actual parameter that comes to __tls_get_addr
+// is a pointer to a struct with two words in it:
+struct TlsGetAddrParam {
+  uptr dso_id;
+  uptr offset;
+};
+
+// Glibc starting from 2.19 allocates tls using __signal_safe_memalign,
+// which has such header.
+struct Glibc_2_19_tls_header {
+  uptr size;
+  uptr start;
+};
+
+// This must be static TLS
+__attribute__((tls_model("initial-exec")))
+static __thread DTLS dtls;
+
+// Make sure we properly destroy the DTLS objects:
+// this counter should never get too large.
+static atomic_uintptr_t number_of_live_dtls;
+
+static const uptr kDestroyedThread = -1;
+
+static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
+  if (!size) return;
+  VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
+  UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
+  atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
+}
+
+static inline void DTLS_Resize(uptr new_size) {
+  if (dtls.dtv_size >= new_size) return;
+  new_size = RoundUpToPowerOfTwo(new_size);
+  new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
+  DTLS::DTV *new_dtv =
+      (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
+  uptr num_live_dtls =
+      atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
+  VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
+  CHECK_LT(num_live_dtls, 1 << 20);
+  uptr old_dtv_size = dtls.dtv_size;
+  DTLS::DTV *old_dtv = dtls.dtv;
+  if (old_dtv_size)
+    internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
+  dtls.dtv = new_dtv;
+  dtls.dtv_size = new_size;
+  if (old_dtv_size)
+    DTLS_Deallocate(old_dtv, old_dtv_size);
+}
+
+void DTLS_Destroy() {
+  if (!common_flags()->intercept_tls_get_addr) return;
+  VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
+  uptr s = dtls.dtv_size;
+  dtls.dtv_size = kDestroyedThread;  // Do this before unmap for AS-safety.
+  DTLS_Deallocate(dtls.dtv, s);
+}
+
+void DTLS_on_tls_get_addr(void *arg_void, void *res) {
+  if (!common_flags()->intercept_tls_get_addr) return;
+  TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
+  uptr dso_id = arg->dso_id;
+  if (dtls.dtv_size == kDestroyedThread) return;
+  DTLS_Resize(dso_id + 1);
+  if (dtls.dtv[dso_id].beg)
+    return;
+  uptr tls_size = 0;
+  uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
+  VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
+             "num_live_dtls %zd\n",
+          arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
+          atomic_load(&number_of_live_dtls, memory_order_relaxed));
+  if (dtls.last_memalign_ptr == tls_beg) {
+    tls_size = dtls.last_memalign_size;
+    VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
+        tls_beg, tls_size);
+  } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
+    // We may want to check gnu_get_libc_version().
+    Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
+    tls_size = header->size;
+    tls_beg = header->start;
+    VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
+        tls_beg, tls_size);
+  } else {
+    VPrintf(2, "__tls_get_addr: Can't guess glibc version\n");
+    // This may happen inside the DTOR of main thread, so just ignore it.
+    tls_size = 0;
+  }
+  dtls.dtv[dso_id].beg = tls_beg;
+  dtls.dtv[dso_id].size = tls_size;
+}
+
+void DTLS_on_libc_memalign(void *ptr, uptr size) {
+  if (!common_flags()->intercept_tls_get_addr) return;
+  VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
+  dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
+  dtls.last_memalign_size = size;
+}
+
+DTLS *DTLS_Get() { return &dtls; }
+
+#else
+void DTLS_on_libc_memalign(void *ptr, uptr size) {}
+void DTLS_on_tls_get_addr(void *arg, void *res) {}
+DTLS *DTLS_Get() { return 0; }
+void DTLS_Destroy() {}
+#endif  // SANITIZER_INTERCEPT_TLS_GET_ADDR
+
+}  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.h b/lib/sanitizer_common/sanitizer_tls_get_addr.h
new file mode 100644
index 0000000..a64f11e
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_tls_get_addr.h
@@ -0,0 +1,58 @@
+//===-- sanitizer_tls_get_addr.h --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handle the __tls_get_addr call.
+//
+// All this magic is specific to glibc and is required to workaround
+// the lack of interface that would tell us about the Dynamic TLS (DTLS).
+// https://sourceware.org/bugzilla/show_bug.cgi?id=16291
+//
+// The matters get worse because the glibc implementation changed between
+// 2.18 and 2.19:
+// https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM
+//
+// Before 2.19, every DTLS chunk is allocated with __libc_memalign,
+// which we intercept and thus know where is the DTLS.
+// Since 2.19, DTLS chunks are allocated with __signal_safe_memalign,
+// which is an internal function that wraps a mmap call, neither of which
+// we can intercept. Luckily, __signal_safe_memalign has a simple parseable
+// header which we can use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_TLS_GET_ADDR_H
+#define SANITIZER_TLS_GET_ADDR_H
+
+#include "sanitizer_common.h"
+
+namespace __sanitizer {
+
+struct DTLS {
+  // Array of DTLS chunks for the current Thread.
+  // If beg == 0, the chunk is unused.
+  struct DTV {
+    uptr beg, size;
+  };
+
+  uptr dtv_size;
+  DTV *dtv;  // dtv_size elements, allocated by MmapOrDie.
+
+  // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cc
+  uptr last_memalign_size;
+  uptr last_memalign_ptr;
+};
+
+void DTLS_on_tls_get_addr(void *arg, void *res);
+void DTLS_on_libc_memalign(void *ptr, uptr size);
+DTLS *DTLS_Get();
+void DTLS_Destroy();  // Make sure to call this before the thread is destroyed.
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_TLS_GET_ADDR_H
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 362c8c9..697c59f 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -80,8 +80,9 @@
 void *MmapOrDie(uptr size, const char *mem_type) {
   void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
   if (rv == 0) {
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
-           size, size, mem_type);
+    Report("ERROR: %s failed to "
+           "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
+           SanitizerToolName, size, size, mem_type, GetLastError());
     CHECK("unable to mmap" && 0);
   }
   return rv;
@@ -89,8 +90,9 @@
 
 void UnmapOrDie(void *addr, uptr size) {
   if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
-    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
-           size, size, addr);
+    Report("ERROR: %s failed to "
+           "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
+           SanitizerToolName, size, size, addr, GetLastError());
     CHECK("unable to unmap" && 0);
   }
 }
@@ -101,8 +103,9 @@
   void *p = VirtualAlloc((LPVOID)fixed_addr, size,
       MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
   if (p == 0)
-    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
-           size, size, fixed_addr, GetLastError());
+    Report("ERROR: %s failed to "
+           "allocate %p (%zd) bytes at %p (error code: %d)\n",
+           SanitizerToolName, size, size, fixed_addr, GetLastError());
   return p;
 }
 
@@ -110,6 +113,11 @@
   return MmapFixedNoReserve(fixed_addr, size);
 }
 
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+  // FIXME: make this really NoReserve?
+  return MmapOrDie(size, mem_type);
+}
+
 void *Mprotect(uptr fixed_addr, uptr size) {
   return VirtualAlloc((LPVOID)fixed_addr, size,
                       MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
@@ -177,14 +185,15 @@
 }
 
 void DisableCoreDumper() {
-  UNIMPLEMENTED();
+  // Do nothing.
 }
 
 void ReExec() {
   UNIMPLEMENTED();
 }
 
-void PrepareForSandboxing() {
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  (void)args;
   // Nothing here for now.
 }
 
@@ -215,7 +224,7 @@
 
 void Abort() {
   abort();
-  _exit(-1);  // abort is not NORETURN on Windows.
+  internal__exit(-1);  // abort is not NORETURN on Windows.
 }
 
 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
@@ -266,13 +275,48 @@
 uptr internal_write(fd_t fd, const void *buf, uptr count) {
   if (fd != kStderrFd)
     UNIMPLEMENTED();
-  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
-  if (err == 0)
-    return 0;  // FIXME: this might not work on some apps.
-  DWORD ret;
-  if (!WriteFile(err, buf, count, &ret, 0))
+
+  static HANDLE output_stream = 0;
+  // Abort immediately if we know printing is not possible.
+  if (output_stream == INVALID_HANDLE_VALUE)
     return 0;
-  return ret;
+
+  // If called for the first time, try to use stderr to output stuff,
+  // falling back to stdout if anything goes wrong.
+  bool fallback_to_stdout = false;
+  if (output_stream == 0) {
+    output_stream = GetStdHandle(STD_ERROR_HANDLE);
+    // We don't distinguish "no such handle" from error.
+    if (output_stream == 0)
+      output_stream = INVALID_HANDLE_VALUE;
+
+    if (output_stream == INVALID_HANDLE_VALUE) {
+      // Retry with stdout?
+      output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+      if (output_stream == 0)
+        output_stream = INVALID_HANDLE_VALUE;
+      if (output_stream == INVALID_HANDLE_VALUE)
+        return 0;
+    } else {
+      // Successfully got an stderr handle.  However, if WriteFile() fails,
+      // we can still try to fallback to stdout.
+      fallback_to_stdout = true;
+    }
+  }
+
+  DWORD ret;
+  if (WriteFile(output_stream, buf, count, &ret, 0))
+    return ret;
+
+  // Re-try with stdout if using a valid stderr handle fails.
+  if (fallback_to_stdout) {
+    output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
+    if (output_stream == 0)
+      output_stream = INVALID_HANDLE_VALUE;
+    if (output_stream != INVALID_HANDLE_VALUE)
+      return internal_write(fd, buf, count);
+  }
+  return 0;
 }
 
 uptr internal_stat(const char *path, void *buf) {
@@ -305,7 +349,7 @@
 }
 
 void internal__exit(int exitcode) {
-  _exit(exitcode);
+  ExitProcess(exitcode);
 }
 
 // ---------------------- BlockingMutex ---------------- {{{1
@@ -377,16 +421,25 @@
 }
 
 void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+  CHECK_GE(max_depth, 2);
   // FIXME: CaptureStackBackTrace might be too slow for us.
   // FIXME: Compare with StackWalk64.
   // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
   size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
                                (void**)trace, 0);
+  if (size == 0)
+    return;
+
   // Skip the RTL frames by searching for the PC in the stacktrace.
   uptr pc_location = LocatePcInTrace(pc);
   PopStackFrames(pc_location);
 }
 
+void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+                                            uptr max_depth) {
+  UNREACHABLE("no signal context on windows");
+}
+
 void MaybeOpenReportFile() {
   // Windows doesn't have native fork, and we don't support Cygwin or other
   // environments that try to fake it, so the initial report_fd will always be
@@ -394,8 +447,6 @@
 }
 
 void RawWrite(const char *buffer) {
-  static const char *kRawWriteError =
-      "RawWrite can't output requested buffer!\n";
   uptr length = (uptr)internal_strlen(buffer);
   if (length != internal_write(report_fd, buffer, length)) {
     // stderr may be closed, but we may be able to print to the debugger
@@ -405,6 +456,24 @@
   }
 }
 
+void SetAlternateSignalStack() {
+  // FIXME: Decide what to do on Windows.
+}
+
+void UnsetAlternateSignalStack() {
+  // FIXME: Decide what to do on Windows.
+}
+
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {
+  (void)handler;
+  // FIXME: Decide what to do on Windows.
+}
+
+bool IsDeadlySignal(int signum) {
+  // FIXME: Decide what to do on Windows.
+  return false;
+}
+
 }  // namespace __sanitizer
 
 #endif  // _WIN32
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 5f1bd4b..0b7aea1 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
 
@@ -7,10 +7,12 @@
   LLVM_CHECKOUT="${SCRIPT_DIR}/../../../../../"
 fi
 
-# Cpplint setup
+# python tools setup
 CPPLINT=${SCRIPT_DIR}/cpplint.py
+LITLINT=${SCRIPT_DIR}/litlint.py
 if [ "${PYTHON_EXECUTABLE}" != "" ]; then
   CPPLINT="${PYTHON_EXECUTABLE} ${CPPLINT}"
+  LITLINT="${PYTHON_EXECUTABLE} ${LITLINT}"
 fi
 
 # Filters
@@ -19,7 +21,7 @@
 COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\
 -build/namespaces
 ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
-ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf
+ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn
 ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length
 TSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 TSAN_TEST_LINT_FILTER=${TSAN_RTL_LINT_FILTER},-runtime/threadsafe_fn,-runtime/int
@@ -27,7 +29,8 @@
 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
-COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf
+DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references
+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"
 cd ${LLVM_CHECKOUT}
@@ -47,13 +50,17 @@
   if [[ "${SILENT}" != "1" ]]; then
     cat $TASK_LOG
   fi
+  ${LITLINT} "$@" 2>>$ERROR_LOG
 }
 
 run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \
   lib/Transforms/Instrumentation/*Sanitizer.cpp \
   lib/Transforms/Utils/SpecialCaseList.cpp &
 
-COMPILER_RT=projects/compiler-rt
+if [ "${COMPILER_RT}" == "" ]; then
+  COMPILER_RT=projects/compiler-rt
+fi
+LIT_TESTS=${COMPILER_RT}/test
 # Headers
 SANITIZER_INCLUDES=${COMPILER_RT}/include/sanitizer
 run_lint ${SANITIZER_INCLUDES_LINT_FILTER} ${SANITIZER_INCLUDES}/*.h &
@@ -71,14 +78,14 @@
 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_LIT_TEST_LINT_FILTER} ${ASAN_RTL}/lit_tests/*/*.cc &
+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} \
                                   ${TSAN_RTL}/tests/unit/*.cc &
-run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${TSAN_RTL}/lit_tests/*.cc &
+run_lint ${TSAN_LIT_TEST_LINT_FILTER} ${LIT_TESTS}/tsan/*.cc &
 
 # MSan
 MSAN_RTL=${COMPILER_RT}/lib/msan
@@ -86,9 +93,13 @@
 
 # LSan
 LSAN_RTL=${COMPILER_RT}/lib/lsan
-run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,h} \
-                                 ${LSAN_RTL}/tests/*.{cc,h} &
-run_lint ${LSAN_LIT_TEST_LINT_FILTER} ${LSAN_RTL}/lit_tests/*/*.cc &
+run_lint ${LSAN_RTL_LINT_FILTER} ${LSAN_RTL}/*.{cc,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} &
+${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
 
 # Misc files
 FILES=${COMMON_RTL}/*.inc
diff --git a/lib/sanitizer_common/scripts/cpplint.py b/lib/sanitizer_common/scripts/cpplint.py
index a8c9f67..742459a 100755
--- a/lib/sanitizer_common/scripts/cpplint.py
+++ b/lib/sanitizer_common/scripts/cpplint.py
@@ -3634,7 +3634,7 @@
     io: The io factory to use to read the file. Provided for testability.
 
   Returns:
-    True if a header was succesfully added. False otherwise.
+    True if a header was successfully added. False otherwise.
   """
   headerfile = None
   try:
@@ -3706,7 +3706,7 @@
   # Let's copy the include_state so it is only messed up within this function.
   include_state = include_state.copy()
 
-  # Did we find the header for this file (if any) and succesfully load it?
+  # Did we find the header for this file (if any) and successfully load it?
   header_found = False
 
   # Use the absolute path so that matching works properly.
diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py
index 32ba922..fdc442a 100755
--- a/lib/sanitizer_common/scripts/gen_dynamic_list.py
+++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py
@@ -35,7 +35,7 @@
   functions = []
   nm_proc = subprocess.Popen(['nm', library], stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
-  nm_out = nm_proc.communicate()[0].split('\n')
+  nm_out = nm_proc.communicate()[0].decode().split('\n')
   if nm_proc.returncode != 0:
     raise subprocess.CalledProcessError(nm_proc.returncode, 'nm')
   for line in nm_out:
@@ -75,11 +75,11 @@
     for line in f:
       result.append(line.rstrip())
   # Print the resulting list in the format recognized by ld.
-  print '{'
+  print('{')
   result.sort()
   for f in result:
-    print '  ' + f + ';'
-  print '};'
+    print('  ' + f + ';')
+  print('};')
 
 if __name__ == '__main__':
   main(sys.argv)
diff --git a/lib/sanitizer_common/scripts/litlint.py b/lib/sanitizer_common/scripts/litlint.py
new file mode 100755
index 0000000..1e78448
--- /dev/null
+++ b/lib/sanitizer_common/scripts/litlint.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+#
+# litlint
+#
+# Ensure RUN commands in lit tests are free of common errors.
+#
+# If any errors are detected, litlint returns a nonzero exit code.
+#
+
+import optparse
+import re
+import sys
+
+# Compile regex once for all files
+runRegex = re.compile(r'(?<!-o)(?<!%run) %t\s')
+
+def LintLine(s):
+  """ Validate a line
+
+  Args:
+    s: str, the line to validate
+
+  Returns:
+    Returns an error message and a 1-based column number if an error was
+    detected, otherwise (None, None).
+  """
+
+  # Check that RUN command can be executed with an emulator
+  m = runRegex.search(s)
+  if m:
+    start, end = m.span()
+    return ('missing %run before %t', start + 2)
+
+  # No errors
+  return (None, None)
+
+
+def LintFile(p):
+  """ Check that each RUN command can be executed with an emulator
+
+  Args:
+    p: str, valid path to a file
+
+  Returns:
+    The number of errors detected.
+  """
+  errs = 0
+  with open(p, 'r') as f:
+    for i, s in enumerate(f.readlines(), start=1):
+      msg, col = LintLine(s)
+      if msg != None:
+        errs += 1
+        errorMsg = 'litlint: {}:{}:{}: error: {}.\n{}{}\n'
+        arrow = (col-1) * ' ' + '^'
+        sys.stderr.write(errorMsg.format(p, i, col, msg, s, arrow))
+  return errs
+
+
+if __name__ == "__main__":
+  # Parse args
+  parser = optparse.OptionParser()
+  parser.add_option('--filter')  # ignored
+  (options, filenames) = parser.parse_args()
+
+  # Lint each file
+  errs = 0
+  for p in filenames:
+    errs += LintFile(p)
+
+  # If errors, return nonzero
+  if errs > 0:
+    sys.exit(1)
diff --git a/lib/sanitizer_common/scripts/litlint_test.py b/lib/sanitizer_common/scripts/litlint_test.py
new file mode 100755
index 0000000..3ce482d
--- /dev/null
+++ b/lib/sanitizer_common/scripts/litlint_test.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+# Tests for litlint.py
+#
+# Usage: python litlint_test.py
+#
+# Returns nonzero if any test fails
+
+import litlint
+import unittest
+
+class TestLintLine(unittest.TestCase):
+  def test_missing_run(self):
+    f = litlint.LintLine
+    self.assertEqual(f(' %t '),     ('missing %run before %t', 2))
+    self.assertEqual(f(' %t\n'),    ('missing %run before %t', 2))
+    self.assertEqual(f(' %t.so '),  (None, None))
+    self.assertEqual(f(' %t.o '),   (None, None))
+    self.assertEqual(f('%run %t '), (None, None))
+    self.assertEqual(f('-o %t '),   (None, None))
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index aa791bc..dfb65b2 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -4,23 +4,26 @@
 # We need to merge these integers into a set and then
 # either print them (as hex) or dump them into another file.
 import array
+import struct
 import sys
+import bisect
+import os.path
 
 prog_name = "";
 
 def Usage():
   print >> sys.stderr, "Usage: \n" + \
       " " + prog_name + " merge file1 [file2 ...]  > output\n" \
-      " " + prog_name + " print file1 [file2 ...]\n"
+      " " + prog_name + " print file1 [file2 ...]\n" \
+      " " + prog_name + " unpack file1 [file2 ...]\n"
   exit(1)
 
 def ReadOneFile(path):
-  f = open(path, mode="rb")
-  f.seek(0, 2)
-  size = f.tell()
-  f.seek(0, 0)
-  s = set(array.array('I', f.read(size)))
-  f.close()
+  with open(path, mode="rb") as f:
+    f.seek(0, 2)
+    size = f.tell()
+    f.seek(0, 0)
+    s = set(array.array('I', f.read(size)))
   print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path)
   return s
 
@@ -44,6 +47,93 @@
   a = array.array('I', s)
   a.tofile(sys.stdout)
 
+
+def UnpackOneFile(path):
+  with open(path, mode="rb") as f:
+    print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+    while True:
+      header = f.read(12)
+      if not header: return
+      if len(header) < 12:
+        break
+      pid, module_length, blob_size = struct.unpack('iII', header)
+      module = f.read(module_length)
+      blob = f.read(blob_size)
+      assert(len(module) == module_length)
+      assert(len(blob) == blob_size)
+      extracted_file = "%s.%d.sancov" % (module, pid)
+      print >> sys.stderr, "%s: extracting %s" % \
+        (prog_name, extracted_file)
+      # The packed file may contain multiple blobs for the same pid/module
+      # pair. Append to the end of the file instead of overwriting.
+      with open(extracted_file, 'ab') as f2:
+        f2.write(blob)
+    # fail
+    raise Exception('Error reading file %s' % path)
+
+
+def Unpack(files):
+  for f in files:
+    UnpackOneFile(f)
+
+def UnpackOneRawFile(path, map_path):
+  mem_map = []
+  with open(map_path, mode="rt") as f_map:
+    print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
+    bits = int(f_map.readline())
+    for line in f_map:
+      parts = line.rstrip().split()
+      assert len(parts) == 4
+      mem_map.append((int(parts[0], 16),
+                  int(parts[1], 16),
+                  int(parts[2], 16),
+                  parts[3]))
+  mem_map.sort(key=lambda m : m[0])
+  mem_map_keys = [m[0] for m in mem_map]
+
+  print mem_map
+  with open(path, mode="rb") as f:
+    print >> sys.stderr, "%s: unpacking %s" % (prog_name, path)
+
+    f.seek(0, 2)
+    size = f.tell()
+    f.seek(0, 0)
+    if bits == 64:
+      typecode = 'L'
+    else:
+      typecode = 'I'
+    pcs = array.array(typecode, f.read(size))
+    mem_map_pcs = [[] for i in range(0, len(mem_map))]
+
+    for pc in pcs:
+      if pc == 0: continue
+      map_idx = bisect.bisect(mem_map_keys, pc) - 1
+      (start, end, base, module_path) = mem_map[map_idx]
+      print pc
+      print start, end, base, module_path
+      assert pc >= start
+      if pc >= end:
+        print >> sys.stderr, "warning: %s: pc %x outside of any known mapping" % (prog_name, pc)
+        continue
+      mem_map_pcs[map_idx].append(pc - base)
+
+    for ((start, end, base, module_path), pc_list) in zip(mem_map, mem_map_pcs):
+      if len(pc_list) == 0: continue
+      assert path.endswith('.sancov.raw')
+      dst_path = module_path + '.' + os.path.basename(path)[:-4]
+      print "writing %d PCs to %s" % (len(pc_list), dst_path)
+      arr = array.array('I')
+      arr.fromlist(sorted(pc_list))
+      with open(dst_path, 'ab') as f2:
+        arr.tofile(f2)
+
+def RawUnpack(files):
+  for f in files:
+    if not f.endswith('.sancov.raw'):
+      raise Exception('Unexpected raw file name %s' % f)
+    f_map = f[:-3] + 'map'
+    UnpackOneRawFile(f, f_map)
+
 if __name__ == '__main__':
   prog_name = sys.argv[0]
   if len(sys.argv) <= 2:
@@ -52,5 +142,9 @@
     PrintFiles(sys.argv[2:])
   elif sys.argv[1] == "merge":
     MergeAndPrint(sys.argv[2:])
+  elif sys.argv[1] == "unpack":
+    Unpack(sys.argv[2:])
+  elif sys.argv[1] == "rawunpack":
+    RawUnpack(sys.argv[2:])
   else:
     Usage()
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 5b66917..331117b 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -3,8 +3,12 @@
 set(SANITIZER_UNITTESTS
   sanitizer_allocator_test.cc
   sanitizer_atomic_test.cc
+  sanitizer_bitvector_test.cc
+  sanitizer_bvgraph_test.cc
   sanitizer_common_test.cc
+  sanitizer_deadlock_detector_test.cc
   sanitizer_flags_test.cc
+  sanitizer_format_interceptor_test.cc
   sanitizer_ioctl_test.cc
   sanitizer_libc_test.cc
   sanitizer_linux_test.cc
@@ -13,7 +17,7 @@
   sanitizer_nolibc_test.cc
   sanitizer_posix_test.cc
   sanitizer_printf_test.cc
-  sanitizer_scanf_interceptor_test.cc
+  sanitizer_procmaps_test.cc
   sanitizer_stackdepot_test.cc
   sanitizer_stacktrace_test.cc
   sanitizer_stoptheworld_test.cc
@@ -22,22 +26,55 @@
   sanitizer_thread_registry_test.cc)
 
 set(SANITIZER_TEST_HEADERS
+  sanitizer_pthread_wrappers.h
+  sanitizer_test_config.h
   sanitizer_test_utils.h)
 foreach(header ${SANITIZER_HEADERS})
   list(APPEND SANITIZER_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
 endforeach()
 
 set(SANITIZER_TEST_CFLAGS_COMMON
-  ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+  ${COMPILER_RT_GTEST_CFLAGS}
   -I${COMPILER_RT_SOURCE_DIR}/include
   -I${COMPILER_RT_SOURCE_DIR}/lib
   -I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common
   -DGTEST_HAS_RTTI=0
-  -O2 -g -fno-rtti
-  -Wall -Werror -Werror=sign-compare)
+  -O2
+  -Werror=sign-compare
+  -Wno-non-virtual-dtor)
 
-set(SANITIZER_TEST_LINK_FLAGS_COMMON
-  -lstdc++ -ldl)
+append_if(COMPILER_RT_HAS_G_FLAG -g SANITIZER_TEST_CFLAGS_COMMON)
+append_if(COMPILER_RT_HAS_Zi_FLAG -Zi SANITIZER_TEST_CFLAGS_COMMON)
+
+append_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti SANITIZER_TEST_CFLAGS_COMMON)
+append_if(COMPILER_RT_HAS_GR_FLAG -GR- SANITIZER_TEST_CFLAGS_COMMON)
+
+if(MSVC)
+  # System headers and gtest use a lot of deprecated stuff.
+  list(APPEND SANITIZER_TEST_CFLAGS_COMMON
+       -Wno-deprecated-declarations)
+
+  # clang-cl doesn't support exceptions yet.
+  list(APPEND SANITIZER_TEST_CFLAGS_COMMON
+       /fallback
+       -D_HAS_EXCEPTIONS=0)
+
+  # We should teach clang-cl to understand more pragmas.
+  list(APPEND SANITIZER_TEST_CFLAGS_COMMON
+       -Wno-unknown-pragmas
+       -Wno-undefined-inline)
+endif()
+
+if(NOT MSVC)
+  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 -lpthread SANITIZER_TEST_LINK_FLAGS_COMMON)
+# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests.
+if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
+  list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON "-lc++")
+endif()
 
 include_directories(..)
 include_directories(../..)
@@ -57,7 +94,11 @@
     set(tgt_name "RTSanitizerCommon.test.${arch}")
   endif()
   set(${lib} "${tgt_name}" PARENT_SCOPE)
-  set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+  if(NOT MSVC)
+    set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+  else()
+    set(${lib_name} "${tgt_name}.lib" PARENT_SCOPE)
+  endif()
 endfunction()
 
 # Sanitizer_common unit tests testsuite.
@@ -70,14 +111,17 @@
   get_target_flags_for_arch(${arch} TARGET_FLAGS)
   set(SANITIZER_TEST_SOURCES ${SANITIZER_UNITTESTS}
                              ${COMPILER_RT_GTEST_SOURCE})
+  set(SANITIZER_TEST_COMPILE_DEPS ${SANITIZER_TEST_HEADERS})
+  if(NOT COMPILER_RT_STANDALONE_BUILD)
+    list(APPEND SANITIZER_TEST_COMPILE_DEPS gtest)
+  endif()
   set(SANITIZER_TEST_OBJECTS)
   foreach(source ${SANITIZER_TEST_SOURCES})
     get_filename_component(basename ${source} NAME)
     set(output_obj "${basename}.${arch}.o")
     clang_compile(${output_obj} ${source}
                   CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
-                  DEPS gtest ${SANITIZER_RUNTIME_LIBRARIES}
-                       ${SANITIZER_TEST_HEADERS})
+                  DEPS ${SANITIZER_TEST_COMPILE_DEPS})
     list(APPEND SANITIZER_TEST_OBJECTS ${output_obj})
   endforeach()
   get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB
@@ -89,7 +133,7 @@
                                ${SANITIZER_COMMON_LIB_NAME}
                        DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB}
                        LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON}
-                                  -lpthread ${TARGET_FLAGS})
+                                  ${TARGET_FLAGS})
 
   if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
     # Test that the libc-independent part of sanitizer_common is indeed
@@ -98,7 +142,7 @@
     clang_compile(sanitizer_nolibc_test_main.${arch}.o
                   sanitizer_nolibc_test_main.cc
                   CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
-                  DEPS ${SANITIZER_RUNTIME_LIBRARIES} ${SANITIZER_TEST_HEADERS})
+                  DEPS ${SANITIZER_TEST_COMPILE_DEPS})
     add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc"
                          OBJECTS sanitizer_nolibc_test_main.${arch}.o
                                  -Wl,-whole-archive
@@ -136,18 +180,6 @@
   if(CAN_TARGET_i386)
     add_sanitizer_tests_for_arch(i386)
   endif()
-
-  # Run unittests as a part of lit testsuite.
-  configure_lit_site_cfg(
-    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
-    ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
-    )
-
-  add_lit_testsuite(check-sanitizer "Running sanitizer library unittests"
-    ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS SanitizerUnitTests
-    )
-  set_target_properties(check-sanitizer PROPERTIES FOLDER "Sanitizer unittests")
 endif()
 
 if(ANDROID)
@@ -164,6 +196,7 @@
   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)
 endif()
diff --git a/lib/sanitizer_common/tests/lit.site.cfg.in b/lib/sanitizer_common/tests/lit.site.cfg.in
deleted file mode 100644
index 5ceb9e4..0000000
--- a/lib/sanitizer_common/tests/lit.site.cfg.in
+++ /dev/null
@@ -1,14 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'SanitizerCommon-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with sanitizer_common tests.
-config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", "lib",
-                                     "sanitizer_common", "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index d92a07f..4340f37 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -17,11 +17,11 @@
 #include "sanitizer_common/sanitizer_flags.h"
 
 #include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
 
 #include "gtest/gtest.h"
 
 #include <stdlib.h>
-#include <pthread.h>
 #include <algorithm>
 #include <vector>
 #include <set>
@@ -328,6 +328,7 @@
 }
 #endif
 
+#if !defined(_WIN32)  // FIXME: This currently fails on Windows.
 TEST(SanitizerCommon, LargeMmapAllocator) {
   LargeMmapAllocator<> a;
   a.Init();
@@ -403,6 +404,7 @@
   CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
   a.Deallocate(&stats, p);
 }
+#endif
 
 template
 <class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
@@ -477,11 +479,13 @@
 }
 #endif
 
+#if !defined(_WIN32)  // FIXME: This currently fails on Windows.
 TEST(SanitizerCommon, CombinedAllocator32Compact) {
   TestCombinedAllocator<Allocator32Compact,
       LargeMmapAllocator<>,
       SizeClassAllocatorLocalCache<Allocator32Compact> > ();
 }
+#endif
 
 template <class AllocatorCache>
 void TestSizeClassAllocatorLocalCache() {
@@ -553,8 +557,8 @@
   uptr total_used_memory = 0;
   for (int i = 0; i < 100; i++) {
     pthread_t t;
-    EXPECT_EQ(0, pthread_create(&t, 0, AllocatorLeakTestWorker, &a));
-    EXPECT_EQ(0, pthread_join(t, 0));
+    PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
+    PTHREAD_JOIN(t, 0);
     if (i == 0)
       total_used_memory = a.TotalMemoryUsed();
     EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
@@ -595,8 +599,8 @@
   params->allocator = &allocator;
   params->class_id = class_id;
   pthread_t t;
-  EXPECT_EQ(0, pthread_create(&t, 0, DeallocNewThreadWorker, params));
-  EXPECT_EQ(0, pthread_join(t, 0));
+  PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
+  PTHREAD_JOIN(t, 0);
 }
 #endif
 
@@ -794,4 +798,65 @@
 }
 #endif
 
+TEST(SanitizerCommon, TwoLevelByteMap) {
+  const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;
+  const u64 n = kSize1 * kSize2;
+  TwoLevelByteMap<kSize1, kSize2> m;
+  m.TestOnlyInit();
+  for (u64 i = 0; i < n; i += 7) {
+    m.set(i, (i % 100) + 1);
+  }
+  for (u64 j = 0; j < n; j++) {
+    if (j % 7)
+      EXPECT_EQ(m[j], 0);
+    else
+      EXPECT_EQ(m[j], (j % 100) + 1);
+  }
+
+  m.TestOnlyUnmap();
+}
+
+
+typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
+
+struct TestByteMapParam {
+  TestByteMap *m;
+  size_t shard;
+  size_t num_shards;
+};
+
+void *TwoLevelByteMapUserThread(void *param) {
+  TestByteMapParam *p = (TestByteMapParam*)param;
+  for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) {
+    size_t val = (i % 100) + 1;
+    p->m->set(i, val);
+    EXPECT_EQ((*p->m)[i], val);
+  }
+  return 0;
+}
+
+TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {
+  TestByteMap m;
+  m.TestOnlyInit();
+  TestMapUnmapCallback::map_count = 0;
+  TestMapUnmapCallback::unmap_count = 0;
+  static const int kNumThreads = 4;
+  pthread_t t[kNumThreads];
+  TestByteMapParam p[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    p[i].m = &m;
+    p[i].shard = i;
+    p[i].num_shards = kNumThreads;
+    PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    PTHREAD_JOIN(t[i], 0);
+  }
+  EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+  EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL);
+  m.TestOnlyUnmap();
+  EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+  EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1());
+}
+
 #endif  // #if TSAN_DEBUG==0
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
index f6a944f..0cc3b9b 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
@@ -156,7 +156,7 @@
 void *operator new[](size_t size) ALIAS("malloc");
 void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc");
 void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc");
-void operator delete(void *ptr) ALIAS("free");
-void operator delete[](void *ptr) ALIAS("free");
+void operator delete(void *ptr) throw() ALIAS("free");
+void operator delete[](void *ptr) throw() ALIAS("free");
 void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free");
 void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free");
diff --git a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
index a4a97c4..56bcd35 100644
--- a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
@@ -15,6 +15,79 @@
 
 namespace __sanitizer {
 
+template<typename T>
+struct ValAndMagic {
+  typename T::Type magic0;
+  T a;
+  typename T::Type magic1;
+
+  static ValAndMagic<T> *sink;
+};
+
+template<typename T>
+ValAndMagic<T> *ValAndMagic<T>::sink;
+
+template<typename T, memory_order load_mo, memory_order store_mo>
+void CheckStoreLoad() {
+  typedef typename T::Type Type;
+  ValAndMagic<T> val;
+  // Prevent the compiler from scalarizing the struct.
+  ValAndMagic<T>::sink = &val;
+  // Ensure that surrounding memory is not overwritten.
+  val.magic0 = val.magic1 = (Type)-3;
+  for (u64 i = 0; i < 100; i++) {
+    // Generate a value that occupies all bytes of the variable.
+    u64 v = i;
+    v |= v << 8;
+    v |= v << 16;
+    v |= v << 32;
+    val.a.val_dont_use = (Type)v;
+    EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
+    val.a.val_dont_use = (Type)-1;
+    atomic_store(&val.a, (Type)v, store_mo);
+    EXPECT_EQ(val.a.val_dont_use, (Type)v);
+  }
+  EXPECT_EQ(val.magic0, (Type)-3);
+  EXPECT_EQ(val.magic1, (Type)-3);
+}
+
+TEST(SanitizerCommon, AtomicStoreLoad) {
+  CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
+  CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+  CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
+  CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+  CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
+  CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+  CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
+  CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
+  CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+  CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
+      ();
+  CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
+      ();
+  CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
+      ();
+  CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
+      ();
+  CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
+      ();
+}
+
 // Clang crashes while compiling this test for Android:
 // http://llvm.org/bugs/show_bug.cgi?id=15587
 #if !SANITIZER_ANDROID
diff --git a/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
new file mode 100644
index 0000000..706b4c5
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
@@ -0,0 +1,176 @@
+//===-- sanitizer_bitvector_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 runtime.
+// Tests for sanitizer_bitvector.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bitvector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+
+// Check the 'bv' == 's' and that the indexes go in increasing order.
+// Also check the BV::Iterator
+template <class BV>
+static void CheckBV(const BV &bv, const set<uptr> &s) {
+  BV t;
+  t.copyFrom(bv);
+  set<uptr> t_s(s);
+  uptr last_idx = bv.size();
+  uptr count = 0;
+  for (typename BV::Iterator it(bv); it.hasNext();) {
+    uptr idx = it.next();
+    count++;
+    if (last_idx != bv.size())
+      EXPECT_LT(last_idx, idx);
+    last_idx = idx;
+    EXPECT_TRUE(s.count(idx));
+  }
+  EXPECT_EQ(count, s.size());
+
+  last_idx = bv.size();
+  while (!t.empty()) {
+    uptr idx = t.getAndClearFirstOne();
+    if (last_idx != bv.size())
+      EXPECT_LT(last_idx, idx);
+    last_idx = idx;
+    EXPECT_TRUE(t_s.erase(idx));
+  }
+  EXPECT_TRUE(t_s.empty());
+}
+
+template <class BV>
+void Print(const BV &bv) {
+  BV t;
+  t.copyFrom(bv);
+  while (!t.empty()) {
+    uptr idx = t.getAndClearFirstOne();
+    fprintf(stderr, "%zd ", idx);
+  }
+  fprintf(stderr, "\n");
+}
+
+void Print(const set<uptr> &s) {
+  for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
+    fprintf(stderr, "%zd ", *it);
+  }
+  fprintf(stderr, "\n");
+}
+
+template <class BV>
+void TestBitVector(uptr expected_size) {
+  BV bv, bv1, t_bv;
+  EXPECT_EQ(expected_size, BV::kSize);
+  bv.clear();
+  EXPECT_TRUE(bv.empty());
+  bv.setBit(5);
+  EXPECT_FALSE(bv.empty());
+  EXPECT_FALSE(bv.getBit(4));
+  EXPECT_FALSE(bv.getBit(6));
+  EXPECT_TRUE(bv.getBit(5));
+  bv.clearBit(5);
+  EXPECT_FALSE(bv.getBit(5));
+
+  // test random bits
+  bv.clear();
+  set<uptr> s;
+  for (uptr it = 0; it < 1000; it++) {
+    uptr bit = ((uptr)my_rand() % bv.size());
+    EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+    switch (my_rand() % 2) {
+      case 0:
+        EXPECT_EQ(bv.setBit(bit), s.insert(bit).second);
+        break;
+      case 1:
+        size_t old_size = s.size();
+        s.erase(bit);
+        EXPECT_EQ(bv.clearBit(bit), old_size > s.size());
+        break;
+    }
+    EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+  }
+
+  vector<uptr>bits(bv.size());
+  // Test setUnion, setIntersection, setDifference,
+  // intersectsWith, and getAndClearFirstOne.
+  for (uptr it = 0; it < 30; it++) {
+    // iota
+    for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
+    random_shuffle(bits.begin(), bits.end());
+    set<uptr> s, s1, t_s;
+    bv.clear();
+    bv1.clear();
+    uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
+    uptr n_bits1 = (uptr)my_rand() % (bv.size() / 2);
+    EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
+    EXPECT_TRUE(n_bits1 < bv.size() / 2);
+    for (uptr i = 0; i < n_bits; i++) {
+      bv.setBit(bits[i]);
+      s.insert(bits[i]);
+    }
+    CheckBV(bv, s);
+    for (uptr i = 0; i < n_bits1; i++) {
+      bv1.setBit(bits[bv.size() / 2 + i]);
+      s1.insert(bits[bv.size() / 2 + i]);
+    }
+    CheckBV(bv1, s1);
+
+    vector<uptr> vec;
+    set_intersection(s.begin(), s.end(), s1.begin(), s1.end(),
+                     back_insert_iterator<vector<uptr> >(vec));
+    EXPECT_EQ(bv.intersectsWith(bv1), !vec.empty());
+
+    // setUnion
+    t_s = s;
+    t_bv.copyFrom(bv);
+    t_s.insert(s1.begin(), s1.end());
+    EXPECT_EQ(t_bv.setUnion(bv1), s.size() != t_s.size());
+    CheckBV(t_bv, t_s);
+
+    // setIntersection
+    t_s = set<uptr>(vec.begin(), vec.end());
+    t_bv.copyFrom(bv);
+    EXPECT_EQ(t_bv.setIntersection(bv1), s.size() != t_s.size());
+    CheckBV(t_bv, t_s);
+
+    // setDifference
+    vec.clear();
+    set_difference(s.begin(), s.end(), s1.begin(), s1.end(),
+                     back_insert_iterator<vector<uptr> >(vec));
+    t_s = set<uptr>(vec.begin(), vec.end());
+    t_bv.copyFrom(bv);
+    EXPECT_EQ(t_bv.setDifference(bv1), s.size() != t_s.size());
+    CheckBV(t_bv, t_s);
+  }
+}
+
+TEST(SanitizerCommon, BasicBitVector) {
+  TestBitVector<BasicBitVector<u8> >(8);
+  TestBitVector<BasicBitVector<u16> >(16);
+  TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
+}
+
+TEST(SanitizerCommon, TwoLevelBitVector) {
+  uptr ws = SANITIZER_WORDSIZE;
+  TestBitVector<TwoLevelBitVector<1, BasicBitVector<u8> > >(8 * 8);
+  TestBitVector<TwoLevelBitVector<> >(ws * ws);
+  TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
+  TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
+  TestBitVector<TwoLevelBitVector<3, BasicBitVector<u16> > >(16 * 16 * 3);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
new file mode 100644
index 0000000..3b39f8d
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
@@ -0,0 +1,339 @@
+//===-- sanitizer_bvgraph_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 runtime.
+// Tests for sanitizer_bvgraph.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bvgraph.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+template<class G>
+void PrintGraph(const G &g) {
+  for (uptr i = 0; i < g.size(); i++) {
+    for (uptr j = 0; j < g.size(); j++) {
+      fprintf(stderr, "%d", g.hasEdge(i, j));
+    }
+    fprintf(stderr, "\n");
+  }
+}
+
+
+class SimpleGraph {
+ public:
+  void clear() { s_.clear(); }
+  bool addEdge(uptr from, uptr to) {
+    return s_.insert(idx(from, to)).second;
+  }
+  bool removeEdge(uptr from, uptr to) {
+    return s_.erase(idx(from, to));
+  }
+  template <class G>
+  void checkSameAs(G *g) {
+    for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
+      uptr from = *it >> 16;
+      uptr to = *it & ((1 << 16) - 1);
+      EXPECT_TRUE(g->removeEdge(from, to));
+    }
+    EXPECT_TRUE(g->empty());
+  }
+ private:
+  uptr idx(uptr from, uptr to) {
+    CHECK_LE(from|to, 1 << 16);
+    return (from << 16) + to;
+  }
+  set<uptr> s_;
+};
+
+template <class BV>
+void BasicTest() {
+  BVGraph<BV> g;
+  g.clear();
+  BV target;
+  SimpleGraph s_g;
+  set<uptr> s;
+  set<uptr> s_target;
+  int num_reachable = 0;
+  for (int it = 0; it < 1000; it++) {
+    target.clear();
+    s_target.clear();
+    for (int t = 0; t < 4; t++) {
+      uptr idx = (uptr)my_rand() % g.size();
+      EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
+    }
+    uptr from = my_rand() % g.size();
+    uptr to = my_rand() % g.size();
+    EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+    EXPECT_TRUE(g.hasEdge(from, to));
+    for (int i = 0; i < 10; i++) {
+      from = my_rand() % g.size();
+      bool is_reachable = g.isReachable(from, target);
+      if (is_reachable) {
+        uptr path[BV::kSize];
+        uptr len;
+        for (len = 1; len < BV::kSize; len++) {
+          if (g.findPath(from, target, path, len) == len)
+            break;
+        }
+        EXPECT_LT(len, BV::kSize);
+        EXPECT_TRUE(target.getBit(path[len - 1]));
+        // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
+        //        from, len, path[0], path[1], path[2]);
+        num_reachable++;
+      }
+    }
+  }
+  EXPECT_GT(num_reachable, 0);
+}
+
+TEST(BVGraph, BasicTest) {
+  BasicTest<BV1>();
+  BasicTest<BV2>();
+  BasicTest<BV3>();
+  BasicTest<BV4>();
+}
+
+template <class BV>
+void RemoveEdges() {
+  SimpleGraph s_g;
+  BVGraph<BV> g;
+  g.clear();
+  BV bv;
+  set<uptr> s;
+  for (int it = 0; it < 100; it++) {
+    s.clear();
+    bv.clear();
+    s_g.clear();
+    g.clear();
+    for (uptr j = 0; j < g.size() * 2; j++) {
+      uptr from = my_rand() % g.size();
+      uptr to = my_rand() % g.size();
+      EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+    }
+    for (uptr j = 0; j < 5; j++) {
+      uptr idx = my_rand() % g.size();
+      s.insert(idx);
+      bv.setBit(idx);
+    }
+
+    if (it % 2) {
+      g.removeEdgesFrom(bv);
+      for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
+        for (uptr to = 0; to < g.size(); to++)
+          s_g.removeEdge(*from, to);
+      }
+    } else {
+      g.removeEdgesTo(bv);
+      for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
+        for (uptr from = 0; from < g.size(); from++)
+          s_g.removeEdge(from, *to);
+      }
+    }
+    s_g.checkSameAs(&g);
+  }
+}
+
+TEST(BVGraph, RemoveEdges) {
+  RemoveEdges<BV1>();
+  RemoveEdges<BV2>();
+  RemoveEdges<BV3>();
+  RemoveEdges<BV4>();
+}
+
+template <class BV>
+void Test_isReachable() {
+  uptr path[5];
+  BVGraph<BV> g;
+  g.clear();
+  BV target;
+  target.clear();
+  uptr t0 = 0;
+  uptr t1 = g.size() - 1;
+  target.setBit(t0);
+  target.setBit(t1);
+
+  uptr f0 = 1;
+  uptr f1 = 2;
+  uptr f2 = g.size() / 2;
+  uptr f3 = g.size() - 2;
+
+  EXPECT_FALSE(g.isReachable(f0, target));
+  EXPECT_FALSE(g.isReachable(f1, target));
+  EXPECT_FALSE(g.isReachable(f2, target));
+  EXPECT_FALSE(g.isReachable(f3, target));
+
+  g.addEdge(f0, f1);
+  g.addEdge(f1, f2);
+  g.addEdge(f2, f3);
+  EXPECT_FALSE(g.isReachable(f0, target));
+  EXPECT_FALSE(g.isReachable(f1, target));
+  EXPECT_FALSE(g.isReachable(f2, target));
+  EXPECT_FALSE(g.isReachable(f3, target));
+
+  g.addEdge(f1, t0);
+  EXPECT_TRUE(g.isReachable(f0, target));
+  EXPECT_TRUE(g.isReachable(f1, target));
+  EXPECT_FALSE(g.isReachable(f2, target));
+  EXPECT_FALSE(g.isReachable(f3, target));
+  EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
+  EXPECT_EQ(path[0], f0);
+  EXPECT_EQ(path[1], f1);
+  EXPECT_EQ(path[2], t0);
+  EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
+  EXPECT_EQ(path[0], f1);
+  EXPECT_EQ(path[1], t0);
+
+  g.addEdge(f3, t1);
+  EXPECT_TRUE(g.isReachable(f0, target));
+  EXPECT_TRUE(g.isReachable(f1, target));
+  EXPECT_TRUE(g.isReachable(f2, target));
+  EXPECT_TRUE(g.isReachable(f3, target));
+}
+
+TEST(BVGraph, isReachable) {
+  Test_isReachable<BV1>();
+  Test_isReachable<BV2>();
+  Test_isReachable<BV3>();
+  Test_isReachable<BV4>();
+}
+
+template <class BV>
+void LongCycle() {
+  BVGraph<BV> g;
+  g.clear();
+  vector<uptr> path_vec(g.size());
+  uptr *path = path_vec.data();
+  uptr start = 5;
+  for (uptr i = start; i < g.size() - 1; i++) {
+    g.addEdge(i, i + 1);
+    for (uptr j = 0; j < start; j++)
+      g.addEdge(i, j);
+  }
+  //  Bad graph that looks like this:
+  // 00000000000000
+  // 00000000000000
+  // 00000000000000
+  // 00000000000000
+  // 00000000000000
+  // 11111010000000
+  // 11111001000000
+  // 11111000100000
+  // 11111000010000
+  // 11111000001000
+  // 11111000000100
+  // 11111000000010
+  // 11111000000001
+  // if (g.size() <= 64) PrintGraph(g);
+  BV target;
+  for (uptr i = start + 1; i < g.size(); i += 11) {
+    // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
+    target.clear();
+    target.setBit(i);
+    EXPECT_TRUE(g.isReachable(start, target));
+    EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
+  }
+}
+
+TEST(BVGraph, LongCycle) {
+  LongCycle<BV1>();
+  LongCycle<BV2>();
+  LongCycle<BV3>();
+  LongCycle<BV4>();
+}
+
+template <class BV>
+void ShortestPath() {
+  uptr path[8];
+  BVGraph<BV> g;
+  g.clear();
+  BV t7;
+  t7.clear();
+  t7.setBit(7);
+  // 1=>2=>3=>4=>5=>6=>7
+  // 1=>7
+  g.addEdge(1, 2);
+  g.addEdge(2, 3);
+  g.addEdge(3, 4);
+  g.addEdge(4, 5);
+  g.addEdge(5, 6);
+  g.addEdge(6, 7);
+  g.addEdge(1, 7);
+  EXPECT_TRUE(g.isReachable(1, t7));
+  // No path of length 1.
+  EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
+  // Trying to find a path of len 2..6 gives path of len 2.
+  EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
+  EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
+  EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
+  EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
+  EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
+  // Trying to find a path of len 7 gives path of len 7, because this is DFS.
+  EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
+  // But findShortestPath will find the shortest path.
+  EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
+  EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
+}
+
+TEST(BVGraph, ShortestPath) {
+  ShortestPath<BV1>();
+  ShortestPath<BV2>();
+  ShortestPath<BV3>();
+  ShortestPath<BV4>();
+}
+
+template <class BV>
+void RunAddEdgesTest() {
+  BVGraph<BV> g;
+  BV from;
+  const int kMaxEdges = 10;
+  uptr added_edges[kMaxEdges];
+  g.clear();
+  from.clear();
+  EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
+  EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+  from.setBit(0);
+  EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
+  EXPECT_EQ(0U, added_edges[0]);
+  EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+
+  from.clear();
+  from.setBit(1);
+  EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
+  EXPECT_TRUE(g.hasEdge(1, 4));
+  EXPECT_FALSE(g.hasEdge(1, 5));
+  EXPECT_EQ(1U, added_edges[0]);
+  from.setBit(2);
+  from.setBit(3);
+  EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
+  EXPECT_TRUE(g.hasEdge(2, 4));
+  EXPECT_FALSE(g.hasEdge(2, 5));
+  EXPECT_TRUE(g.hasEdge(3, 4));
+  EXPECT_FALSE(g.hasEdge(3, 5));
+  EXPECT_EQ(2U, added_edges[0]);
+  EXPECT_EQ(3U, added_edges[1]);
+}
+
+TEST(BVGraph, AddEdgesTest) {
+  RunAddEdgesTest<BV2>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 608f904..8dcecaf 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -15,6 +15,9 @@
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_platform.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
 #include "gtest/gtest.h"
 
 namespace __sanitizer {
@@ -113,6 +116,9 @@
     vector.pop_back();
     EXPECT_EQ((uptr)i, vector.size());
   }
+  InternalMmapVector<uptr> empty_vector(0);
+  CHECK_GT(empty_vector.capacity(), 0U);
+  CHECK_EQ(0U, empty_vector.size());
 }
 
 void TestThreadInfo(bool main) {
@@ -156,8 +162,8 @@
 TEST(SanitizerCommon, ThreadStackTlsWorker) {
   InitTlsSize();
   pthread_t t;
-  pthread_create(&t, 0, WorkerThread, 0);
-  pthread_join(t, 0);
+  PTHREAD_CREATE(&t, 0, WorkerThread, 0);
+  PTHREAD_JOIN(t, 0);
 }
 
 bool UptrLess(uptr a, uptr b) {
diff --git a/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
new file mode 100644
index 0000000..ac19dcf
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
@@ -0,0 +1,491 @@
+//===-- sanitizer_deadlock_detector_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 runtime.
+// Tests for sanitizer_deadlock_detector.h
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_deadlock_detector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+// Poor man's unique_ptr.
+template<class BV>
+struct ScopedDD {
+  ScopedDD() {
+    dp = new DeadlockDetector<BV>;
+    dp->clear();
+    dtls.clear();
+  }
+  ~ScopedDD() { delete dp; }
+  DeadlockDetector<BV> *dp;
+  DeadlockDetectorTLS<BV> dtls;
+};
+
+template <class BV>
+void RunBasicTest() {
+  uptr path[10];
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+  set<uptr> s;
+  for (size_t i = 0; i < d.size() * 3; i++) {
+    uptr node = d.newNode(0);
+    EXPECT_TRUE(s.insert(node).second);
+  }
+
+  d.clear();
+  s.clear();
+  // Add size() nodes.
+  for (size_t i = 0; i < d.size(); i++) {
+    uptr node = d.newNode(0);
+    EXPECT_TRUE(s.insert(node).second);
+  }
+  // Remove all nodes.
+  for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it)
+    d.removeNode(*it);
+  // The nodes should be reused.
+  for (size_t i = 0; i < d.size(); i++) {
+    uptr node = d.newNode(0);
+    EXPECT_FALSE(s.insert(node).second);
+  }
+
+  // Cycle: n1->n2->n1
+  {
+    d.clear();
+    dtls.clear();
+    uptr n1 = d.newNode(1);
+    uptr n2 = d.newNode(2);
+    EXPECT_FALSE(d.onLock(&dtls, n1));
+    EXPECT_FALSE(d.onLock(&dtls, n2));
+    d.onUnlock(&dtls, n2);
+    d.onUnlock(&dtls, n1);
+
+    EXPECT_FALSE(d.onLock(&dtls, n2));
+    EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 1));
+    EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 10));
+    EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 2));
+    EXPECT_TRUE(d.onLock(&dtls, n1));
+    EXPECT_EQ(path[0], n1);
+    EXPECT_EQ(path[1], n2);
+    EXPECT_EQ(d.getData(n1), 1U);
+    EXPECT_EQ(d.getData(n2), 2U);
+    d.onUnlock(&dtls, n1);
+    d.onUnlock(&dtls, n2);
+  }
+
+  // Cycle: n1->n2->n3->n1
+  {
+    d.clear();
+    dtls.clear();
+    uptr n1 = d.newNode(1);
+    uptr n2 = d.newNode(2);
+    uptr n3 = d.newNode(3);
+
+    EXPECT_FALSE(d.onLock(&dtls, n1));
+    EXPECT_FALSE(d.onLock(&dtls, n2));
+    d.onUnlock(&dtls, n2);
+    d.onUnlock(&dtls, n1);
+
+    EXPECT_FALSE(d.onLock(&dtls, n2));
+    EXPECT_FALSE(d.onLock(&dtls, n3));
+    d.onUnlock(&dtls, n3);
+    d.onUnlock(&dtls, n2);
+
+    EXPECT_FALSE(d.onLock(&dtls, n3));
+    EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 2));
+    EXPECT_EQ(3U, d.findPathToLock(&dtls, n1, path, 10));
+    EXPECT_TRUE(d.onLock(&dtls, n1));
+    EXPECT_EQ(path[0], n1);
+    EXPECT_EQ(path[1], n2);
+    EXPECT_EQ(path[2], n3);
+    EXPECT_EQ(d.getData(n1), 1U);
+    EXPECT_EQ(d.getData(n2), 2U);
+    EXPECT_EQ(d.getData(n3), 3U);
+    d.onUnlock(&dtls, n1);
+    d.onUnlock(&dtls, n3);
+  }
+}
+
+TEST(DeadlockDetector, BasicTest) {
+  RunBasicTest<BV1>();
+  RunBasicTest<BV2>();
+  RunBasicTest<BV3>();
+  RunBasicTest<BV4>();
+}
+
+template <class BV>
+void RunRemoveNodeTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(1);
+  uptr l2 = d.newNode(2);
+  uptr l3 = d.newNode(3);
+  uptr l4 = d.newNode(4);
+  uptr l5 = d.newNode(5);
+
+  // l0=>l1=>l2
+  d.onLock(&dtls, l0);
+  d.onLock(&dtls, l1);
+  d.onLock(&dtls, l2);
+  d.onUnlock(&dtls, l1);
+  d.onUnlock(&dtls, l0);
+  d.onUnlock(&dtls, l2);
+  // l3=>l4=>l5
+  d.onLock(&dtls, l3);
+  d.onLock(&dtls, l4);
+  d.onLock(&dtls, l5);
+  d.onUnlock(&dtls, l4);
+  d.onUnlock(&dtls, l3);
+  d.onUnlock(&dtls, l5);
+
+  set<uptr> locks;
+  locks.insert(l0);
+  locks.insert(l1);
+  locks.insert(l2);
+  locks.insert(l3);
+  locks.insert(l4);
+  locks.insert(l5);
+  for (uptr i = 6; i < d.size(); i++) {
+    uptr lt = d.newNode(i);
+    locks.insert(lt);
+    d.onLock(&dtls, lt);
+    d.onUnlock(&dtls, lt);
+    d.removeNode(lt);
+  }
+  EXPECT_EQ(locks.size(), d.size());
+  // l2=>l0
+  EXPECT_FALSE(d.onLock(&dtls, l2));
+  EXPECT_TRUE(d.onLock(&dtls, l0));
+  d.onUnlock(&dtls, l2);
+  d.onUnlock(&dtls, l0);
+  // l4=>l3
+  EXPECT_FALSE(d.onLock(&dtls, l4));
+  EXPECT_TRUE(d.onLock(&dtls, l3));
+  d.onUnlock(&dtls, l4);
+  d.onUnlock(&dtls, l3);
+
+  EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+
+  d.removeNode(l2);
+  d.removeNode(l3);
+  locks.clear();
+  // make sure no edges from or to l0,l1,l4,l5 left.
+  for (uptr i = 4; i < d.size(); i++) {
+    uptr lt = d.newNode(i);
+    locks.insert(lt);
+    uptr a, b;
+    // l0 => lt?
+    a = l0; b = lt;
+    EXPECT_FALSE(d.onLock(&dtls, a));
+    EXPECT_FALSE(d.onLock(&dtls, b));
+    d.onUnlock(&dtls, a);
+    d.onUnlock(&dtls, b);
+    // l1 => lt?
+    a = l1; b = lt;
+    EXPECT_FALSE(d.onLock(&dtls, a));
+    EXPECT_FALSE(d.onLock(&dtls, b));
+    d.onUnlock(&dtls, a);
+    d.onUnlock(&dtls, b);
+    // lt => l4?
+    a = lt; b = l4;
+    EXPECT_FALSE(d.onLock(&dtls, a));
+    EXPECT_FALSE(d.onLock(&dtls, b));
+    d.onUnlock(&dtls, a);
+    d.onUnlock(&dtls, b);
+    // lt => l5?
+    a = lt; b = l5;
+    EXPECT_FALSE(d.onLock(&dtls, a));
+    EXPECT_FALSE(d.onLock(&dtls, b));
+    d.onUnlock(&dtls, a);
+    d.onUnlock(&dtls, b);
+
+    d.removeNode(lt);
+  }
+  // Still the same epoch.
+  EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+  EXPECT_EQ(locks.size(), d.size() - 4);
+  // l2 and l3 should have ben reused.
+  EXPECT_EQ(locks.count(l2), 1U);
+  EXPECT_EQ(locks.count(l3), 1U);
+}
+
+TEST(DeadlockDetector, RemoveNodeTest) {
+  RunRemoveNodeTest<BV1>();
+  RunRemoveNodeTest<BV2>();
+  RunRemoveNodeTest<BV3>();
+  RunRemoveNodeTest<BV4>();
+}
+
+template <class BV>
+void RunMultipleEpochsTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  set<uptr> locks;
+  for (uptr i = 0; i < d.size(); i++) {
+    EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+  }
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+  for (uptr i = 0; i < d.size(); i++) {
+    EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+    EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+  }
+  locks.clear();
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  d.onLock(&dtls, l0);
+  d.onLock(&dtls, l1);
+  d.onUnlock(&dtls, l0);
+  EXPECT_EQ(d.testOnlyGetEpoch(), 3 * d.size());
+  for (uptr i = 0; i < d.size(); i++) {
+    EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+  }
+  EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
+
+  // Can not handle the locks from the previous epoch.
+  // The caller should update the lock id.
+  EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
+}
+
+TEST(DeadlockDetector, MultipleEpochsTest) {
+  RunMultipleEpochsTest<BV1>();
+  RunMultipleEpochsTest<BV2>();
+  RunMultipleEpochsTest<BV3>();
+  RunMultipleEpochsTest<BV4>();
+}
+
+template <class BV>
+void RunCorrectEpochFlush() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+  vector<uptr> locks1;
+  for (uptr i = 0; i < d.size(); i++)
+    locks1.push_back(d.newNode(i));
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+  d.onLock(&dtls, locks1[3]);
+  d.onLock(&dtls, locks1[4]);
+  d.onLock(&dtls, locks1[5]);
+
+  // We have a new epoch, old locks in dtls will have to be forgotten.
+  uptr l0 = d.newNode(0);
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+  uptr l1 = d.newNode(0);
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+  d.onLock(&dtls, l0);
+  d.onLock(&dtls, l1);
+  EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
+  EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
+}
+
+TEST(DeadlockDetector, CorrectEpochFlush) {
+  RunCorrectEpochFlush<BV1>();
+  RunCorrectEpochFlush<BV2>();
+}
+
+template <class BV>
+void RunTryLockTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  uptr l2 = d.newNode(0);
+  EXPECT_FALSE(d.onLock(&dtls, l0));
+  EXPECT_FALSE(d.onTryLock(&dtls, l1));
+  EXPECT_FALSE(d.onLock(&dtls, l2));
+  EXPECT_TRUE(d.isHeld(&dtls, l0));
+  EXPECT_TRUE(d.isHeld(&dtls, l1));
+  EXPECT_TRUE(d.isHeld(&dtls, l2));
+  EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
+  EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
+  d.onUnlock(&dtls, l0);
+  d.onUnlock(&dtls, l1);
+  d.onUnlock(&dtls, l2);
+}
+
+TEST(DeadlockDetector, TryLockTest) {
+  RunTryLockTest<BV1>();
+  RunTryLockTest<BV2>();
+}
+
+template <class BV>
+void RunOnFirstLockTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  EXPECT_FALSE(d.onFirstLock(&dtls, l0));  // dtls has old epoch.
+  d.onLock(&dtls, l0);
+  d.onUnlock(&dtls, l0);
+
+  EXPECT_TRUE(d.onFirstLock(&dtls, l0));  // Ok, same ecpoch, first lock.
+  EXPECT_FALSE(d.onFirstLock(&dtls, l1));  // Second lock.
+  d.onLock(&dtls, l1);
+  d.onUnlock(&dtls, l1);
+  d.onUnlock(&dtls, l0);
+
+  EXPECT_TRUE(d.onFirstLock(&dtls, l0));  // Ok
+  d.onUnlock(&dtls, l0);
+
+  vector<uptr> locks1;
+  for (uptr i = 0; i < d.size(); i++)
+    locks1.push_back(d.newNode(i));
+
+  EXPECT_TRUE(d.onFirstLock(&dtls, l0));  // Epoch has changed, but not in dtls.
+
+  uptr l3 = d.newNode(0);
+  d.onLock(&dtls, l3);
+  d.onUnlock(&dtls, l3);
+
+  EXPECT_FALSE(d.onFirstLock(&dtls, l0));  // Epoch has changed in dtls.
+}
+
+TEST(DeadlockDetector, onFirstLockTest) {
+  RunOnFirstLockTest<BV2>();
+}
+
+template <class BV>
+void RunRecusriveLockTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  uptr l2 = d.newNode(0);
+  uptr l3 = d.newNode(0);
+
+  EXPECT_FALSE(d.onLock(&dtls, l0));
+  EXPECT_FALSE(d.onLock(&dtls, l1));
+  EXPECT_FALSE(d.onLock(&dtls, l0));  // Recurisve.
+  EXPECT_FALSE(d.onLock(&dtls, l2));
+  d.onUnlock(&dtls, l0);
+  EXPECT_FALSE(d.onLock(&dtls, l3));
+  d.onUnlock(&dtls, l0);
+  d.onUnlock(&dtls, l1);
+  d.onUnlock(&dtls, l2);
+  d.onUnlock(&dtls, l3);
+  EXPECT_TRUE(d.testOnlyHasEdge(l0, l1));
+  EXPECT_TRUE(d.testOnlyHasEdge(l0, l2));
+  EXPECT_TRUE(d.testOnlyHasEdge(l0, l3));
+}
+
+TEST(DeadlockDetector, RecusriveLockTest) {
+  RunRecusriveLockTest<BV2>();
+}
+
+template <class BV>
+void RunLockContextTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+  uptr l0 = d.newNode(0);
+  uptr l1 = d.newNode(0);
+  uptr l2 = d.newNode(0);
+  uptr l3 = d.newNode(0);
+  uptr l4 = d.newNode(0);
+  EXPECT_FALSE(d.onLock(&dtls, l0, 10));
+  EXPECT_FALSE(d.onLock(&dtls, l1, 11));
+  EXPECT_FALSE(d.onLock(&dtls, l2, 12));
+  EXPECT_FALSE(d.onLock(&dtls, l3, 13));
+  EXPECT_EQ(10U, d.findLockContext(&dtls, l0));
+  EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+  EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+  EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+  d.onUnlock(&dtls, l0);
+  EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+  EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+  EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+  EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+  d.onUnlock(&dtls, l2);
+  EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+  EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+  EXPECT_EQ(0U, d.findLockContext(&dtls, l2));
+  EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+
+  EXPECT_FALSE(d.onLock(&dtls, l4, 14));
+  EXPECT_EQ(14U, d.findLockContext(&dtls, l4));
+}
+
+TEST(DeadlockDetector, LockContextTest) {
+  RunLockContextTest<BV2>();
+}
+
+template <class BV>
+void RunRemoveEdgesTest() {
+  ScopedDD<BV> sdd;
+  DeadlockDetector<BV> &d = *sdd.dp;
+  DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+  vector<uptr> node(BV::kSize);
+  u32 stk_from = 0, stk_to = 0;
+  int unique_tid = 0;
+  for (size_t i = 0; i < BV::kSize; i++)
+    node[i] = d.newNode(0);
+
+  for (size_t i = 0; i < BV::kSize; i++)
+    EXPECT_FALSE(d.onLock(&dtls, node[i], i + 1));
+  for (size_t i = 0; i < BV::kSize; i++) {
+    for (uptr j = i + 1; j < BV::kSize; j++) {
+      EXPECT_TRUE(
+          d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+      EXPECT_EQ(stk_from, i + 1);
+      EXPECT_EQ(stk_to, j + 1);
+    }
+  }
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+  // Remove and re-create half of the nodes.
+  for (uptr i = 1; i < BV::kSize; i += 2)
+    d.removeNode(node[i]);
+  for (uptr i = 1; i < BV::kSize; i += 2)
+    node[i] = d.newNode(0);
+  EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+  // The edges from or to the removed nodes should be gone.
+  for (size_t i = 0; i < BV::kSize; i++) {
+    for (uptr j = i + 1; j < BV::kSize; j++) {
+      if ((i % 2) || (j % 2))
+        EXPECT_FALSE(
+            d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+      else
+        EXPECT_TRUE(
+            d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+    }
+  }
+}
+
+TEST(DeadlockDetector, RemoveEdgesTest) {
+  RunRemoveEdgesTest<BV1>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
index cd3cac1..833816d 100644
--- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -24,14 +24,14 @@
 template <typename T>
 static void TestFlag(T start_value, const char *env, T final_value) {
   T flag = start_value;
-  ParseFlag(env, &flag, kFlagName);
+  ParseFlag(env, &flag, kFlagName, "flag description");
   EXPECT_EQ(final_value, flag);
 }
 
 static void TestStrFlag(const char *start_value, const char *env,
                         const char *final_value) {
   const char *flag = start_value;
-  ParseFlag(env, &flag, kFlagName);
+  ParseFlag(env, &flag, kFlagName, "flag description");
   EXPECT_EQ(0, internal_strcmp(final_value, flag));
 }
 
@@ -70,8 +70,8 @@
                          const char *expected_flag2) {
   bool flag1 = !expected_flag1;
   const char *flag2 = "";
-  ParseFlag(env, &flag1, "flag1");
-  ParseFlag(env, &flag2, "flag2");
+  ParseFlag(env, &flag1, "flag1", "flag1 description");
+  ParseFlag(env, &flag2, "flag2", "flag2 description");
   EXPECT_EQ(expected_flag1, flag1);
   EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
 }
diff --git a/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
new file mode 100644
index 0000000..13918af
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -0,0 +1,259 @@
+//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for *scanf interceptors implementation in sanitizer_common.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <vector>
+
+#include "interception/interception.h"
+#include "sanitizer_test_utils.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "gtest/gtest.h"
+
+using namespace __sanitizer;
+
+#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)                    \
+  do {                                                                         \
+    ((std::vector<unsigned> *)ctx)->push_back(size);                           \
+    ptr = ptr;                                                                 \
+  } while (0)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size)                          \
+  COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                         \
+  COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define SANITIZER_INTERCEPT_PRINTF 1
+#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
+
+static const unsigned I = sizeof(int);
+static const unsigned L = sizeof(long);
+static const unsigned LL = sizeof(long long);
+static const unsigned S = sizeof(short);
+static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
+static const unsigned D = sizeof(double);
+static const unsigned LD = sizeof(long double);
+static const unsigned F = sizeof(float);
+static const unsigned P = sizeof(char *);
+
+static void verifyFormatResults(const char *format, unsigned n,
+                                const std::vector<unsigned> &computed_sizes,
+                                va_list expected_sizes) {
+  // "+ 1" because of format string
+  ASSERT_EQ(n + 1,
+            computed_sizes.size()) << "Unexpected number of format arguments: '"
+                                   << format << "'";
+  for (unsigned i = 0; i < n; ++i)
+    EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1])
+        << "Unexpect write size for argument " << i << ", format string '"
+        << format << "'";
+}
+
+static const char test_buf[] = "Test string.";
+static const size_t test_buf_size = sizeof(test_buf);
+
+static const unsigned SCANF_ARGS_MAX = 16;
+
+static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
+                       const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  scanf_common(ctx, result, allowGnuMalloc, format, ap);
+  va_end(ap);
+}
+
+static void testScanf2(const char *format, int scanf_result,
+                       bool allowGnuMalloc, unsigned n,
+                       va_list expected_sizes) {
+  std::vector<unsigned> scanf_sizes;
+  // 16 args should be enough.
+  testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
+             test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+             test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+             test_buf, test_buf, test_buf, test_buf);
+  verifyFormatResults(format, n, scanf_sizes, expected_sizes);
+}
+
+static void testScanf(const char *format, unsigned n, ...) {
+  va_list ap;
+  va_start(ap, n);
+  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
+  va_end(ap);
+}
+
+static void testScanfPartial(const char *format, int scanf_result, unsigned n,
+                             ...) {
+  va_list ap;
+  va_start(ap, n);
+  testScanf2(format, scanf_result, /* allowGnuMalloc */ true,  n, ap);
+  va_end(ap);
+}
+
+static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
+  va_list ap;
+  va_start(ap, n);
+  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
+  va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Scanf) {
+  testScanf("%d", 1, I);
+  testScanf("%d%d%d", 3, I, I, I);
+  testScanf("ab%u%dc", 2, I, I);
+  testScanf("%ld", 1, L);
+  testScanf("%llu", 1, LL);
+  testScanf("%qd", 1, LL);
+  testScanf("a %hd%hhx", 2, S, C);
+  testScanf("%c", 1, C);
+  testScanf("%lc", 1, LC);
+
+  testScanf("%%", 0);
+  testScanf("a%%", 0);
+  testScanf("a%%b", 0);
+  testScanf("a%%%%b", 0);
+  testScanf("a%%b%%", 0);
+  testScanf("a%%%%%%b", 0);
+  testScanf("a%%%%%b", 0);
+  testScanf("a%%%%%f", 1, F);
+  testScanf("a%%%lxb", 1, L);
+  testScanf("a%lf%%%lxb", 2, D, L);
+  testScanf("%nf", 1, I);
+
+  testScanf("%10s", 1, 11);
+  testScanf("%10c", 1, 10);
+  testScanf("%10ls", 1, 11 * LC);
+  testScanf("%10lc", 1, 10 * LC);
+  testScanf("%%10s", 0);
+  testScanf("%*10s", 0);
+  testScanf("%*d", 0);
+
+  testScanf("%4d%8f%c", 3, I, F, C);
+  testScanf("%s%d", 2, test_buf_size, I);
+  testScanf("%[abc]", 1, test_buf_size);
+  testScanf("%4[bcdef]", 1, 5);
+  testScanf("%[]]", 1, test_buf_size);
+  testScanf("%8[^]%d0-9-]%c", 2, 9, C);
+
+  testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
+
+  testScanf("%*d%u", 1, I);
+
+  testScanf("%c%d", 2, C, I);
+  testScanf("%A%lf", 2, F, D);
+
+  testScanf("%ms %Lf", 2, P, LD);
+  testScanf("s%Las", 1, LD);
+  testScanf("%ar", 1, F);
+
+  // In the cases with std::min below the format spec can be interpreted as
+  // either floating-something, or (GNU extension) callee-allocated string.
+  // Our conservative implementation reports one of the two possibilities with
+  // the least store range.
+  testScanf("%a[", 0);
+  testScanf("%a[]", 0);
+  testScanf("%a[]]", 1, std::min(F, P));
+  testScanf("%a[abc]", 1, std::min(F, P));
+  testScanf("%a[^abc]", 1, std::min(F, P));
+  testScanf("%a[ab%c] %d", 0);
+  testScanf("%a[^ab%c] %d", 0);
+  testScanf("%as", 1, std::min(F, P));
+  testScanf("%aS", 1, std::min(F, P));
+  testScanf("%a13S", 1, std::min(F, P));
+  testScanf("%alS", 1, std::min(F, P));
+
+  testScanfNoGnuMalloc("s%Las", 1, LD);
+  testScanfNoGnuMalloc("%ar", 1, F);
+  testScanfNoGnuMalloc("%a[", 1, F);
+  testScanfNoGnuMalloc("%a[]", 1, F);
+  testScanfNoGnuMalloc("%a[]]", 1, F);
+  testScanfNoGnuMalloc("%a[abc]", 1, F);
+  testScanfNoGnuMalloc("%a[^abc]", 1, F);
+  testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
+  testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
+  testScanfNoGnuMalloc("%as", 1, F);
+  testScanfNoGnuMalloc("%aS", 1, F);
+  testScanfNoGnuMalloc("%a13S", 1, F);
+  testScanfNoGnuMalloc("%alS", 1, F);
+
+  testScanf("%5$d", 0);
+  testScanf("%md", 0);
+  testScanf("%m10s", 0);
+
+  testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
+  testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
+  testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
+  testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
+
+  testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
+  testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
+
+  testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
+  testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
+                   test_buf_size);
+}
+
+static void testPrintf3(void *ctx, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  printf_common(ctx, format, ap);
+  va_end(ap);
+}
+
+static void testPrintf2(const char *format, unsigned n,
+                       va_list expected_sizes) {
+  std::vector<unsigned> printf_sizes;
+  // 16 args should be enough.
+  testPrintf3((void *)&printf_sizes, format,
+             test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+             test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+             test_buf, test_buf, test_buf, test_buf);
+  verifyFormatResults(format, n, printf_sizes, expected_sizes);
+}
+
+static void testPrintf(const char *format, unsigned n, ...) {
+  va_list ap;
+  va_start(ap, n);
+  testPrintf2(format, n, ap);
+  va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Printf) {
+  // Only test functionality which differs from scanf
+
+  // Indexed arguments
+  testPrintf("%5$d", 0);
+  testPrintf("%.*5$d", 0);
+
+  // errno
+  testPrintf("%0-m", 0);
+
+  // Dynamic width
+  testPrintf("%*n", 1, I);
+  testPrintf("%*.10n", 1, I);
+
+  // Precision
+  testPrintf("%10.10n", 1, I);
+  testPrintf("%.3s", 1, 3);
+  testPrintf("%.20s", 1, test_buf_size);
+
+  // Dynamic precision
+  testPrintf("%.*n", 1, I);
+  testPrintf("%10.*n", 1, I);
+
+  // Dynamic precision for strings is not implemented yet.
+  testPrintf("%.*s", 1, 0);
+
+  // Checks for wide-character strings are not implemented yet.
+  testPrintf("%ls", 1, 0);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
index 154d986..4a32af5 100644
--- a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -47,6 +47,7 @@
     // Avoid unused function warnings.
     (void)&ioctl_common_pre;
     (void)&ioctl_common_post;
+    (void)&ioctl_decode;
   }
 } ioctl_static_initializer;
 
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index c4f3d80..660710d 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -55,6 +55,8 @@
   unsigned char z;
 };
 
+// FIXME: File manipulations are not yet supported on Windows
+#if !defined(_WIN32)
 TEST(SanitizerCommon, FileOps) {
   const char *str1 = "qwerty";
   uptr len1 = internal_strlen(str1);
@@ -114,6 +116,7 @@
   EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
   internal_close(fd);
 }
+#endif
 
 TEST(SanitizerCommon, InternalStrFunctions) {
   const char *haystack = "haystack";
diff --git a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
index 06f742b..d14e7c2 100644
--- a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
@@ -12,6 +12,9 @@
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_mutex.h"
 #include "sanitizer_common/sanitizer_common.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
 #include "gtest/gtest.h"
 
 #include <string.h>
@@ -103,9 +106,9 @@
   TestData<SpinMutex> data(&mtx);
   pthread_t threads[kThreads];
   for (int i = 0; i < kThreads; i++)
-    pthread_create(&threads[i], 0, lock_thread<SpinMutex>, &data);
+    PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
   for (int i = 0; i < kThreads; i++)
-    pthread_join(threads[i], 0);
+    PTHREAD_JOIN(threads[i], 0);
 }
 
 TEST(SanitizerCommon, SpinMutexTry) {
@@ -114,9 +117,9 @@
   TestData<SpinMutex> data(&mtx);
   pthread_t threads[kThreads];
   for (int i = 0; i < kThreads; i++)
-    pthread_create(&threads[i], 0, try_thread<SpinMutex>, &data);
+    PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
   for (int i = 0; i < kThreads; i++)
-    pthread_join(threads[i], 0);
+    PTHREAD_JOIN(threads[i], 0);
 }
 
 TEST(SanitizerCommon, BlockingMutex) {
@@ -125,9 +128,9 @@
   TestData<BlockingMutex> data(mtx);
   pthread_t threads[kThreads];
   for (int i = 0; i < kThreads; i++)
-    pthread_create(&threads[i], 0, lock_thread<BlockingMutex>, &data);
+    PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
   for (int i = 0; i < kThreads; i++)
-    pthread_join(threads[i], 0);
+    PTHREAD_JOIN(threads[i], 0);
   check_locked(mtx);
 }
 
diff --git a/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
index 2c478cc..d0b46ac 100644
--- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -103,6 +103,11 @@
   EXPECT_EQ(buf[9], 0);
 }
 
+#if defined(_WIN32)
+// Oh well, MSVS headers don't define snprintf.
+# define snprintf _snprintf
+#endif
+
 template<typename T>
 static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
   char buf[1024];
@@ -115,12 +120,14 @@
 
 TEST(Printf, MinMax) {
   TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
-  TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
   TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
-  TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
   TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
+#if !defined(_WIN32)
+  // %z* format doesn't seem to be supported by MSVS.
+  TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
+  TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
   TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX);  // NOLINT
-  Report("%zd\n", LONG_MIN);
+#endif
 }
 
 TEST(Printf, Padding) {
@@ -136,4 +143,14 @@
   TestAgainstLibc<int>("%03d - %03d", -12, -1234);
 }
 
+TEST(Printf, Precision) {
+  char buf[1024];
+  uptr len = internal_snprintf(buf, sizeof(buf), "%.*s", 3, "12345");
+  EXPECT_EQ(3U, len);
+  EXPECT_STREQ("123", buf);
+  len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");
+  EXPECT_EQ(5U, len);
+  EXPECT_STREQ("12345", buf);
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
index d16e2ee..495b726 100644
--- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -10,21 +10,48 @@
 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
 //
 //===----------------------------------------------------------------------===//
+#if !defined(_WIN32)  // There are no /proc/maps on Windows.
+
 #include "sanitizer_common/sanitizer_procmaps.h"
-//#include "sanitizer_common/sanitizer_internal_defs.h"
-//#include "sanitizer_common/sanitizer_libc.h"
 #include "gtest/gtest.h"
 
+#include <stdlib.h>
+
+static void noop() {}
+extern const char *argv0;
+
 namespace __sanitizer {
 
-#ifdef SANITIZER_LINUX
-TEST(ProcMaps, CodeRange) {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(MemoryMappingLayout, CodeRange) {
   uptr start, end;
   bool res = GetCodeRangeForFile("[vdso]", &start, &end);
   EXPECT_EQ(res, true);
-  EXPECT_GT(start, (uptr)0);
+  EXPECT_GT(start, 0U);
   EXPECT_LT(start, end);
 }
 #endif
 
+TEST(MemoryMappingLayout, DumpListOfModules) {
+  const char *last_slash = strrchr(argv0, '/');
+  const char *binary_name = last_slash ? last_slash + 1 : argv0;
+  MemoryMappingLayout memory_mapping(false);
+  const uptr kMaxModules = 100;
+  LoadedModule *modules =
+      (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+  uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
+  EXPECT_GT(n_modules, 0U);
+  bool found = false;
+  for (uptr i = 0; i < n_modules; ++i) {
+    if (modules[i].containsAddress((uptr)&noop)) {
+      // Verify that the module name is sane.
+      if (strstr(modules[i].full_name(), binary_name) != 0)
+        found = true;
+    }
+  }
+  EXPECT_TRUE(found);
+  free(modules);
+}
+
 }  // namespace __sanitizer
+#endif  // !defined(_WIN32)
diff --git a/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
new file mode 100644
index 0000000..47b0f97
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
@@ -0,0 +1,66 @@
+//===-- sanitizer_pthread_wrappers.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 a part of *Sanitizer runtime.
+// It provides handy wrappers for thread manipulation, that:
+//  a) assert on any failure rather than returning an error code
+//  b) defines pthread-like interface on platforms where where <pthread.h>
+//     is not supplied by default.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTHREAD_WRAPPERS_H
+#define SANITIZER_PTHREAD_WRAPPERS_H
+
+#include "sanitizer_test_utils.h"
+
+#if !defined(_WIN32)
+# include <pthread.h>
+// Simply forward the arguments and check that the pthread functions succeed.
+# define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
+# define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
+#else
+typedef HANDLE pthread_t;
+
+struct PthreadHelperCreateThreadInfo {
+  void *(*start_routine)(void *);
+  void *arg;
+};
+
+inline DWORD WINAPI PthreadHelperThreadProc(void *arg) {
+  PthreadHelperCreateThreadInfo *start_data =
+      reinterpret_cast<PthreadHelperCreateThreadInfo*>(arg);
+  void *ret = (start_data->start_routine)(start_data->arg);
+  delete start_data;
+  return (DWORD)ret;
+}
+
+inline void PTHREAD_CREATE(pthread_t *thread, void *attr,
+                           void *(*start_routine)(void *), void *arg) {
+  ASSERT_EQ(0, attr) << "Thread attributes are not supported yet.";
+  PthreadHelperCreateThreadInfo *data = new PthreadHelperCreateThreadInfo;
+  data->start_routine = start_routine;
+  data->arg = arg;
+  *thread = CreateThread(0, 0, PthreadHelperThreadProc, data, 0, 0);
+  ASSERT_NE(nullptr, *thread) << "Failed to create a thread.";
+}
+
+inline void PTHREAD_JOIN(pthread_t thread, void **value_ptr) {
+  ASSERT_EQ(0, value_ptr) << "Nonzero value_ptr is not supported yet.";
+  ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+  ASSERT_NE(0, CloseHandle(thread));
+}
+
+inline void pthread_exit(void *retval) {
+  ASSERT_EQ(0, retval) << "Nonzero retval is not supported yet.";
+  ExitThread((DWORD)retval);
+}
+#endif  // _WIN32
+
+#endif  // SANITIZER_PTHREAD_WRAPPERS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
deleted file mode 100644
index e035406..0000000
--- a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-//===-- sanitizer_scanf_interceptor_test.cc -------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Tests for *scanf interceptors implementation in sanitizer_common.
-//
-//===----------------------------------------------------------------------===//
-#include <vector>
-
-#include "interception/interception.h"
-#include "sanitizer_test_utils.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "gtest/gtest.h"
-
-using namespace __sanitizer;
-
-#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size)                         \
-  ((std::vector<unsigned> *)ctx)->push_back(size)
-
-#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
-
-static const char scanf_buf[] = "Test string.";
-static size_t scanf_buf_size = sizeof(scanf_buf);
-static const unsigned SCANF_ARGS_MAX = 16;
-
-static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
-                       const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  scanf_common(ctx, result, allowGnuMalloc, format, ap);
-  va_end(ap);
-}
-
-static void testScanf2(const char *format, int scanf_result,
-                       bool allowGnuMalloc, unsigned n,
-                       va_list expected_sizes) {
-  std::vector<unsigned> scanf_sizes;
-  // 16 args should be enough.
-  testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
-             scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
-             scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
-             scanf_buf, scanf_buf, scanf_buf, scanf_buf);
-  ASSERT_EQ(n, scanf_sizes.size()) << "Unexpected number of format arguments: '"
-                                   << format << "'";
-  for (unsigned i = 0; i < n; ++i)
-    EXPECT_EQ(va_arg(expected_sizes, unsigned), scanf_sizes[i])
-        << "Unexpect write size for argument " << i << ", format string '"
-        << format << "'";
-}
-
-static void testScanf(const char *format, unsigned n, ...) {
-  va_list ap;
-  va_start(ap, n);
-  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
-  va_end(ap);
-}
-
-static void testScanfPartial(const char *format, int scanf_result, unsigned n,
-                             ...) {
-  va_list ap;
-  va_start(ap, n);
-  testScanf2(format, scanf_result, /* allowGnuMalloc */ true,  n, ap);
-  va_end(ap);
-}
-
-static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
-  va_list ap;
-  va_start(ap, n);
-  testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
-  va_end(ap);
-}
-
-TEST(SanitizerCommonInterceptors, Scanf) {
-  const unsigned I = sizeof(int);          // NOLINT
-  const unsigned L = sizeof(long);         // NOLINT
-  const unsigned LL = sizeof(long long);   // NOLINT
-  const unsigned S = sizeof(short);        // NOLINT
-  const unsigned C = sizeof(char);         // NOLINT
-  const unsigned D = sizeof(double);       // NOLINT
-  const unsigned LD = sizeof(long double); // NOLINT
-  const unsigned F = sizeof(float);        // NOLINT
-  const unsigned P = sizeof(char *);       // NOLINT
-
-  testScanf("%d", 1, I);
-  testScanf("%d%d%d", 3, I, I, I);
-  testScanf("ab%u%dc", 2, I, I);
-  testScanf("%ld", 1, L);
-  testScanf("%llu", 1, LL);
-  testScanf("a %hd%hhx", 2, S, C);
-  testScanf("%c", 1, C);
-
-  testScanf("%%", 0);
-  testScanf("a%%", 0);
-  testScanf("a%%b", 0);
-  testScanf("a%%%%b", 0);
-  testScanf("a%%b%%", 0);
-  testScanf("a%%%%%%b", 0);
-  testScanf("a%%%%%b", 0);
-  testScanf("a%%%%%f", 1, F);
-  testScanf("a%%%lxb", 1, L);
-  testScanf("a%lf%%%lxb", 2, D, L);
-  testScanf("%nf", 1, I);
-
-  testScanf("%10s", 1, 11);
-  testScanf("%10c", 1, 10);
-  testScanf("%%10s", 0);
-  testScanf("%*10s", 0);
-  testScanf("%*d", 0);
-
-  testScanf("%4d%8f%c", 3, I, F, C);
-  testScanf("%s%d", 2, scanf_buf_size, I);
-  testScanf("%[abc]", 1, scanf_buf_size);
-  testScanf("%4[bcdef]", 1, 5);
-  testScanf("%[]]", 1, scanf_buf_size);
-  testScanf("%8[^]%d0-9-]%c", 2, 9, C);
-
-  testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
-
-  testScanf("%*d%u", 1, I);
-
-  testScanf("%c%d", 2, C, I);
-  testScanf("%A%lf", 2, F, D);
-
-  testScanf("%ms %Lf", 2, P, LD);
-  testScanf("s%Las", 1, LD);
-  testScanf("%ar", 1, F);
-
-  // In the cases with std::min below the format spec can be interpreted as
-  // either floating-something, or (GNU extension) callee-allocated string.
-  // Our conservative implementation reports one of the two possibilities with
-  // the least store range.
-  testScanf("%a[", 0);
-  testScanf("%a[]", 0);
-  testScanf("%a[]]", 1, std::min(F, P));
-  testScanf("%a[abc]", 1, std::min(F, P));
-  testScanf("%a[^abc]", 1, std::min(F, P));
-  testScanf("%a[ab%c] %d", 0);
-  testScanf("%a[^ab%c] %d", 0);
-  testScanf("%as", 1, std::min(F, P));
-  testScanf("%aS", 1, std::min(F, P));
-  testScanf("%a13S", 1, std::min(F, P));
-  testScanf("%alS", 1, std::min(F, P));
-
-  testScanfNoGnuMalloc("s%Las", 1, LD);
-  testScanfNoGnuMalloc("%ar", 1, F);
-  testScanfNoGnuMalloc("%a[", 1, F);
-  testScanfNoGnuMalloc("%a[]", 1, F);
-  testScanfNoGnuMalloc("%a[]]", 1, F);
-  testScanfNoGnuMalloc("%a[abc]", 1, F);
-  testScanfNoGnuMalloc("%a[^abc]", 1, F);
-  testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
-  testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
-  testScanfNoGnuMalloc("%as", 1, F);
-  testScanfNoGnuMalloc("%aS", 1, F);
-  testScanfNoGnuMalloc("%a13S", 1, F);
-  testScanfNoGnuMalloc("%alS", 1, F);
-
-  testScanf("%5$d", 0);
-  testScanf("%md", 0);
-  testScanf("%m10s", 0);
-
-  testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
-  testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
-  testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
-  testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
-
-  testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
-  testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
-
-  testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, scanf_buf_size);
-  testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, scanf_buf_size,
-                   scanf_buf_size);
-}
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index 2b842cd..b71044a 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -23,7 +23,7 @@
   bool TryFastUnwind(uptr max_depth) {
     if (!StackTrace::WillUseFastUnwind(true))
       return false;
-    trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], fake_top,
+    trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
                  fake_bottom, true);
     return true;
   }
@@ -102,4 +102,26 @@
   EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
 }
 
+TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
+  if (!TryFastUnwind(0))
+    return;
+  EXPECT_EQ(0U, trace.size);
+  EXPECT_EQ(0U, trace.top_frame_bp);
+}
+
+TEST(SlowUnwindTest, ShortStackTrace) {
+  if (StackTrace::WillUseFastUnwind(false))
+    return;
+  StackTrace stack;
+  uptr pc = StackTrace::GetCurrentPc();
+  uptr bp = GET_CURRENT_FRAME();
+  stack.Unwind(0, pc, bp, 0, 0, 0, false);
+  EXPECT_EQ(0U, stack.size);
+  EXPECT_EQ(0U, stack.top_frame_bp);
+  stack.Unwind(1, pc, bp, 0, 0, 0, false);
+  EXPECT_EQ(1U, stack.size);
+  EXPECT_EQ(pc, stack.trace[0]);
+  EXPECT_EQ(bp, stack.top_frame_bp);
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index ea8741d..93fc8a3 100644
--- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -67,8 +67,10 @@
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
   CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
       "called_from_lib"));
+  CHECK(
+      !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
   // Ensure this test is up-to-date when suppression types are added.
-  CHECK_EQ(SuppressionTypeCount, 7);
+  CHECK_EQ(SuppressionTypeCount, 8);
 }
 
 class SuppressionContextTest : public ::testing::Test {
diff --git a/lib/sanitizer_common/tests/sanitizer_test_config.h b/lib/sanitizer_common/tests/sanitizer_test_config.h
new file mode 100644
index 0000000..bdf6146
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_test_config.h
@@ -0,0 +1,30 @@
+//===-- sanitizer_test_config.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 a part of *Sanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_SANITIZER_TEST_UTILS_H)
+# error "This file should be included into sanitizer_test_utils.h only"
+#endif
+
+#ifndef SANITIZER_TEST_CONFIG_H
+#define SANITIZER_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#if SANITIZER_USE_DEJAGNU_GTEST
+# include "dejagnu-gtest.h"
+#else
+# include "gtest/gtest.h"
+#endif
+
+#endif  // SANITIZER_TEST_CONFIG_H
diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h
index 17adb26..37105ac 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_utils.h
+++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h
@@ -16,21 +16,34 @@
 #define SANITIZER_TEST_UTILS_H
 
 #if defined(_WIN32)
-typedef unsigned __int8  uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef __int8           int8_t;
-typedef __int16          int16_t;
-typedef __int32          int32_t;
-typedef __int64          int64_t;
-# define NOINLINE __declspec(noinline)
-# define USED
-#else  // defined(_WIN32)
-# define NOINLINE __attribute__((noinline))
-# define USED __attribute__((used))
+// <windows.h> should always be the first include on Windows.
+# include <windows.h>
+// MSVS headers define max/min as macros, so std::max/min gets crazy.
+# undef max
+# undef min
+#endif
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+# include "sanitizer_test_config.h"
+# undef INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+#endif
+
 #include <stdint.h>
-#endif  // defined(_WIN32)
+
+#if defined(_MSC_VER)
+# define NOINLINE __declspec(noinline)
+#else  // defined(_MSC_VER)
+# define NOINLINE __attribute__((noinline))
+#endif  // defined(_MSC_VER)
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
+# define USED __attribute__((used))
+#else
+# define UNUSED
+# define USED
+#endif
 
 #if !defined(__has_feature)
 #define __has_feature(x) 0
@@ -53,7 +66,9 @@
 
 // Make the compiler thinks that something is going on there.
 inline void break_optimization(void *arg) {
+#if !defined(_WIN32) || defined(__clang__)
   __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
 }
 
 // This function returns its parameter but in such a way that compiler
@@ -78,5 +93,28 @@
   return my_rand_r(&global_seed);
 }
 
+// Set availability of platform-specific functions.
+
+#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 1
+#else
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_MEMALIGN 1
+# define SANITIZER_TEST_HAS_PVALLOC 1
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1
+#else
+# define SANITIZER_TEST_HAS_MEMALIGN 0
+# define SANITIZER_TEST_HAS_PVALLOC 0
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0
+#endif
+
+#if !defined(__APPLE__)
+# define SANITIZER_TEST_HAS_STRNLEN 1
+#else
+# define SANITIZER_TEST_HAS_STRNLEN 0
+#endif
 
 #endif  // SANITIZER_TEST_UTILS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index ddc8dba..b6a60d5 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -11,6 +11,9 @@
 //
 //===----------------------------------------------------------------------===//
 #include "sanitizer_common/sanitizer_thread_registry.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
 #include "gtest/gtest.h"
 
 #include <vector>
@@ -48,7 +51,7 @@
 
 static bool HasName(ThreadContextBase *tctx, void *arg) {
   char *name = (char*)arg;
-  return (tctx->name && 0 == internal_strcmp(tctx->name, name));
+  return (0 == internal_strcmp(tctx->name, name));
 }
 
 static bool HasUid(ThreadContextBase *tctx, void *arg) {
@@ -203,10 +206,10 @@
   for (int i = 0; i < kNumShards; i++) {
     args[i].registry = registry;
     args[i].shard = i + 1;
-    pthread_create(&threads[i], 0, RunThread, &args[i]);
+    PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
   }
   for (int i = 0; i < kNumShards; i++) {
-    pthread_join(threads[i], 0);
+    PTHREAD_JOIN(threads[i], 0);
   }
   // Check that each thread created/started/joined correct amount
   // of "threads" in thread_registry.