diff options
author | brad kittenbrink <brad@lindenlab.com> | 2010-05-27 15:40:16 -0700 |
---|---|---|
committer | brad kittenbrink <brad@lindenlab.com> | 2010-05-27 15:40:16 -0700 |
commit | d9052212b5c575e31ddfe358c228e0ba9a7403ed (patch) | |
tree | 1670d0c29894ff18f8a48dcfab99877bddd11eaf /indra/llcommon | |
parent | 0c7fafb70425853df26c703969e7a1892de2374e (diff) | |
parent | 4e8d423cc5fae86c8273df5e7ea583a9e0475711 (diff) |
Merge of latest dessie/viewer-public with brad/viewer-public
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llcommon/llapp.cpp | 159 | ||||
-rw-r--r-- | indra/llcommon/llapp.h | 19 |
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 |