Index: lib/asan/CMakeLists.txt
===================================================================
--- lib/asan/CMakeLists.txt
+++ lib/asan/CMakeLists.txt
@@ -126,6 +126,7 @@
                 RTSanitizerCommon
                 RTSanitizerCommonLibc
                 RTSanitizerCommonCoverage
+                RTSanitizerCommonSymbolizer
                 RTLSanCommon
                 RTUbsan
     CFLAGS ${ASAN_DYNAMIC_CFLAGS}
@@ -140,6 +141,7 @@
     RTSanitizerCommon
     RTSanitizerCommonLibc
     RTSanitizerCommonCoverage
+    RTSanitizerCommonSymbolizer
     RTLSanCommon
     RTUbsan)
 
Index: lib/msan/CMakeLists.txt
===================================================================
--- lib/msan/CMakeLists.txt
+++ lib/msan/CMakeLists.txt
@@ -41,6 +41,7 @@
             $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
             $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
+            $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
             $<TARGET_OBJECTS:RTUbsan.${arch}>
     CFLAGS ${MSAN_RTL_CFLAGS}
     PARENT_TARGET msan)
Index: lib/sanitizer_common/CMakeLists.txt
===================================================================
--- lib/sanitizer_common/CMakeLists.txt
+++ lib/sanitizer_common/CMakeLists.txt
@@ -31,16 +31,8 @@
   sanitizer_procmaps_mac.cc
   sanitizer_procmaps_solaris.cc
   sanitizer_solaris.cc
-  sanitizer_stackdepot.cc
-  sanitizer_stacktrace.cc
-  sanitizer_stacktrace_printer.cc
   sanitizer_stoptheworld_mac.cc
   sanitizer_suppressions.cc
-  sanitizer_symbolizer.cc
-  sanitizer_symbolizer_fuchsia.cc
-  sanitizer_symbolizer_libbacktrace.cc
-  sanitizer_symbolizer_mac.cc
-  sanitizer_symbolizer_win.cc
   sanitizer_tls_get_addr.cc
   sanitizer_thread_registry.cc
   sanitizer_win.cc)
@@ -67,11 +59,7 @@
   sanitizer_linux_libcdep.cc
   sanitizer_mac_libcdep.cc
   sanitizer_posix_libcdep.cc
-  sanitizer_stacktrace_libcdep.cc
-  sanitizer_stoptheworld_linux_libcdep.cc
-  sanitizer_symbolizer_libcdep.cc
-  sanitizer_symbolizer_posix_libcdep.cc
-  sanitizer_unwind_linux_libcdep.cc)
+  sanitizer_stoptheworld_linux_libcdep.cc)
 
 set(SANITIZER_COVERAGE_SOURCES
   sancov_flags.cc
@@ -79,6 +67,21 @@
   sanitizer_coverage_libcdep_new.cc
   sanitizer_coverage_win_sections.cc)
 
+set(SANITIZER_SYMBOLIZER_SOURCES
+  sanitizer_stackdepot.cc
+  sanitizer_stacktrace.cc
+  sanitizer_stacktrace_libcdep.cc
+  sanitizer_stacktrace_printer.cc
+  sanitizer_symbolizer.cc
+  sanitizer_symbolizer_fuchsia.cc
+  sanitizer_symbolizer_libbacktrace.cc
+  sanitizer_symbolizer_libcdep.cc
+  sanitizer_symbolizer_mac.cc
+  sanitizer_symbolizer_posix_libcdep.cc
+  sanitizer_symbolizer_report.cc
+  sanitizer_symbolizer_win.cc
+  sanitizer_unwind_linux_libcdep.cc)
+
 # Explicitly list all sanitizer_common headers. Not all of these are
 # included in sanitizer_common source files, but we need to depend on
 # headers when building our custom unit tests.
@@ -216,6 +219,12 @@
   SOURCES ${SANITIZER_COVERAGE_SOURCES}
   CFLAGS ${SANITIZER_CFLAGS}
   DEFS ${SANITIZER_COMMON_DEFINITIONS})
