diff --git a/BuildParams b/BuildParams
old mode 100755
new mode 100644
diff --git a/build.sh b/build.sh
index 3b0cf97731cf5201ad48583e5e41c79dd64108e3..96bcff0e8e08b22c1e3e6d0d4b8f77adf302d7bc 100755
--- a/build.sh
+++ b/build.sh
@@ -129,11 +129,6 @@ pre_build()
     then # show that we're doing this, just not the contents
          echo source "$bugsplat_sh"
          source "$bugsplat_sh"
-         # important: we test this and use its value in [grand-]child processes
-         if [ -n "${BUGSPLAT_DB:-}" ]
-         then echo export BUGSPLAT_DB
-              export BUGSPLAT_DB
-         fi
     fi
     set -x
 
@@ -429,6 +424,15 @@ then
   fi
 fi
 
+# Some of the uploads takes a long time to finish in the codeticket backend,
+# causing the next codeticket upload attempt to fail.
+# Inserting this after each potentially large upload may prevent those errors.
+# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed
+wait_for_codeticket()
+{
+    sleep $(( 60 * 6 ))
+}
+
 # check status and upload results to S3
 if $succeeded
 then
@@ -445,6 +449,7 @@ then
       # Upload base package.
       python_cmd "$helpers/codeticket.py" addoutput Installer "$package"  \
           || fatal "Upload of installer failed"
+      wait_for_codeticket
 
       # Upload additional packages.
       for package_id in $additional_packages
@@ -454,6 +459,7 @@ then
         then
           python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
               || fatal "Upload of installer $package_id failed"
+          wait_for_codeticket
         else
           record_failure "Failed to find additional package for '$package_id'."
         fi
@@ -467,6 +473,7 @@ then
               # Upload crash reporter file
               python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
                   || fatal "Upload of symbolfile failed"
+              wait_for_codeticket
           fi
 
           # Upload the llphysicsextensions_tpv package, if one was produced
@@ -474,6 +481,9 @@ then
           if [ -r "$build_dir/llphysicsextensions_package" ]
           then
               llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package)
+              # This next upload is a frequent failure; see if giving the last one some time helps
+              # JJ is making changes to Codeticket that we hope will eliminate this failure soon
+              sleep 300
               python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
                   || fatal "Upload of physics extensions package failed"
           fi
@@ -486,6 +496,7 @@ then
               begin_section "Upload Extension $extension"
               . $extension
               [ $? -eq 0 ] || fatal "Upload of extension $extension failed"
+              wait_for_codeticket
               end_section "Upload Extension $extension"
           done
       fi
@@ -495,7 +506,6 @@ then
     record_event "skipping upload of installer"
   fi
 
-  
 else
     record_event "skipping upload of installer due to failed build"
 fi
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 53e5d7b6a54e5ad31f5f85b6a98ba1dda4ad7fd8..db88e441270ed4b57e89dadacfb2dea460c8c1d7 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -13,6 +13,7 @@ project(${ROOT_PROJECT_NAME})
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 
 include(Variables)
+include(bugsplat)
 include(BuildVersion)
 
 set(LEGACY_STDIO_LIBS)
@@ -50,7 +51,10 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
 
 add_custom_target(viewer)
 
+if (NOT USE_BUGSPLAT)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
+endif (NOT USE_BUGSPLAT)
+
 add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
 add_subdirectory(${LIBS_OPEN_PREFIX}llui)
 add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
@@ -64,29 +68,18 @@ add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
 endif (ENABLE_MEDIA_PLUGINS)
 
 if (LINUX)
-  add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
   if (INSTALL_PROPRIETARY)
       include(LLAppearanceUtility)
       add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})
   endif (INSTALL_PROPRIETARY)
-  add_dependencies(viewer linux-crash-logger-strip-target)
-elseif (DARWIN)
-  add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
-  add_dependencies(viewer mac-crash-logger)
-elseif (WINDOWS)
-  add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
-  # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
-  if (EXISTS ${VIEWER_DIR}win_setup)
-    add_subdirectory(${VIEWER_DIR}win_setup)
-  endif (EXISTS ${VIEWER_DIR}win_setup)
-  # add_dependencies(viewer windows-setup windows-crash-logger)
-  add_dependencies(viewer windows-crash-logger)
 endif (LINUX)
 
-add_subdirectory(${VIEWER_PREFIX}newview)
-add_dependencies(viewer secondlife-bin)
-
-add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
+if (WINDOWS)
+    # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake
+    if (EXISTS ${VIEWER_DIR}win_setup)
+      add_subdirectory(${VIEWER_DIR}win_setup)
+    endif (EXISTS ${VIEWER_DIR}win_setup)
+endif (WINDOWS)
 
 # sets the 'startup project' for debugging from visual studio.
 set_property(
@@ -94,6 +87,32 @@ set_property(
     PROPERTY VS_STARTUP_PROJECT secondlife-bin
     )
 
+if (USE_BUGSPLAT)
+    if (BUGSPLAT_DB)
+        message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'")
+    else (BUGSPLAT_DB)
+        message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)")
+    endif (BUGSPLAT_DB)
+else (USE_BUGSPLAT)
+    message(STATUS "Not building with BugSplat")
+    if (LINUX)
+      add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
+      add_dependencies(viewer linux-crash-logger-strip-target)
+    elseif (DARWIN)
+      add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
+      add_dependencies(viewer mac-crash-logger)
+    elseif (WINDOWS)
+      add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
+      # add_dependencies(viewer windows-setup windows-crash-logger)
+      add_dependencies(viewer windows-crash-logger)
+    endif (LINUX)
+endif (USE_BUGSPLAT)
+
+add_subdirectory(${VIEWER_PREFIX}newview)
+add_dependencies(viewer secondlife-bin)
+
+add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
+
 if (LL_TESTS)
   # Define after the custom targets are created so
   # individual apps can add themselves as dependencies
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index de81512eef5aba9a14005e15ff6a933c030f3590..46ddb9d15bbe57b944ade97248dfb4c5e1e00ce4 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -66,7 +66,7 @@ if(WINDOWS)
 
     # Filenames are different for 32/64 bit BugSplat file and we don't
     # have any control over them so need to branch.
-    if (BUGSPLAT_DB)
+    if (USE_BUGSPLAT)
       if(ADDRESS_SIZE EQUAL 32)
         set(release_files ${release_files} BugSplat.dll)
         set(release_files ${release_files} BugSplatRc.dll)
@@ -76,7 +76,7 @@ if(WINDOWS)
         set(release_files ${release_files} BugSplatRc64.dll)
         set(release_files ${release_files} BsSndRpt64.exe)
       endif(ADDRESS_SIZE EQUAL 32)
-    endif (BUGSPLAT_DB)
+    endif (USE_BUGSPLAT)
 
     if (FMODSTUDIO)
         set(debug_files ${debug_files} fmodL.dll)
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 4932e9044f3949678df593c4758ca447bf251cba..4937c2a9d7735a5cb78933e970e6987ccab80275 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -2,6 +2,7 @@
 include(00-Common)
 include(LLTestCommand)
 include(GoogleMock)
+include(bugsplat)
 include(Tut)
 
 #*****************************************************************************
@@ -22,7 +23,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
   # there is another branch that will conflict heavily with any changes here.
 INCLUDE(GoogleMock)
 
-
   IF(LL_TEST_VERBOSE)
     MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
   ENDIF(LL_TEST_VERBOSE)
@@ -87,6 +87,12 @@ INCLUDE(GoogleMock)
     IF(LL_TEST_VERBOSE)
       MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
     ENDIF(LL_TEST_VERBOSE)
