summaryrefslogtreecommitdiff
path: root/indra/llcommon/llapp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llapp.cpp')
-rwxr-xr-x[-rw-r--r--]indra/llcommon/llapp.cpp580
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