+add_compiler_rt_object_libraries(RTSanitizerCommonSymbolizer
+  ${OS_OPTION}
+  ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
+  SOURCES ${SANITIZER_SYMBOLIZER_SOURCES}
+  CFLAGS ${SANITIZER_CFLAGS}
+  DEFS ${SANITIZER_COMMON_DEFINITIONS})
 
 set(SANITIZER_NO_WEAK_HOOKS_CFLAGS ${SANITIZER_CFLAGS})
 list(APPEND SANITIZER_NO_WEAK_HOOKS_CFLAGS "-DSANITIZER_SUPPORTS_WEAK_HOOKS=0")
Index: lib/sanitizer_common/sanitizer_common.h
===================================================================
--- lib/sanitizer_common/sanitizer_common.h
+++ lib/sanitizer_common/sanitizer_common.h
@@ -281,7 +281,7 @@
 bool AddressSpaceIsUnlimited();
 void SetAddressSpaceUnlimited();
 void AdjustStackSize(void *attr);
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
+void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
 void SetSandboxingCallback(void (*f)());
 
 void InitializeCoverage(bool enabled, const char *coverage_dir);
Index: lib/sanitizer_common/sanitizer_common.cc
===================================================================
--- lib/sanitizer_common/sanitizer_common.cc
+++ lib/sanitizer_common/sanitizer_common.cc
@@ -17,8 +17,6 @@
 #include "sanitizer_flags.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_placement_new.h"
-#include "sanitizer_stacktrace_printer.h"
-#include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
@@ -98,27 +96,6 @@
   return module;
 }
 
-void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
-  if (!common_flags()->print_summary)
-    return;
-  InternalScopedString buff(kMaxSummaryLength);
-  buff.append("SUMMARY: %s: %s",
-              alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
-  __sanitizer_report_error_summary(buff.data());
-}
-
-#if !SANITIZER_GO
-void ReportErrorSummary(const char *error_type, const AddressInfo &info,
-                        const char *alt_tool_name) {
-  if (!common_flags()->print_summary) return;
-  InternalScopedString buff(kMaxSummaryLength);
-  buff.append("%s ", error_type);
-  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
-              common_flags()->strip_path_prefix);
-  ReportErrorSummary(buff.data(), alt_tool_name);
-}
-#endif
-
 // Removes the ANSI escape sequences from the input string (in-place).
 void RemoveANSIEscapeSequencesFromString(char *str) {
   if (!str)
Index: lib/sanitizer_common/sanitizer_common_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -14,111 +14,29 @@
 #include "sanitizer_common.h"
 
 #include "sanitizer_allocator_interface.h"
-#include "sanitizer_file.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_report_decorator.h"
-#include "sanitizer_stackdepot.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
-
-#if SANITIZER_POSIX
-#include "sanitizer_posix.h"
-#include <sys/mman.h>
-#endif
 
 namespace __sanitizer {
 
-#if !SANITIZER_FUCHSIA
-
-bool ReportFile::SupportsColors() {
-  SpinMutexLock l(mu);
-  ReopenIfNecessary();
-  return SupportsColoredOutput(fd);
-}
-
-static INLINE bool ReportSupportsColors() {
-  return report_file.SupportsColors();
-}
-
-#else  // SANITIZER_FUCHSIA
-
-// Fuchsia's logs always go through post-processing that handles colorization.
-static INLINE bool ReportSupportsColors() { return true; }
-
-#endif  // !SANITIZER_FUCHSIA
-
-bool ColorizeReports() {
-  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
-  // printing on Windows.
-  if (SANITIZER_WINDOWS)
-    return false;
-
-  const char *flag = common_flags()->color;
-  return internal_strcmp(flag, "always") == 0 ||
-         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
-}
-
 static void (*sandboxing_callback)();
 void SetSandboxingCallback(void (*f)()) {
   sandboxing_callback = f;
 }
 
-void ReportErrorSummary(const char *error_type, const StackTrace *stack,
-                        const char *alt_tool_name) {
-#if !SANITIZER_GO
-  if (!common_flags()->print_summary)
-    return;
-  if (stack->size == 0) {
-    ReportErrorSummary(error_type);
-    return;
-  }
-  // Currently, we include the first stack frame into the report summary.
-  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
-  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
-  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
-  ReportErrorSummary(error_type, frame->info, alt_tool_name);
-  frame->ClearAll();
-#endif
-}
-
-void ReportMmapWriteExec(int prot) {
-#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID)
-  if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC))
-    return;
-
-  ScopedErrorReportLock l;
-  SanitizerCommonDecorator d;
-
-  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
-  BufferedStackTrace *stack = stack_buffer.data();
-  stack->Reset();
-  uptr top = 0;
-  uptr bottom = 0;
-  GET_CALLER_PC_BP_SP;
-  (void)sp;
-  bool fast = common_flags()->fast_unwind_on_fatal;
-  if (fast)
-    GetThreadStackTopAndBottom(false, &top, &bottom);
-  stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast);
-
-  Printf("%s", d.Warning());
-  Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName);
-  Printf("%s", d.Default());
-
-  stack->Print();
-  ReportErrorSummary("w-and-x-usage", stack);
-#endif
-}
-
 static void (*SoftRssLimitExceededCallback)(bool exceeded);
 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
   CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
   SoftRssLimitExceededCallback = Callback;
 }
 
