diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index faf9da8b148e96f3b7c1d34d93c5d365be6f0db6..89422fbdb2d8fa76dca4b0464cf0c208ce2714c7 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -19,7 +19,7 @@ if(WINDOWS)
     set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
     set(vivox_files
         SLVoice.exe
-	libsndfile-1.dll
+        libsndfile-1.dll
         vivoxplatform.dll
         vivoxsdk.dll
         ortp.dll
@@ -167,6 +167,7 @@ elseif(DARWIN)
         libexpat.dylib
         libllqtwebkit.dylib
         libndofdev.dylib
+        libexception_handler.dylib
        )
 
     # fmod is statically linked on darwin
@@ -216,6 +217,7 @@ elseif(LINUX)
         libapr-1.so.0
         libaprutil-1.so.0
         libatk-1.0.so
+        libbreakpad_client.so.0
         libcrypto.so.0.9.7
         libdb-4.2.so
         libexpat.so
diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8270c0fabb0024b6cac4a88c573c812a10059947
--- /dev/null
+++ b/indra/cmake/GoogleBreakpad.cmake
@@ -0,0 +1,19 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+if (STANDALONE)
+  MESSAGE(FATAL_ERROR "*TODO standalone support for google breakad is unimplemented")
+  # *TODO - implement this include(FindGoogleBreakpad)
+else (STANDALONE)
+  use_prebuilt_binary(google_breakpad)
+  if (DARWIN)
+    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler)
+  endif (DARWIN)
+  if (LINUX)
+    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client)
+  endif (LINUX)
+  if (WINDOWS)
+    set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client common)
+  endif (WINDOWS)
+endif (STANDALONE)
+
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp
index 039b70ec4a9cdb910885a9d8631027f7b54ea2da..ce03ea0d6fd638e7500ed16a42ca41e6e94cb0f3 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.cpp
+++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp
@@ -120,7 +120,6 @@ LLCrashLoggerLinux::~LLCrashLoggerLinux(void)
 
 void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
 {
-	mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str();
 }
 
 bool LLCrashLoggerLinux::mainLoop()
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3c689930b8b795267b1611401b83756429a9c8aa..2fcb04321ccff7956fd1e4332db43ea002c5b1f5 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -9,6 +9,7 @@ include(Linking)
 include(Boost)
 include(Pth)
 include(LLSharedLibs)
+include(GoogleBreakpad)
 include(GooglePerfTools)
 include(Copy3rdPartyLibs)
 
@@ -259,6 +260,7 @@ endif(LLCOMMON_LINK_SHARED)
 
 target_link_libraries(
     llcommon
+    ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
     ${APRUTIL_LIBRARIES}
     ${APR_LIBRARIES}
     ${EXPAT_LIBRARIES}
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 6b2d1b7c201f0937a52aab2cebdc00fa23c3c173..eedec0b24e21f1db5f183d5ee5f36c192abdf99b 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -30,6 +30,8 @@
  * $/LicenseInfo$
  */
 
+#include <cstdlib>
+
 #include "linden_common.h"
 #include "llapp.h"
 
@@ -41,8 +43,11 @@
 #include "lllivefile.h"
 #include "llmemory.h"
 #include "llstl.h" // for DeletePointer()
+#include "llstring.h"
 #include "lleventtimer.h"
 
+#include "google_breakpad/exception_handler.h"
+
 //
 // Signal handling
 //
@@ -51,11 +56,22 @@
 #if LL_WINDOWS
 LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
 BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+									const wchar_t* minidump_id,
+									void* context,
+									EXCEPTION_POINTERS* exinfo,
+									MDRawAssertionInfo* assertion,
+									bool succeeded);
 #else
 # include <signal.h>
 # include <unistd.h> // for fork()
 void setup_signals();
 void default_unix_signal_handler(int signum, siginfo_t *info, void *);
+
+// Called by breakpad exception handler after the minidump has been generated.
+bool unix_post_minidump_callback(const char *dump_dir,
+					  const char *minidump_id,
+					  void *context, bool succeeded);
 # if LL_DARWIN
 /* OSX doesn't support SIGRT* */
 S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
@@ -81,7 +97,6 @@ BOOL LLApp::sLogInSignal = FALSE;
 // static
 LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
 LLAppErrorHandler LLApp::sErrorHandler = NULL;
-LLAppErrorHandler LLApp::sSyncErrorHandler = NULL;
 BOOL LLApp::sErrorThreadRunning = FALSE;
 #if !LL_WINDOWS
 LLApp::child_map LLApp::sChildMap;
@@ -123,7 +138,12 @@ void LLApp::commonCtor()
 
 	// Set the application to this instance.
 	sApplication = this;
-
+	
+	mExceptionHandler = 0;
+	
+	// initialize the buffer to write the minidump filename to
+	// (this is used to avoid allocating memory in the crash handler)
+	memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH);
 }
 
 LLApp::LLApp(LLErrorThread *error_thread) :
@@ -152,6 +172,8 @@ LLApp::~LLApp()
 		delete mThreadErrorp;
 		mThreadErrorp = NULL;
 	}
+	
+	if(mExceptionHandler != 0) delete mExceptionHandler;
 
 	LLCommon::cleanupClass();
 }
@@ -262,19 +284,18 @@ void LLApp::setupErrorHandling()
 	// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
 
 #if LL_WINDOWS
-	// Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
-	// a signal handling thread implementation.
-	// What we do is install an unhandled exception handler, which will try to do the right thing
-	// in the case of an error (generate a minidump)
-
-	// Disable this until the viewer gets ported so server crashes can be JIT debugged.
-	//LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
-	//prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler);
-
 	// This sets a callback to handle w32 signals to the console window.
 	// The viewer shouldn't be affected, sicne its a windowed app.
 	SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
 
+	// Install the Google Breakpad crash handler for Windows
+	if(mExceptionHandler == 0)
+	{
+		llwarns << "adding breakpad exception handler" << llendl;
+		mExceptionHandler = new google_breakpad::ExceptionHandler(
+			L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL);
+	}
+
 #else
 	//
 	// Start up signal handling.
@@ -282,9 +303,14 @@ void LLApp::setupErrorHandling()
 	// There are two different classes of signals.  Synchronous signals are delivered to a specific
 	// thread, asynchronous signals can be delivered to any thread (in theory)
 	//
-
 	setup_signals();
-
+	
+	// Add google breakpad exception handler configured for Darwin/Linux.
+	if(mExceptionHandler == 0)
+	{
+		std::string dumpPath = "/tmp/";
+		mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true);
+	}
 #endif
 
 	startErrorThread();
@@ -310,21 +336,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
 	LLApp::sErrorHandler = handler;
 }
 
-
-void LLApp::setSyncErrorHandler(LLAppErrorHandler handler)
-{
-	LLApp::sSyncErrorHandler = handler;
-}
-
-// static
-void LLApp::runSyncErrorHandler()
-{
-	if (LLApp::sSyncErrorHandler)
-	{
-		LLApp::sSyncErrorHandler();
-	}
-}
-
 // static
 void LLApp::runErrorHandler()
 {
@@ -337,7 +348,6 @@ void LLApp::runErrorHandler()
 	LLApp::setStopped();
 }
 
-
 // static
 void LLApp::setStatus(EAppStatus status)
 {
@@ -348,15 +358,27 @@ void LLApp::setStatus(EAppStatus status)
 // static
 void LLApp::setError()
 {
-	if (!isError())
-	{
-		// perform any needed synchronous error-handling
-		runSyncErrorHandler();
-		// set app status to ERROR so that the LLErrorThread notices
-		setStatus(APP_STATUS_ERROR);
-	}
+	// set app status to ERROR so that the LLErrorThread notices
+	setStatus(APP_STATUS_ERROR);
 }
 
+void LLApp::setMiniDumpDir(const std::string &path)
+{
+	llassert(mExceptionHandler);
+#ifdef LL_WINDOWS
+	wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
+	mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH);
+	mExceptionHandler->set_dump_path(std::wstring(buffer));
+#else
+	mExceptionHandler->set_dump_path(path);
+#endif
+}
+
+void LLApp::writeMiniDump()
+{
+	llassert(mExceptionHandler);
+	mExceptionHandler->WriteMinidump();
+}
 
 // static
 void LLApp::setQuitting()
@@ -587,6 +609,7 @@ void setup_signals()
 
 	// Asynchronous signals that result in core
 	sigaction(SIGQUIT, &act, NULL);
+	
 }
 
 void clear_signals()
@@ -765,4 +788,97 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
 	}
 }
 
+bool unix_post_minidump_callback(const char *dump_dir,
+					  const char *minidump_id,
+					  void *context, bool succeeded)
+{
+	// Copy minidump file path into fixed buffer in the app instance to avoid
+	// heap allocations in a crash handler.
+	
+	// path format: <dump_dir>/<minidump_id>.dmp
+	int dirPathLength = strlen(dump_dir);
+	int idLength = strlen(minidump_id);
+	
+	// The path must not be truncated.
+	llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
+	
+	char * path = LLApp::instance()->getMiniDumpFilename();
+	S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+	strncpy(path, dump_dir, remaining);
+	remaining -= dirPathLength;
+	path += dirPathLength;
+	if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
+	{
+		*path++ = '/';
+		--remaining;
+	}
+	if (remaining > 0)
+	{
+		strncpy(path, minidump_id, remaining);
+		remaining -= idLength;
+		path += idLength;
+		strncpy(path, ".dmp", remaining);
+	}
+	
+	llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+	LLApp::runErrorHandler();
+	return true;
+}
 #endif // !WINDOWS