+
+    if (USE_BUGSPLAT)
+      SET_PROPERTY(SOURCE ${${name}_test_SOURCE_FILES}
+          APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+    endif (USE_BUGSPLAT)
+
     # Headers
     GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
     SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
@@ -224,6 +230,11 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
     SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
   endif(USESYSTEMLIBS)
 
+  if (USE_BUGSPLAT)
+      SET_PROPERTY(SOURCE ${source_files}
+          APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+  endif (USE_BUGSPLAT)
+
   # The following was copied to llcorehttp/CMakeLists.txt's texture_load target. 
   # Any changes made here should be replicated there.
   if (WINDOWS)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index a5770c5528dd38ed50af1c45ae1e109f18788af7..c81b22e572d94a60b5956777e861f0001f54fb46 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -34,7 +34,6 @@ set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable fo
 set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
 set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
 set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
-set(BUGSPLAT_DB "" CACHE STRING "BugSplat database name, if BugSplat crash reporting is desired")
 
 if(LIBS_CLOSED_DIR)
   file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)
diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake
index 59644b73ce13f2bdbf63f56d2113e2fbb8c5bd16..5f5cc51f631c84aa3d545f4b2049116546a74433 100644
--- a/indra/cmake/bugsplat.cmake
+++ b/indra/cmake/bugsplat.cmake
@@ -1,25 +1,32 @@
-# BugSplat is engaged by setting BUGSPLAT_DB to the target BugSplat database
-# name.
-if (BUGSPLAT_DB)
-  if (USESYSTEMLIBS)
-    message(STATUS "Looking for system BugSplat")
-    set(BUGSPLAT_FIND_QUIETLY ON)
-    set(BUGSPLAT_FIND_REQUIRED ON)
-    include(FindBUGSPLAT)
-  else (USESYSTEMLIBS)
-    message(STATUS "Engaging autobuild BugSplat")
-    include(Prebuilt)
-    use_prebuilt_binary(bugsplat)
-    if (WINDOWS)
-      set(BUGSPLAT_LIBRARIES 
-        ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
-        )
-    elseif (DARWIN)
-      find_library(BUGSPLAT_LIBRARIES BugsplatMac
-        PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
-    else (WINDOWS)
+if (INSTALL_PROPRIETARY)
+    set(USE_BUGSPLAT ON  CACHE BOOL "Use the BugSplat crash reporting system")
+else (INSTALL_PROPRIETARY)
+    set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system")
+endif (INSTALL_PROPRIETARY)
+
+if (USE_BUGSPLAT)
+    if (NOT USESYSTEMLIBS)
+        include(Prebuilt)
+        use_prebuilt_binary(bugsplat)
+        if (WINDOWS)
+            set(BUGSPLAT_LIBRARIES 
+                ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
+                )
+        elseif (DARWIN)
+            find_library(BUGSPLAT_LIBRARIES BugsplatMac REQUIRED
+                NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
+        else (WINDOWS)
+            message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF")
+        endif (WINDOWS)
+    else (NOT USESYSTEMLIBS)
+        set(BUGSPLAT_FIND_QUIETLY ON)
+        set(BUGSPLAT_FIND_REQUIRED ON)
+        include(FindBUGSPLAT)
+    endif (NOT USESYSTEMLIBS)
+
+    set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name")
 
-    endif (WINDOWS)
     set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
-  endif (USESYSTEMLIBS)
-endif (BUGSPLAT_DB)
+    set(BUGSPLAT_DEFINE "LL_BUGSPLAT")
+endif (USE_BUGSPLAT)
+
diff --git a/indra/linux_crash_logger/README.txt b/indra/linux_crash_logger/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6932a8d9c3172993246b786c17fcda455a1626c9
--- /dev/null
+++ b/indra/linux_crash_logger/README.txt
@@ -0,0 +1,3 @@
+This component is no longer used in Linden Lab builds.
+Change requests to support continued use by open source
+builds are welcome.
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index cecfadcd91f0c22a727d4c59884684a9e292ede9..dd266630ea725c0753cb7ca19b4843935cc06dfb 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -4,6 +4,7 @@ project(llcommon)
 
 include(00-Common)
 include(LLCommon)
+include(bugsplat)
 include(Linking)
 include(Boost)
 include(LLSharedLibs)
@@ -260,10 +261,10 @@ set(llcommon_HEADER_FILES
 set_source_files_properties(${llcommon_HEADER_FILES}
                             PROPERTIES HEADER_FILE_ONLY TRUE)
 
-if (BUGSPLAT_DB)
-  set_source_files_properties(llapp.cpp
-    PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT")
-endif (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
+  set_source_files_properties(${llcommon_SOURCE_FILES}
+    PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
 
 list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
 
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index a90b2945504298cfeee03477d6d31c3183ba1b40..6064a843ae7985c4d7f77fd17c5d366b0ec941aa 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -528,7 +528,12 @@ void LLApp::setupErrorHandling(bool second_instance)
 #endif // LL_LINUX
 
 #endif // ! LL_WINDOWS
+
+#ifdef LL_BUGSPLAT
+    // do not start our own error thread
+#else // ! LL_BUGSPLAT
 	startErrorThread();
+#endif
 }
 
 void LLApp::startErrorThread()
@@ -808,7 +813,9 @@ void setup_signals()
 	act.sa_flags = SA_SIGINFO;
 
 	// Synchronous signals
+#   ifndef LL_BUGSPLAT
 	sigaction(SIGABRT, &act, NULL);
+#   endif
 	sigaction(SIGALRM, &act, NULL);
 	sigaction(SIGBUS, &act, NULL);
 	sigaction(SIGFPE, &act, NULL);
@@ -845,7 +852,9 @@ void clear_signals()
 	act.sa_flags = SA_SIGINFO;
 
 	// Synchronous signals
+#   ifndef LL_BUGSPLAT
 	sigaction(SIGABRT, &act, NULL);
+#   endif
 	sigaction(SIGALRM, &act, NULL);
 	sigaction(SIGBUS, &act, NULL);
 	sigaction(SIGFPE, &act, NULL);
@@ -898,6 +907,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
 
 		return;
 	case SIGABRT:
+        // Note that this handler is not set for SIGABRT when using Bugsplat
 		// Abort just results in termination of the app, no funky error handling.
 		if (LLApp::sLogInSignal)
 		{
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index f876b8ee4a50676fde4c2fae872585c6f6855d8f..8355df90454588f486871460b39a5e4e8c3a5219 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -442,8 +442,6 @@ namespace
     protected:
 		Globals();
 	public:
-		std::ostringstream messageStream;
-		bool messageStreamInUse;
 		std::string mFatalMessage;
 
 		void addCallSite(LLError::CallSite&);
@@ -453,12 +451,7 @@ namespace
 		CallSiteVector callSites;
 	};
 
-	Globals::Globals()
-		: messageStream(),
-		messageStreamInUse(false),
-		callSites()
-	{
-	}
+	Globals::Globals() {}
 
     Globals* Globals::getInstance()
     {
@@ -549,7 +542,7 @@ namespace LLError
 		mFileLevelMap(),
 		mTagLevelMap(),
 		mUniqueLogMessages(),
-		mCrashFunction(NULL),
+		mCrashFunction([](const std::string&){}),
 		mTimeFunction(NULL),
 		mRecorders(),
 		mShouldLogCallCounter(0)
@@ -728,7 +721,6 @@ namespace
 		LLError::setDefaultLevel(LLError::LEVEL_INFO);
 		LLError::setAlwaysFlush(true);
 		LLError::setEnabledLogTypesMask(0xFFFFFFFF);
-		LLError::setFatalFunction(LLError::crashAndLoop);
 		LLError::setTimeFunction(LLError::utcTime);
 
 		// log_to_stderr is only false in the unit and integration tests to keep builds quieter
@@ -1360,57 +1352,7 @@ namespace LLError
 	}
 
 
-	std::ostringstream* Log::out()
-	{
-		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
-
-		if (lock.isLocked())
-		{
-			Globals* g = Globals::getInstance();
-
-			if (!g->messageStreamInUse)
-			{
-				g->messageStreamInUse = true;
-				return &g->messageStream;
-			}
-		}
-
-		return new std::ostringstream;
-	}
-
-	void Log::flush(std::ostringstream* out, char* message)
-	{
-		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
-		if (!lock.isLocked())
-		{
-			return;
-		}
-
-		if(strlen(out->str().c_str()) < 128)
-		{
-			strcpy(message, out->str().c_str());
-		}
-		else
-		{
-			strncpy(message, out->str().c_str(), 127);
-			message[127] = '\0' ;
-		}
-
-		Globals* g = Globals::getInstance();
-		if (out == &g->messageStream)
-		{
-			g->messageStream.clear();
-			g->messageStream.str("");
-			g->messageStreamInUse = false;
-		}
-		else
-		{
-			delete out;
-		}
-		return ;
-	}
-
-	void Log::flush(std::ostringstream* out, const CallSite& site)
+	void Log::flush(const std::ostringstream& out, const CallSite& site)
 	{
 		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
@@ -1421,22 +1363,11 @@ namespace LLError
 		Globals* g = Globals::getInstance();
 		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
 
-		std::string message = out->str();
-		if (out == &g->messageStream)
-		{
-			g->messageStream.clear();
-			g->messageStream.str("");
-			g->messageStreamInUse = false;
-		}
-		else
-		{
-			delete out;
-		}
-
+		std::string message = out.str();
 
 		if (site.mPrintOnce)
 		{
-            std::ostringstream message_stream;
+			std::ostringstream message_stream;
 
 			std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
 			if (messageIter != s->mUniqueLogMessages.end())
@@ -1457,8 +1388,8 @@ namespace LLError
 				message_stream << "ONCE: ";
 				s->mUniqueLogMessages[message] = 1;
 			}
-            message_stream << message;
-            message = message_stream.str();
+			message_stream << message;
+			message = message_stream.str();
 		}
 		
 		writeToRecorders(site, message);
@@ -1466,10 +1397,7 @@ namespace LLError
 		if (site.mLevel == LEVEL_ERROR)
 		{
 			g->mFatalMessage = message;
-			if (s->mCrashFunction)
-			{
-				s->mCrashFunction(message);
-			}
+			s->mCrashFunction(message);
 		}
 	}
 }
@@ -1533,29 +1461,6 @@ namespace LLError
 		return s->mShouldLogCallCounter;
 	}
 
-#if LL_WINDOWS
-		// VC80 was optimizing the error away.
-		#pragma optimize("", off)
-#endif
-	void crashAndLoop(const std::string& message)
-	{
-		// Now, we go kaboom!
-		int* make_me_crash = NULL;
-
-		*make_me_crash = 0;
-
-		while(true)
-		{
-			// Loop forever, in case the crash didn't work?
-		}
-		
-		// this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever.
-		exit(EXIT_FAILURE);
-	}
-#if LL_WINDOWS
-		#pragma optimize("", on)
-#endif
-
 	std::string utcTime()
 	{
 		time_t now = time(NULL);
@@ -1572,33 +1477,7 @@ namespace LLError
 
 namespace LLError
 {     
-	char** LLCallStacks::sBuffer = NULL ;
-	S32    LLCallStacks::sIndex  = 0 ;
-
-	//static
-    void LLCallStacks::allocateStackBuffer()
-    {
-        if(sBuffer == NULL)
-        {
-            sBuffer = new char*[512] ;
-            sBuffer[0] = new char[512 * 128] ;
-            for(S32 i = 1 ; i < 512 ; i++)
-            {
-                sBuffer[i] = sBuffer[i-1] + 128 ;
-            }
-            sIndex = 0 ;
-        }
-    }
-
-    void LLCallStacks::freeStackBuffer()
-    {
-        if(sBuffer != NULL)
-        {
-            delete [] sBuffer[0] ;
-            delete [] sBuffer ;
-            sBuffer = NULL ;
-        }
-    }
+    LLCallStacks::StringVector LLCallStacks::sBuffer ;
 
     //static
     void LLCallStacks::push(const char* function, const int line)
@@ -1609,33 +1488,24 @@ namespace LLError
             return;
         }
 
-        if(sBuffer == NULL)
-        {
-            allocateStackBuffer();
-        }
-
-        if(sIndex > 511)
+        if(sBuffer.size() > 511)
         {
             clear() ;
         }
 
-        strcpy(sBuffer[sIndex], function) ;
-        sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
-        sIndex++ ;
-
-        return ;
+        std::ostringstream out;
+        insert(out, function, line);
+        sBuffer.push_back(out.str());
     }
 
     //static
-    std::ostringstream* LLCallStacks::insert(const char* function, const int line)
+    void LLCallStacks::insert(std::ostream& out, const char* function, const int line)
     {
-        std::ostringstream* _out = LLError::Log::out();
-        *_out << function << " line " << line << " " ;
-        return _out ;
+        out << function << " line " << line << " " ;
     }
 
     //static
-    void LLCallStacks::end(std::ostringstream* _out)
+    void LLCallStacks::end(const std::ostringstream& out)
     {
         LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
         if (!lock.isLocked())
@@ -1643,17 +1513,12 @@ namespace LLError
             return;
         }
 
-        if(sBuffer == NULL)
-        {
-            allocateStackBuffer();
-        }
-
-        if(sIndex > 511)
+        if(sBuffer.size() > 511)
         {
             clear() ;
         }
 
-        LLError::Log::flush(_out, sBuffer[sIndex++]) ;
+        sBuffer.push_back(out.str());
     }
 
     //static
@@ -1665,33 +1530,30 @@ namespace LLError
             return;
         }
 
-        if(sIndex > 0)
+        if(! sBuffer.empty())
         {
             LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
-            while(sIndex > 0)
+            for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend());
+                 ri != re; ++ri)
             {                  
-                sIndex-- ;
-                LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
+                LL_INFOS() << (*ri) << LL_ENDL;
             }
             LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
         }
 