+// Weak default implementation for StackDepotGetStats.
+SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
+  return nullptr;
+}
+
 #if SANITIZER_LINUX && !SANITIZER_GO
-void BackgroundThread(void *arg) {
+static void BackgroundThread(void *arg) {
   uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
   uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
   bool heap_profile = common_flags()->heap_profile;
@@ -136,14 +54,15 @@
         prev_reported_rss = current_rss_mb;
       }
       // If stack depot has grown 10% since last time, print it too.
-      StackDepotStats *stack_depot_stats = StackDepotGetStats();
-      if (prev_reported_stack_depot_size * 11 / 10 <
-          stack_depot_stats->allocated) {
-        Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
-               SanitizerToolName,
-               stack_depot_stats->n_uniq_ids,
-               stack_depot_stats->allocated >> 20);
-        prev_reported_stack_depot_size = stack_depot_stats->allocated;
+      if (StackDepotStats *stack_depot_stats = StackDepotGetStats()) {
+        if (prev_reported_stack_depot_size * 11 / 10 <
+            stack_depot_stats->allocated) {
+          Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
+                 SanitizerToolName,
+                 stack_depot_stats->n_uniq_ids,
+                 stack_depot_stats->allocated >> 20);
+          prev_reported_stack_depot_size = stack_depot_stats->allocated;
+        }
       }
     }
     // Check RSS against the limit.
@@ -177,127 +96,6 @@
 }
 #endif
 