+
+#ifdef LL_WINDOWS
+bool windows_post_minidump_callback(const wchar_t* dump_path,
+									const wchar_t* minidump_id,
+									void* context,
+									EXCEPTION_POINTERS* exinfo,
+									MDRawAssertionInfo* assertion,
+									bool succeeded)
+{
+	char * path = LLApp::instance()->getMiniDumpFilename();
+	S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+	size_t bytesUsed;
+
+	bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
+	remaining -= bytesUsed;
+	path += bytesUsed;
+	if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
+	{
+		*path++ = '\\';
+		--remaining;
+	}
+	if(remaining > 0)
+	{
+		bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
+		remaining -= bytesUsed;
+		path += bytesUsed;
+	}
+	if(remaining > 0)
+	{
+		strncpy(path, ".dmp", remaining);
+	}
+
+	llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
+    // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
+	//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
+    // *TODO: Translate the signals/exceptions into cross-platform stuff
+	// Windows implementation
+	llinfos << "Entering Windows Exception Handler..." << llendl;
+
+	if (LLApp::isError())
+	{
+		llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
+	}
+
+	// Flag status to error, so thread_error starts its work
+	LLApp::setError();
+
+	// Block in the exception handler until the app has stopped
+	// This is pretty sketchy, but appears to work just fine
+	while (!LLApp::isStopped())
+	{
+		ms_sleep(10);
+	}
+
+	return true;
+}
+#endif
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index e5b8edf9c398ddbff4b299d528251f819e3f1218..fef05a7939f479090357a61fb26ea4b9184c1b17 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -66,6 +66,10 @@ class LLChildInfo
 };
 #endif
 
+namespace google_breakpad {
+	class ExceptionHandler; // See exception_handler.h
+}
+
 class LL_COMMON_API LLApp : public LLOptionInterface
 {
 	friend class LLErrorThread;
@@ -227,8 +231,20 @@ class LL_COMMON_API LLApp : public LLOptionInterface
 	void setupErrorHandling();
 
 	void setErrorHandler(LLAppErrorHandler handler);
-	void setSyncErrorHandler(LLAppErrorHandler handler);
+	static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
 	//@}
+	
+	// the maximum length of the minidump filename returned by getMiniDumpFilename()
+	static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
+
+	// change the directory where Breakpad minidump files are written to
+	void setMiniDumpDir(const std::string &path);
+
+	// Return the Google Breakpad minidump filename after a crash.
+	char *getMiniDumpFilename() { return minidump_path; }
+
+	// Write out a Google Breakpad minidump file.
+	void writeMiniDump();
 
 #if !LL_WINDOWS
 	//
@@ -286,15 +302,14 @@ class LL_COMMON_API LLApp : public LLOptionInterface
 private:
 	void startErrorThread();
 	
-	static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
-	static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread.
+	// Contains the filename of the minidump file after a crash.
+	char minidump_path[MAX_MINDUMP_PATH_LENGTH];
 
 	// *NOTE: On Windows, we need a routine to reset the structured
 	// exception handler when some evil driver has taken it over for
 	// their own purposes
 	typedef int(*signal_handler_func)(int signum);
 	static LLAppErrorHandler sErrorHandler;
-	static LLAppErrorHandler sSyncErrorHandler;
 
 	// Default application threads
 	LLErrorThread* mThreadErrorp;		// Waits for app to go to status ERROR, then runs the error callback
@@ -315,6 +330,8 @@ class LL_COMMON_API LLApp : public LLOptionInterface
 private:
 	// the static application instance if it was created.
 	static LLApp* sApplication;
+	
+	google_breakpad::ExceptionHandler * mExceptionHandler;
 
 
 #if !LL_WINDOWS
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index c1022c1195ec62bed7ed615276ca1da1ce3f274f..51e5f14bfe033de01e9a5e1329d5589ea3045339 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -155,25 +155,6 @@ std::string getStartupStateFromLog(std::string& sllog)
 
 void LLCrashLogger::gatherFiles()
 {
-
-	/*
-	//TODO:This function needs to be reimplemented somewhere in here...
-	if(!previous_crash && is_crash_log)
-	{
-		// Make sure the file isn't too old.
-		double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
-		
-		//			llinfos << "age is " << age << llendl;
-		
-		if(age > 60.0)
-		{
-				// The file was last modified more than 60 seconds before the crash reporter was launched.  Assume it's stale.
-			llwarns << "File " << mFilename << " is too old!" << llendl;
-			return;
-		}
-	}
-	*/
-
 	updateApplication("Gathering logs...");
 
 	// Figure out the filename of the debug log
@@ -209,11 +190,9 @@ void LLCrashLogger::gatherFiles()
 		mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
 	}
 
-#if !LL_DARWIN
 	if(mCrashInPreviousExec)
-#else
-#endif
 	{
+		// Restarting after freeze.
 		// Replace the log file ext with .old, since the 
 		// instance that launched this process has overwritten
 		// SecondLife.log
@@ -225,7 +204,12 @@ void LLCrashLogger::gatherFiles()
 	gatherPlatformSpecificFiles();
 
 	//Use the debug log to reconstruct the URL to send the crash report to
-	if(mDebugLog.has("CurrentSimHost"))
+	if(mDebugLog.has("CrashHostUrl"))
+	{
+		// Crash log receiver has been manually configured.
+		mCrashHost = mDebugLog["CrashHostUrl"].asString();
+	}
+	else if(mDebugLog.has("CurrentSimHost"))
 	{
 		mCrashHost = "https://";
 		mCrashHost += mDebugLog["CurrentSimHost"].asString();
@@ -247,7 +231,6 @@ void LLCrashLogger::gatherFiles()
 
 	mCrashInfo["DebugLog"] = mDebugLog;
 	mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
-	mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
 	
 	updateApplication("Encoding files...");
 
@@ -272,8 +255,30 @@ void LLCrashLogger::gatherFiles()
 			trimSLLog(crash_info);
 		}
 
-		mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info);
+		mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info));
+	}
+	
+	// Add minidump as binary.
+	std::string minidump_path = mDebugLog["MinidumpPath"];
+	if(minidump_path != "")
+	{
+		std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
+		if(minidump_stream.is_open())
+		{
+			minidump_stream.seekg(0, std::ios::end);
+			size_t length = minidump_stream.tellg();
+			minidump_stream.seekg(0, std::ios::beg);
+			
+			LLSD::Binary data;
+			data.resize(length);
+			
+			minidump_stream.read(reinterpret_cast<char *>(&(data[0])),length);
+			minidump_stream.close();
+			
+			mCrashInfo["Minidump"] = data;
+		}
 	}
+	mCrashInfo["DebugLog"].erase("MinidumpPath");
 }
 
 LLSD LLCrashLogger::constructPostData()
diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp
index 16efa4fe2c7c89512f628f43374faaa2e6fd69fc..90de39ba270c406cefce46460819d196e0619a01 100644
--- a/indra/mac_crash_logger/llcrashloggermac.cpp
+++ b/indra/mac_crash_logger/llcrashloggermac.cpp
@@ -211,89 +211,6 @@ bool LLCrashLoggerMac::init(void)
 void LLCrashLoggerMac::gatherPlatformSpecificFiles()
 {
 	updateApplication("Gathering hardware information...");
-	char path[MAX_PATH];		
-	FSRef folder;
-	
-	if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
-	{
-		// folder is an FSRef to ~/Library/Logs/
-		if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
-		{
-			struct stat dw_stat;
-			std::string mBuf;
-			bool isLeopard = false;
-			// Try the 10.3 path first...
-			std::string dw_file_name = std::string(path) + std::string("/CrashReporter/Second Life.crash.log");
-			int res = stat(dw_file_name.c_str(), &dw_stat);
-
-			if (res)
-			{
-				// Try the 10.2 one next...
-				dw_file_name = std::string(path) + std::string("/Second Life.crash.log");
-				res = stat(dw_file_name.c_str(), &dw_stat);
-			}
-	
-			if(res)
-			{
-				//10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up
-				//using asterisks. Get a directory listing, search for files starting with second life,
-				//use the last one found.
-				std::string old_file_name, current_file_name, pathname, mask;
-				pathname = std::string(path) + std::string("/CrashReporter/");
-				mask = "Second Life*";
-				while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false))
-				{
-					old_file_name = current_file_name;
-				}
-				if(old_file_name != "")
-				{
-					dw_file_name = pathname + old_file_name;
-					res=stat(dw_file_name.c_str(), &dw_stat);
-					isLeopard = true;
-				}
-			}
-			
-			if (!res)
-			{
-				std::ifstream fp(dw_file_name.c_str());
-				std::stringstream str;
-				if(!fp.is_open()) return;
-				str << fp.rdbuf();
-				mBuf = str.str();
-				
-				if(!isLeopard)
-				{
-					// Crash logs consist of a number of entries, one per crash.
-					// Each entry is preceeded by "**********" on a line by itself.
-					// We want only the most recent (i.e. last) one.
-					const char *sep = "**********";
-					const char *start = mBuf.c_str();
-					const char *cur = start;
-					const char *temp = strstr(cur, sep);
-				
-					while(temp != NULL)
-					{
-						// Skip past the marker we just found
-						cur = temp + strlen(sep);		/* Flawfinder: ignore */
-						
-						// and try to find another
-						temp = strstr(cur, sep);
-					}
-				
-					// If there's more than one entry in the log file, strip all but the last one.
-					if(cur != start)
-					{
-						mBuf.erase(0, cur - start);
-					}
-				}
-				mCrashInfo["CrashLog"] = mBuf;
-			}
-			else
-			{
-				llwarns << "Couldn't find any CrashReporter files..." << llendl;
-			}
-		}
-	}
 }
 
 bool LLCrashLoggerMac::mainLoop()
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7dbe650625ad07c81ee6d6f92ca6a38744ce0e3d..2eff65f46ed578c960c8fd32429e5a2a2e0bdfab 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1066,7 +1066,6 @@ set(viewer_HEADER_FILES
     llwearabletype.h
     llweb.h
     llwind.h
-    llwindebug.h
     llwlanimator.h
     llwldaycycle.h
     llwlparammanager.h
@@ -1140,12 +1139,10 @@ endif (LINUX)
 if (WINDOWS)
     list(APPEND viewer_SOURCE_FILES
          llappviewerwin32.cpp
-         llwindebug.cpp
          )
 
     list(APPEND viewer_HEADER_FILES
          llappviewerwin32.h
-         llwindebug.h
          )
 
     # precompiled header configuration
@@ -1702,6 +1699,29 @@ if (LINUX)
     add_dependencies(package linux-updater-target)
     check_message_template(package)
   endif (NOT INSTALL)
+
+  add_custom_command(
+    OUTPUT  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched
+    COMMAND ${PYTHON_EXECUTABLE}
+    ARGS
+      ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+      --arch=${ARCH}
+      --actions=copy
+      --artwork=${ARTWORK_DIR}
+      --build=${CMAKE_CURRENT_BINARY_DIR}
+      --buildtype=${CMAKE_BUILD_TYPE}
+      --configuration=${CMAKE_CFG_INTDIR}
+      --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged
+      --grid=${GRID}
+      --source=${CMAKE_CURRENT_SOURCE_DIR}
+    DEPENDS 
+      ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+      ${COPY_INPUT_DEPENDENCIES}
+    COMMENT "Performing viewer_manifest copy"
+    )
+    
+  add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) 
+  add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target)
 endif (LINUX)
 
 if (DARWIN)