-        if(sBuffer != NULL)
-        {
-            freeStackBuffer();
-        }
+        cleanup();
     }
 
     //static
     void LLCallStacks::clear()
     {
-        sIndex = 0 ;
+        sBuffer.clear();
     }
 
     //static
     void LLCallStacks::cleanup()
     {
-        freeStackBuffer();
+        clear();
     }
 
     std::ostream& operator<<(std::ostream& out, const LLStacktrace&)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index ffaa464d77a256ff799f27d3ba4e69cd9b4a5600..d439136ca8525721ee0917f388ad12053e672bd2 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -29,7 +29,9 @@
 #define LL_LLERROR_H
 
 #include <sstream>
+#include <string>
 #include <typeinfo>
+#include <vector>
 
 #include "stdtypes.h"
 
@@ -198,9 +200,7 @@ namespace LLError
 	{
 	public:
 		static bool shouldLog(CallSite&);
-		static std::ostringstream* out();
-		static void flush(std::ostringstream* out, char* message);
-		static void flush(std::ostringstream*, const CallSite&);
+		static void flush(const std::ostringstream&, const CallSite&);
 		static std::string demangle(const char* mangled);
 		/// classname<TYPE>()
 		template <typename T>
@@ -281,18 +281,15 @@ namespace LLError
     class LL_COMMON_API LLCallStacks
     {
     private:
-        static char**  sBuffer ;
-        static S32     sIndex ;
-
-        static void allocateStackBuffer();
-        static void freeStackBuffer();
+        typedef std::vector<std::string> StringVector;
+        static StringVector sBuffer ;
               
     public:   
         static void push(const char* function, const int line) ;
-        static std::ostringstream* insert(const char* function, const int line) ;
+        static void insert(std::ostream& out, const char* function, const int line) ;
         static void print() ;
         static void clear() ;
-        static void end(std::ostringstream* _out) ;
+        static void end(const std::ostringstream& out) ;
         static void cleanup();
     };
 
@@ -306,10 +303,11 @@ namespace LLError
 //this is cheaper than llcallstacks if no need to output other variables to call stacks. 
 #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
 
-#define llcallstacks                                                                      \
-	{                                                                                     \
-       std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \
-       (*_out)
+#define llcallstacks                                                    \
+	{                                                                   \
+		std::ostringstream _out;                                        \
+		LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ;   \
+		_out
 
 #define llcallstacksendl                   \
 		LLError::End();                    \
@@ -355,11 +353,11 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 		static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
 		lllog_test_()
 
-#define lllog_test_()                                       \
-		if (LL_UNLIKELY(_site.shouldLog()))                 \
-		{                                                   \
-			std::ostringstream* _out = LLError::Log::out(); \
-			(*_out)
+#define lllog_test_()                           \
+		if (LL_UNLIKELY(_site.shouldLog()))     \
+		{                                       \
+			std::ostringstream _out;            \
+			_out
 
 #define lllog_site_args_(level, once, tags)                 \
 	level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG),    \
@@ -378,15 +376,27 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 //	LL_CONT << " for " << t << " seconds" << LL_ENDL;
 //	
 //Such computation is done iff the message will be logged.
-#define LL_CONT	(*_out)
+#define LL_CONT	_out
 
 #define LL_NEWLINE '\n'
 
-#define LL_ENDL                               \
-			LLError::End();                   \
-			LLError::Log::flush(_out, _site); \
-		}                                     \
-	} while(0)
+// Use this only in LL_ERRS or in a place that LL_ERRS may not be used
+#define LLERROR_CRASH         \
+{                             \
+    int* make_me_crash = NULL;\
+    *make_me_crash = 0;       \
+    exit(*make_me_crash);     \
+}
+
+#define LL_ENDL                                         \
+            LLError::End();                             \
+            LLError::Log::flush(_out, _site);           \
+            if (_site.mLevel == LLError::LEVEL_ERROR)   \
+            {                                           \
+                LLERROR_CRASH                           \
+            }                                           \
+        }                                               \
+    } while(0)
 
 // NEW Macros for debugging, allow the passing of a string tag
 
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 25786d5457c7e8b309fb0f052c39497ab508942a..e87bb7bf350abf85f7c99f0008847a0ee65a7035 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -94,14 +94,16 @@ namespace LLError
 	*/
 
 	typedef boost::function<void(const std::string&)> FatalFunction;
-	LL_COMMON_API void crashAndLoop(const std::string& message);
-		// Default fatal function: access null pointer and loops forever
 
 	LL_COMMON_API void setFatalFunction(const FatalFunction&);
-		// The fatal function will be called when an message of LEVEL_ERROR
+		// The fatal function will be called after an message of LEVEL_ERROR
 		// is logged.  Note: supressing a LEVEL_ERROR message from being logged
 		// (by, for example, setting a class level to LEVEL_NONE), will keep
-		// the that message from causing the fatal funciton to be invoked.
+		// that message from causing the fatal function to be invoked.
+		// The passed FatalFunction will be the LAST log function called
+		// before LL_ERRS crashes its caller. A FatalFunction can throw an
+		// exception, or call exit(), to bypass the crash. It MUST disrupt the
+		// flow of control because no caller expects LL_ERRS to return.
 
 	LL_COMMON_API FatalFunction getFatalFunction();
 		// Retrieve the previously-set FatalFunction
@@ -147,14 +149,14 @@ namespace LLError
 		virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;
 			// use the level for better display, not for filtering
 
-        virtual bool enabled() { return true; }
+		virtual bool enabled() { return true; }
 
 		bool wantsTime();
 		bool wantsTags();
 		bool wantsLevel();
 		bool wantsLocation(); 
 		bool wantsFunctionName();
-        bool wantsMultiline();
+		bool wantsMultiline();
 
 		void showTime(bool show);
 		void showTags(bool show);
@@ -165,15 +167,35 @@ namespace LLError
 
 	protected:
 		bool mWantsTime;
-        bool mWantsTags;
-        bool mWantsLevel;
-        bool mWantsLocation;
-        bool mWantsFunctionName;
-        bool mWantsMultiline;
+		bool mWantsTags;
+		bool mWantsLevel;
+		bool mWantsLocation;
+		bool mWantsFunctionName;
+		bool mWantsMultiline;
 	};
 
 	typedef boost::shared_ptr<Recorder> RecorderPtr;
 
+    /**
+     * Instantiate GenericRecorder with a callable(level, message) to get
+     * control on every log message without having to code an explicit
+     * Recorder subclass.
+     */
+    template <typename CALLABLE>
+    class GenericRecorder: public Recorder
+    {
+    public:
+        GenericRecorder(const CALLABLE& callable):
+            mCallable(callable)
+        {}
+        void recordMessage(LLError::ELevel level, const std::string& message) override
+        {
+            mCallable(level, message);
+        }
+    private:
+        CALLABLE mCallable;
+    };
+
 	/**
 	 * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership
 	 * while still ensuring that the allocated memory is eventually freed
@@ -181,6 +203,19 @@ namespace LLError
 	LL_COMMON_API void addRecorder(RecorderPtr);
 	LL_COMMON_API void removeRecorder(RecorderPtr);
 		// each error message is passed to each recorder via recordMessage()
+	/**
+	 * Call addGenericRecorder() with a callable(level, message) to get
+	 * control on every log message without having to code an explicit
+	 * Recorder subclass. Save the returned RecorderPtr if you later want to
+	 * call removeRecorder().
+	 */
+	template <typename CALLABLE>
+	RecorderPtr addGenericRecorder(const CALLABLE& callable)
+	{
+		RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) };
+		addRecorder(ptr);
+		return ptr;
+	}
 
 	LL_COMMON_API void logToFile(const std::string& filename);
 	LL_COMMON_API void logToStderr();
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index cf8f8cc6a5ee9c8ca7c3168cbcc8f4ef6f69ed75..e8ea0ab398edf1fd319ab20d98ebcbbe69fefd8b 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -59,7 +59,6 @@ class LLLeapImpl: public LLLeap
         // pump name -- so it should NOT need tweaking for uniqueness.
         mReplyPump(LLUUID::generateNewID().asString()),
         mExpect(0),
-        mPrevFatalFunction(LLError::getFatalFunction()),
         // Instantiate a distinct LLLeapListener for this plugin. (Every
         // plugin will want its own collection of managed listeners, etc.)
         // Pass it a callback to our connect() method, so it can send events
@@ -146,7 +145,9 @@ class LLLeapImpl: public LLLeap
             .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));
 
         // For our lifespan, intercept any LL_ERRS so we can notify plugin
-        LLError::setFatalFunction(boost::bind(&LLLeapImpl::fatalFunction, this, _1));
+        mRecorder = LLError::addGenericRecorder(
+            [this](LLError::ELevel level, const std::string& message)
+            { onError(level, message); });
 
         // Send child a preliminary event reporting our own reply-pump name --
         // which would otherwise be pretty tricky to guess!
@@ -162,8 +163,7 @@ class LLLeapImpl: public LLLeap
     virtual ~LLLeapImpl()
     {
         LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL;
-        // Restore original FatalFunction
-        LLError::setFatalFunction(mPrevFatalFunction);
+        LLError::removeRecorder(mRecorder);
     }
 
     // Listener for failed launch attempt
@@ -377,28 +377,28 @@ class LLLeapImpl: public LLLeap
         return false;
     }
 
