summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrad kittenbrink <brad@lindenlab.com>2010-06-01 10:06:40 -0700
committerbrad kittenbrink <brad@lindenlab.com>2010-06-01 10:06:40 -0700
commit592ee60a1367f37e8bc02d9e5ffcc593d01d92e3 (patch)
tree4deddc4bc53dcdaea3870e23940ced3387891812
parent4cc5c7d2a4511ffc65bf3b6b0b2e29beb5b0fed4 (diff)
parent648b55390709f832aac01b914ef4834e40c7b5f9 (diff)
Automated merge with http://hg.lindenlab.com/dessie/viewer-public
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake4
-rw-r--r--indra/cmake/GoogleBreakpad.cmake19
-rw-r--r--indra/linux_crash_logger/llcrashloggerlinux.cpp1
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llapp.cpp188
-rw-r--r--indra/llcommon/llapp.h25
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp67
-rw-r--r--indra/newview/CMakeLists.txt39
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/generate_breakpad_symbols.py78
-rw-r--r--indra/newview/llappviewer.cpp63
-rw-r--r--indra/newview/llappviewer.h2
-rw-r--r--indra/newview/llappviewerlinux.cpp226
-rw-r--r--indra/newview/llappviewerlinux.h1
-rw-r--r--indra/newview/llappviewermacosx.cpp37
-rw-r--r--indra/newview/llappviewermacosx.h1
-rw-r--r--indra/newview/llappviewerwin32.cpp65
-rw-r--r--indra/newview/llappviewerwin32.h1
-rw-r--r--indra/newview/llstartup.cpp1
-rw-r--r--indra/newview/llviewermessage.cpp4
-rw-r--r--indra/newview/llwindebug.cpp912
-rw-r--r--indra/newview/llwindebug.h75
-rwxr-xr-xindra/newview/viewer_manifest.py9
-rw-r--r--indra/win_crash_logger/llcrashloggerwindows.cpp1
-rw-r--r--install.xml33
25 files changed, 430 insertions, 1435 deletions
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index faf9da8b14..89422fbdb2 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 0000000000..8270c0fabb
--- /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 039b70ec4a..ce03ea0d6f 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 3c689930b8..2fcb04321c 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 6b2d1b7c20..eedec0b24e 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 e5b8edf9c3..fef05a7939 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -66,6 +66,10 @@ public:
};
#endif
+namespace google_breakpad {
+ class ExceptionHandler; // See exception_handler.h
+}
+
class LL_COMMON_API LLApp : public LLOptionInterface
{
friend class LLErrorThread;
@@ -227,8 +231,20 @@ public:
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 @@ protected:
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 @@ private:
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 c1022c1195..aa2ea17af9 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,23 +190,22 @@ void LLCrashLogger::gatherFiles()
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
}
-#if !LL_DARWIN
- if(mCrashInPreviousExec)
-#else
-#endif
- {
- // Replace the log file ext with .old, since the
- // instance that launched this process has overwritten
- // SecondLife.log
- std::string log_filename = mFileMap["SecondLifeLog"];
- log_filename.replace(log_filename.size() - 4, 4, ".old");
- mFileMap["SecondLifeLog"] = log_filename;
- }
+ // Replace the log file ext with .old, since the
+ // instance that launched this process has overwritten
+ // SecondLife.log
+ std::string log_filename = mFileMap["SecondLifeLog"];
+ log_filename.replace(log_filename.size() - 4, 4, ".old");
+ mFileMap["SecondLifeLog"] = log_filename;
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 +227,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...");
@@ -274,6 +253,28 @@ void LLCrashLogger::gatherFiles()
mCrashInfo[(*itr).first] = 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/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9ba44e787b..b145fbee1f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1062,7 +1062,6 @@ set(viewer_HEADER_FILES
llwearabletype.h
llweb.h
llwind.h
- llwindebug.h
llwlanimator.h
llwldaycycle.h
llwlparammanager.h
@@ -1136,12 +1135,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
@@ -1785,6 +1782,42 @@ 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-windows.breakpad.bz2")
+ set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME} SLPlugin.exe")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
+ 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-darwin.breakpad.bz2")
+ set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME} SLPlugin")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
+ 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-linux.breakpad.bz2")
+ set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin")
+ set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*")
+ 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
+ )
+ add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}")
+ add_dependencies(generate_breakpad_symbols viewer)
+ 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 c0be54a105..22c9c92349 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 0000000000..f281846918
--- /dev/null
+++ b/indra/newview/generate_breakpad_symbols.py
@@ -0,0 +1,78 @@
+#!/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 os
+import sys
+import subprocess
+import bz2
+
+def usage():
+ print >>sys.stderr, "usage: %s viewer_dir viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0]
+
+def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
+ # print "generate_breakpad_symbols: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+
+ def matches(f):
+ return f in viewer_exes or 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 out
+
+ out = bz2.BZ2File(viewer_symbol_file, 'w')
+
+ for symbols in map(dump_module, list_files()):
+ out.writelines(symbols)
+
+ out.close()
+
+ 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 deafb20af7..351c0cbae5 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().
@@ -1237,6 +1242,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)
@@ -2293,17 +2306,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;
//
@@ -2534,13 +2537,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;
@@ -2564,9 +2560,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
@@ -2598,6 +2598,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;
@@ -2675,10 +2681,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)
{
@@ -2691,8 +2693,6 @@ void LLAppViewer::handleViewerCrash()
// Call to pure virtual, handled by platform specific llappviewer instance.
pApp->handleCrashReporting();
-
-#endif //!LL_DARWIN
return;
}
@@ -3336,13 +3336,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"
@@ -3355,6 +3348,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 5acd6e11c4..0b862a92a1 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -92,9 +92,7 @@ public:
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 78b0f7ba83..78afdc8995 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 230c0dc24b..b17380d4d8 100644
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -68,7 +68,6 @@ protected:
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 0b5f18c330..1e66e55f3d 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 cbf7e6c209..3d7bb55556 100644
--- a/indra/newview/llappviewermacosx.h
+++ b/indra/newview/llappviewermacosx.h
@@ -55,7 +55,6 @@ public:
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 60a6d2f072..e3ef04d03d 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 13454edeec..52dcc583a4 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -57,7 +57,6 @@ protected:
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 6418551517..8021c71d3f 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 5836aff4e7..41aa80f40d 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 59bc9dc62b..0000000000
--- 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 f4a6a2d54d..0000000000
--- 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 2a966f4adf..dac1409aee 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -636,7 +636,9 @@ class DarwinManifest(ViewerManifest):
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
@@ -657,7 +659,9 @@ class DarwinManifest(ViewerManifest):
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,
@@ -888,6 +892,7 @@ class Linux_i686Manifest(LinuxManifest):
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")
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index c9e01c8418..2884231299 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 ccebe2fe50..fb6b6fa803 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>