@@ -1789,6 +1809,45 @@ if (INSTALL)
   include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
 endif (INSTALL)
 
+if (PACKAGE)
+  if (WINDOWS)
+    set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
+    set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows.tar.bz2")
+    set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
+    set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
+    set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
+  endif (WINDOWS)
+  if (DARWIN)
+    set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app")
+    set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin.tar.bz2")
+    set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin")
+    set(VIEWER_LIB_GLOB "*.dylib")
+  endif (DARWIN)
+  if (LINUX)
+    set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/packaged")
+    set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-linux.tar.bz2")
+    set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
+    set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
+    set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
+  endif (LINUX)
+
+  add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
+    COMMAND "${PYTHON_EXECUTABLE}"
+    ARGS
+      "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+      "${VIEWER_DIST_DIR}"
+      "${VIEWER_EXE_GLOBS}"
+      "${VIEWER_LIB_GLOB}"
+      "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
+      "${VIEWER_SYMBOL_FILE}"
+    DEPENDS generate_breakpad_symbols.py
+    VERBATIM
+  )
+  add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}")
+  add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
+  add_dependencies(package generate_breakpad_symbols)
+endif (PACKAGE)
+
 if (LL_TESTS)
   # To add a viewer unit test, just add the test .cpp file below
   # This creates a separate test project per file listed.
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 53af87a870e03a7b775bdad009c589be850e1565..1c5e2435de4bbaf9ddd0a7ea27b97a87c75c7c44 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,6 +1,17 @@
 <?xml version="1.0" ?>
 <llsd>
 <map>
+	<key>CrashHostUrl</key>
+    <map>
+      <key>Comment</key>
+      <string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
     <key>AFKTimeout</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py
new file mode 100644
index 0000000000000000000000000000000000000000..d94301d62e5d575fb47b26e242336e64de364b1b
--- /dev/null
+++ b/indra/newview/generate_breakpad_symbols.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# @file generate_breakpad_symbols.py
+# @author Brad Kittenbrink <brad@lindenlab.com>
+# @brief Simple tool for generating google_breakpad symbol information
+#        for the crash reporter.
+#
+# $LicenseInfo:firstyear=2010&license=viewergpl$
+# 
+# Copyright (c) 2010-2010, Linden Research, Inc.
+# 
+# Second Life Viewer Source Code
+# The source code in this file ("Source Code") is provided by Linden Lab
+# to you under the terms of the GNU General Public License, version 2.0
+# ("GPL"), unless you have obtained a separate licensing agreement
+# ("Other License"), formally executed by you and Linden Lab.  Terms of
+# the GPL can be found in doc/GPL-license.txt in this distribution, or
+# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+# 
+# There are special exceptions to the terms and conditions of the GPL as
+# it is applied to this Source Code. View the full text of the exception
+# in the file doc/FLOSS-exception.txt in this software distribution, or
+# online at
+# http://secondlifegrid.net/programs/open_source/licensing/flossexception
+# 
+# By copying, modifying or distributing this software, you acknowledge
+# that you have read and understood your obligations described above,
+# and agree to abide by those obligations.
+# 
+# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+# COMPLETENESS OR PERFORMANCE.
+# $/LicenseInfo$
+
+
+import collections
+import fnmatch
+import itertools
+import operator
+import os
+import sys
+import shlex
+import subprocess
+import tarfile
+import StringIO
+
+def usage():
+    print >>sys.stderr, "usage: %s viewer_dir viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0]
+
+class MissingModuleError(Exception):
+    def __init__(self, modules):
+        Exception.__init__(self, "Failed to find required modules: %r" % modules)
+        self.modules = modules
+
+def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
+    print "generate_breakpad_symbols run with args: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+
+    # split up list of viewer_exes
+    # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
+    viewer_exes = shlex.split(viewer_exes)
+
+    found_required = dict([(module, False) for module in viewer_exes])
+
+    def matches(f):
+        if f in viewer_exes:
+            found_required[f] = True
+            return True
+        return fnmatch.fnmatch(f, libs_suffix)
+
+    def list_files():
+        for (dirname, subdirs, filenames) in os.walk(viewer_dir):
+            #print "scanning '%s' for modules..." % dirname
+            for f in itertools.ifilter(matches, filenames):
+                yield os.path.join(dirname, f)
+
+    def dump_module(m):
+        print "dumping module '%s' with '%s'..." % (m, dump_syms_tool)
+        child = subprocess.Popen([dump_syms_tool, m] , stdout=subprocess.PIPE)
+        out, err = child.communicate()
+        return (m,child.returncode, out, err)
+
+    out = tarfile.open(viewer_symbol_file, 'w:bz2')
+
+    for (filename,status,symbols,err) in itertools.imap(dump_module, list_files()):
+        if status == 0:
+            module_line = symbols[:symbols.index('\n')]
+            module_line = module_line.split()
+            hash_id = module_line[3]
+            module = ' '.join(module_line[4:])
+            if sys.platform in ['win32', 'cygwin']:
+                mod_name = module[:module.rindex('.pdb')]
+            else:
+                mod_name = module
+            symbolfile = StringIO.StringIO(symbols)
+            info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name))
+            info.size = symbolfile.len
+            out.addfile(info, symbolfile)
+        else:
+            print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err)
+
+    out.close()
+
+    missing_modules = [m for (m,_) in
+        itertools.ifilter(lambda (k,v): not v, found_required.iteritems())
+    ]
+    if missing_modules:
+        print >> sys.stderr, "failed to generate %s" % viewer_symbol_file
+        os.remove(viewer_symbol_file)
+        raise MissingModuleError(missing_modules)
+
+    symbols = tarfile.open(viewer_symbol_file, 'r:bz2')
+    tarfile_members = symbols.getnames()
+    def match_module_basename(m):
+        return os.path.splitext(required_module)[0] == os.path.splitext(os.path.basename(m))[0]
+    for required_module in viewer_exes:
+        # there must be at least one .sym file in tarfile_members that matches each required module (ignoring file extensions)
+        if not reduce(operator.or_, itertools.imap(match_module_basename, tarfile_members)):
+            print >> sys.stderr, "failed to find required %s in generated %s" % (required_module, viewer_symbol_file)
+            os.remove(viewer_symbol_file)
+            raise MissingModuleError([required_module])
+
+    print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes)
+
+    return 0
+
+if __name__ == "__main__":
+    if len(sys.argv) != 6:
+        usage()
+        sys.exit(1)
+    sys.exit(main(*sys.argv[1:]))
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 95084666bb9d27d105e7502b28b916bfab1e0f57..0e93d3c395b9028ad1a5fa67ee8e11705474c625 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -103,8 +103,8 @@
 // Third party library includes
 #include <boost/bind.hpp>
 
+
 #if LL_WINDOWS
-	#include "llwindebug.h"
 #	include <share.h> // For _SH_DENYWR in initMarkerFile
 #else
 #   include <sys/file.h> // For initMarkerFile support
@@ -603,6 +603,11 @@ bool LLAppViewer::init()
 	if (!initConfiguration())
 		return false;
 
+	// write Google Breakpad minidump files to our log directory
+	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+	logdir += gDirUtilp->getDirDelimiter();
+	setMiniDumpDir(logdir);
+
 	// Although initLogging() is the right place to mess with
 	// setFatalFunction(), we can't query gSavedSettings until after
 	// initConfiguration().
@@ -1243,6 +1248,14 @@ bool LLAppViewer::cleanup()
 	// workaround for DEV-35406 crash on shutdown
 	LLEventPumps::instance().reset();
 
+	// remove any old breakpad minidump files from the log directory
+	if (! isError())
+	{
+		std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+		logdir += gDirUtilp->getDirDelimiter();
+		gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
+	}
+
 	// *TODO - generalize this and move DSO wrangling to a helper class -brad
 	std::set<struct apr_dso_handle_t *>::const_iterator i;
 	for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