-#if !SANITIZER_FUCHSIA && !SANITIZER_GO
-void StartReportDeadlySignal() {
-  // Write the first message using fd=2, just in case.
-  // It may actually fail to write in case stderr is closed.
-  CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
-  static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
-  CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
-}
-
-static void MaybeReportNonExecRegion(uptr pc) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
-  MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
-  MemoryMappedSegment segment;
-  while (proc_maps.Next(&segment)) {
-    if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
-      Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
-  }
-#endif
-}
-
-static void PrintMemoryByte(InternalScopedString *str, const char *before,
-                            u8 byte) {
-  SanitizerCommonDecorator d;
-  str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
-              d.Default());
-}
-
-static void MaybeDumpInstructionBytes(uptr pc) {
-  if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
-    return;
-  InternalScopedString str(1024);
-  str.append("First 16 instruction bytes at pc: ");
-  if (IsAccessibleMemoryRange(pc, 16)) {
-    for (int i = 0; i < 16; ++i) {
-      PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
-    }
-    str.append("\n");
-  } else {
-    str.append("unaccessible\n");
-  }
-  Report("%s", str.data());
-}
-
-static void MaybeDumpRegisters(void *context) {
-  if (!common_flags()->dump_registers) return;
-  SignalContext::DumpAllRegisters(context);
-}
-
-static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
-                                    UnwindSignalStackCallbackType unwind,
-                                    const void *unwind_context) {
-  SanitizerCommonDecorator d;
-  Printf("%s", d.Warning());
-  static const char kDescription[] = "stack-overflow";
-  Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
-         SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
-         (void *)sig.bp, (void *)sig.sp, tid);
-  Printf("%s", d.Default());
-  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
-  BufferedStackTrace *stack = stack_buffer.data();
-  stack->Reset();
-  unwind(sig, unwind_context, stack);
-  stack->Print();
-  ReportErrorSummary(kDescription, stack);
-}
-
-static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
-                                   UnwindSignalStackCallbackType unwind,
-                                   const void *unwind_context) {
-  SanitizerCommonDecorator d;
-  Printf("%s", d.Warning());
-  const char *description = sig.Describe();
-  Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
-         SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
-         (void *)sig.bp, (void *)sig.sp, tid);
-  Printf("%s", d.Default());
-  if (sig.pc < GetPageSizeCached())
-    Report("Hint: pc points to the zero page.\n");
-  if (sig.is_memory_access) {
-    const char *access_type =
-        sig.write_flag == SignalContext::WRITE
-            ? "WRITE"
-            : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
-    Report("The signal is caused by a %s memory access.\n", access_type);
-    if (sig.addr < GetPageSizeCached())
-      Report("Hint: address points to the zero page.\n");
-  }
-  MaybeReportNonExecRegion(sig.pc);
-  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
-  BufferedStackTrace *stack = stack_buffer.data();
-  stack->Reset();
-  unwind(sig, unwind_context, stack);
-  stack->Print();
-  MaybeDumpInstructionBytes(sig.pc);
-  MaybeDumpRegisters(sig.context);
-  Printf("%s can not provide additional info.\n", SanitizerToolName);
-  ReportErrorSummary(description, stack);
-}
-
-void ReportDeadlySignal(const SignalContext &sig, u32 tid,
-                        UnwindSignalStackCallbackType unwind,
-                        const void *unwind_context) {
-  if (sig.IsStackOverflow())
-    ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
-  else
-    ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
-}
-
-void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
-                        UnwindSignalStackCallbackType unwind,
-                        const void *unwind_context) {
-  StartReportDeadlySignal();
-  ScopedErrorReportLock rl;
-  SignalContext sig(siginfo, context);
-  ReportDeadlySignal(sig, tid, unwind, unwind_context);
-  Report("ABORTING\n");
-  Die();
-}
-
-#endif  // !SANITIZER_FUCHSIA && !SANITIZER_GO
-
 void WriteToSyslog(const char *msg) {
   InternalScopedString msg_copy(kErrorMessageBufferSize);
   msg_copy.append("%s", msg);
@@ -328,45 +126,8 @@
 #endif
 }
 
-static atomic_uintptr_t reporting_thread = {0};
-static StaticSpinMutex CommonSanitizerReportMutex;
-
-ScopedErrorReportLock::ScopedErrorReportLock() {
-  uptr current = GetThreadSelf();
-  for (;;) {
-    uptr expected = 0;
-    if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
-                                       memory_order_relaxed)) {
-      // We've claimed reporting_thread so proceed.
-      CommonSanitizerReportMutex.Lock();
-      return;
-    }
-
-    if (expected == current) {
-      // This is either asynch signal or nested error during error reporting.
-      // Fail simple to avoid deadlocks in Report().
-
-      // Can't use Report() here because of potential deadlocks in nested
-      // signal handlers.
-      CatastrophicErrorWrite(SanitizerToolName,
-                             internal_strlen(SanitizerToolName));
-      static const char msg[] = ": nested bug in the same thread, aborting.\n";
-      CatastrophicErrorWrite(msg, sizeof(msg) - 1);
-
-      internal__exit(common_flags()->exitcode);
-    }
-
-    internal_sched_yield();
-  }
-}
-
-ScopedErrorReportLock::~ScopedErrorReportLock() {
-  CommonSanitizerReportMutex.Unlock();
-  atomic_store_relaxed(&reporting_thread, 0);
-}
-
-void ScopedErrorReportLock::CheckLocked() {
-  CommonSanitizerReportMutex.CheckLocked();
+static void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
+  PlatformPrepareForSandboxing(args);
 }
 
 }  // namespace __sanitizer