-    void fatalFunction(const std::string& error)
+    void onError(LLError::ELevel level, const std::string& error)
     {
-        // Notify plugin
-        LLSD event;
-        event["type"] = "error";
-        event["error"] = error;
-        mReplyPump.post(event);
-
-        // All the above really accomplished was to buffer the serialized
-        // event in our WritePipe. Have to pump mainloop a couple times to
-        // really write it out there... but time out in case we can't write.
-        LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
-        LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
-        LLSD nop;
-        F64 until = (LLTimer::getElapsedSeconds() + 2).value();
-        while (childin.size() && LLTimer::getElapsedSeconds() < until)
+        if (level == LLError::LEVEL_ERROR)
         {
-            mainloop.post(nop);
+            // Notify plugin
+            LLSD event;
+            event["type"] = "error";
+            event["error"] = error;
+            mReplyPump.post(event);
+
+            // All the above really accomplished was to buffer the serialized
+            // event in our WritePipe. Have to pump mainloop a couple times to
+            // really write it out there... but time out in case we can't write.
+            LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
+            LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
+            LLSD nop;
+            F64 until = (LLTimer::getElapsedSeconds() + 2).value();
+            while (childin.size() && LLTimer::getElapsedSeconds() < until)
+            {
+                mainloop.post(nop);
+            }
         }
-
-        // forward the call to the previous FatalFunction
-        mPrevFatalFunction(error);
     }
 
 private:
@@ -421,7 +421,7 @@ class LLLeapImpl: public LLLeap
         mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;
     boost::scoped_ptr<LLEventPump::Blocker> mBlocker;
     LLProcess::ReadPipe::size_type mExpect;
-    LLError::FatalFunction mPrevFatalFunction;
+    LLError::RecorderPtr mRecorder;
     boost::scoped_ptr<LLLeapListener> mListener;
 };
 
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index ad933154c21196503f7ed13d2cd66eb947e926a4..6b1986d0e9191d8702a920e7b6bf26e5d0e6e522 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -38,11 +38,6 @@
 #include <sstream>
 #include <stdexcept>
 
-namespace {
-void log(LLError::ELevel level,
-         const char* p1, const char* p2, const char* p3, const char* p4);
-} // anonymous namespace
-
 // Our master list of all LLSingletons is itself an LLSingleton. We used to
 // store it in a function-local static, but that could get destroyed before
 // the last of the LLSingletons -- and ~LLSingletonBase() definitely wants to
@@ -218,8 +213,8 @@ void LLSingletonBase::pop_initializing()
 
     if (list.empty())
     {
-        logerrs("Underflow in stack of currently-initializing LLSingletons at ",
-                classname(this).c_str(), "::getInstance()");
+        logerrs({"Underflow in stack of currently-initializing LLSingletons at ",
+                classname(this), "::getInstance()"});
     }
 
     // Now we know list.back() exists: capture it
@@ -240,9 +235,9 @@ void LLSingletonBase::pop_initializing()
     // Now validate the newly-popped LLSingleton.
     if (back != this)
     {
-        logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
-                classname(this).c_str(), "::getInstance() trying to pop ",
-                classname(back).c_str());
+        logerrs({"Push/pop mismatch in stack of currently-initializing LLSingletons: ",
+                classname(this), "::getInstance() trying to pop ",
+                classname(back)});
     }
 
     // log AFTER popping so logging singletons don't cry circularity
@@ -331,15 +326,15 @@ void LLSingletonBase::capture_dependency()
                 //
                 // Example: LLNotifications singleton initializes default channels.
                 // Channels register themselves with singleton once done.
-                logdebugs("LLSingleton circularity: ", out.str().c_str(),
-                    classname(this).c_str(), "");
+                logdebugs({"LLSingleton circularity: ", out.str(),
+                          classname(this)});
             }
             else
             {
                 // Actual circularity with other singleton (or single singleton is used extensively).
                 // Dependency can be unclear.
-                logwarns("LLSingleton circularity: ", out.str().c_str(),
-                    classname(this).c_str(), "");
+                logwarns({"LLSingleton circularity: ", out.str(),
+                         classname(this)});
             }
         }
         else
@@ -352,8 +347,8 @@ void LLSingletonBase::capture_dependency()
             if (current->mDepends.insert(this).second)
             {
                 // only log the FIRST time we hit this dependency!
-                logdebugs(classname(current).c_str(),
-                          " depends on ", classname(this).c_str());
+                logdebugs({classname(current),
+                          " depends on ", classname(this)});
             }
         }
     }
@@ -401,7 +396,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort()
 
 void LLSingletonBase::cleanup_()
 {
-    logdebugs("calling ", classname(this).c_str(), "::cleanupSingleton()");
+    logdebugs({"calling ", classname(this), "::cleanupSingleton()"});
     try
     {
         cleanupSingleton();
@@ -427,23 +422,23 @@ void LLSingletonBase::deleteAll()
             if (! sp->mDeleteSingleton)
             {
                 // This Should Not Happen... but carry on.
-                logwarns(name.c_str(), "::mDeleteSingleton not initialized!");
+                logwarns({name, "::mDeleteSingleton not initialized!"});
             }
             else
             {
                 // properly initialized: call it.
-                logdebugs("calling ", name.c_str(), "::deleteSingleton()");
+                logdebugs({"calling ", name, "::deleteSingleton()"});
                 // From this point on, DO NOT DEREFERENCE sp!
                 sp->mDeleteSingleton();
             }
         }
         catch (const std::exception& e)
         {
-            logwarns("Exception in ", name.c_str(), "::deleteSingleton(): ", e.what());
+            logwarns({"Exception in ", name, "::deleteSingleton(): ", e.what()});
         }
         catch (...)
         {
-            logwarns("Unknown exception in ", name.c_str(), "::deleteSingleton()");
+            logwarns({"Unknown exception in ", name, "::deleteSingleton()"});
         }
     }
 }
@@ -451,49 +446,40 @@ void LLSingletonBase::deleteAll()
 /*---------------------------- Logging helpers -----------------------------*/
 namespace {
 
-void log(LLError::ELevel level,
-         const char* p1, const char* p2, const char* p3, const char* p4)
+std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params& args)
 {
-    LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL;
+    // However many args there are in args, stream each of them to 'out'.
+    for (auto arg : args)
+    {
+        out << arg;
+    }
+    return out;
 }
 
 } // anonymous namespace        
 
 //static
-void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4)
+void LLSingletonBase::logwarns(const string_params& args)
 {
-    log(LLError::LEVEL_WARN, p1, p2, p3, p4);
+    LL_WARNS("LLSingleton") << args << LL_ENDL;
 }
 
 //static
-void LLSingletonBase::loginfos(const char* p1, const char* p2, const char* p3, const char* p4)
+void LLSingletonBase::loginfos(const string_params& args)
 {
-    log(LLError::LEVEL_INFO, p1, p2, p3, p4);
+    LL_INFOS("LLSingleton") << args << LL_ENDL;
 }
 
 //static
-void LLSingletonBase::logdebugs(const char* p1, const char* p2, const char* p3, const char* p4)
+void LLSingletonBase::logdebugs(const string_params& args)
 {
-    log(LLError::LEVEL_DEBUG, p1, p2, p3, p4);
+    LL_DEBUGS("LLSingleton") << args << LL_ENDL;
 }
 
 //static
-void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4)
+void LLSingletonBase::logerrs(const string_params& args)
 {
-    log(LLError::LEVEL_ERROR, p1, p2, p3, p4);
-    // The other important side effect of LL_ERRS() is
-    // https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
-    std::ostringstream out;
-    out << p1 << p2 << p3 << p4;
-    auto crash = LLError::getFatalFunction();
-    if (crash)
-    {
-        crash(out.str());
-    }
-    else
-    {
-        LLError::crashAndLoop(out.str());
-    }
+    LL_ERRS("LLSingleton") << args << LL_ENDL;
 }
 
 std::string LLSingletonBase::demangle(const char* mangled)
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 30a5b21cf86e1307c440482dc795428be2f9ad7b..7c81d65a8bb3edc613730c0130353b46f223849c 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -27,9 +27,10 @@
 
 #include <boost/noncopyable.hpp>
 #include <boost/unordered_set.hpp>
+#include <initializer_list>
 #include <list>
-#include <vector>
 #include <typeinfo>
+#include <vector>
 #include "mutex.h"
 #include "lockstatic.h"
 #include "llthread.h"               // on_main_thread()
@@ -111,14 +112,13 @@ class LLSingletonBase: private boost::noncopyable
     void capture_dependency();
 
     // delegate logging calls to llsingleton.cpp
-    static void logerrs(const char* p1, const char* p2="",
-                        const char* p3="", const char* p4="");
-    static void logwarns(const char* p1, const char* p2="",
-                         const char* p3="", const char* p4="");
-    static void loginfos(const char* p1, const char* p2="",
-                         const char* p3="", const char* p4="");
-    static void logdebugs(const char* p1, const char* p2="",
-                          const char* p3="", const char* p4="");
+public:
+    typedef std::initializer_list<const std::string> string_params;
+protected:
+    static void logerrs  (const string_params&);
+    static void logwarns (const string_params&);
+    static void loginfos (const string_params&);
+    static void logdebugs(const string_params&);
     static std::string demangle(const char* mangled);
     // these classname() declarations restate template functions declared in
     // llerror.h because we avoid #including that here
@@ -327,8 +327,8 @@ class LLSingleton : public LLSingletonBase
             // init stack to its previous size BEFORE logging so log-machinery
             // LLSingletons don't record a dependency on DERIVED_TYPE!
             LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size);
-            logwarns("Error constructing ", classname<DERIVED_TYPE>().c_str(),
-                     ": ", err.what());
+            logwarns({"Error constructing ", classname<DERIVED_TYPE>(),
+                     ": ", err.what()});
             // There isn't a separate EInitState value meaning "we attempted
             // to construct this LLSingleton subclass but could not," so use
             // DELETED. That seems slightly more appropriate than UNINITIALIZED.
@@ -356,8 +356,8 @@ class LLSingleton : public LLSingletonBase
             // BEFORE logging, so log-machinery LLSingletons don't record a
             // dependency on DERIVED_TYPE!
             pop_initializing(lk->mInstance);
-            logwarns("Error in ", classname<DERIVED_TYPE>().c_str(),
-                     "::initSingleton(): ", err.what());
+            logwarns({"Error in ", classname<DERIVED_TYPE>(),
+                     "::initSingleton(): ", err.what()});
             // Get rid of the instance entirely. This call depends on our
             // recursive_mutex. We could have a deleteSingleton(LockStatic&)
             // overload and pass lk, but we don't strictly need it.
@@ -506,9 +506,9 @@ class LLSingleton : public LLSingletonBase
             case CONSTRUCTING:
                 // here if DERIVED_TYPE's constructor (directly or indirectly)
                 // calls DERIVED_TYPE::getInstance()