@@ -2299,17 +2312,7 @@ void LLAppViewer::checkForCrash(void)
 {
     
 #if LL_SEND_CRASH_REPORTS
-	//*NOTE:Mani The current state of the crash handler has the MacOSX
-	// sending all crash reports as freezes, in order to let 
-	// the MacOSX CrashRepoter generate stacks before spawning the 
-	// SL crash logger.
-	// The Linux and Windows clients generate their own stacks and
-	// spawn the SL crash logger immediately. This may change in the future. 
-#if LL_DARWIN
-	if(gLastExecEvent != LAST_EXEC_NORMAL)
-#else		
 	if (gLastExecEvent == LAST_EXEC_FROZE)
-#endif
     {
         llinfos << "Last execution froze, requesting to send crash report." << llendl;
         //
@@ -2540,13 +2543,6 @@ void LLAppViewer::writeSystemInfo()
 	writeDebugInfo(); // Save out debug_info.log early, in case of crash.
 }
 
-void LLAppViewer::handleSyncViewerCrash()
-{
-	LLAppViewer* pApp = LLAppViewer::instance();
-	// Call to pure virtual, handled by platform specific llappviewer instance.
-	pApp->handleSyncCrashTrace(); 
-}
-
 void LLAppViewer::handleViewerCrash()
 {
 	llinfos << "Handle viewer crash entry." << llendl;
@@ -2570,9 +2566,13 @@ void LLAppViewer::handleViewerCrash()
 		return;
 	}
 	pApp->mReportedCrash = TRUE;
-
-	// Make sure the watchdog gets turned off...
-// 	pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why.
+	
+	// Insert crash host url (url to post crash log to) if configured.
+	std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
+	if(crashHostUrl != "")
+	{
+		gDebugInfo["CrashHostUrl"] = crashHostUrl;
+	}
 	
 	//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
 	//to check against no matter what
@@ -2604,6 +2604,12 @@ void LLAppViewer::handleViewerCrash()
 	gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
 	gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
 
+	char *minidump_file = pApp->getMiniDumpFilename();
+	if(minidump_file && minidump_file[0] != 0)
+	{
+		gDebugInfo["MinidumpPath"] = minidump_file;
+	}
+	
 	if(gLogoutInProgress)
 	{
 		gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
@@ -2681,10 +2687,6 @@ void LLAppViewer::handleViewerCrash()
 
 	LLError::logToFile("");
 
-// On Mac, we send the report on the next run, since we need macs crash report
-// for a stack trace, so we have to let it the app fail.
-#if !LL_DARWIN
-
 	// Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
 	if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
 	{
@@ -2697,8 +2699,6 @@ void LLAppViewer::handleViewerCrash()
 	
 	// Call to pure virtual, handled by platform specific llappviewer instance.
 	pApp->handleCrashReporting(); 
-
-#endif //!LL_DARWIN
     
 	return;
 }
@@ -3342,13 +3342,6 @@ void LLAppViewer::badNetworkHandler()
 
 	mPurgeOnExit = TRUE;
 
-#if LL_WINDOWS
-	// Generates the minidump.
-	LLWinDebug::generateCrashStacks(NULL);
-#endif
-	LLAppViewer::handleSyncViewerCrash();
-	LLAppViewer::handleViewerCrash();
-
 	std::ostringstream message;
 	message <<
 		"The viewer has detected mangled network data indicative\n"
@@ -3361,6 +3354,8 @@ void LLAppViewer::badNetworkHandler()
 		"If the problem continues, see the Tech Support FAQ at: \n"
 		"www.secondlife.com/support";
 	forceDisconnect(message.str());
+	
+	LLApp::instance()->writeMiniDump();
 }
 
 // This routine may get called more than once during the shutdown process.
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 5acd6e11c4da645a4b505ab1a4a806fe52ed5b79..0b862a92a1acfdca774e40d44e3d46822b79eac3 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -92,9 +92,7 @@ class LLAppViewer : public LLApp
 	virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
 	                                     // return false if the error trap needed restoration.
 	virtual void handleCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
-	virtual void handleSyncCrashTrace() = 0; // any low-level crash-prep that has to happen in the context of the crashing thread before the crash report is delivered.
 	static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
-	static void handleSyncViewerCrash(); // Hey! The viewer crashed. Do this right NOW in the context of the crashing thread.
     void checkForCrash();
     
 	// Thread accessors
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 78b0f7ba831d05c01bd4c4f2f370cd664290a803..78afdc89952ac2cfa3f3540bffab8543b47dfeab 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -46,23 +46,6 @@
 
 #include <exception>
 
-#if LL_LINUX
-# include <dlfcn.h>		// RTLD_LAZY
-# include <execinfo.h>  // backtrace - glibc only
-#elif LL_SOLARIS
-# include <sys/types.h>
-# include <unistd.h>
-# include <fcntl.h>
-# include <ucontext.h>
-#endif
-
-#ifdef LL_ELFBIN
-# ifdef __GNUC__
-#  include <cxxabi.h>			// for symbol demangling
-# endif
-# include "ELFIO/ELFIO.h"		// for better backtraces
-#endif
-
 #if LL_DBUS_ENABLED
 # include "llappviewerlinux_api_dbus.h"
 
@@ -86,7 +69,6 @@ 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.
-	LLAppViewer::handleSyncViewerCrash();
 	LLAppViewer::handleViewerCrash();
 	// we've probably been killed-off before now, but...
 	gOldTerminateHandler(); // call old terminate() handler
@@ -109,7 +91,6 @@ int main( int argc, char **argv )
 	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
 	// install crash handlers
 	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
-	viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash);
 
 	bool ok = viewer_app_ptr->init();
 	if(!ok)
@@ -138,201 +119,6 @@ int main( int argc, char **argv )
 	return 0;
 }
 
-#ifdef LL_SOLARIS
-static inline BOOL do_basic_glibc_backtrace()
-{
-	BOOL success = FALSE;
-
-	std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
-	llinfos << "Opening stack trace file " << strace_filename << llendl;
-	LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");
-	if (!StraceFile)
-	{
-		llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
-		StraceFile = stderr;
-	}
-
-	printstack(fileno(StraceFile));
-
-	if (StraceFile != stderr)
-		fclose(StraceFile);
-
-	return success;
-}
-#else
-#define MAX_STACK_TRACE_DEPTH 40
-// This uses glibc's basic built-in stack-trace functions for a not very
-// amazing backtrace.
-static inline BOOL do_basic_glibc_backtrace()
-{
-	void *stackarray[MAX_STACK_TRACE_DEPTH];
-	size_t size;
-	char **strings;
-	size_t i;
-	BOOL success = FALSE;
-
-	size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
-	strings = backtrace_symbols(stackarray, size);
-
-	std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
-	llinfos << "Opening stack trace file " << strace_filename << llendl;
-	LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");		// Flawfinder: ignore
-        if (!StraceFile)
-	{
-		llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
-		StraceFile = stderr;
-	}
-
-	if (size)
-	{
-		for (i = 0; i < size; i++)
-		{
-			// the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
-			fprintf(StraceFile, "%-3lu ", (unsigned long)i);
-			fprintf(StraceFile, "%-32s\t", "unknown");
-			fprintf(StraceFile, "%p ", stackarray[i]);
-			fprintf(StraceFile, "%s\n", strings[i]);
-		}
-
-		success = TRUE;
-	}
-	
-	if (StraceFile != stderr)
-		fclose(StraceFile);
-
-	free (strings);
-	return success;
-}
-
-#if LL_ELFBIN
-// This uses glibc's basic built-in stack-trace functions together with
-// ELFIO's ability to parse the .symtab ELF section for better symbol
-// extraction without exporting symbols (which'd cause subtle, fatal bugs).
-static inline BOOL do_elfio_glibc_backtrace()
-{
-	void *stackarray[MAX_STACK_TRACE_DEPTH];
-	size_t btsize;
-	char **strings;
-	BOOL success = FALSE;
-
-	std::string appfilename = gDirUtilp->getExecutablePathAndName();
-
-	std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
-	llinfos << "Opening stack trace file " << strace_filename << llendl;
-	LLFILE* StraceFile = LLFile::fopen(strace_filename, "w");		// Flawfinder: ignore
-        if (!StraceFile)
-	{
-		llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
-		StraceFile = stderr;
-	}
-
-	// get backtrace address list and basic symbol info
-	btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH);
-	strings = backtrace_symbols(stackarray, btsize);
-
-	// create ELF reader for our app binary
-	IELFI* pReader;
-	const IELFISection* pSec = NULL;
-	IELFISymbolTable* pSymTbl = 0;
-	if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
-	    ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
-	    // find symbol table, create reader-object
-	    NULL == (pSec = pReader->GetSection( ".symtab" )) ||
-	    ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
-	{
-		// Failed to open our binary and read its symbol table somehow
-		llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
-		if (StraceFile != stderr)
-			fclose(StraceFile);
-		// note that we may be leaking some of the above ELFIO
-		// objects now, but it's expected that we'll be dead soon
-		// and we want to tread delicately until we get *some* kind
-		// of useful backtrace.
-		return do_basic_glibc_backtrace();
-	}
-
-	// iterate over trace and symtab, looking for plausible symbols
-	std::string   name;
-	Elf32_Addr    value;
-	Elf32_Word    ssize;
-	unsigned char bind;
-	unsigned char type;
-	Elf32_Half    section;
-	int nSymNo = pSymTbl->GetSymbolNum();
-	size_t btpos;
-	for (btpos = 0; btpos < btsize; ++btpos)
-	{
-		// the format of the StraceFile is very specific, to allow (kludgy) machine-parsing
-		fprintf(StraceFile, "%-3ld ", (long)btpos);
-		int symidx;
-		for (symidx = 0; symidx < nSymNo; ++symidx)
-		{
-			if (ERR_ELFIO_NO_ERROR ==
-			    pSymTbl->GetSymbol(symidx, name, value, ssize,
-					       bind, type, section))
-			{
-				// check if trace address within symbol range
-				if (uintptr_t(stackarray[btpos]) >= value &&
-				    uintptr_t(stackarray[btpos]) < value+ssize)
-				{
-					// symbol is inside viewer
-					fprintf(StraceFile, "%-32s\t", "com.secondlife.indra.viewer");
-					fprintf(StraceFile, "%p ", stackarray[btpos]);
-
-					char *demangled_str = NULL;
-					int demangle_result = 1;
-					demangled_str =
-						abi::__cxa_demangle
-						(name.c_str(), NULL, NULL,
-						 &demangle_result);
-					if (0 == demangle_result &&
-					    NULL != demangled_str) {
-						fprintf(StraceFile,
-							"%s", demangled_str);
-						free(demangled_str);
-					}
-					else // failed demangle; print it raw
-					{
-						fprintf(StraceFile,
-							"%s", name.c_str());
-					}
-					// print offset from symbol start
-					fprintf(StraceFile,
-						" + %lu\n",
-						uintptr_t(stackarray[btpos]) -
-						value);
-					goto got_sym; // early escape
-				}
-			}
-		}
-		// Fallback:
-		// Didn't find a suitable symbol in the binary - it's probably
-		// a symbol in a DSO; use glibc's idea of what it should be.
-		fprintf(StraceFile, "%-32s\t", "unknown");
-		fprintf(StraceFile, "%p ", stackarray[btpos]);
-		fprintf(StraceFile, "%s\n", strings[btpos]);
-	got_sym:;
-	}
-	
-	if (StraceFile != stderr)
-		fclose(StraceFile);
-
-	pSymTbl->Release();
-	pSec->Release();
-	pReader->Release();
-
-	free(strings);
-
-	llinfos << "Finished generating stack trace." << llendl;
-
-	success = TRUE;
-	return success;
-}
-#endif // LL_ELFBIN
-
-#endif // LL_SOLARIS
-
-
 LLAppViewerLinux::LLAppViewerLinux()
 {
 }