Index: lib/sanitizer_common/sanitizer_file.h
===================================================================
--- lib/sanitizer_common/sanitizer_file.h
+++ lib/sanitizer_common/sanitizer_file.h
@@ -16,8 +16,8 @@
 #ifndef SANITIZER_FILE_H
 #define SANITIZER_FILE_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_interface_internal.h"
-#include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_mutex.h"
 
Index: lib/sanitizer_common/sanitizer_fuchsia.cc
===================================================================
--- lib/sanitizer_common/sanitizer_fuchsia.cc
+++ lib/sanitizer_common/sanitizer_fuchsia.cc
@@ -89,7 +89,6 @@
 }
 
 void MaybeReexec() {}
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}
 void DisableCoreDumperIfNecessary() {}
 void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
 void StartReportDeadlySignal() {}
Index: lib/sanitizer_common/sanitizer_linux.cc
===================================================================
--- lib/sanitizer_common/sanitizer_linux.cc
+++ lib/sanitizer_common/sanitizer_linux.cc
@@ -26,8 +26,6 @@
 #include "sanitizer_mutex.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
 
 #if SANITIZER_LINUX
 #include <asm/param.h>
Index: lib/sanitizer_common/sanitizer_linux_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -26,7 +26,6 @@
 #include "sanitizer_linux.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_stacktrace.h"
 
 #include <dlfcn.h>  // for dlsym()
 #include <link.h>
Index: lib/sanitizer_common/sanitizer_posix.cc
===================================================================
--- lib/sanitizer_common/sanitizer_posix.cc
+++ lib/sanitizer_common/sanitizer_posix.cc
@@ -21,7 +21,6 @@
 #include "sanitizer_libc.h"
 #include "sanitizer_posix.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_stacktrace.h"
 
 #include <errno.h>
 #include <fcntl.h>
Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -24,8 +24,6 @@
 #include "sanitizer_platform_limits_solaris.h"
 #include "sanitizer_posix.h"
 #include "sanitizer_procmaps.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -292,18 +290,6 @@
   return result;
 }
 
-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
-  Symbolizer::GetOrInit()->PrepareForSandboxing();
-#endif
-}
-
 #if SANITIZER_ANDROID || SANITIZER_GO
 int GetNamedMappingFd(const char *name, uptr size) {
   return -1;
@@ -517,6 +503,14 @@
   return state == PTHREAD_CREATE_DETACHED;
 }
 
+void PlatformPrepareForSandboxing(__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();
+}
+
 } // namespace __sanitizer
 
 #endif // SANITIZER_POSIX
Index: lib/sanitizer_common/sanitizer_symbolizer.h
===================================================================
--- lib/sanitizer_common/sanitizer_symbolizer.h
+++ lib/sanitizer_common/sanitizer_symbolizer.h
@@ -107,7 +107,6 @@
   void Flush();
   // Attempts to demangle the provided C++ mangled name.
   const char *Demangle(const char *name);
-  void PrepareForSandboxing();
 
   // Allow user to install hooks that would be called before/after Symbolizer
   // does the actual file/line info fetching. Specific sanitizers may need this
@@ -158,7 +157,6 @@
 
   // Platform-specific default demangler, must not return nullptr.
   const char *PlatformDemangle(const char *name);
-  void PlatformPrepareForSandboxing();
 
   static Symbolizer *symbolizer_;
   static StaticSpinMutex init_mu_;
Index: lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -145,11 +145,6 @@
   return PlatformDemangle(name);
 }
 
-void Symbolizer::PrepareForSandboxing() {
-  BlockingMutexLock l(&mu_);
-  PlatformPrepareForSandboxing();
-}
-
 bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
                                                    const char **module_name,
                                                    uptr *module_offset,
Index: lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
===================================================================
--- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -445,8 +445,6 @@
   return DemangleSwiftAndCXX(name);
 }
 
