diff options
Diffstat (limited to 'indra/llcommon/llapp.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/llcommon/llapp.cpp | 580 |
1 files changed, 431 insertions, 149 deletions
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 6b2d1b7c20..5a40845e7d 100644..100755 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -2,37 +2,40 @@ * @file llapp.cpp * @brief Implementation of the LLApp class. * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" + #include "llapp.h" +#include <cstdlib> + +#ifdef LL_DARWIN +#include <sys/types.h> +#include <unistd.h> +#include <sys/sysctl.h> +#endif + #include "llcommon.h" #include "llapr.h" #include "llerrorcontrol.h" @@ -41,7 +44,10 @@ #include "lllivefile.h" #include "llmemory.h" #include "llstl.h" // for DeletePointer() +#include "llstring.h" #include "lleventtimer.h" +#include "google_breakpad/exception_handler.h" +#include "stringize.h" // // Signal handling @@ -49,13 +55,34 @@ // Windows uses structured exceptions, so it's handled a bit differently. // #if LL_WINDOWS +#include "windows.h" + 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 *); + +#if LL_LINUX +#include "google_breakpad/minidump_descriptor.h" +static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, + void* context, + bool succeeded); +#else +// 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); +#endif + # if LL_DARWIN /* OSX doesn't support SIGRT* */ S32 LL_SMACKDOWN_SIGNAL = SIGUSR1; @@ -74,6 +101,10 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2; // the static application instance LLApp* LLApp::sApplication = NULL; +// Allows the generation of core files for post mortem under gdb +// and disables crashlogger +BOOL LLApp::sDisableCrashlogger = FALSE; + // Local flag for whether or not to do logging in signal handlers. //static BOOL LLApp::sLogInSignal = FALSE; @@ -81,13 +112,7 @@ 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; -LLAtomicU32* LLApp::sSigChildCount = NULL; -LLAppChildCallback LLApp::sDefaultChildCallback = NULL; -#endif LLApp::LLApp() : mThreadErrorp(NULL) @@ -102,11 +127,6 @@ void LLApp::commonCtor() LLCommon::initClass(); -#if !LL_WINDOWS - // This must be initialized before the error handler. - sSigChildCount = new LLAtomicU32(0); -#endif - // initialize the options structure. We need to make this an array // because the structured data will not auto-allocate if we // reference an invalid location with the [] operator. @@ -124,6 +144,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(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::LLApp(LLErrorThread *error_thread) : @@ -135,10 +161,6 @@ LLApp::LLApp(LLErrorThread *error_thread) : LLApp::~LLApp() { -#if !LL_WINDOWS - delete sSigChildCount; - sSigChildCount = NULL; -#endif // reclaim live file memory std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); @@ -152,6 +174,8 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } + + if(mExceptionHandler != 0) delete mExceptionHandler; LLCommon::cleanupClass(); } @@ -185,8 +209,8 @@ bool LLApp::parseCommandOptions(int argc, char** argv) { if(argv[ii][0] != '-') { - llinfos << "Did not find option identifier while parsing token: " - << argv[ii] << llendl; + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; return false; } int offset = 1; @@ -211,6 +235,20 @@ bool LLApp::parseCommandOptions(int argc, char** argv) } ++ii; value.assign(argv[ii]); + +#if LL_WINDOWS + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } +#endif + commands[name] = value; } setOptionData(PRIORITY_COMMAND_LINE, commands); @@ -255,26 +293,103 @@ void LLApp::stepFrame() mRunner.run(); } +#if LL_WINDOWS +//The following code is needed for 32-bit apps on 64-bit windows to keep it from eating +//crashes. It is a lovely undocumented 'feature' in SP1 of Windows 7. An excellent +//in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ +void EnableCrashingOnCrashes() +{ + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } +} +#endif -void LLApp::setupErrorHandling() +void LLApp::setupErrorHandling(bool second_instance) { // Error handling is done by starting up an error handling thread, which just sleeps and // 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); +#if LL_SEND_CRASH_REPORTS + EnableCrashingOnCrashes(); // 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) + { + if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second + { + mExceptionHandler = new google_breakpad::ExceptionHandler( + L"C:\\Temp\\", + 0, //No filter + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info. + } + else + { + LL_WARNS() << "adding breakpad exception handler" << LL_ENDL; + + std::wstring wpipe_name; + wpipe_name = mCrashReportPipeStr + wstringize(getPid()); + + const std::wstring wdump_path(wstringize(mDumpPath)); + + int retries = 30; + for (; retries > 0; --retries) + { + if (mExceptionHandler != 0) delete mExceptionHandler; + + mExceptionHandler = new google_breakpad::ExceptionHandler( + wdump_path, + NULL, //No filter + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, //Generate a 'normal' minidump. + wpipe_name.c_str(), + NULL); //No custom client info. + if (mExceptionHandler->IsOutOfProcess()) + { + LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL; + break; + } + else + { + LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL; + ::Sleep(100); //Wait a tick and try again. + } + } + + if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL; + } + + if (mExceptionHandler) + { + mExceptionHandler->set_handle_debug_exceptions(true); + } + } +#endif #else // // Start up signal handling. @@ -282,11 +397,61 @@ 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. + bool installHandler = true; +#if LL_DARWIN + // For the special case of Darwin, we do not want to install the handler if + // the process is being debugged as the app will exit with value ABRT (6) if + // we do. Unfortunately, the code below which performs that test relies on + // the structure kinfo_proc which has been tagged by apple as an unstable + // API. We disable this test for shipping versions to avoid conflicts with + // future releases of Darwin. This test is really only needed for developers + // starting the app from a debugger anyway. + #ifndef LL_RELEASE_FOR_DOWNLOAD + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + struct kinfo_proc info; + memset(&info, 0, sizeof(info)); + + size_t size = sizeof(info); + int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + if((result == 0) || (errno == ENOMEM)) + { + // P_TRACED flag is set, so this process is being debugged; do not install + // the handler + if(info.kp_proc.p_flag & P_TRACED) installHandler = false; + } + else + { + // Failed to discover if the process is being debugged; default to + // installing the handler. + installHandler = true; + } + #endif + if(installHandler && (mExceptionHandler == 0)) + { + mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0); + } +#elif LL_LINUX + if(installHandler && (mExceptionHandler == 0)) + { + if (mDumpPath.empty()) + { + mDumpPath = "/tmp"; + } + google_breakpad::MinidumpDescriptor desc(mDumpPath); + mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); + } #endif +#endif startErrorThread(); } @@ -298,7 +463,7 @@ void LLApp::startErrorThread() // if(!mThreadErrorp) { - llinfos << "Starting error thread" << llendl; + LL_INFOS() << "Starting error thread" << LL_ENDL; mThreadErrorp = new LLErrorThread(); mThreadErrorp->setUserData((void *) this); mThreadErrorp->start(); @@ -310,21 +475,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() { @@ -333,11 +483,10 @@ void LLApp::runErrorHandler() LLApp::sErrorHandler(); } - //llinfos << "App status now STOPPED" << llendl; + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; LLApp::setStopped(); } - // static void LLApp::setStatus(EAppStatus status) { @@ -348,15 +497,46 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - if (!isError()) + // set app status to ERROR so that the LLErrorThread notices + setStatus(APP_STATUS_ERROR); +} + +void LLApp::setMiniDumpDir(const std::string &path) +{ + if (path.empty()) + { + mDumpPath = "/tmp"; + } + else { - // perform any needed synchronous error-handling - runSyncErrorHandler(); - // set app status to ERROR so that the LLErrorThread notices - setStatus(APP_STATUS_ERROR); + mDumpPath = path; } + + if(mExceptionHandler == 0) return; +#ifdef LL_WINDOWS + wchar_t buffer[MAX_MINDUMP_PATH_LENGTH]; + mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH); + mExceptionHandler->set_dump_path(std::wstring(buffer)); +#elif LL_LINUX + //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. + google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. + mExceptionHandler->set_minidump_descriptor(desc); +#else + mExceptionHandler->set_dump_path(mDumpPath); +#endif +} + +void LLApp::setDebugFileNames(const std::string &path) +{ + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; } +void LLApp::writeMiniDump() +{ + if(mExceptionHandler == 0) return; + mExceptionHandler->WriteMinidump(); +} // static void LLApp::setQuitting() @@ -364,7 +544,7 @@ void LLApp::setQuitting() if (!isExiting()) { // If we're already exiting, we don't want to reset our state back to quitting. - llinfos << "Setting app state to QUITTING" << llendl; + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; setStatus(APP_STATUS_QUITTING); } } @@ -404,39 +584,35 @@ bool LLApp::isQuitting() return (APP_STATUS_QUITTING == sStatus); } +// static bool LLApp::isExiting() { return isQuitting() || isError(); } -#if !LL_WINDOWS -// static -U32 LLApp::getSigChildCount() +void LLApp::disableCrashlogger() { - if (sSigChildCount) + // Disable Breakpad exception handler. + if (mExceptionHandler != 0) { - return U32(*sSigChildCount); + delete mExceptionHandler; + mExceptionHandler = 0; } - return 0; + + sDisableCrashlogger = TRUE; } // static -void LLApp::incSigChildCount() +bool LLApp::isCrashloggerDisabled() { - if (sSigChildCount) - { - (*sSigChildCount)++; - } + return (sDisableCrashlogger == TRUE); } -#endif - - // static int LLApp::getPid() { #if LL_WINDOWS - return 0; + return GetCurrentProcessId(); #else return getpid(); #endif @@ -453,7 +629,7 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except if (LLApp::isError()) { - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; retval = EXCEPTION_EXECUTE_HANDLER; return retval; } @@ -499,7 +675,7 @@ BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return TRUE; } @@ -512,43 +688,6 @@ BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) } #else //!LL_WINDOWS -void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback) -{ - LLChildInfo child_info; - child_info.mCallback = callback; - LLApp::sChildMap[pid] = child_info; -} - -void LLApp::setDefaultChildCallback(LLAppChildCallback callback) -{ - LLApp::sDefaultChildCallback = callback; -} - -pid_t LLApp::fork() -{ - fflush(NULL); // flush all buffers before the child inherits them - pid_t pid = ::fork(); - if( pid < 0 ) - { - int system_error = errno; - llwarns << "Unable to fork! Operating system error code: " - << system_error << llendl; - } - else if (pid == 0) - { - // Sleep a bit to allow the parent to set up child callbacks. - ms_sleep(10); - - // We need to disable signal handling, because we don't have a - // signal handling thread anymore. - setupErrorHandling(); - } - else - { - llinfos << "Forked child process " << pid << llendl; - } - return pid; -} void setup_signals() { @@ -587,6 +726,7 @@ void setup_signals() // Asynchronous signals that result in core sigaction(SIGQUIT, &act, NULL); + } void clear_signals() @@ -636,7 +776,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl; + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; } @@ -645,28 +785,15 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGCHLD: if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl; + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; } - // Check result code for all child procs for which we've - // registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT - // w/o killing the child (Go, launcher!) - // TODO: Now that we're using SIGACTION, we can actually - // implement the launcher behavior to determine who sent the - // SIGCHLD even if it doesn't result in child termination - if (LLApp::sChildMap.count(info->si_pid)) - { - LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE; - } - - LLApp::incSigChildCount(); - return; case SIGABRT: // Abort just results in termination of the app, no funky error handling. if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGABRT, terminating" << llendl; + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; } clear_signals(); raise(signum); @@ -676,7 +803,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGTERM: if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl; + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; } // Graceful exit // Just set our state to quitting, not error @@ -685,7 +812,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return; } @@ -707,7 +834,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // Smackdown treated just like any other app termination, for now if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling smackdown signal!" << llendl; + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; } else { @@ -721,7 +848,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling fatal signal!" << llendl; + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; } if (LLApp::isError()) { @@ -731,7 +858,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; } raise(signum); return; @@ -739,8 +866,17 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl; + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; } + + if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem + { + clear_signals(); + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; + raise(signum); + return; + } + // Flag status to ERROR, so thread_error does its work. LLApp::setError(); // Block in the signal handler until somebody says that we're done. @@ -751,7 +887,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - App is stopped, reraising signal" << llendl; + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; } clear_signals(); raise(signum); @@ -759,10 +895,156 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } else { if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl; + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; } } } } +#if LL_LINUX +bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, 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 + + //HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space + //to avoid doing allocation during crash. + char * path = LLApp::instance()->getMiniDumpFilename(); + int dir_path_len = strlen(path); + + // The path must not be truncated. + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len; + + llassert( (remaining - strlen(minidump_desc.path())) > 5); + + path += dir_path_len; + + if (dir_path_len > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + + strncpy(path, minidump_desc.path(), remaining); + + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + LLApp::runErrorHandler(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + clear_signals(); + return false; +#else + return true; +#endif + +} +#endif + + +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); + } + + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + LLApp::runErrorHandler(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + clear_signals(); + return false; +#else + return true; +#endif +} #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; + + LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL; + 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); + } + + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + // *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 + LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL; + + if (LLApp::isError()) + { + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; + } + + // 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); + } + +#ifndef LL_RELEASE_FOR_DOWNLOAD + return false; +#else + return true; +#endif +} +#endif |