summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorbrad kittenbrink <brad@lindenlab.com>2010-05-27 15:40:16 -0700
committerbrad kittenbrink <brad@lindenlab.com>2010-05-27 15:40:16 -0700
commitd9052212b5c575e31ddfe358c228e0ba9a7403ed (patch)
tree1670d0c29894ff18f8a48dcfab99877bddd11eaf /indra/llcommon
parent0c7fafb70425853df26c703969e7a1892de2374e (diff)
parent4e8d423cc5fae86c8273df5e7ea583a9e0475711 (diff)
Merge of latest dessie/viewer-public with brad/viewer-public
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llapp.cpp159
-rw-r--r--indra/llcommon/llapp.h19
3 files changed, 140 insertions, 40 deletions
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..da14020f2b 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"
@@ -43,6 +45,8 @@
#include "llstl.h" // for DeletePointer()
#include "lleventtimer.h"
+#include "google_breakpad/exception_handler.h"
+
//
// Signal handling
//
@@ -51,11 +55,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 +96,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 +137,10 @@ void LLApp::commonCtor()
// Set the application to this instance.
sApplication = this;
-
+
+ mExceptionHandler = 0;
+
+ memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH);
}
LLApp::LLApp(LLErrorThread *error_thread) :
@@ -152,6 +169,8 @@ LLApp::~LLApp()
delete mThreadErrorp;
mThreadErrorp = NULL;
}
+
+ if(mExceptionHandler != 0) delete mExceptionHandler;
LLCommon::cleanupClass();
}
@@ -262,19 +281,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 +300,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 +333,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 +345,6 @@ void LLApp::runErrorHandler()
LLApp::setStopped();
}
-
// static
void LLApp::setStatus(EAppStatus status)
{
@@ -348,15 +355,14 @@ 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::writeMiniDump()
+{
+ mExceptionHandler->WriteMinidump();
+}
// static
void LLApp::setQuitting()
@@ -587,6 +593,7 @@ void setup_signals()
// Asynchronous signals that result in core
sigaction(SIGQUIT, &act, NULL);
+
}
void clear_signals()
@@ -765,4 +772,84 @@ 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()->minidump_path;
+ S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
+ strncpy(path, dump_dir, remaining);
+ remaining -= dirPathLength;
+ path += dirPathLength;
+ strncpy(path, minidump_id, remaining);
+ remaining -= idLength;
+ path += idLength;
+ strncpy(path, ".dmp", remaining);
+
+ llinfos << "generated minidump: " << LLApp::instance()->minidump_path << 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()->minidump_path;
+ 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 = 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()->minidump_path << 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..a6294a5e1a 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,13 @@ 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.
//@}
+
+ //
+ // Write out a Google Breakpad minidump file.
+ //
+ void writeMiniDump();
#if !LL_WINDOWS
//
@@ -265,6 +274,9 @@ public:
typedef std::map<std::string, std::string> string_map;
string_map mOptionMap; // Contains all command-line options and arguments in a map
+ // Contains the path to minidump file after a crash.
+ static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
+ char minidump_path[MAX_MINDUMP_PATH_LENGTH];
protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
@@ -286,15 +298,12 @@ 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.
// *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 +324,8 @@ private:
private:
// the static application instance if it was created.
static LLApp* sApplication;
+
+ google_breakpad::ExceptionHandler * mExceptionHandler;
#if !LL_WINDOWS