@@ -541,16 +327,6 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
 }
 #endif // LL_DBUS_ENABLED
 
-void LLAppViewerLinux::handleSyncCrashTrace()
-{
-	// This backtrace writes into stack_trace.log
-#  if LL_ELFBIN
-	do_elfio_glibc_backtrace(); // more useful backtrace
-#  else
-	do_basic_glibc_backtrace(); // only slightly useful backtrace
-#  endif // LL_ELFBIN
-}
-
 void LLAppViewerLinux::handleCrashReporting(bool reportFreeze)
 {
 	std::string cmd =gDirUtilp->getExecutableDir();
@@ -686,6 +462,8 @@ bool LLAppViewerLinux::beingDebugged()
 bool LLAppViewerLinux::initLogging()
 {
 	// Remove the last stack trace, if any
+	// This file is no longer created, since the move to Google Breakpad
+	// The code is left here to clean out any old state in the log dir
 	std::string old_stack_file =
 		gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
 	LLFile::remove(old_stack_file);
diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h
index 230c0dc24bdd1388a969d1abd638b8ffc64893ad..b17380d4d8dd5506d8c015f53d91d667efe93c07 100644
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -68,7 +68,6 @@ class LLAppViewerLinux : public LLAppViewer
 	
 	virtual bool restoreErrorTrap();
 	virtual void handleCrashReporting(bool reportFreeze);
-	virtual void handleSyncCrashTrace();
 
 	virtual bool initLogging();
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 0b5f18c330a1ed6a5defb0205a4782c571c94a24..1e66e55f3d4708ae634bfc9c15409f8204173705 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -264,11 +264,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
 	return reset_count == 0;
 }
 
-void LLAppViewerMacOSX::handleSyncCrashTrace()
-{
-	// do nothing
-}
-
 static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef, 
 								   EventRef inEvent, 
 								   void* inUserData)
@@ -384,38 +379,6 @@ void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze)
 		}
 		
 	}
-
-	if(!reportFreeze)
-	{
-		_exit(1);
-	}
-	
-	// TODO from palmer: Find a better way to handle managing old crash logs
-	// when this is a separate imbedable module.  Ideally just sort crash stack
-	// logs based on date, and grab the latest one as opposed to deleting them
-	// for thoughts on what the module would look like.
-	// See: https://wiki.lindenlab.com/wiki/Viewer_Crash_Reporter_Round_4
-	
-	// Remove the crash stack log from previous executions.
-	// Since we've started logging a new instance of the app, we can assume 
-	// The old crash stack is invalid for the next crash report.
-	char path[MAX_PATH];		
-	FSRef folder;
-	if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
-	{
-		// folder is an FSRef to ~/Library/Logs/
-		if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
-		{
-			std::string pathname = std::string(path) + std::string("/CrashReporter/");
-			std::string mask = "Second Life*";
-			std::string file_name;
-			while(gDirUtilp->getNextFileInDir(pathname, mask, file_name, false))
-			{
-				LLFile::remove(pathname + file_name);
-			}
-		}
-	}
-	
 }
 
 std::string LLAppViewerMacOSX::generateSerialNumber()
diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h
index cbf7e6c2095485b7fdc61bbe1240a5c3f2fad09a..3d7bb555566664d5fa44e78d72d4d24111e2ecfd 100644
--- a/indra/newview/llappviewermacosx.h
+++ b/indra/newview/llappviewermacosx.h
@@ -55,7 +55,6 @@ class LLAppViewerMacOSX : public LLAppViewer
 protected:
 	virtual bool restoreErrorTrap();
 	virtual void handleCrashReporting(bool reportFreeze); 
-	virtual void handleSyncCrashTrace();
 
 	std::string generateSerialNumber();
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 60a6d2f072be002643486eb135a88033178e8155..e3ef04d03d6cea04c2dbe90f4f17df1d5f35cccb 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -57,8 +57,6 @@
 #include "llweb.h"
 #include "llsecondlifeurls.h"
 
-#include "llwindebug.h"
-
 #include "llviewernetwork.h"
 #include "llmd5.h"
 #include "llfindlocale.h"
@@ -81,51 +79,6 @@ extern "C" {
 
 const std::string LLAppViewerWin32::sWindowClass = "Second Life";
 
-LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
-{
-    // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
-	//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
-    // *TODO: Translate the signals/exceptions into cross-platform stuff
-	// Windows implementation
-    _tprintf( _T("Entering Windows Exception Handler...\n") );
-	llinfos << "Entering Windows Exception Handler..." << llendl;
-
-	// Make sure the user sees something to indicate that the app crashed.
-	LONG retval;
-
-	if (LLApp::isError())
-	{
-	    _tprintf( _T("Got another fatal signal while in the error handler, die now!\n") );
-		llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
-
-		retval = EXCEPTION_EXECUTE_HANDLER;
-		return retval;
-	}
-
-	// Generate a minidump if we can.
-	// Before we wake the error thread...
-	// Which will start the crash reporting.
-	LLWinDebug::generateCrashStacks(exception_infop);
-	
-	// Flag status to error, so thread_error starts its work
-	LLApp::setError();
-
-	// Block in the exception handler until the app has stopped
-	// This is pretty sketchy, but appears to work just fine
-	while (!LLApp::isStopped())
-	{
-		ms_sleep(10);
-	}
-
-	//
-	// At this point, we always want to exit the app.  There's no graceful
-	// recovery for an unhandled exception.
-	// 
-	// Just kill the process.
-	retval = EXCEPTION_EXECUTE_HANDLER;	
-	return retval;
-}
-
 // Create app mutex creates a unique global windows object. 
 // If the object can be created it returns true, otherwise
 // it returns false. The false result can be used to determine 
@@ -191,8 +144,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 	gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
 
 	LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
-
-	LLWinDebug::initExceptionHandler(viewer_windows_exception_handler); 
 	
 	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
 
@@ -405,12 +356,6 @@ bool LLAppViewerWin32::cleanup()
 
 bool LLAppViewerWin32::initLogging()
 {
-	// Remove the crash stack log from previous executions.
-	// Since we've started logging a new instance of the app, we can assume 
-	// *NOTE: This should happen before the we send a 'previous instance froze'
-	// crash report, but it must happen after we initialize the DirUtil.
-	LLWinDebug::clearCrashStacks();
-
 	return LLAppViewer::initLogging();
 }
 
@@ -529,13 +474,9 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
 }
 
 bool LLAppViewerWin32::restoreErrorTrap()