-                logerrs("Tried to access singleton ",
-                        classname<DERIVED_TYPE>().c_str(),
-                        " from singleton constructor!");
+                logerrs({"Tried to access singleton ",
+                        classname<DERIVED_TYPE>(),
+                        " from singleton constructor!"});
                 return nullptr;
 
             case INITIALIZING:
@@ -523,9 +523,9 @@ class LLSingleton : public LLSingletonBase
 
             case DELETED:
                 // called after deleteSingleton()
-                logwarns("Trying to access deleted singleton ",
-                         classname<DERIVED_TYPE>().c_str(),
-                         " -- creating new instance");
+                logwarns({"Trying to access deleted singleton ",
+                         classname<DERIVED_TYPE>(),
+                         " -- creating new instance"});
                 // fall through
             case UNINITIALIZED:
             case QUEUED:
@@ -552,8 +552,8 @@ class LLSingleton : public LLSingletonBase
         } // unlock 'lk'
 
         // Per the comment block above, dispatch to the main thread.
-        loginfos(classname<DERIVED_TYPE>().c_str(),
-                 "::getInstance() dispatching to main thread");
+        loginfos({classname<DERIVED_TYPE>(),
+                 "::getInstance() dispatching to main thread"});
         auto instance = LLMainThreadTask::dispatch(
             [](){
                 // VERY IMPORTANT to call getInstance() on the main thread,
@@ -563,16 +563,16 @@ class LLSingleton : public LLSingletonBase
                 // the main thread processes them, only the FIRST such request
                 // actually constructs the instance -- every subsequent one
                 // simply returns the existing instance.
-                loginfos(classname<DERIVED_TYPE>().c_str(),
-                         "::getInstance() on main thread");
+                loginfos({classname<DERIVED_TYPE>(),
+                         "::getInstance() on main thread"});
                 return getInstance();
             });
         // record the dependency chain tracked on THIS thread, not the main
         // thread (consider a getInstance() overload with a tag param that
         // suppresses dep tracking when dispatched to the main thread)
         capture_dependency(instance);
-        loginfos(classname<DERIVED_TYPE>().c_str(),
-                 "::getInstance() returning on requesting thread");
+        loginfos({classname<DERIVED_TYPE>(),
+                 "::getInstance() returning on requesting thread"});
         return instance;
     }
 
@@ -641,16 +641,16 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
         // For organizational purposes this function shouldn't be called twice
         if (lk->mInitState != super::UNINITIALIZED)
         {
-            super::logerrs("Tried to initialize singleton ",
-                           super::template classname<DERIVED_TYPE>().c_str(),
-                           " twice!");
+            super::logerrs({"Tried to initialize singleton ",
+                           super::template classname<DERIVED_TYPE>(),
+                           " twice!"});
             return nullptr;
         }
         else if (on_main_thread())
         {
             // on the main thread, simply construct instance while holding lock
-            super::logdebugs(super::template classname<DERIVED_TYPE>().c_str(),
-                             "::initParamSingleton()");
+            super::logdebugs({super::template classname<DERIVED_TYPE>(),
+                             "::initParamSingleton()"});
             super::constructSingleton(lk, std::forward<Args>(args)...);
             return lk->mInstance;
         }
@@ -662,8 +662,8 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
             lk->mInitState = super::QUEUED;
             // very important to unlock here so main thread can actually process
             lk.unlock();
-            super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
-                            "::initParamSingleton() dispatching to main thread");
+            super::loginfos({super::template classname<DERIVED_TYPE>(),
+                            "::initParamSingleton() dispatching to main thread"});
             // Normally it would be the height of folly to reference-bind
             // 'args' into a lambda to be executed on some other thread! By
             // the time that thread executed the lambda, the references would
@@ -674,12 +674,12 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
             // references.
             auto instance = LLMainThreadTask::dispatch(
                 [&](){
-                    super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
-                                    "::initParamSingleton() on main thread");
+                    super::loginfos({super::template classname<DERIVED_TYPE>(),
+                                    "::initParamSingleton() on main thread"});
                     return initParamSingleton_(std::forward<Args>(args)...);
                 });
-            super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
-                            "::initParamSingleton() returning on requesting thread");
+            super::loginfos({super::template classname<DERIVED_TYPE>(),
+                            "::initParamSingleton() returning on requesting thread"});
             return instance;
         }
     }
@@ -707,14 +707,14 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
         {
         case super::UNINITIALIZED:
         case super::QUEUED:
-            super::logerrs("Uninitialized param singleton ",
-                           super::template classname<DERIVED_TYPE>().c_str());
+            super::logerrs({"Uninitialized param singleton ",
+                           super::template classname<DERIVED_TYPE>()});
             break;
 
         case super::CONSTRUCTING:
-            super::logerrs("Tried to access param singleton ",
-                           super::template classname<DERIVED_TYPE>().c_str(),
-                           " from singleton constructor!");
+            super::logerrs({"Tried to access param singleton ",
+                           super::template classname<DERIVED_TYPE>(),
+                           " from singleton constructor!"});
             break;
 
         case super::INITIALIZING:
@@ -726,8 +726,8 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
             return lk->mInstance;
 
         case super::DELETED:
-            super::logerrs("Trying to access deleted param singleton ",
-                           super::template classname<DERIVED_TYPE>().c_str());
+            super::logerrs({"Trying to access deleted param singleton ",
+                           super::template classname<DERIVED_TYPE>()});
             break;
         }
 
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 8e1f4c14accc5236dd50b63dc91656c45256b148..148c18aabea3c82c826d5585d50259c4ed8a1b9e 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -26,6 +26,7 @@
  */
 
 #include <vector>
+#include <stdexcept>
 
 #include "linden_common.h"
 
@@ -69,21 +70,41 @@ namespace
 
 namespace
 {
-	static bool fatalWasCalled;
-	void fatalCall(const std::string&) { fatalWasCalled = true; }
+	static bool fatalWasCalled = false;
+    struct FatalWasCalled: public std::runtime_error
+    {
+        FatalWasCalled(const std::string& what): std::runtime_error(what) {}
+    };
+    void fatalCall(const std::string& msg) { throw FatalWasCalled(msg); }
 }
 
+// Because we use LLError::setFatalFunction(fatalCall), any LL_ERRS call we
+// issue will throw FatalWasCalled. But we want the test program to continue.
+// So instead of writing:
+// LL_ERRS("tag") << "some message" << LL_ENDL;
+// write:
+// CATCH(LL_ERRS("tag"), "some message");
+#define CATCH(logcall, expr)                    \
+    try                                         \
+    {                                           \
+        logcall << expr << LL_ENDL;             \
+    }                                           \
+    catch (const FatalWasCalled&)               \
+    {                                           \
+        fatalWasCalled = true;                  \
+    }
+
 namespace tut
 {
 	class TestRecorder : public LLError::Recorder
 	{
 	public:
 		TestRecorder()
-            {
-                showTime(false);
-            }
+			{
+				showTime(false);
+			}
 		virtual ~TestRecorder()
-            {}
+			{}
 
 		virtual void recordMessage(LLError::ELevel level,
 						   const std::string& message)
@@ -252,7 +273,7 @@ namespace
 		LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL;
 		LL_INFOS("WriteTag") << "two" << LL_ENDL;
 		LL_WARNS("WriteTag") << "three" << LL_ENDL;
-		LL_ERRS("WriteTag") << "four" << LL_ENDL;
+		CATCH(LL_ERRS("WriteTag"), "four");
 	}
 };
 
@@ -380,7 +401,7 @@ namespace
 
 	std::string errorReturningLocation()
 	{
-		LL_ERRS() << "die" << LL_ENDL;	int this_line = __LINE__;
+		int this_line = __LINE__;	CATCH(LL_ERRS(), "die");
 		return locationString(this_line);
 	}
 }
@@ -701,7 +722,7 @@ class TestAlpha
 	static void doDebug()	{ LL_DEBUGS() << "add dice" << LL_ENDL; }
 	static void doInfo()	{ LL_INFOS()  << "any idea" << LL_ENDL; }
 	static void doWarn()	{ LL_WARNS()  << "aim west" << LL_ENDL; }
-	static void doError()	{ LL_ERRS()   << "ate eels" << LL_ENDL; }
+	static void doError()	{ CATCH(LL_ERRS(), "ate eels"); }
 	static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
 };
 
@@ -712,7 +733,7 @@ class TestBeta
 	static void doDebug()	{ LL_DEBUGS() << "bed down" << LL_ENDL; }
 	static void doInfo()	{ LL_INFOS()  << "buy iron" << LL_ENDL; }
 	static void doWarn()	{ LL_WARNS()  << "bad word" << LL_ENDL; }
-	static void doError()	{ LL_ERRS()   << "big easy" << LL_ENDL; }
+	static void doError()	{ CATCH(LL_ERRS(), "big easy"); }
 	static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }
 };
 
@@ -874,13 +895,10 @@ namespace tut
 namespace
 {
     std::string writeTagWithSpaceReturningLocation()
-	{
-        LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL;	int this_line = __LINE__;
-        
-        std::ostringstream location;
-        location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")";
-        return location.str();
-	}
+    {
+        int this_line = __LINE__; CATCH(LL_DEBUGS("Write Tag"), "not allowed");
+        return locationString(this_line);
+    }
 };
 
 namespace tut
@@ -894,9 +912,9 @@ namespace tut
 
         std::string location = writeTagWithSpaceReturningLocation();
         std::string expected = "Space is not allowed in a log tag at " + location;
-		ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
-		ensure_message_field_equals(0, MSG_FIELD, expected);
-		ensure("fatal callback called", fatalWasCalled);
+        ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
+        ensure_message_field_equals(0, MSG_FIELD, expected);
+        ensure("fatal callback called", fatalWasCalled);
     }
 }
 
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index b07d5afbd8fa7a7582356f670b6f9bee27896dd6..3779fb41bcd94fab43f21e61bc755ef7c8d41c3f 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -44,10 +44,6 @@
 #include <list>
 #include <string>
 
-// statically reference the function in test.cpp... it's short, we could
-// replicate, but better to reuse
-extern void wouldHaveCrashed(const std::string& message);
-
 struct WrapLLErrs
 {
     WrapLLErrs():
@@ -59,7 +55,8 @@ struct WrapLLErrs
         mPriorFatal(LLError::getFatalFunction())
     {
         // Make LL_ERRS call our own operator() method
-        LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1));
+        LLError::setFatalFunction(
+            [this](const std::string& message){ (*this)(message); });
     }
 
     ~WrapLLErrs()