-void Symbolizer::PlatformPrepareForSandboxing() {}
-
 static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
   const char *path = common_flags()->external_symbolizer_path;
   const char *binary_name = path ? StripModuleName(path) : "";
Index: lib/sanitizer_common/sanitizer_symbolizer_report.cc
===================================================================
--- /dev/null
+++ lib/sanitizer_common/sanitizer_symbolizer_report.cc
@@ -0,0 +1,271 @@
+#include "sanitizer_file.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_report_decorator.h"
+
+#if SANITIZER_POSIX
+#include "sanitizer_posix.h"
+#include <sys/mman.h>
+#endif
+
+namespace __sanitizer {
+
+#if !SANITIZER_FUCHSIA
+bool ReportFile::SupportsColors() {
+  SpinMutexLock l(mu);
+  ReopenIfNecessary();
+  return SupportsColoredOutput(fd);
+}
+
+static INLINE bool ReportSupportsColors() {
+  return report_file.SupportsColors();
+}
+#else  // SANITIZER_FUCHSIA
+// Fuchsia's logs always go through post-processing that handles colorization.
+static INLINE bool ReportSupportsColors() { return true; }
+#endif  // !SANITIZER_FUCHSIA
+
+bool ColorizeReports() {
+  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
+  // printing on Windows.
+  if (SANITIZER_WINDOWS)
+    return false;
+
+  const char *flag = common_flags()->color;
+  return internal_strcmp(flag, "always") == 0 ||
+         (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
+}
+
+void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
+  if (!common_flags()->print_summary)
+    return;
+  InternalScopedString buff(kMaxSummaryLength);
+  buff.append("SUMMARY: %s: %s",
+              alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
+  __sanitizer_report_error_summary(buff.data());
+}
+
+#if !SANITIZER_GO
+void ReportErrorSummary(const char *error_type, const AddressInfo &info,
+                        const char *alt_tool_name) {
+  if (!common_flags()->print_summary) return;
+  InternalScopedString buff(kMaxSummaryLength);
+  buff.append("%s ", error_type);
+  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
+              common_flags()->strip_path_prefix);
+  ReportErrorSummary(buff.data(), alt_tool_name);
+}
+#endif
+
+void ReportErrorSummary(const char *error_type, const StackTrace *stack,
+                        const char *alt_tool_name) {
+#if !SANITIZER_GO
+  if (!common_flags()->print_summary)
+    return;
+  if (stack->size == 0) {
+    ReportErrorSummary(error_type);
+    return;
+  }
+  // Currently, we include the first stack frame into the report summary.
+  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+  ReportErrorSummary(error_type, frame->info, alt_tool_name);
+  frame->ClearAll();
+#endif
+}
+
+void ReportMmapWriteExec(int prot) {
+#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID)
+  if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC))
+    return;
+
+  ScopedErrorReportLock l;
+  SanitizerCommonDecorator d;
+
+  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
+  BufferedStackTrace *stack = stack_buffer.data();
+  stack->Reset();
+  uptr top = 0;
+  uptr bottom = 0;
+  GET_CALLER_PC_BP_SP;
+  (void)sp;
+  bool fast = common_flags()->fast_unwind_on_fatal;
+  if (fast)
+    GetThreadStackTopAndBottom(false, &top, &bottom);
+  stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast);
+
+  Printf("%s", d.Warning());
+  Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName);
+  Printf("%s", d.Default());
+
+  stack->Print();
+  ReportErrorSummary("w-and-x-usage", stack);
+#endif
+}
+
+#if !SANITIZER_FUCHSIA && !SANITIZER_GO
+void StartReportDeadlySignal() {
+  // Write the first message using fd=2, just in case.
+  // It may actually fail to write in case stderr is closed.
+  CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
+  static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
+  CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
+}
+
+static void MaybeReportNonExecRegion(uptr pc) {
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
+  MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
+  MemoryMappedSegment segment;
+  while (proc_maps.Next(&segment)) {
+    if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
+      Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
+  }
+#endif
+}
+
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+                            u8 byte) {
+  SanitizerCommonDecorator d;
+  str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
+              d.Default());
+}
+
+static void MaybeDumpInstructionBytes(uptr pc) {
+  if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
+    return;
+  InternalScopedString str(1024);
+  str.append("First 16 instruction bytes at pc: ");
+  if (IsAccessibleMemoryRange(pc, 16)) {
+    for (int i = 0; i < 16; ++i) {
+      PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
+    }
+    str.append("\n");
+  } else {
+    str.append("unaccessible\n");
+  }
+  Report("%s", str.data());
+}
+
+static void MaybeDumpRegisters(void *context) {
+  if (!common_flags()->dump_registers) return;
+  SignalContext::DumpAllRegisters(context);
+}
+
+static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
+                                    UnwindSignalStackCallbackType unwind,
+                                    const void *unwind_context) {
+  SanitizerCommonDecorator d;
+  Printf("%s", d.Warning());
+  static const char kDescription[] = "stack-overflow";
+  Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
+         SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
+         (void *)sig.bp, (void *)sig.sp, tid);
+  Printf("%s", d.Default());
+  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
+  BufferedStackTrace *stack = stack_buffer.data();
+  stack->Reset();
+  unwind(sig, unwind_context, stack);
+  stack->Print();
+  ReportErrorSummary(kDescription, stack);
+}
+
+static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
+                                   UnwindSignalStackCallbackType unwind,
+                                   const void *unwind_context) {
+  SanitizerCommonDecorator d;
+  Printf("%s", d.Warning());
+  const char *description = sig.Describe();
+  Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
+         SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
+         (void *)sig.bp, (void *)sig.sp, tid);
+  Printf("%s", d.Default());
+  if (sig.pc < GetPageSizeCached())
+    Report("Hint: pc points to the zero page.\n");
+  if (sig.is_memory_access) {
+    const char *access_type =
+        sig.write_flag == SignalContext::WRITE
+            ? "WRITE"
+            : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
+    Report("The signal is caused by a %s memory access.\n", access_type);
+    if (sig.addr < GetPageSizeCached())
+      Report("Hint: address points to the zero page.\n");
+  }
+  MaybeReportNonExecRegion(sig.pc);
+  InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
+  BufferedStackTrace *stack = stack_buffer.data();
+  stack->Reset();
+  unwind(sig, unwind_context, stack);
+  stack->Print();
+  MaybeDumpInstructionBytes(sig.pc);
+  MaybeDumpRegisters(sig.context);
+  Printf("%s can not provide additional info.\n", SanitizerToolName);
+  ReportErrorSummary(description, stack);
+}
+
+void ReportDeadlySignal(const SignalContext &sig, u32 tid,
+                        UnwindSignalStackCallbackType unwind,
+                        const void *unwind_context) {
+  if (sig.IsStackOverflow())
+    ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
+  else
+    ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
+}
+
+void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
+                        UnwindSignalStackCallbackType unwind,
+                        const void *unwind_context) {
+  StartReportDeadlySignal();
+  ScopedErrorReportLock rl;
+  SignalContext sig(siginfo, context);
+  ReportDeadlySignal(sig, tid, unwind, unwind_context);
+  Report("ABORTING\n");
+  Die();
+}
+
+static atomic_uintptr_t reporting_thread = {0};
+static StaticSpinMutex CommonSanitizerReportMutex;
+
+ScopedErrorReportLock::ScopedErrorReportLock() {
+  uptr current = GetThreadSelf();
+  for (;;) {
+    uptr expected = 0;
+    if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
+                                       memory_order_relaxed)) {
+      // We've claimed reporting_thread so proceed.
+      CommonSanitizerReportMutex.Lock();
+      return;
+    }
+
+    if (expected == current) {
+      // This is either asynch signal or nested error during error reporting.
+      // Fail simple to avoid deadlocks in Report().
+
+      // Can't use Report() here because of potential deadlocks in nested
+      // signal handlers.
+      CatastrophicErrorWrite(SanitizerToolName,
+                             internal_strlen(SanitizerToolName));
+      static const char msg[] = ": nested bug in the same thread, aborting.\n";
+      CatastrophicErrorWrite(msg, sizeof(msg) - 1);
+
+      internal__exit(common_flags()->exitcode);
+    }
+
+    internal_sched_yield();
+  }
+}
+
+ScopedErrorReportLock::~ScopedErrorReportLock() {
+  CommonSanitizerReportMutex.Unlock();
+  atomic_store_relaxed(&reporting_thread, 0);
+}
+
+void ScopedErrorReportLock::CheckLocked() {
+  CommonSanitizerReportMutex.CheckLocked();
+}
+
+#endif  // !SANITIZER_FUCHSIA && !SANITIZER_GO
+
+}  // namespace __sanitizer
Index: lib/sanitizer_common/sanitizer_symbolizer_win.cc
===================================================================
--- lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -176,10 +176,6 @@
   return name;
 }
 