-{
-	return LLWinDebug::checkExceptionHandler();
-}
-
-void LLAppViewerWin32::handleSyncCrashTrace()
-{
-	// do nothing
+{	
+	return true;
+	//return LLWinDebug::checkExceptionHandler();
 }
 
 void LLAppViewerWin32::handleCrashReporting(bool reportFreeze)
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 13454edeec237b2fbc12da95496243bafd20c6ee..52dcc583a4995637b80f7e30e0881b7415b23a52 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -57,7 +57,6 @@ class LLAppViewerWin32 : public LLAppViewer
 
 	virtual bool restoreErrorTrap();
 	virtual void handleCrashReporting(bool reportFreeze); 
-	virtual void handleSyncCrashTrace();
 
 	virtual bool sendURLToOtherInstance(const std::string& url);
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index e51e6363dd0567e2ecf179b82fe48ff74dc54bf1..35e86b75e71abc5206ee23b9beda33c3bd162861 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -199,7 +199,6 @@
 #include "llstartuplistener.h"
 
 #if LL_WINDOWS
-#include "llwindebug.h"
 #include "lldxhardware.h"
 #endif
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 5836aff4e759a17e9988d355dc8ed99bf4d4ecda..41aa80f40de4fd74533c211a774464d3dfc325f6 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -109,10 +109,6 @@
 #include <boost/algorithm/string/split.hpp> //
 #include <boost/regex.hpp>
 
-#if LL_WINDOWS // For Windows specific error handler
-#include "llwindebug.h"	// For the invalid message handler
-#endif
-
 #include "llnotificationmanager.h" //
 
 #if LL_MSVC
diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp
deleted file mode 100644
index 59bc9dc62b9ba2041b31129fae98ae8115bd0e47..0000000000000000000000000000000000000000
--- a/indra/newview/llwindebug.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/** 
- * @file llwindebug.cpp
- * @brief Windows debugging functions
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- * 
- * Copyright (c) 2004-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include <tchar.h>
-#include <tlhelp32.h>
-#include "llwindebug.h"
-#include "llviewercontrol.h"
-#include "lldir.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-
-#pragma warning(disable: 4200)	//nonstandard extension used : zero-sized array in struct/union
-#pragma warning(disable: 4100)	//unreferenced formal parameter
-
-
-/*
-LLSD Block for Windows Dump Information
-<llsd>
-  <map>
-    <key>Platform</key>
-    <string></string>
-    <key>Process</key>
-    <string></string>
-    <key>Module</key>
-    <string></string>
-    <key>DateModified</key>
-    <string></string>
-    <key>ExceptionCode</key>
-    <string></string>
-    <key>ExceptionRead/WriteAddress</key>
-    <string></string>
-    <key>Instruction</key>
-    <string></string>
-    <key>Registers</key>
-    <map>
-      <!-- Continued for all registers -->
-      <key>EIP</key>
-      <string>...</string>
-      <!-- ... -->
-    </map>
-    <key>Call Stack</key>
-    <array>
-      <!-- One map per stack frame -->
-      <map>
-	<key>ModuleName</key>
-	<string></string>
-	<key>ModuleBaseAddress</key>
-	<string></string>
-	<key>ModuleOffsetAddress</key>
-	<string></string>
-	<key>Parameters</key>
-	<array>
-	  <string></string>
-	</array>
-      </map>
-      <!-- ... -->
-    </array>
-  </map>
-</llsd>
-
-*/
-
-
-extern void (*gCrashCallback)(void);
-
-// based on dbghelp.h
-typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
-									CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
-									CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
-									CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
-									);
-
-MINIDUMPWRITEDUMP f_mdwp = NULL;
-
-#undef UNICODE
-
-static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL;
-
-HMODULE	hDbgHelp;
-
-// Tool Help functions.
-typedef	HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
-typedef	BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-typedef	BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
-
-CREATE_TOOL_HELP32_SNAPSHOT	CreateToolhelp32Snapshot_;
-MODULE32_FIRST	Module32First_;
-MODULE32_NEST	Module32Next_;
-
-#define	DUMP_SIZE_MAX	8000	//max size of our dump
-#define	CALL_TRACE_MAX	((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))	//max number of traced calls
-#define	NL				L"\r\n"	//new line
-
-
-typedef struct STACK
-{
-	STACK *	Ebp;
-	PBYTE	Ret_Addr;
-	DWORD	Param[0];
-} STACK, * PSTACK;
-
-BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr);
-void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, 
-						   const CONTEXT* context_record, 
-						   LLSD& info);
-
-void printError( CHAR* msg )
-{
-  DWORD eNum;
-  TCHAR sysMsg[256];
-  TCHAR* p;
-
-  eNum = GetLastError( );
-  FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-         NULL, eNum,
-         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
-         sysMsg, 256, NULL );
-
-  // Trim the end of the line and terminate it with a null
-  p = sysMsg;
-  while( ( *p > 31 ) || ( *p == 9 ) )
-    ++p;
-  do { *p-- = 0; } while( ( p >= sysMsg ) &&
-                          ( ( *p == '.' ) || ( *p < 33 ) ) );
-
-  // Display the message
-  printf( "\n  WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg );
-}
-
-BOOL GetProcessThreadIDs(DWORD process_id, std::vector<DWORD>& thread_ids) 
-{ 
-  HANDLE hThreadSnap = INVALID_HANDLE_VALUE; 
-  THREADENTRY32 te32; 
- 
-  // Take a snapshot of all running threads  
-  hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 
-  if( hThreadSnap == INVALID_HANDLE_VALUE ) 
-    return( FALSE ); 
- 
-  // Fill in the size of the structure before using it. 
-  te32.dwSize = sizeof(THREADENTRY32 ); 
- 
-  // Retrieve information about the first thread,
-  // and exit if unsuccessful
-  if( !Thread32First( hThreadSnap, &te32 ) ) 
-  {
-    printError( "Thread32First" );  // Show cause of failure
-    CloseHandle( hThreadSnap );     // Must clean up the snapshot object!
-    return( FALSE );
-  }
-
-  // Now walk the thread list of the system,
-  // and display information about each thread
-  // associated with the specified process
-  do 
-  { 
-    if( te32.th32OwnerProcessID == process_id )
-    {
-      thread_ids.push_back(te32.th32ThreadID); 
-    }
-  } while( Thread32Next(hThreadSnap, &te32 ) ); 
-
-//  Don't forget to clean up the snapshot object.
-  CloseHandle( hThreadSnap );
-  return( TRUE );
-}
-
-BOOL GetThreadCallStack(DWORD thread_id, LLSD& info)
-{
-    if(GetCurrentThreadId() == thread_id)
-    {
-        // Early exit for the current thread.
-        // Suspending the current thread would be a bad idea.
-        // Plus you can't retrieve a valid current thread context.
-        return false;
-    }
-
-    HANDLE thread_handle = INVALID_HANDLE_VALUE; 
-    thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
-    if(INVALID_HANDLE_VALUE == thread_handle)
-    {
-        return FALSE;
-    }
-
-    BOOL result = false;
-    if(-1 != SuspendThread(thread_handle))
-    {
-        CONTEXT context_struct;
-        context_struct.ContextFlags = CONTEXT_FULL;
-        if(GetThreadContext(thread_handle, &context_struct))
-        {
-            Get_Call_Stack(NULL, &context_struct, info);
-            result = true;
-        }
-        ResumeThread(thread_handle);
-    }
-    else
-    {
-        // Couldn't suspend thread.
-    }
-
-    CloseHandle(thread_handle);
-    return result;
-}
-
-
-//Windows Call Stack Construction idea from 
-//http://www.codeproject.com/tools/minidump.asp
-
-//****************************************************************************************
-BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr)
-//****************************************************************************************
-// Find module by Ret_Addr (address in the module).
-// Return Module_Name (full path) and Module_Addr (start address).
-// Return TRUE if found.
-{
-	MODULEENTRY32	M = {sizeof(M)};
-	HANDLE	hSnapshot;
-
-	bool found = false;
-	
-	if (CreateToolhelp32Snapshot_)
-	{
-		hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);
-		
-		if ((hSnapshot != INVALID_HANDLE_VALUE) &&
-			Module32First_(hSnapshot, &M))
-		{
-			do
-			{
-				if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)
-				{
-					lstrcpyn(Module_Name, M.szExePath, MAX_PATH);
-					Module_Addr = M.modBaseAddr;
-					found = true;
-					break;
-				}
-			} while (Module32Next_(hSnapshot, &M));
-		}
-
-		CloseHandle(hSnapshot);
-	}
-
-	return found;
-} //Get_Module_By_Ret_Addr
-
-bool has_valid_call_before(PDWORD cur_stack_loc)
-{
-	PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1);
-	PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2);
-	PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5);
-	PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6);
-
-	// make sure we can read it
-	if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE)))
-	{
-		return false;
-	}
-
-	// check for 9a + 4 bytes
-	if(*p_fifth_byte == 0x9A)
-	{
-		return true;
-	}
-
-	// Check for E8 + 4 bytes and last byte is 00 or FF
-	if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF))
-	{
-		return true;
-	}
-	
-	// the other is six bytes
-	if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF)
-	{
-		return true;
-	}
-
-	return false;
-}
-
-PBYTE get_valid_frame(PBYTE esp)
-{
-	PDWORD cur_stack_loc = NULL;
-	const int max_search = 400;
-	WCHAR	module_name[MAX_PATH];
-	PBYTE	module_addr = 0;
-
-	// round to highest multiple of four
-	esp = (esp + (4 - ((int)esp % 4)) % 4);
-
-	// scroll through stack a few hundred places.
-	for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1)
-	{
-		// if you can read the pointer,
-		if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD)))
-		{
-			continue;
-		}
-
-		//  check if it's in a module
-		if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr))
-		{
-			continue;
-		}
-
-		// check if the code before the instruction ptr is a call 
-		if(!has_valid_call_before(cur_stack_loc))
-		{
-			continue;
-		}
-		
-		// if these all pass, return that ebp, otherwise continue till we're dead
-		return (PBYTE)(cur_stack_loc - 1);
-	}
-
-	return NULL;
-}
-
-bool shouldUseStackWalker(PSTACK Ebp, int max_depth)
-{
-	WCHAR	Module_Name[MAX_PATH];
-	PBYTE	Module_Addr = 0;
-	int depth = 0;
-
-	while (depth < max_depth) 
-	{
-		if (IsBadReadPtr(Ebp, sizeof(PSTACK)) || 
-			IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) ||
-			Ebp->Ebp < Ebp ||
-			Ebp->Ebp - Ebp > 0xFFFFFF ||
-			IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) ||
-			!Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr))
-		{
-			return true;
-		}
-		depth++;
-		Ebp = Ebp->Ebp;
-	}
-
-	return false;
-}
-
-//******************************************************************
-void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, 
-						   const CONTEXT* context_record, 
-						   LLSD& info)
-//******************************************************************
-// Fill Str with call stack info.
-// pException can be either GetExceptionInformation() or NULL.
-// If pException = NULL - get current call stack.
-{
-	LPWSTR	Module_Name = new WCHAR[MAX_PATH];
-	PBYTE	Module_Addr = 0;
-	LLSD params;
-	PBYTE	Esp = NULL;
-	LLSD tmp_info;
-
-	bool fake_frame = false;
-	bool ebp_used = false;
-	const int HEURISTIC_MAX_WALK = 20;
-	int heuristic_walk_i = 0;
-	int Ret_Addr_I = 0;
-
-	STACK	Stack = {0, 0};
-	PSTACK	Ebp;
-
-	if (exception_record && context_record)		//fake frame for exception address
-	{
-		Stack.Ebp = (PSTACK)(context_record->Ebp);
-		Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress;
-		Ebp = &Stack;
-		Esp = (PBYTE) context_record->Esp;
-		fake_frame = true;
-	}
-	else if(context_record)
-	{
-        Ebp = (PSTACK)(context_record->Ebp);
-		Esp = (PBYTE)(context_record->Esp);
-	}
-	else
-	{
-		Ebp = (PSTACK)&exception_record - 1;	//frame addr of Get_Call_Stack()
-		Esp = (PBYTE)&exception_record;
-
-		// Skip frame of Get_Call_Stack().
-		if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
-			Ebp = Ebp->Ebp;		//caller ebp
-	}
-
-	// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.
-	// Break trace on wrong stack frame.
-	for (Ret_Addr_I = 0;
-		heuristic_walk_i < HEURISTIC_MAX_WALK && 
-		Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
-		Ret_Addr_I++)
-	{
-		// If module with Ebp->Ret_Addr found.
-		if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr))
-		{
-			// Save module's address and full path.
-			tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name);
-			tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr;
-			tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr);
-
-			// Save 5 params of the call. We don't know the real number of params.
-			if (fake_frame && !Ret_Addr_I)	//fake frame for exception address
-				params[0] = "Exception Offset";
-			else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))
-			{
-				for(int j = 0; j < 5; ++j)
-				{
-					params[j] = (int)Ebp->Param[j];
-				}
-			}
-			tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params;
-		}
-
-		tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr;
-
-		// get ready for next frame
-		// Set ESP to just after return address.  Not the real esp, but just enough after the return address
-		if(!fake_frame) {
-			Esp = (PBYTE)Ebp + 8;
-		} 
-		else
-		{
-			fake_frame = false;
-		}
-
-		// is next ebp valid?
-		// only run if we've never found a good ebp
-		// and make sure the one after is valid as well
-		if(	!ebp_used && 
-			shouldUseStackWalker(Ebp, 2))
-		{
-			heuristic_walk_i++;
-			PBYTE new_ebp = get_valid_frame(Esp);
-			if (new_ebp != NULL)
-			{
-				Ebp = (PSTACK)new_ebp;
-			}
-		}
-		else
-		{
-			ebp_used = true;
-			Ebp = Ebp->Ebp;
-		}
-	}
-/* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer
-	// Now go back through and edit out heuristic stacks that could very well be bogus.
-	// Leave the top and the last 3 stack chosen by the heuristic, however.
-	if(heuristic_walk_i > 2)
-	{
-		info["CallStack"][0] = tmp_info["CallStack"][0];
-		std::string ttest = info["CallStack"][0]["ModuleName"];
-		for(int cur_frame = 1; 
-			(cur_frame + heuristic_walk_i - 2 < Ret_Addr_I); 
-			++cur_frame)
-		{
-			// edit out the middle heuristic found frames
-			info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2];
-		}
-	}
-	else
-	{
-		info = tmp_info;
-	}
-*/
-	info = tmp_info;
-	info["HeuristicWalkI"] = heuristic_walk_i;
-	info["EbpUsed"] = ebp_used;
-
-} //Get_Call_Stack
-
-//***********************************
-void WINAPI Get_Version_Str(LLSD& info)
-//***********************************
-// Fill Str with Windows version.
-{
-	OSVERSIONINFOEX	V = {sizeof(OSVERSIONINFOEX)};	//EX for NT 5.0 and later
-
-	if (!GetVersionEx((POSVERSIONINFO)&V))
-	{
-		ZeroMemory(&V, sizeof(V));
-		V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-		GetVersionEx((POSVERSIONINFO)&V);
-	}
-
-	if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
-		V.dwBuildNumber = LOWORD(V.dwBuildNumber);	//for 9x HIWORD(dwBuildNumber) = 0x04xx
-
-	info["Platform"] = llformat("Windows:  %d.%d.%d, SP %d.%d, Product Type %d",	//SP - service pack, Product Type - VER_NT_WORKSTATION,...
-		V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType);
-} //Get_Version_Str
-
-//*************************************************************
-LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)
-//*************************************************************
-// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.
-{
-	LLSD info;
-	LPWSTR		Str;
-	int			Str_Len;
-//	int			i;
-	LPWSTR		Module_Name = new WCHAR[MAX_PATH];
-	PBYTE		Module_Addr;
-	HANDLE		hFile;
-	FILETIME	Last_Write_Time;
-	FILETIME	Local_File_Time;
-	SYSTEMTIME	T;
-
-	Str = new WCHAR[DUMP_SIZE_MAX];
-	Str_Len = 0;
-	if (!Str)
-		return NULL;
-	
-	Get_Version_Str(info);
-	
-	GetModuleFileName(NULL, Str, MAX_PATH);
-	info["Process"] = ll_convert_wide_to_string(Str);
-	info["ThreadID"] = (S32)GetCurrentThreadId();
-
-	// If exception occurred.
-	if (pException)
-	{
-		EXCEPTION_RECORD &	E = *pException->ExceptionRecord;
-		CONTEXT &			C = *pException->ContextRecord;
-
-		// If module with E.ExceptionAddress found - save its path and date.
-		if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))
-		{
-			info["Module"] = ll_convert_wide_to_string(Module_Name);
-
-			if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
-				FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
-			{
-				if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))
-				{
-					FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);
-					FileTimeToSystemTime(&Local_File_Time, &T);
-
-					info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear);
-				}
-				CloseHandle(hFile);
-			}
-		}
-		else
-		{
-			info["ExceptionAddr"] = (int)E.ExceptionAddress;
-		}
-		
-		info["ExceptionCode"] = (int)E.ExceptionCode;
-		
-		/*
-		//TODO: Fix this
-		if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
-		{
-			// Access violation type - Write/Read.
-			LLSD exception_info;
-			exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read";
-			exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]);
-			info["Exception Information"] = exception_info;
-		}
-		*/
-
-		
-		// Save instruction that caused exception.
-		/*
-		std::string str;
-		for (i = 0; i < 16; i++)
-			str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]);
-		info["Instruction"] = str;
-		*/
-		LLSD registers;
-		registers["EAX"] = (int)C.Eax;
-		registers["EBX"] = (int)C.Ebx;
-		registers["ECX"] = (int)C.Ecx;
-		registers["EDX"] = (int)C.Edx;
-		registers["ESI"] = (int)C.Esi;
-		registers["EDI"] = (int)C.Edi;
-		registers["ESP"] = (int)C.Esp;
-		registers["EBP"] = (int)C.Ebp;
-		registers["EIP"] = (int)C.Eip;
-		registers["EFlags"] = (int)C.EFlags;
-		info["Registers"] = registers;
-	} //if (pException)
-	
-	// Save call stack info.
-	Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info);
-
-	return info;
-} //Get_Exception_Info
-
-#define UNICODE
-
-
-class LLMemoryReserve {
-public:
-	LLMemoryReserve();
-	~LLMemoryReserve();
-	void reserve();
-	void release();
-protected:
-	unsigned char *mReserve;
-	static const size_t MEMORY_RESERVATION_SIZE;
-};
-
-LLMemoryReserve::LLMemoryReserve() :
-	mReserve(NULL)
-{
-};
-
-LLMemoryReserve::~LLMemoryReserve()
-{
-	release();
-}
-
-// I dunno - this just seemed like a pretty good value.
-const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;
-
-void LLMemoryReserve::reserve()
-{
-	if(NULL == mReserve)
-		mReserve = new unsigned char[MEMORY_RESERVATION_SIZE];
-};
-
-void LLMemoryReserve::release()
-{
-	delete [] mReserve;
-	mReserve = NULL;
-};
-
-static LLMemoryReserve gEmergencyMemoryReserve;
-
-#ifndef _M_IX86
-	#error "The following code only works for x86!"
-#endif
-LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(
-	LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
-{
-	if(lpTopLevelExceptionFilter ==  gFilterFunc)
-		return gFilterFunc;
-
-	llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl;
-	LLSD cs_info;
-	Get_Call_Stack(NULL, NULL, cs_info);
-	
-	if(cs_info.has("CallStack") && cs_info["CallStack"].isArray())
-	{
-		LLSD cs = cs_info["CallStack"];
-		for(LLSD::array_iterator i = cs.beginArray(); 
-			i != cs.endArray(); 
-			++i)
-		{
-			llinfos << "Module: " << (*i)["ModuleName"] << llendl;
-		}
-	}
-	
-	return gFilterFunc;
-}
-
-BOOL PreventSetUnhandledExceptionFilter()
-{
-	HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
-	if (hKernel32 == NULL) 
-		return FALSE;
-
-	void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
-	if(pOrgEntry == NULL) 
-		return FALSE;
-	
-	unsigned char newJump[ 100 ];
-	DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
-	dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
-	void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
-	DWORD dwNewEntryAddr = (DWORD) pNewFunc;
-	DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
-
-	newJump[ 0 ] = 0xE9;  // JMP absolute
-	memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
-	SIZE_T bytesWritten;
-	BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
-	pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
-	return bRet;
-}
-
-// static
-void  LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func)
-{
-
-	static bool s_first_run = true;
-	// Load the dbghelp dll now, instead of waiting for the crash.
-	// Less potential for stack mangling
-
-	if (s_first_run)
-	{
-		// First, try loading from the directory that the app resides in.
-		std::string local_dll_name = gDirUtilp->findFile("dbghelp.dll", gDirUtilp->getWorkingDir(), gDirUtilp->getExecutableDir());
-
-		HMODULE hDll = NULL;
-		hDll = LoadLibraryA(local_dll_name.c_str());
-		if (!hDll)
-		{
-			hDll = LoadLibrary(L"dbghelp.dll");
-		}
-
-		if (!hDll)
-		{
-			LL_WARNS("AppInit") << "Couldn't find dbghelp.dll!" << LL_ENDL;
-		}
-		else
-		{
-			f_mdwp = (MINIDUMPWRITEDUMP) GetProcAddress(hDll, "MiniDumpWriteDump");
-
-			if (!f_mdwp)
-			{
-				FreeLibrary(hDll);
-				hDll = NULL;
-			}
-		}
-
-		gEmergencyMemoryReserve.reserve();
-
-		s_first_run = false;
-	}
-
-	// Try to get Tool Help library functions.
-	HMODULE hKernel32;
-	hKernel32 = GetModuleHandle(_T("KERNEL32"));
-	CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
-	Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW");
-	Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW");
-
-    LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
-	prev_filter = SetUnhandledExceptionFilter(filter_func);
-
-	// *REMOVE:Mani
-	//PreventSetUnhandledExceptionFilter();
-
-	if(prev_filter != gFilterFunc)
-	{
-		LL_WARNS("AppInit") 
-			<< "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL;
-	}
-	
-	gFilterFunc = filter_func;
-}
-
-bool LLWinDebug::checkExceptionHandler()
-{
-	bool ok = true;
-	LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
-	prev_filter = SetUnhandledExceptionFilter(gFilterFunc);
-
-	if (prev_filter != gFilterFunc)
-	{
-		LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL;
-		ok = false;
-	}
-
-	if (prev_filter == NULL)
-	{
-		ok = FALSE;
-		if (gFilterFunc == NULL)
-		{
-			LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
-		}
-		else
-		{
-			LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL;
-		}
-	}
-
-	return ok;
-}
-
-void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename)
-{
-	if(f_mdwp == NULL || gDirUtilp == NULL) 
-	{
-		return;
-		//write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n");
-	}
-	else
-	{
-		std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename);
-
-		HANDLE hFile = CreateFileA(dump_path.c_str(),
-									GENERIC_WRITE,
-									FILE_SHARE_WRITE,
-									NULL,
-									CREATE_ALWAYS,
-									FILE_ATTRIBUTE_NORMAL,
-									NULL);
-
-		if (hFile != INVALID_HANDLE_VALUE)
-		{
-			// Write the dump, ignoring the return value
-			f_mdwp(GetCurrentProcess(),
-					GetCurrentProcessId(),
-					hFile,
-					type,
-					ExInfop,
-					NULL,
-					NULL);
-
-			CloseHandle(hFile);
-		}
-
-	}
-}
-
-// static
-void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop)
-{
-	// *NOTE:Mani - This method is no longer the exception handler.
-	// Its called from viewer_windows_exception_handler() and other places.
-
-	// 
-	// Let go of a bunch of reserved memory to give library calls etc
-	// a chance to execute normally in the case that we ran out of
-	// memory.
-	//
-	LLSD info;
-	std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
-												"SecondLifeException");
-	std::string log_path = dump_path + ".log";
-
-	if (exception_infop)
-	{
-		// Since there is exception info... Release the hounds.
-		gEmergencyMemoryReserve.release();
-
-		if(gSavedSettings.getControl("SaveMinidump").notNull() && gSavedSettings.getBOOL("SaveMinidump"))
-		{
-			_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
-
-			ExInfo.ThreadId = ::GetCurrentThreadId();
-			ExInfo.ExceptionPointers = exception_infop;
-			ExInfo.ClientPointers = NULL;
-
-			writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp");
-			writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp");
-		}
-
-		info = Get_Exception_Info(exception_infop);
-	}
-
-	LLSD threads;
-    std::vector<DWORD> thread_ids;
-    GetProcessThreadIDs(GetCurrentProcessId(), thread_ids);
-
-    for(std::vector<DWORD>::iterator th_itr = thread_ids.begin(); 
-                th_itr != thread_ids.end();
-                ++th_itr)
-    {
-        LLSD thread_info;
-        if(*th_itr != GetCurrentThreadId())
-        {
-            GetThreadCallStack(*th_itr, thread_info);
-        }
-
-        if(thread_info)
-        {
-            threads[llformat("ID %d", *th_itr)] = thread_info;
-        }
-    }
-
-    info["Threads"] = threads;
-
-	llofstream out_file(log_path);
-	LLSDSerialize::toPrettyXML(info, out_file);
-	out_file.close();
-}
-
-void LLWinDebug::clearCrashStacks()
-{
-	LLSD info;
-	std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException.log");
-	LLFile::remove(dump_path);
-}
diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h
deleted file mode 100644
index f4a6a2d54d97c399cc85763146015ae44b1408af..0000000000000000000000000000000000000000
--- a/indra/newview/llwindebug.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/** 
- * @file llwindebug.h
- * @brief LLWinDebug class header file
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- * 
- * Copyright (c) 2004-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLWINDEBUG_H
-#define LL_LLWINDEBUG_H
-
-#include "stdtypes.h"
-#include <dbghelp.h>
-
-class LLWinDebug
-{
-public:
-
-	/** 
-	* @brief initialize the llwindebug exception filter callback
-	* 
-	* Hand a windows unhandled exception filter to LLWinDebug
-	* This method should only be called to change the
-	* exception filter used by llwindebug.
-	*
-	* Setting filter_func to NULL will clear any custom filters.
-	**/
-	static void initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func);
-
-	/** 
-	* @brief check the status of the exception filter.
-	*
-	* Resets unhandled exception filter to the filter specified 
-	* w/ initExceptionFilter). 
-	* Returns false if the exception filter was modified.
-	*
-	* *NOTE:Mani In the past mozlib has been accused of
-	* overriding the exception filter. If the mozlib filter 
-	* is required, perhaps we can chain calls from our 
-	* filter to mozlib's.
-	**/
-	static bool checkExceptionHandler();
-
-	static void generateCrashStacks(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL);
-	static void clearCrashStacks(); // Delete the crash stack file(s).
-
-	static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename);
-private:
-};
-
-#endif // LL_LLWINDEBUG_H
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 8c089c0b794bf07358bbae4a24f49697dd231f88..8d2525dd2643de6d14293e01f63bf941c318644a 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -41,9 +41,12 @@
 
 class ViewerManifest(LLManifest):
     def is_packaging_viewer(self):