@@ -199,11 +196,13 @@ class CaptureLog : public boost::noncopyable
         // with that output. If it turns out that saveAndResetSettings() has
         // some bad effect, give up and just let the DEBUG level log messages
         // display.
-		: boost::noncopyable(),
+        : boost::noncopyable(),
+        mFatalFunction(LLError::getFatalFunction()),
         mOldSettings(LLError::saveAndResetSettings()),
-		mRecorder(new CaptureLogRecorder())
+        mRecorder(new CaptureLogRecorder())
     {
-        LLError::setFatalFunction(wouldHaveCrashed);
+        // reinstate the FatalFunction we just reset
+        LLError::setFatalFunction(mFatalFunction);
         LLError::setDefaultLevel(level);
         LLError::addRecorder(mRecorder);
     }
@@ -219,17 +218,18 @@ class CaptureLog : public boost::noncopyable
     /// for the sought string.
     std::string messageWith(const std::string& search, bool required=true)
     {
-		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
+        return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
     }
 
     std::ostream& streamto(std::ostream& out) const
     {
-		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
+        return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
     }
 
 private:
+    LLError::FatalFunction mFatalFunction;
     LLError::SettingsStoragePtr mOldSettings;
-	LLError::RecorderPtr mRecorder;
+    LLError::RecorderPtr mRecorder;
 };
 
 #endif /* ! defined(LL_WRAPLLERRS_H) */
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 240ea2da839ee0bc56054208c811eef23bf02ae8..8bb6a657b10fcc8af9ea17392e624a4ee0c4297d 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -13,6 +13,7 @@ include(LLAddBuildTest)
 include(LLMessage)
 include(LLCommon)
 include(Tut)
+include(bugsplat)
 
 include_directories (${CMAKE_CURRENT_SOURCE_DIR})
 
diff --git a/indra/llcrashlogger/README.txt b/indra/llcrashlogger/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6932a8d9c3172993246b786c17fcda455a1626c9
--- /dev/null
+++ b/indra/llcrashlogger/README.txt
@@ -0,0 +1,3 @@
+This component is no longer used in Linden Lab builds.
+Change requests to support continued use by open source
+builds are welcome.
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 293ada7548e598a182bed2402b45cba2c84f81ac..28b8e8c06d866f347026b64c16ddf366a34f46e0 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -11,6 +11,7 @@ include(LLKDU)
 include(LLImageJ2COJ)
 include(ZLIB)
 include(LLAddBuildTest)
+include(bugsplat)
 include(Tut)
 
 include_directories(
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 999bee0a3fe04a64d2b46562f24008acce55510a..552e8201279564695b4cfa119f15ec6ad76897c5 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -4,6 +4,7 @@ project(llmath)
 
 include(00-Common)
 include(LLCommon)
+include(bugsplat)
 include(Boost)
 
 include_directories(
diff --git a/indra/mac_crash_logger/README.txt b/indra/mac_crash_logger/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6932a8d9c3172993246b786c17fcda455a1626c9
--- /dev/null
+++ b/indra/mac_crash_logger/README.txt
@@ -0,0 +1,3 @@
+This component is no longer used in Linden Lab builds.
+Change requests to support continued use by open source
+builds are welcome.
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 5ea2d0f7a5859d5174d7c7a330e5b6fef4df989c..62e73b78da44e3e44afb5c125b0cc9d91ed39ec9 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -8,9 +8,7 @@ include(00-Common)
 include(Linking)
 
 include(Boost)
-if (BUGSPLAT_DB)
-  include(bugsplat)
-endif (BUGSPLAT_DB)
+include(bugsplat)
 include(BuildPackagesInfo)
 include(BuildVersion)
 include(CMakeCopyIfDifferent)
@@ -96,18 +94,18 @@ include_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}
     )
 
-if (BUGSPLAT_DB)
-  include_directories(
-    ${BUGSPLAT_INCLUDE_DIR}
-    )
-endif (BUGSPLAT_DB)
-
 include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
     ${LLXML_SYSTEM_INCLUDE_DIRS}
     ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS}
     )
 
+if (USE_BUGSPLAT)
+  include_directories(AFTER
+    ${BUGSPLAT_INCLUDE_DIR}
+    )
+endif (USE_BUGSPLAT)
+
 set(viewer_SOURCE_FILES
     groupchatlistener.cpp
     llaccountingcostmanager.cpp
@@ -1414,11 +1412,11 @@ if (DARWIN)
     ${COREAUDIO_LIBRARY}
     )
 
-  if (BUGSPLAT_DB)
+  if (USE_BUGSPLAT)
     list(APPEND viewer_LIBRARIES
       ${BUGSPLAT_LIBRARIES}
       )
-  endif (BUGSPLAT_DB)
+  endif (USE_BUGSPLAT)
 
   # Add resource files to the project.
   set(viewer_RESOURCE_FILES
@@ -1756,10 +1754,10 @@ if (SDL_FOUND)
     )
 endif (SDL_FOUND)
 
-if (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
   set_property(TARGET ${VIEWER_BINARY_NAME}
-    PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT")
-endif (BUGSPLAT_DB)
+    PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
 
 # add package files
 file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST
@@ -1838,9 +1836,12 @@ if (WINDOWS)
       media_plugin_libvlc
       media_plugin_example
       winmm_shim
-      windows-crash-logger
       )
 
+    if (NOT USE_BUGSPLAT)
+        LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger)
+    endif (NOT USE_BUGSPLAT)
+
     if (ADDRESS_SIZE EQUAL 64)
         list(APPEND COPY_INPUT_DEPENDENCIES
             ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll
@@ -1903,10 +1904,11 @@ if (WINDOWS)
       add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)
     endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts)
 
-    add_dependencies(${VIEWER_BINARY_NAME}
-      SLPlugin
-      windows-crash-logger
-    )
+    add_dependencies(${VIEWER_BINARY_NAME} SLPlugin)
+
+    if (NOT USE_BUGSPLAT)
+        add_dependencies(${VIEWER_BINARY_NAME} windows-crash-logger)
+    endif (NOT USE_BUGSPLAT)
 
     # sets the 'working directory' for debugging from visual studio.
     # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865)
@@ -2058,11 +2060,11 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLAPPEARANCE_LIBRARIES}
     )
 
-if (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
   target_link_libraries(${VIEWER_BINARY_NAME}
     ${BUGSPLAT_LIBRARIES}
     )
-endif (BUGSPLAT_DB)
+endif (USE_BUGSPLAT)
 
 set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
     "Path to artwork files.")
@@ -2073,13 +2075,16 @@ if (LINUX)
   # These are the generated targets that are copied to package/
   set(COPY_INPUT_DEPENDENCIES
     ${VIEWER_BINARY_NAME}
-    linux-crash-logger
     SLPlugin
     media_plugin_gstreamer010
     media_plugin_libvlc
     llcommon
     )
 
+  if (NOT USE_BUGSPLAT)
+      LIST(APPEND COPY_INPUT_DEPENDENCIES linux-crash-logger)
+  endif (NOT USE_BUGSPLAT)
+
   add_custom_command(
       OUTPUT ${product}.tar.bz2
       COMMAND ${PYTHON_EXECUTABLE}
@@ -2210,8 +2215,11 @@ if (DARWIN)
       ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
     )
 
-  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef mac-crash-logger)
-  add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
+  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef)
+
+  if (NOT USE_BUGSPLAT)
+      add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
+  endif (NOT USE_BUGSPLAT)
 
   if (ENABLE_SIGNING)
       set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}")
@@ -2254,7 +2262,7 @@ endif (INSTALL)
 
 # Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh
 if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE)
-  if (NOT BUGSPLAT_DB)
+  if (NOT USE_BUGSPLAT)
     # Breakpad symbol-file generation
     set(SYMBOL_SEARCH_DIRS "")
     if (WINDOWS)
@@ -2271,7 +2279,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
       list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")
       list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")
       list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}")
-      set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger")
+      set(VIEWER_EXE_GLOBS "'${product}' SLPlugin")
       set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger")
       set(VIEWER_LIB_GLOB "*.dylib")
     endif (DARWIN)
@@ -2309,7 +2317,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
       add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
     endif (WINDOWS OR LINUX)
 
-  else (NOT BUGSPLAT_DB)
+  else (NOT USE_BUGSPLAT)
     # BugSplat symbol-file generation
     if (WINDOWS)
       # Just pack up a tarball containing only the .pdb file for the
@@ -2393,9 +2401,9 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
     if (LINUX)
       # TBD
     endif (LINUX)
-  endif (NOT BUGSPLAT_DB)
+  endif (NOT USE_BUGSPLAT)
 
-  # for both BUGSPLAT_DB and Breakpad
+  # for both Bugsplat and Breakpad
   add_dependencies(llpackage generate_symbols)
 endif ()
 
diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm
index 3f1b5139c5c98693a355c77723bdc3bd8614fdba..aeb3294f53bab4b527b944c563fc2a32a73a584d 100644
--- a/indra/newview/llappdelegate-objc.mm
+++ b/indra/newview/llappdelegate-objc.mm
@@ -66,6 +66,7 @@
 	constructViewer();
 
 #if defined(LL_BUGSPLAT)
+    infos("bugsplat setup");
 	// Engage BugsplatStartupManager *before* calling initViewer() to handle
 	// any crashes during initialization.
 	// https://www.bugsplat.com/docs/platforms/os-x#initialization
@@ -74,6 +75,7 @@
 	[BugsplatStartupManager sharedManager].delegate = self;
 	[[BugsplatStartupManager sharedManager] start];
 #endif
+    infos("post-bugsplat setup");
 
 	frameTimer = nil;
 
@@ -301,9 +303,13 @@ struct AttachmentInfo
 
     // We "happen to know" that info[0].basename is "SecondLife.old" -- due to
     // the fact that BugsplatMac only notices a crash during the viewer run
-    // following the crash. Replace .old with .log to reduce confusion.
+    // following the crash. 
+    // The Bugsplat service doesn't respect the MIME type above when returning
+    // the log data to a browser, so take this opportunity to rename the file
+    // from <base>.old to <base>_log.txt
     info[0].basename = 