-void Symbolizer::PlatformPrepareForSandboxing() {
-  // Do nothing.
-}
-
 namespace {
 struct ScopedHandle {
   ScopedHandle() : h_(nullptr) {}
Index: lib/sanitizer_common/sanitizer_win.cc
===================================================================
--- lib/sanitizer_common/sanitizer_win.cc
+++ lib/sanitizer_common/sanitizer_win.cc
@@ -467,9 +467,6 @@
   UNIMPLEMENTED();
 }
 
-void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
-}
-
 bool StackSizeIsUnlimited() {
   UNIMPLEMENTED();
 }
Index: lib/scudo/CMakeLists.txt
===================================================================
--- lib/scudo/CMakeLists.txt
+++ lib/scudo/CMakeLists.txt
@@ -28,7 +28,10 @@
   # TODO(kostyak): remove when stacktraces are split off of RTSanitizerCommon
   list(APPEND SCUDO_DYNAMIC_LIBS unwind_shared)
 else()
-  list(APPEND SCUDO_OBJECT_LIBS RTSanitizerCommonCoverage RTUbsan)
+  list(APPEND SCUDO_OBJECT_LIBS
+    RTSanitizerCommonCoverage
+    RTSanitizerCommonSymbolizer
+    RTUbsan)
   list(APPEND SCUDO_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY})
 endif()
 
