summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt3
-rw-r--r--indra/llcommon/llapp.cpp243
-rw-r--r--indra/llcommon/llapp.h8
-rw-r--r--indra/llcommon/llcoros.cpp27
-rw-r--r--indra/llcommon/lleventcoro.cpp2
-rw-r--r--indra/llcommon/llsdutil.cpp7
-rw-r--r--indra/llcommon/llsdutil.h4
7 files changed, 272 insertions, 22 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 22dfe12e40..dd266630ea 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -9,6 +9,7 @@ include(Linking)
include(Boost)
include(LLSharedLibs)
include(JsonCpp)
+include(GoogleBreakpad)
include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
@@ -18,6 +19,7 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
+ ${BREAKPAD_INCLUDE_DIRECTORIES}
${URIPARSER_INCLUDE_DIRS}
)
@@ -286,6 +288,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 df2a066f62..6064a843ae 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -46,6 +46,7 @@
#include "llstl.h" // for DeletePointer()
#include "llstring.h"
#include "lleventtimer.h"
+#include "google_breakpad/exception_handler.h"
#include "stringize.h"
#include "llcleanup.h"
#include "llevents.h"
@@ -61,6 +62,12 @@
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()
@@ -139,6 +146,8 @@ 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)
@@ -168,6 +177,8 @@ LLApp::~LLApp()
delete mThreadErrorp;
mThreadErrorp = NULL;
}
+
+ if(mExceptionHandler != 0) delete mExceptionHandler;
SUBSYSTEM_CLEANUP_DBG(LLCommon);
}
@@ -383,18 +394,139 @@ void LLApp::setupErrorHandling(bool second_instance)
#if LL_WINDOWS
+#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
+ 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(utf8str_to_utf16str(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 // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
#else // ! LL_WINDOWS
-#if ! defined(LL_BUGSPLAT)
- //
- // Start up signal handling.
- //
- // 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();
+#if defined(LL_BUGSPLAT)
+ // Don't install our own signal handlers -- BugSplat needs to hook them,
+ // or it's completely ineffectual.
+ bool installHandler = false;
+
+#else // ! LL_BUGSPLAT
+ //
+ // Start up signal handling.
+ //
+ // 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;
#endif // ! LL_BUGSPLAT
+#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 // ! LL_RELEASE_FOR_DOWNLOAD
+
+ 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 // LL_LINUX
+
#endif // ! LL_WINDOWS
#ifdef LL_BUGSPLAT
@@ -482,6 +614,31 @@ void LLApp::setError()
setStatus(APP_STATUS_ERROR);
}
+void LLApp::setMiniDumpDir(const std::string &path)
+{
+ if (path.empty())
+ {
+ mDumpPath = "/tmp";
+ }
+ else
+ {
+ mDumpPath = path;
+ }
+
+ if(mExceptionHandler == 0) return;
+#ifdef LL_WINDOWS
+ std::wstring buffer(utf8str_to_utf16str(mDumpPath));
+ if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH);
+ mExceptionHandler->set_dump_path(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";
@@ -490,6 +647,8 @@ void LLApp::setDebugFileNames(const std::string &path)
void LLApp::writeMiniDump()
{
+ if(mExceptionHandler == 0) return;
+ mExceptionHandler->WriteMinidump();
}
// static
@@ -546,6 +705,13 @@ bool LLApp::isExiting()
void LLApp::disableCrashlogger()
{
+ // Disable Breakpad exception handler.
+ if (mExceptionHandler != 0)
+ {
+ delete mExceptionHandler;
+ mExceptionHandler = 0;
+ }
+
sDisableCrashlogger = TRUE;
}
@@ -939,3 +1105,64 @@ bool unix_post_minidump_callback(const char *dump_dir,
}
#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("CRASHREPORT") << "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
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 83f3bf3f93..5fa91b8bf5 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -49,6 +49,10 @@ void clear_signals();
#endif
+namespace google_breakpad {
+ class ExceptionHandler; // See exception_handler.h
+}
+
class LL_COMMON_API LLApp
{
friend class LLErrorThread;
@@ -232,6 +236,7 @@ public:
static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
// change the directory where Breakpad minidump files are written to
+ void setMiniDumpDir(const std::string &path);
void setDebugFileNames(const std::string &path);
// Return the Google Breakpad minidump filename after a crash.
@@ -311,6 +316,9 @@ private:
private:
// the static application instance if it was created.
static LLApp* sApplication;
+
+ google_breakpad::ExceptionHandler * mExceptionHandler;
+
#if !LL_WINDOWS
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 111c50af93..3693aa3890 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -240,14 +240,25 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
// protected_fixedsize_stack sets a guard page past the end of the new
// stack so that stack underflow will result in an access violation
// instead of weird, subtle, possibly undiagnosed memory stomps.
- boost::fibers::fiber newCoro(boost::fibers::launch::dispatch,
- std::allocator_arg,
- boost::fibers::protected_fixedsize_stack(mStackSize),
- [this, &name, &callable](){ toplevel(name, callable); });
- // You have two choices with a fiber instance: you can join() it or you
- // can detach() it. If you try to destroy the instance before doing
- // either, the program silently terminates. We don't need this handle.
- newCoro.detach();
+
+ try
+ {
+ boost::fibers::fiber newCoro(boost::fibers::launch::dispatch,
+ std::allocator_arg,
+ boost::fibers::protected_fixedsize_stack(mStackSize),
+ [this, &name, &callable]() { toplevel(name, callable); });
+
+ // You have two choices with a fiber instance: you can join() it or you
+ // can detach() it. If you try to destroy the instance before doing
+ // either, the program silently terminates. We don't need this handle.
+ newCoro.detach();
+ }
+ catch (std::bad_alloc&)
+ {
+ // Out of memory on stack allocation?
+ LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL;
+ }
+
return name;
}
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 995356dc52..067b5e6fbc 100644
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -101,7 +101,7 @@ void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value)
}
// Drill down to where we should store 'value'.
- llsd::drill(dest, path) = value;
+ llsd::drill_ref(dest, path) = value;
}
} // anonymous
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index eb3a96b133..fc10fcece3 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llsdutil.h"
+#include <sstream>
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
@@ -862,7 +863,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
namespace llsd
{
-LLSD& drill(LLSD& blob, const LLSD& rawPath)
+LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
{
// Treat rawPath uniformly as an array. If it's not already an array,
// store it as the only entry in one. (But let's say Undefined means an
@@ -917,9 +918,9 @@ LLSD& drill(LLSD& blob, const LLSD& rawPath)
LLSD drill(const LLSD& blob, const LLSD& path)
{
- // non-const drill() does exactly what we want. Temporarily cast away
+ // drill_ref() does exactly what we want. Temporarily cast away
// const-ness and use that.
- return drill(const_cast<LLSD&>(blob), path);
+ return drill_ref(const_cast<LLSD&>(blob), path);
}
} // namespace llsd
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 8678ca97f2..1321615805 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -184,10 +184,10 @@ namespace llsd
* - Anything else is an error.
*
* By implication, if path.isUndefined() or otherwise equivalent to an empty
- * LLSD::Array, drill() returns 'blob' as is.
+ * LLSD::Array, drill[_ref]() returns 'blob' as is.
*/
LLSD drill(const LLSD& blob, const LLSD& path);
-LLSD& drill( LLSD& blob, const LLSD& path);
+LLSD& drill_ref( LLSD& blob, const LLSD& path);
}