-        boost::filesystem::path(info[0].pathname).stem().string() + ".log";
+        boost::filesystem::path(info[0].pathname).stem().string() + "_log.txt";
+    infos("attachmentsForBugsplatStartupManager attaching log " + info[0].basename);
 
     NSMutableArray *attachments = [[NSMutableArray alloc] init];
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a13ba97987d0ed69019381193abc380d2497cf39..959587dd11b1dcc8b47e07b9d3d3f7edef6ac62e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -728,14 +728,14 @@ LLAppViewer::LLAppViewer()
 	// from the previous viewer run between this constructor call and the
 	// init() call, which will overwrite the static_debug_info.log file for
 	// THIS run. So setDebugFileNames() early.
-#if LL_BUGSPLAT
+#   ifdef LL_BUGSPLAT
 	// MAINT-8917: don't create a dump directory just for the
 	// static_debug_info.log file
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
-#else // ! LL_BUGSPLAT
+#   else // ! LL_BUGSPLAT
 	// write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
-#endif // ! LL_BUGSPLAT
+#   endif // ! LL_BUGSPLAT
 	mDumpPath = logdir;
 	setMiniDumpDir(logdir);
 	setDebugFileNames(logdir);
@@ -760,17 +760,6 @@ class LLUITranslationBridge : public LLTranslationBridge
 	}
 };
 
-namespace {
-// With Xcode 6, _exit() is too magical to use with boost::bind(), so provide
-// this little helper function.
-void fast_exit(int rc)
-{
-	_exit(rc);
-}
-
-
-}
-
 
 bool LLAppViewer::init()
 {
@@ -822,9 +811,9 @@ bool LLAppViewer::init()
 	if (rc >= 0)
 	{
 		// QAModeTermCode set, terminate with that rc on LL_ERRS. Use
-		// fast_exit() rather than exit() because normal cleanup depends too
+		// _exit() rather than exit() because normal cleanup depends too
 		// much on successful startup!
-		LLError::setFatalFunction(boost::bind(fast_exit, rc));
+		LLError::setFatalFunction([rc](const std::string&){ _exit(rc); });
 	}
 
     mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
@@ -2185,28 +2174,6 @@ bool LLAppViewer::cleanup()
 	return true;
 }
 
-// A callback for LL_ERRS() to call during the watchdog error.
-void watchdog_llerrs_callback(const std::string &error_string)
-{
-	gLLErrorActivated = true;
-
-	gDebugInfo["FatalMessage"] = error_string;
-	LLAppViewer::instance()->writeDebugInfo();
-
-#ifdef LL_WINDOWS
-	RaiseException(0,0,0,0);
-#else
-	raise(SIGQUIT);
-#endif
-}
-
-// A callback for the watchdog to call.
-void watchdog_killer_callback()
-{
-	LLError::setFatalFunction(watchdog_llerrs_callback);
-	LL_ERRS() << "Watchdog killer event" << LL_ENDL;
-}
-
 bool LLAppViewer::initThreads()
 {
 	static const bool enable_threads = true;
@@ -2241,24 +2208,23 @@ bool LLAppViewer::initThreads()
 	return true;
 }
 
-void errorCallback(const std::string &error_string)
+void errorCallback(LLError::ELevel level, const std::string &error_string)
 {
+    if (level == LLError::LEVEL_ERROR)
+    {
 #ifndef LL_RELEASE_FOR_DOWNLOAD
-	OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
+        OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
 #endif
 
-	//Set the ErrorActivated global so we know to create a marker file
-	gLLErrorActivated = true;
-
-	gDebugInfo["FatalMessage"] = error_string;
-	// We're not already crashing -- we simply *intend* to crash. Since we
-	// haven't actually trashed anything yet, we can afford to write the whole
-	// static info file.
-	LLAppViewer::instance()->writeDebugInfo();
+        //Set the ErrorActivated global so we know to create a marker file
+        gLLErrorActivated = true;
 
-#ifndef SHADER_CRASH_NONFATAL
-	LLError::crashAndLoop(error_string);
-#endif
+        gDebugInfo["FatalMessage"] = error_string;
+        // We're not already crashing -- we simply *intend* to crash. Since we
+        // haven't actually trashed anything yet, we can afford to write the whole
+        // static info file.
+        LLAppViewer::instance()->writeDebugInfo();
+    }
 }
 
 void LLAppViewer::initLoggingAndGetLastDuration()
@@ -2269,7 +2235,7 @@ void LLAppViewer::initLoggingAndGetLastDuration()
 	LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "")
                                 ,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")
                                 );
-	LLError::setFatalFunction(errorCallback);
+	LLError::addGenericRecorder(&errorCallback);
 	//LLError::setTimeFunction(getRuntime);
 
 	// Remove the last ".old" log file.
@@ -3028,11 +2994,16 @@ bool LLAppViewer::initWindow()
 		use_watchdog = bool(watchdog_enabled_setting);
 	}
 
+	LL_INFOS("AppInit") << "watchdog"
+						<< (use_watchdog ? " " : " NOT ")
+						<< "enabled"
+						<< " (setting = " << watchdog_enabled_setting << ")"
+						<< LL_ENDL;
+
 	if (use_watchdog)
 	{
-		LLWatchdog::getInstance()->init(watchdog_killer_callback);
+		LLWatchdog::getInstance()->init();
 	}
-	LL_INFOS("AppInit") << "watchdog setting is done." << LL_ENDL;
 
 	LLNotificationsUI::LLNotificationManager::getInstance();
 
@@ -3465,8 +3436,8 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
 	gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
 
-	gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB().value());
-	gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>());
+	gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value());
+	gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>());
 	gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple();
 
 	// The user is not logged on yet, but record the current grid choice login url
@@ -3479,12 +3450,18 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["MainloopThreadID"] = (S32)thread_id;
 #endif
 
+#ifndef LL_BUGSPLAT
 	// "CrashNotHandled" is set here, while things are running well,
 	// in case of a freeze. If there is a freeze, the crash logger will be launched
 	// and can read this value from the debug_info.log.
 	// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
 	// then the value of "CrashNotHandled" will be set to true.
-	gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
+	gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true);
+#else // LL_BUGSPLAT
+	// "CrashNotHandled" is obsolete; it used (not very successsfully)
+    // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze
+	gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false);
+#endif // ! LL_BUGSPLAT
 
 	// Insert crash host url (url to post crash log to) if configured. This insures
 	// that the crash report will go to the proper location in the case of a
@@ -3515,7 +3492,7 @@ void LLAppViewer::writeSystemInfo()
     gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
 	gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
 	gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
-	gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
+	gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin());
 	gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
     gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
 
@@ -3645,7 +3622,7 @@ void LLAppViewer::handleViewerCrash()
 
 	// The crash is being handled here so set this value to false.
 	// Otherwise the crash logger will think this crash was a freeze.
-	gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false;
+	gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false);
 
 	//Write out the crash status file
 	//Use marker file style setup, as that's the simplest, especially since
@@ -3718,6 +3695,8 @@ void LLAppViewer::handleViewerCrash()
 
 	if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]);
 
+	gDebugInfo["FatalMessage"] = LLError::getFatalMessage();
+
 	// Close the debug file
 	pApp->writeDebugInfo(false);  //false answers the isStatic question with the least overhead.
 }
@@ -3816,9 +3795,8 @@ void LLAppViewer::processMarkerFiles()
 		else if (marker_is_same_version)
 		{
 			// the file existed, is ours, and matched our version, so we can report on what it says
-			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL;
-			gLastExecEvent = LAST_EXEC_FROZE;
-
+			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL;
+			gLastExecEvent = LAST_EXEC_OTHER_CRASH;
 		}
 		else
 		{
@@ -5754,11 +5732,6 @@ void LLAppViewer::pauseMainloopTimeout()
 
 void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
 {
-//	if(!restoreErrorTrap())
-//	{
-//		LL_WARNS() << "!!!!!!!!!!!!! Its an error trap!!!!" << state << LL_ENDL;
-//	}
-
 	if(mMainloopTimeout)
 	{
 		if(secs < 0.0f)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 662164af2dc74a4f9e0e6259a65d226aeacd9e90..42946e44155fc0e5afa5ca06e0f2038bda92d74c 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -68,39 +68,21 @@ namespace
 	int gArgC;
 	char** gArgV;
 	LLAppViewerMacOSX* gViewerAppPtr = NULL;
-
-    void (*gOldTerminateHandler)() = NULL;
     std::string gHandleSLURL;
 }
 
-static void exceptionTerminateHandler()
-{
-	// reinstall default terminate() handler in case we re-terminate.
-	if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler);
-	// treat this like a regular viewer crash, with nice stacktrace etc.
-    long *null_ptr;
-    null_ptr = 0;
-    *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad.
-	//LLAppViewer::handleViewerCrash();
-	// we've probably been killed-off before now, but...
-	gOldTerminateHandler(); // call old terminate() handler
-}
-
 void constructViewer()
 {
 	// Set the working dir to <bundle>/Contents/Resources
 	if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1)
 	{
-		LL_WARNS() << "Could not change directory to "
+		LL_WARNS("InitOSX") << "Could not change directory to "
 				<< gDirUtilp->getAppRODataDir() << ": " << strerror(errno)
 				<< LL_ENDL;
 	}
 
 	gViewerAppPtr = new LLAppViewerMacOSX();
 
-    // install unexpected exception handler
-	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
-
 	gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);
 }
 
@@ -109,7 +91,7 @@ bool initViewer()
 	bool ok = gViewerAppPtr->init();
 	if(!ok)
 	{
-		LL_WARNS() << "Application init failed." << LL_ENDL;
+		LL_WARNS("InitOSX") << "Application init failed." << LL_ENDL;
 	}
 	else if (!gHandleSLURL.empty())
 	{
@@ -172,7 +154,7 @@ class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMeta
     std::string get_metadata(const LLSD& info, const LLSD::String& key) const
     {
         std::string data(info[key].asString());
-        LL_INFOS() << "  " << key << "='" << data << "'" << LL_ENDL;
+        LL_INFOS("Bugsplat") << "  " << key << "='" << data << "'" << LL_ENDL;
         return data;
     }
 };