Index: lib/tsan/CMakeLists.txt
===================================================================
--- lib/tsan/CMakeLists.txt
+++ lib/tsan/CMakeLists.txt
@@ -115,6 +115,7 @@
                 RTSanitizerCommon
                 RTSanitizerCommonLibc
                 RTSanitizerCommonCoverage
+                RTSanitizerCommonSymbolizer
                 RTUbsan
     CFLAGS ${TSAN_RTL_CFLAGS}
     LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
@@ -165,6 +166,7 @@
               $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
               $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
               $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
               $<TARGET_OBJECTS:RTUbsan.${arch}>
       CFLAGS ${TSAN_RTL_CFLAGS}
       PARENT_TARGET tsan)
Index: lib/ubsan/CMakeLists.txt
===================================================================
--- lib/ubsan/CMakeLists.txt
+++ lib/ubsan/CMakeLists.txt
@@ -77,6 +77,7 @@
                   RTSanitizerCommon
                   RTSanitizerCommonLibc
                   RTSanitizerCommonCoverage
+                  RTSanitizerCommonSymbolizer
                   RTInterception
       LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
       PARENT_TARGET ubsan)
@@ -90,6 +91,7 @@
                   RTSanitizerCommonNoHooks
                   RTSanitizerCommonLibcNoHooks
                   RTSanitizerCommonCoverage
+                  RTSanitizerCommonSymbolizer
                   RTInterception
       LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
       PARENT_TARGET ubsan)
@@ -157,6 +159,7 @@
       OBJECT_LIBS RTSanitizerCommon
               RTSanitizerCommonLibc
               RTSanitizerCommonCoverage
+              RTSanitizerCommonSymbolizer
               RTUbsan
               RTUbsan_standalone
               RTInterception
@@ -177,6 +180,7 @@
         OBJECT_LIBS RTSanitizerCommon
               RTSanitizerCommonLibc
               RTSanitizerCommonCoverage
+              RTSanitizerCommonSymbolizer
               RTUbsan
               RTUbsan_cxx
               RTUbsan_standalone