-        # This is overridden by the WindowsManifest sub-class,
-        # which has different behavior if it is not packaging the viewer.
-        return True
+        # Some commands, files will only be included
+        # if we are packaging the viewer on windows.
+        # This manifest is also used to copy
+        # files during the build (see copy_w_viewer_manifest
+        # and copy_l_viewer_manifest targets)
+        return 'package' in self.args['actions']
     
     def construct(self):
         super(ViewerManifest, self).construct()
@@ -175,13 +178,6 @@ def final_exe(self):
         else:
             return ''.join(self.channel().split()) + '.exe'
 
-    def is_packaging_viewer(self):
-        # Some commands, files will only be included
-        # if we are packaging the viewer on windows.
-        # This manifest is also used to copy
-        # files during the build.
-        return 'package' in self.args['actions']
-
     def test_msvcrt_and_copy_action(self, src, dst):
         # This is used to test a dll manifest.
         # It is used as a temporary override during the construct method
@@ -641,7 +637,9 @@ def construct(self):
                 if dylibs["llcommon"]:
                     for libfile in ("libapr-1.0.3.7.dylib",
                                     "libaprutil-1.0.3.8.dylib",
-                                    "libexpat.0.5.0.dylib"):
+                                    "libexpat.0.5.0.dylib",
+                                    "libexception_handler.dylib",
+                                    ):
                         self.path(os.path.join(libdir, libfile), libfile)
 
                 #libfmodwrapper.dylib