@@ -188,22 +170,22 @@ CrashMetadataSingleton::CrashMetadataSingleton()
     LLSD info;
     if (! static_file.is_open())
     {
-        LL_INFOS() << "Can't open '" << staticDebugPathname
+        LL_WARNS("Bugsplat") << "Can't open '" << staticDebugPathname
                    << "'; no metadata about previous run" << LL_ENDL;
     }
     else if (! LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED))
     {
-        LL_INFOS() << "Can't parse '" << staticDebugPathname
+        LL_WARNS("Bugsplat") << "Can't parse '" << staticDebugPathname
                    << "'; no metadata about previous run" << LL_ENDL;
     }
     else
     {
-        LL_INFOS() << "Metadata from '" << staticDebugPathname << "':" << LL_ENDL;
-        logFilePathname         = get_metadata(info, "SLLog");
-        userSettingsPathname    = get_metadata(info, "SettingsFilename");
+        LL_INFOS("Bugsplat") << "Previous run metadata from '" << staticDebugPathname << "':" << LL_ENDL;
+        logFilePathname      = get_metadata(info, "SLLog");
+        userSettingsPathname = get_metadata(info, "SettingsFilename");
         accountSettingsPathname = get_metadata(info, "PerAccountSettingsFilename");
-        OSInfo                  = get_metadata(info, "OSInfo");
-        agentFullname           = get_metadata(info, "LoginName");
+        OSInfo               = get_metadata(info, "OSInfo");
+        agentFullname        = get_metadata(info, "LoginName");
         // Translate underscores back to spaces
         LLStringUtil::replaceChar(agentFullname, '_', ' ');
         regionName           = get_metadata(info, "CurrentRegion");
@@ -219,7 +201,7 @@ CrashMetadata& CrashMetadata_instance()
 
 void infos(const std::string& message)
 {
-    LL_INFOS() << message << LL_ENDL;
+    LL_INFOS("InitOSX", "Bugsplat") << message << LL_ENDL;
 }
 
 int main( int argc, char **argv ) 
@@ -242,14 +224,11 @@ bool LLAppViewerMacOSX::init()
 {
 	bool success = LLAppViewer::init();
     
-#if LL_SEND_CRASH_REPORTS
     if (success)
     {
         LLAppViewer* pApp = LLAppViewer::instance();
         pApp->initCrashReporting();
     }
-#endif
-    
     return success;
 }
 
@@ -334,11 +313,12 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
 	
 	unsigned int reset_count = 0;
 	
-#define SET_SIG(S) 	sigaction(SIGABRT, &act, &old_act); \
-					if(act.sa_sigaction != old_act.sa_sigaction) \
-						++reset_count;
+#define SET_SIG(SIGNAL) sigaction(SIGNAL, &act, &old_act); \
+                        if(act.sa_sigaction != old_act.sa_sigaction) ++reset_count;
 	// Synchronous signals
-	SET_SIG(SIGABRT)
+#   ifndef LL_BUGSPLAT
+	SET_SIG(SIGABRT) // let bugsplat catch this
+#   endif        
 	SET_SIG(SIGALRM)
 	SET_SIG(SIGBUS)
 	SET_SIG(SIGFPE)
@@ -369,6 +349,10 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
 
 void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
 {
+#if defined LL_BUGSPLAT
+    LL_DEBUGS("InitOSX", "Bugsplat") << "using BugSplat crash logger" << LL_ENDL;
+#elif LL_SEND_CRASH_REPORTS
+    LL_DEBUGS("InitOSX") << "Initializing legacy crash logger" << LL_ENDL;
 	std::string command_str = "mac-crash-logger.app";
     
     std::stringstream pid_str;
@@ -380,6 +364,9 @@ void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
     LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str()
                << " " << logdir << " " << appname << LL_ENDL;
     launchApplication(&command_str, &args);
+#else
+    LL_DEBUGS("InitOSX") << "No crash logger enabled" << LL_ENDL;    
+#endif // ! LL_BUGSPLAT
 }
 
 std::string LLAppViewerMacOSX::generateSerialNumber()
@@ -391,7 +378,8 @@ std::string LLAppViewerMacOSX::generateSerialNumber()
 	CFStringRef serialNumber = NULL;
 	io_service_t    platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
 																 IOServiceMatching("IOPlatformExpertDevice"));
-	if (platformExpert) {
+	if (platformExpert)
+    {
 		serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert,
 																	 CFSTR(kIOPlatformSerialNumberKey),
 																	 kCFAllocatorDefault, 0);		
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index ce36d3458ef67a9fa5808b23eb735034222e76f5..9daea515e56ad4541637e15aee4db9cac27c5170 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -177,7 +177,7 @@ static void exceptionTerminateHandler()
     long *null_ptr;
     null_ptr = 0;
     *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad.
-	//LLAppViewer::handleViewerCrash();
+
 	// we've probably been killed-off before now, but...
 	gOldTerminateHandler(); // call old terminate() handler
 }
@@ -365,10 +365,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 
 	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
 
-#if LL_SEND_CRASH_REPORTS 
-	// ::SetUnhandledExceptionFilter(catchallCrashHandler); 
-#endif
-
 	// Set a debug info flag to indicate if multiple instances are running.
 	bool found_other_instance = !create_app_mutex();
 	gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);
@@ -847,8 +843,7 @@ bool LLAppViewerWin32::beingDebugged()
 
 bool LLAppViewerWin32::restoreErrorTrap()
 {	
-	return true;
-	//return LLWinDebug::checkExceptionHandler();
+	return true; // we don't check for handler collisions on windows, so just say they're ok
 }
 
 void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 43e77e0b083e981c0efc5e29e4847ed1f32f78c3..0416ec088340586d5d81342849d06b43c5ad0b5e 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1812,7 +1812,8 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	
 	if (!LLAppViewer::instance()->restoreErrorTrap())
 	{
-		LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
+        // this always happens, so downgrading it to INFO
+		LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL;
 	}
 
 	const bool do_not_enforce = false;
diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp
index 6273f10c697f80ebf435bc4d4654fee3ce396df5..0aa0280b25720b304c00ad249e4be4de8bfd9f70 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/newview/llwatchdog.cpp
@@ -31,15 +31,6 @@
 
 const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
 
-void default_killer_callback()
-{
-#ifdef LL_WINDOWS
-	RaiseException(0,0,0,0);
-#else
-	raise(SIGQUIT);
-#endif
-}
-
 // This class runs the watchdog timing thread.
 class LLWatchdogTimerThread : public LLThread
 {
@@ -158,11 +149,10 @@ void LLWatchdogTimeout::ping(const std::string& state)
 }
 
 // LLWatchdog
-LLWatchdog::LLWatchdog() :
-	mSuspectsAccessMutex(),
-	mTimer(NULL),
-	mLastClockCount(0),
-	mKillerCallback(&default_killer_callback)
+LLWatchdog::LLWatchdog()
+    :mSuspectsAccessMutex()
+    ,mTimer(NULL)
+	,mLastClockCount(0)
 {
 }
 
@@ -184,9 +174,8 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
 	unlockThread();
 }
 
-void LLWatchdog::init(killer_event_callback func)
+void LLWatchdog::init()
 {
-	mKillerCallback = func;
 	if(!mSuspectsAccessMutex && !mTimer)
 	{
 		mSuspectsAccessMutex = new LLMutex();
@@ -253,8 +242,7 @@ void LLWatchdog::run()
 				mTimer->stop();
 			}
 
-			LL_INFOS() << "Watchdog detected error:" << LL_ENDL;
-			mKillerCallback();
+            LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL;
 		}
 	}
 
diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h
index 9a6624258e90f43c43a114fa1250d579b45ec990..ce5cf748f4f98afb8dfd8075905d8a027c227953 100644
--- a/indra/newview/llwatchdog.h
+++ b/indra/newview/llwatchdog.h
@@ -83,9 +83,7 @@ class LLWatchdog : public LLSingleton<LLWatchdog>
 	void add(LLWatchdogEntry* e);
 	void remove(LLWatchdogEntry* e);
 
-	typedef boost::function<void (void)> killer_event_callback;
-
-	void init(killer_event_callback func = NULL);
+	void init();
 	void run();
 	void cleanup();
     
@@ -98,8 +96,6 @@ class LLWatchdog : public LLSingleton<LLWatchdog>
 	LLMutex* mSuspectsAccessMutex;
 	LLWatchdogTimerThread* mTimer;
 	U64 mLastClockCount;
-
-	killer_event_callback mKillerCallback;
 };
 
 #endif // LL_LLTHREADWATCHDOG_H
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index adac7af71235ea45c359ede17115d61058012093..9f9821b4bee6b1eeeb7e36218b7b53b25f11ace6 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -683,10 +683,11 @@ def construct(self):
                 self.path("libvlccore.dll")
                 self.path("plugins/")
 
-        # pull in the crash logger from other projects
-        # tag:"crash-logger" here as a cue to the exporter
-        self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
-                  dst="win_crash_logger.exe")
+        if not self.args.get('bugsplat'): # don't include the win_crash_logger if we are using BugSplat
+            # pull in the crash logger from other projects
+            # tag:"crash-logger" here as a cue to the exporter
+            self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
+                      dst="win_crash_logger.exe")
 
         if not self.is_packaging_viewer():
             self.package_file = "copied_deps"    
@@ -1068,10 +1069,8 @@ def path_optional(src, dst):
 
                 # our apps
                 executable_path = {}
-                for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
-                                         # plugin launcher
-                                         (os.path.join("llplugin", "slplugin"), "SLPlugin.app"),
-                                         ):
+                embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ]
+                for app_bld_dir, app in embedded_apps:
                     self.path2basename(os.path.join(os.pardir,
                                                     app_bld_dir, self.args['configuration']),
                                        app)
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 87536e146ba6f81f7a1a626c8504a1606c23b6c0..251100867f25e9a3840ba30eaa818b1b7f74f635 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -13,7 +13,7 @@ include(LLXML)
 include(Linking)
 include(Tut)
 include(LLAddBuildTest)
-
+include(bugsplat)
 include(GoogleMock)
 
 include_directories(
@@ -83,6 +83,10 @@ list(APPEND test_SOURCE_FILES ${test_HEADER_FILES})
 
 add_executable(lltest ${test_SOURCE_FILES})
 
+if (USE_BUGSPLAT)
+  set_target_properties(lltest PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
+
 target_link_libraries(lltest
     ${LEGACY_STDIO_LIBS}
     ${LLDATABASE_LIBRARIES}
diff --git a/indra/win_crash_logger/README.txt b/indra/win_crash_logger/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6932a8d9c3172993246b786c17fcda455a1626c9
--- /dev/null
+++ b/indra/win_crash_logger/README.txt
@@ -0,0 +1,3 @@
+This component is no longer used in Linden Lab builds.
+Change requests to support continued use by open source
+builds are welcome.