@@ -662,7 +660,9 @@ def construct(self):
                     for libfile in ("libllcommon.dylib",
                                     "libapr-1.0.3.7.dylib",
                                     "libaprutil-1.0.3.8.dylib",
-                                    "libexpat.0.5.0.dylib"):
+                                    "libexpat.0.5.0.dylib",
+                                    "libexception_handler.dylib",
+                                    ):
                         target_lib = os.path.join('../../..', libfile)
                         self.run_command("ln -sf %(target)r %(link)r" % 
                                          {'target': target_lib,
@@ -893,6 +893,7 @@ def construct(self):
         if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
             self.path("libapr-1.so.0")
             self.path("libaprutil-1.so.0")
+            self.path("libbreakpad_client.so.0.0.0", "libbreakpad_client.so.0")
             self.path("libdb-4.2.so")
             self.path("libcrypto.so.0.9.7")
             self.path("libexpat.so.1")
@@ -930,7 +931,7 @@ def construct(self):
                     self.path("libvivoxplatform.so")
                     self.end_prefix("lib")
 
-        if self.args['buildtype'].lower() == 'release':
+        if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
             print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
             self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
 
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index c9e01c8418ad590ca10895a203f70454b270dd66..288423129915f5d14f9876688d404e0878239f52 100644
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ b/indra/win_crash_logger/llcrashloggerwindows.cpp
@@ -299,7 +299,6 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
 	// At this point we're responsive enough the user could click the close button
 	SetCursor(gCursorArrow);
 	mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();
-	mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log");
 }
 
 bool LLCrashLoggerWindows::mainLoop()
diff --git a/install.xml b/install.xml
index ccebe2fe50064546e61d30b7c0bbe05db863894b..fb6b6fa803c10dbf2a15b15d2ff274f5490706bc 100644
--- a/install.xml
+++ b/install.xml
@@ -583,6 +583,39 @@
           </map>
         </map>
       </map>
+      <key>google_breakpad</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (c) 2006, Google Inc.</string>
+        <key>description</key>
+        <string>An open-source multi-platform crash reporting system </string>
+        <key>license</key>
+        <string>bsd</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>ced4010b59f1a579caa7fe3c18512499</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-darwin-20100528a.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>29c3e7dad60bbf02c811786436d99523</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-linux-20100521b.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>0859d47242990125f17eaab30bece2ff</string>
+            <key>url</key>
+            <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/google_breakpad-0.0.0-rev599-windows-20100524.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>googlemock</key>
       <map>
         <key>copyright</key>